diff --git a/.github/workflows/apple-ipad-post-deployment-smoke.yml b/.github/workflows/apple-ipad-post-deployment-smoke.yml index 2ab788d..daf8b1a 100644 --- a/.github/workflows/apple-ipad-post-deployment-smoke.yml +++ b/.github/workflows/apple-ipad-post-deployment-smoke.yml @@ -43,7 +43,7 @@ jobs: test "$(jq -r '.deployment_result' "$evidence")" = DEPLOYED_PENDING_SMOKE manifest="$(mktemp)" trap 'rm -f "$manifest" ipad-apps.json' EXIT - curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_3_3_CURRENT_MAIN_MANIFEST_PROPOSAL.json --output "$manifest" + curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_4_0_RC1_APPLE_OPERATIONAL_MANIFEST.json --output "$manifest" manifest_status="$(jq -r '.status' "$manifest")" case "$manifest_status" in APPROVED_DEPLOYMENT_DISPATCH_PENDING|APPROVED_PARTIAL_DEPLOYMENT_OPERATIONAL) ;; diff --git a/.github/workflows/apple-ipad-secure-distribution-relay.yml b/.github/workflows/apple-ipad-secure-distribution-relay.yml index dae40bf..92088f2 100644 --- a/.github/workflows/apple-ipad-secure-distribution-relay.yml +++ b/.github/workflows/apple-ipad-secure-distribution-relay.yml @@ -40,7 +40,7 @@ jobs: printf '%s' "$PLATFORM_VERSION" | grep -Eq '^[0-9]+\.[0-9]+$' manifest="$(mktemp)" trap 'rm -f "$manifest"' EXIT - curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_3_3_CURRENT_MAIN_MANIFEST_PROPOSAL.json --output "$manifest" + curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_4_0_RC1_APPLE_OPERATIONAL_MANIFEST.json --output "$manifest" manifest_status="$(jq -r '.status' "$manifest")" case "$manifest_status" in APPROVED_DEPLOYMENT_DISPATCH_PENDING|APPROVED_PARTIAL_DEPLOYMENT_OPERATIONAL) ;; @@ -49,7 +49,7 @@ jobs: test "$(jq -r '.approval.state' "$manifest")" = APPROVED test "$(jq -r '.manifest_id' "$manifest")" = "$MANIFEST_ID" test "$(jq -r '.release_profile' "$manifest")" = "$RELEASE_PROFILE" - release_version="$(jq -r --arg sha "$CANDIDATE_SHA" '.repositories[] | select(.repository == "pcvantol/djconnect-app" and .source_sha == $sha and .version == "3.3.0") | .version' "$manifest")" + release_version="$(jq -r --arg sha "$CANDIDATE_SHA" '.repositories[] | select(.repository == "pcvantol/djconnect-app" and .source_sha == $sha and .version == "4.0.0") | .version' "$manifest")" printf '%s' "$release_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' test "$ARTIFACT_ID" = "release-asset:pcvantol/djconnect-app-releases:ios/v${release_version}:DJConnect-iOS-${release_version}-unsigned.zip" binding="$(jq -cer --arg artifact "$ARTIFACT_ID" --arg checksum "$ARTIFACT_SHA256" '.artifact_bindings[] | select(.target == "apple_private_device" and .target_device == "ipad" and .artifact_id == $artifact and .artifact_sha256 == $checksum and .signing == "local_developer_provisioning_required" and (has("paired_watch_validation") | not))' "$manifest")" diff --git a/.github/workflows/apple-iphone-post-deployment-smoke.yml b/.github/workflows/apple-iphone-post-deployment-smoke.yml index fe619c3..da9cb52 100644 --- a/.github/workflows/apple-iphone-post-deployment-smoke.yml +++ b/.github/workflows/apple-iphone-post-deployment-smoke.yml @@ -43,7 +43,7 @@ jobs: test "$(jq -r '.deployment_result' "$evidence")" = DEPLOYED_PENDING_SMOKE manifest="$(mktemp)" trap 'rm -f "$manifest" iphone-apps.json watch-apps.json' EXIT - curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_3_3_CURRENT_MAIN_MANIFEST_PROPOSAL.json --output "$manifest" + curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_4_0_RC1_APPLE_OPERATIONAL_MANIFEST.json --output "$manifest" manifest_status="$(jq -r '.status' "$manifest")" case "$manifest_status" in APPROVED_DEPLOYMENT_DISPATCH_PENDING|APPROVED_PARTIAL_DEPLOYMENT_OPERATIONAL) ;; diff --git a/.github/workflows/apple-iphone-secure-distribution-relay.yml b/.github/workflows/apple-iphone-secure-distribution-relay.yml index dbfaa7e..25b6940 100644 --- a/.github/workflows/apple-iphone-secure-distribution-relay.yml +++ b/.github/workflows/apple-iphone-secure-distribution-relay.yml @@ -41,7 +41,7 @@ jobs: printf '%s' "$PLATFORM_VERSION" | grep -Eq '^[0-9]+\.[0-9]+$' manifest="$(mktemp)" trap 'rm -f "$manifest"' EXIT - curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_3_3_CURRENT_MAIN_MANIFEST_PROPOSAL.json --output "$manifest" + curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_4_0_RC1_APPLE_OPERATIONAL_MANIFEST.json --output "$manifest" manifest_status="$(jq -r '.status' "$manifest")" case "$manifest_status" in APPROVED_DEPLOYMENT_DISPATCH_PENDING|APPROVED_PARTIAL_DEPLOYMENT_OPERATIONAL) ;; @@ -50,7 +50,7 @@ jobs: test "$(jq -r '.approval.state' "$manifest")" = APPROVED test "$(jq -r '.manifest_id' "$manifest")" = "$MANIFEST_ID" test "$(jq -r '.release_profile' "$manifest")" = "$RELEASE_PROFILE" - jq -e --arg sha "$CANDIDATE_SHA" '.repositories[] | select(.repository == "pcvantol/djconnect-app" and .source_sha == $sha and .version == "3.3.0")' "$manifest" >/dev/null + jq -e --arg sha "$CANDIDATE_SHA" '.repositories[] | select(.repository == "pcvantol/djconnect-app" and .source_sha == $sha and .version == "4.0.0")' "$manifest" >/dev/null binding="$(jq -cer --arg artifact "$ARTIFACT_ID" --arg checksum "$ARTIFACT_SHA256" '.artifact_bindings[] | select(.target == "apple_private_device" and .target_device == "iphone" and .paired_watch_validation == "required" and .artifact_id == $artifact and .artifact_sha256 == $checksum and .signing == "local_developer_provisioning_required")' "$manifest")" printf 'artifact_url=%s\n' "$(jq -r '.artifact_url' <<<"$binding")" >> "$GITHUB_OUTPUT" - name: Verify exact physical iPhone, paired Watch and local signing scope diff --git a/.github/workflows/apple-post-deployment-smoke.yml b/.github/workflows/apple-post-deployment-smoke.yml index 4d89fa4..b715d11 100644 --- a/.github/workflows/apple-post-deployment-smoke.yml +++ b/.github/workflows/apple-post-deployment-smoke.yml @@ -61,7 +61,7 @@ jobs: set -euo pipefail manifest="$(mktemp)" trap 'rm -f "$manifest"' EXIT - curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_3_3_CURRENT_MAIN_MANIFEST_PROPOSAL.json --output "$manifest" + curl --fail --silent --show-error --location https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_4_0_RC1_APPLE_OPERATIONAL_MANIFEST.json --output "$manifest" manifest_status="$(jq -r '.status' "$manifest")" case "$manifest_status" in APPROVED_DEPLOYMENT_DISPATCH_PENDING|APPROVED_PARTIAL_DEPLOYMENT_OPERATIONAL) ;; diff --git a/.github/workflows/apple-secure-distribution-relay.yml b/.github/workflows/apple-secure-distribution-relay.yml index 82f520a..c110e8e 100644 --- a/.github/workflows/apple-secure-distribution-relay.yml +++ b/.github/workflows/apple-secure-distribution-relay.yml @@ -65,7 +65,7 @@ jobs: manifest="$(mktemp)" trap 'rm -f "$manifest"' EXIT curl --fail --silent --show-error --location \ - https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_3_3_CURRENT_MAIN_MANIFEST_PROPOSAL.json \ + https://raw.githubusercontent.com/pcvantol/djconnect/main/docs/release/PLATFORM_4_0_RC1_APPLE_OPERATIONAL_MANIFEST.json \ --output "$manifest" manifest_status="$(jq -r '.status' "$manifest")" case "$manifest_status" in diff --git a/Apps/DJConnectWatch/DJConnectWatchModel.swift b/Apps/DJConnectWatch/DJConnectWatchModel.swift index fcadddc..ea5f19e 100644 --- a/Apps/DJConnectWatch/DJConnectWatchModel.swift +++ b/Apps/DJConnectWatch/DJConnectWatchModel.swift @@ -517,7 +517,7 @@ final class DJConnectWatchModel: NSObject, ObservableObject { sendCompanionPairingRegistration() } } - appendDiagnosticLog("Version metadata: release_version=\(DJConnectApplicationVersion.releaseVersion); build_version=\(DJConnectApplicationVersion.buildVersion); protocol_version=\(DJConnectProtocolVersion.current)") + appendDiagnosticLog("Version metadata: release_version=\(DJConnectApplicationVersion.releaseVersion); public_release=\(DJConnectApplicationVersion.publicReleaseIdentity); build_version=\(DJConnectApplicationVersion.buildVersion); protocol_version=\(DJConnectProtocolVersion.current)") if !isDemoMode { startNetworkMonitor() } diff --git a/CHANGELOG.md b/CHANGELOG.md index c699ae6..d2d2c81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to DJConnect App are documented here. ## Unreleased +## 4.0.0-rc.1 - 2026-08-06 + +### Changed + +- Prepare the native Apple `4.0.0` / build `40001` package for the Platform + `4.0.0-rc.1` candidate and report the RC identity in diagnostics. +- Move the Apple runtime protocol contract to `4.0.0-rc.1`, which enforces the + shared `4.0` compatibility line with Home Assistant. + ## 3.2.35 - 2026-07-09 ### Fixed diff --git a/DJConnectApp.xcodeproj/project.pbxproj b/DJConnectApp.xcodeproj/project.pbxproj index 2bd5d41..32ab778 100644 --- a/DJConnectApp.xcodeproj/project.pbxproj +++ b/DJConnectApp.xcodeproj/project.pbxproj @@ -1749,7 +1749,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 40001; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -1770,7 +1770,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 26.0; MACOSX_DEPLOYMENT_TARGET = 26.0; - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 4.0.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -1898,7 +1898,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 40001; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; ENABLE_NS_ASSERTIONS = NO; @@ -1913,7 +1913,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 26.0; MACOSX_DEPLOYMENT_TARGET = 26.0; - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 4.0.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/README.md b/README.md index 8025c8f..9a3d61f 100644 --- a/README.md +++ b/README.md @@ -607,7 +607,7 @@ must keep pairing and token state, show an update-required state, and pause command/voice retries until the app or integration is updated. Successful status and command responses may also include `ha_version` or -`ha_major_minor`. App `3.2.x` requires HA integration `3.2.x` and disables +`ha_major_minor`. App `4.0.x` requires HA integration `4.0.x` and disables playback, queue, playlist, output, liked, and voice controls when the runtime contract is outside that range. Settings and pairing reset remain available. diff --git a/Sources/DJConnectCore/DJConnectModels.swift b/Sources/DJConnectCore/DJConnectModels.swift index 656b284..147bb54 100644 --- a/Sources/DJConnectCore/DJConnectModels.swift +++ b/Sources/DJConnectCore/DJConnectModels.swift @@ -1,6 +1,9 @@ import Foundation public enum DJConnectApplicationVersion { + /// Public cross-platform identity for the native numeric 4.0.0 / 40001 package. + public static let publicReleaseIdentity = "4.0.0-rc.1" + public static var releaseVersion: String { bundleValue(for: "CFBundleShortVersionString") } @@ -20,7 +23,7 @@ public enum DJConnectApplicationVersion { } public enum DJConnectProtocolVersion { - public static let current = "3.2.33" + public static let current = "4.0.0-rc.1" } public enum DJConnectClientType: String, Codable, Sendable { diff --git a/Tests/DJConnectCoreTests/DJConnectCoreTests.swift b/Tests/DJConnectCoreTests/DJConnectCoreTests.swift index e105edb..a2eff20 100644 --- a/Tests/DJConnectCoreTests/DJConnectCoreTests.swift +++ b/Tests/DJConnectCoreTests/DJConnectCoreTests.swift @@ -1151,6 +1151,11 @@ private func makePairedMusicDNAModel( #expect(watchAboutSource.contains("DJConnectApplicationVersion.releaseVersion")) } +@Test func platformFourReleaseCandidateUsesNativePackageAndPublicProtocolMapping() { + #expect(DJConnectApplicationVersion.publicReleaseIdentity == "4.0.0-rc.1") + #expect(DJConnectProtocolVersion.current == "4.0.0-rc.1") +} + @Test func homeAssistantClientRoutesUseCanonicalV1Prefix() throws { let checkedRoots = ["Sources", "Apps"] let legacyRoutes = [ @@ -10303,9 +10308,9 @@ private func makePairedMusicDNAModel( )) let updateMessage = try #require(model.updateRequiredMessage) - #expect(updateMessage.contains("3.2.x")) - #expect(updateMessage.contains(">=3.2.0")) - #expect(updateMessage.contains("<3.3.0")) + #expect(updateMessage.contains("4.0.x")) + #expect(updateMessage.contains(">=4.0.0")) + #expect(updateMessage.contains("<4.1.0")) #expect(model.canUsePlaybackFeatures == false) #expect(model.backendAvailable == false) #expect(model.playback == nil) @@ -10327,7 +10332,7 @@ private func makePairedMusicDNAModel( model.apply(commandResponse: DJConnectCommandResponse( success: true, backendAvailable: true, - haVersion: "3.2.99", + haVersion: "4.0.99", playback: DJConnectPlayback(trackName: "Compatible Track") )) model.apply(musicBackendSummary: DJConnectMusicBackendSummary(remoteSupported: true)) diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 3dfa6ab..a30d512 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -279,7 +279,7 @@ protocol version: - HA `3.0.z` accepts clients `3.0.z`. - HA `3.1.z` accepts clients `3.1.z`. -- HA `3.2.z` accepts clients `3.2.z`. +- HA `4.0.z` accepts clients `4.0.z`. - Patch versions may differ. - `0.0.0` is reserved as a dev-client escape hatch. @@ -288,8 +288,8 @@ reset pairing or discard the token. Show an update-required state and pause command/voice retries until the user updates the app or integration. The Apple app also validates `ha_version` / `ha_major_minor` fields on normal -status and command responses. App `3.2.x` requires HA integration `3.2.x` -(`>=3.2.0`, `<3.3.0`). If HA is outside that range, the app must show a clear +status and command responses. App `4.0.x` requires HA integration `4.0.x` +(`>=4.0.0`, `<4.1.0`). If HA is outside that range, the app must show a clear message to update the Home Assistant integration, disable playback/output/ queue/playlist/liked/voice controls, and keep Settings plus pairing reset available. diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 737cdde..a13e3df 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -68,8 +68,10 @@ After renewing the Apple Developer Program membership: Local Network, Microphone, Speech Recognition. - Confirm app icons, launch screen, welcome screen, About screen, and website link match the current DJConnect branding. -- Confirm the HA integration compatibility line is documented: - app `3.2.x` requires HA integration `3.2.x`. +- Confirm the HA integration compatibility line is documented. For this + candidate, Apple clients and HA integration use the shared `4.0` line; the + native Apple package remains numeric `4.0.0` while the platform identity is + `4.0.0-rc.1`. - Confirm the public macOS release helper works in dry/local mode before the first public binary release. diff --git a/docs/release-notes/de/v4.0.0.md b/docs/release-notes/de/v4.0.0.md new file mode 100644 index 0000000..4b4071c --- /dev/null +++ b/docs/release-notes/de/v4.0.0.md @@ -0,0 +1,9 @@ +# DJConnect App 4.0.0 RC 1 + +## Geändert + +- Dieser interne Release Candidate bringt die Clients für iPhone, iPad und + Apple Watch auf die gemeinsame DJConnect-4.0-Kompatibilitätslinie. +- Der Bereitstellungsweg für private Geräte prüft jetzt das spezielle + Betriebsmanifest für Platform 4.0, bevor ein freigegebener Build installiert wird. + diff --git a/docs/release-notes/en/v4.0.0.md b/docs/release-notes/en/v4.0.0.md new file mode 100644 index 0000000..f228610 --- /dev/null +++ b/docs/release-notes/en/v4.0.0.md @@ -0,0 +1,9 @@ +# DJConnect App 4.0.0 RC 1 + +## Changed + +- This internal release candidate moves the iPhone, iPad, and Apple Watch + clients to the shared DJConnect 4.0 compatibility line. +- The private-device deployment route now validates the dedicated Platform 4.0 + operational manifest before it installs an approved build. + diff --git a/docs/release-notes/es/v4.0.0.md b/docs/release-notes/es/v4.0.0.md new file mode 100644 index 0000000..e983982 --- /dev/null +++ b/docs/release-notes/es/v4.0.0.md @@ -0,0 +1,9 @@ +# DJConnect App 4.0.0 RC 1 + +## Cambiado + +- Esta versión candidata interna lleva los clientes de iPhone, iPad y Apple + Watch a la línea de compatibilidad compartida de DJConnect 4.0. +- La ruta de despliegue para dispositivos privados ahora valida el manifiesto + operativo específico de Platform 4.0 antes de instalar una compilación aprobada. + diff --git a/docs/release-notes/fr/v4.0.0.md b/docs/release-notes/fr/v4.0.0.md new file mode 100644 index 0000000..5013380 --- /dev/null +++ b/docs/release-notes/fr/v4.0.0.md @@ -0,0 +1,9 @@ +# DJConnect App 4.0.0 RC 1 + +## Modifié + +- Cette version candidate interne aligne les clients iPhone, iPad et Apple + Watch sur la ligne de compatibilité partagée DJConnect 4.0. +- Le parcours de déploiement sur appareil privé vérifie désormais le manifeste + opérationnel dédié à Platform 4.0 avant d’installer une build approuvée. + diff --git a/docs/release-notes/nl/v4.0.0.md b/docs/release-notes/nl/v4.0.0.md new file mode 100644 index 0000000..ba13307 --- /dev/null +++ b/docs/release-notes/nl/v4.0.0.md @@ -0,0 +1,9 @@ +# DJConnect App 4.0.0 RC 1 + +## Gewijzigd + +- Deze interne release candidate brengt de iPhone-, iPad- en Apple + Watch-clients naar de gedeelde DJConnect 4.0-compatibiliteitslijn. +- De private-device-uitrol controleert nu het specifieke Platform + 4.0-operationele manifest vóór een goedgekeurde build wordt geïnstalleerd. + diff --git a/project.yml b/project.yml index 490953b..535ddac 100644 --- a/project.yml +++ b/project.yml @@ -10,8 +10,8 @@ options: settings: base: SWIFT_VERSION: "6.0" - CURRENT_PROJECT_VERSION: "1" - MARKETING_VERSION: "3.3.0" + CURRENT_PROJECT_VERSION: "40001" + MARKETING_VERSION: "4.0.0" DEVELOPMENT_TEAM: "" CODE_SIGN_STYLE: Automatic packages: {}