From f5d3810f5f43d2061eef8679a52478462f60ac6b Mon Sep 17 00:00:00 2001 From: EdisonJwa Date: Sat, 16 May 2026 16:03:39 +0900 Subject: [PATCH] feat(ios,macos): Apple privacy manifest (PrivacyInfo.xcprivacy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apple has enforced a `PrivacyInfo.xcprivacy` privacy manifest at App Store submission since May 2024 for iOS / iPadOS / visionOS / watchOS, and rolled the requirement out to macOS in late 2024. Without the file, App Store Connect rejects archive uploads with "missing required privacy manifest". This commit adds the manifest for both iOS and macOS Runner targets. apps/chanora_flutter/ios/Runner/PrivacyInfo.xcprivacy apps/chanora_flutter/macos/Runner/PrivacyInfo.xcprivacy Identical content. Declarations: NSPrivacyCollectedDataTypes: NSPrivacyCollectedDataTypeAudioData Microphone audio transmitted to the user's chosen voice server while connected and unmuted. Not linked to user identity (no Apple ID / IDFA tied), not used for tracking. Purpose: AppFunctionality (communications). NSPrivacyTracking: false NSPrivacyTrackingDomains: [] Chanora performs no cross-app / cross-website tracking. NSPrivacyAccessedAPITypes: FileTimestamp (C617.1) tokio + rusqlite file I/O for identity.tskey, chanora.db, audio_meta.json, chanora.log inside the app container. UserDefaults (CA92.1) Indirect via path_provider Flutter plugin querying for Application Support / Documents directories. SystemBootTime (35F9.1) tracing-subscriber timestamps log records relative to boot. DiskSpace (85F4.1) rusqlite checks before sqlite page writes. All four "required reason" API categories use Apple's published allow-list reason codes; no fingerprinting / analytics usage. apps/chanora_flutter/ios/Runner.xcodeproj/project.pbxproj apps/chanora_flutter/macos/Runner.xcodeproj/project.pbxproj Added PrivacyInfo.xcprivacy to the Runner group and to the Runner target's "Copy Bundle Resources" build phase via the xcodeproj Ruby gem (via a one-shot script). With this, the file is placed at Runner.app/PrivacyInfo.xcprivacy where Apple's validator looks for it — `find Runner.app -name PrivacyInfo.xcprivacy` shows our manifest at the bundle root alongside Flutter's and connectivity_plus's. Verified on the M1 Mac (coder@100.118.130.73): flutter build ios --release --no-codesign 4.0 s -> Runner.app/PrivacyInfo.xcprivacy present flutter build ipa --release --no-codesign 28.4 s -> Runner.xcarchive built (171.4 MB) -> archive's Runner.app/PrivacyInfo.xcprivacy present -> archive's Runner.app/Frameworks/chanora_bridge.framework built fresh via the chanora_bridge.podspec prepare_command under xcodebuild's sandbox (no PATH / env weirdness). P1 follow-ups noted by xcodebuild's validator (not blockers for this commit but for App Store submission): * Real app icon (currently default placeholder) * Real launch image (currently default placeholder) * Paid Apple Developer Program account, registered App ID, and Distribution provisioning profile (Personal Team sideloads still work as today). --- .../ios/Runner.xcodeproj/project.pbxproj | 4 + .../ios/Runner/PrivacyInfo.xcprivacy | 114 ++++++++++++++++++ .../macos/Runner.xcodeproj/project.pbxproj | 4 + .../macos/Runner/PrivacyInfo.xcprivacy | 114 ++++++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 apps/chanora_flutter/ios/Runner/PrivacyInfo.xcprivacy create mode 100644 apps/chanora_flutter/macos/Runner/PrivacyInfo.xcprivacy diff --git a/apps/chanora_flutter/ios/Runner.xcodeproj/project.pbxproj b/apps/chanora_flutter/ios/Runner.xcodeproj/project.pbxproj index 6b7db73..338213f 100644 --- a/apps/chanora_flutter/ios/Runner.xcodeproj/project.pbxproj +++ b/apps/chanora_flutter/ios/Runner.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + FD3C80659716BF7A0C95C7AF /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 1937FD83C5CC909094CDC137 /* PrivacyInfo.xcprivacy */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -47,6 +48,7 @@ 0B4754099284EEDCD859A973 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1937FD83C5CC909094CDC137 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; @@ -164,6 +166,7 @@ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + 1937FD83C5CC909094CDC137 /* PrivacyInfo.xcprivacy */, ); path = Runner; sourceTree = ""; @@ -267,6 +270,7 @@ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + FD3C80659716BF7A0C95C7AF /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/apps/chanora_flutter/ios/Runner/PrivacyInfo.xcprivacy b/apps/chanora_flutter/ios/Runner/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..5b07871 --- /dev/null +++ b/apps/chanora_flutter/ios/Runner/PrivacyInfo.xcprivacy @@ -0,0 +1,114 @@ + + + + + + + + NSPrivacyCollectedDataTypes + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeAudioData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + + NSPrivacyAccessedAPITypes + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + 85F4.1 + + + + + diff --git a/apps/chanora_flutter/macos/Runner.xcodeproj/project.pbxproj b/apps/chanora_flutter/macos/Runner.xcodeproj/project.pbxproj index 1998a6d..07e62ca 100644 --- a/apps/chanora_flutter/macos/Runner.xcodeproj/project.pbxproj +++ b/apps/chanora_flutter/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 45F255D1DE0134185DB5423D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 06E1AA7E1FB968C1D78DA8DE /* PrivacyInfo.xcprivacy */; }; 9B86175918197ECC64969956 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EFEADEEFAB54DFEAAD7A70E9 /* Pods_Runner.framework */; }; C2DC22E19FDCE26B9D79442E /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FDE04BBB936AA14C2B58FA0E /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ @@ -62,6 +63,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 06E1AA7E1FB968C1D78DA8DE /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; @@ -181,6 +183,7 @@ 33E51914231749380026EE4D /* Release.entitlements */, 33CC11242044D66E0003C045 /* Resources */, 33BA886A226E78AF003329D5 /* Configs */, + 06E1AA7E1FB968C1D78DA8DE /* PrivacyInfo.xcprivacy */, ); path = Runner; sourceTree = ""; @@ -315,6 +318,7 @@ files = ( 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + 45F255D1DE0134185DB5423D /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/apps/chanora_flutter/macos/Runner/PrivacyInfo.xcprivacy b/apps/chanora_flutter/macos/Runner/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..5b07871 --- /dev/null +++ b/apps/chanora_flutter/macos/Runner/PrivacyInfo.xcprivacy @@ -0,0 +1,114 @@ + + + + + + + + NSPrivacyCollectedDataTypes + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeAudioData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + + NSPrivacyAccessedAPITypes + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + 85F4.1 + + + + +