前言
在这篇文章中介绍了App Store最新的审核政策,其中最需要注意的就是隐私清单(Privacy Manifest)中的所用API声明,毕竟如果你不声明,App Store在机审阶段会直接把你拒了。在2024/05/01之前,暂时还只是收到这样的警告邮件:
Although submission for App Store review was successful, you may want to correct the following issues in your next submission for App Store review. Once you've corrected the issues, upload a new binary to App Store Connect.
ITMS-91053: Missing API declaration - Your app’s code in the “Runner” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryDiskSpace. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.
ITMS-91053: Missing API declaration - Your app’s code in the “Runner” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.
ITMS-91053: Missing API declaration - Your app’s code in the “Runner” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategorySystemBootTime. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.
ITMS-91053: Missing API declaration - Your app’s code in the “Runner” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryUserDefaults. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.
在隐私清单中声明所用API很简单,难的是怎么知道这些API是在哪用到了。我看到文档中列出的这么多API,说实话有点蒙,就算一个个拿去项目中搜索,那也累的够呛,更何况这些API可能在二进制文件里面也有。
当然,以上还不是最麻烦的,最麻烦的是如果第三方库是静态链接库又用了这些API,那么项目最终打包后,这些静态链接库是会和你的程序一起合并到应用的可执行文件。App Store机审的时候用工具一扫,哦吼!你要背锅了,你都不知道应用可执行文件被扫出来的API是哪个第三方库的。
基于以上这些,花时间写了一个脚本专门用于分析项目的隐私清单,经过多次迭代,已经非常易用与准确。强烈推荐大家试试,反正试试也不亏,顶多浪费几分钟,对吧?
开发环境
- macOS: 14.4
项目地址
下载安装
下载最新版本,然后解压即用。
环境要求
需要安装有Xcode Command Line Tools
。
这一般不是问题,都开发iOS项目了,Xcode应该都有安装。
快速使用
通过以下命令开始分析你的项目:
sh analyser.sh <directory_path>
关于脚本路径和项目目录路径问题,最便捷的方式是拖拽。打开终端应用,先输入sh
,然后依次将analyser.sh
脚本文件和项目目录拖入终端应用即可。
脚本开始执行后,如果你分析的是你的项目目录,你会得到类似这样的分析结果:
==================== Analyzing Target Directory ====================
💡 Found privacy manifest file(s): 1
[0] ./Runner/PrivacyInfo.xcprivacy
API usage analysis result(s): 0
✅ All required API reasons have been described in the privacy manifest.
==================== Analyzing Pods Directory ====================
Analyzing FBSDKCoreKit 🎯 ...
💡 Found privacy manifest file(s): 3
[0] ./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit.framework/PrivacyInfo.xcprivacy
[1] ./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit.framework/Versions/A/Resources/PrivacyInfo.xcprivacy
[2] ./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64/FBSDKCoreKit.framework/PrivacyInfo.xcprivacy
API usage analysis result(s): 3
[0] NSPrivacyAccessedAPICategoryUserDefaults:NSUserDefaults:./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64/FBSDKCoreKit.framework/FBSDKCoreKit
[1] NSPrivacyAccessedAPICategoryUserDefaults:NSUserDefaults:./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit.framework/FBSDKCoreKit
[2] NSPrivacyAccessedAPICategoryUserDefaults:NSUserDefaults:./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit.framework/FBSDKCoreKit
✅ All required API reasons have been described in the privacy manifest.
Analyzing DKImagePickerController 🎯 ...
⚠️ Missing privacy manifest file!
API usage analysis result(s): 1
[0] NSPrivacyAccessedAPICategoryFileTimestamp:.modificationDate:./Pods/DKImagePickerController/Sources/DKImagePickerController/DKImageAssetExporter.swift
🛠️ Descriptions for the following required API reason(s) may be missing: 1
[0] NSPrivacyAccessedAPICategoryFileTimestamp
Analyzing SDWebImage 🎯 ...
💡 Found privacy manifest file(s): 1
[0] ./Pods/SDWebImage/WebImage/PrivacyInfo.xcprivacy
API usage analysis result(s): 1
[0] NSPrivacyAccessedAPICategoryFileTimestamp:NSURLContentModificationDateKey,NSURLCreationDateKey:./Pods/SDWebImage/SDWebImage/Core/SDDiskCache.m
✅ All required API reasons have been described in the privacy manifest.
Analyzing Mantle ...
⚠️ Missing privacy manifest file!
API usage analysis result(s): 0
...
==================== Analyzing Flutter Plugins Directory ====================
Analyzing device_info_plus-9.1.0 🎯 ...
⚠️ Missing privacy manifest file!
API usage analysis result(s): 0
Analyzing shared_preferences_ios-2.1.1 🎯 ...
⚠️ Missing privacy manifest file!
API usage analysis result(s): 3
[0] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults,NSUserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/FLTSharedPreferencesPlugin.m
[1] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/messages.g.h
[2] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/messages.g.m
🛠️ Descriptions for the following required API reason(s) may be missing: 1
[0] NSPrivacyAccessedAPICategoryUserDefaults
...
==================== Analysis completed! 💡: 6 ⚠️ : 30 🛠️ : 10 ✅: 6 🎯: 10 ====================
⚠️ 🛠️ https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
🎯 https://developer.apple.com/support/third-party-SDK-requirements
🔔 If the directory you are analyzing is the app project directory, your app's privacy manifest may be affected by these analysis results: 20
[0] NSPrivacyAccessedAPICategoryFileTimestamp:.modificationDate:./Pods/DKImagePickerController/Sources/DKImagePickerController/DKImageAssetExporter.swift
[1] NSPrivacyAccessedAPICategoryFileTimestamp:NSURLContentModificationDateKey,NSURLCreationDateKey:./Pods/SDWebImage/SDWebImage/Core/SDDiskCache.m
[2] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults,NSUserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/FLTSharedPreferencesPlugin.m
[3] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/messages.g.h
[4] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/messages.g.m
...
Target
目录分析,即主要分析你自己的项目代码,Pods
和Flutter Plugins
目录分析的是第三方库(也可能是你自己封装的库)。
如果发现隐私清单文件,会以这样的形式列出:
💡 Found privacy manifest file(s): 3
[0] ./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit.framework/PrivacyInfo.xcprivacy
[1] ./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit.framework/Versions/A/Resources/PrivacyInfo.xcprivacy
[2] ./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64/FBSDKCoreKit.framework/PrivacyInfo.xcprivacy
当存在多个时,会取路径最短的那个用于后面的隐私清单分析(一般没区别)。如果缺失隐私清单会提示:⚠️ Missing privacy manifest file!
。
如果有分析到API使用,会以这样的形式列出:
API usage analysis result(s): 3
[0] NSPrivacyAccessedAPICategoryUserDefaults:NSUserDefaults:./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64/FBSDKCoreKit.framework/FBSDKCoreKit
[1] NSPrivacyAccessedAPICategoryUserDefaults:NSUserDefaults:./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit.framework/FBSDKCoreKit
[2] NSPrivacyAccessedAPICategoryUserDefaults:NSUserDefaults:./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit.framework/FBSDKCoreKit
每条分析结果的内容可以分为三部分(用:
分隔):
- 第一部分是所用API的分类,例如
NSPrivacyAccessedAPICategoryUserDefaults
,也就是填写隐私清单时的Privacy Accessed API Type
- 第二部分是该API分类下使用的API,例如
NSURLContentModificationDateKey,NSURLCreationDateKey
,用,
分隔 - 第三部分是使用该API的文件路径,例如
./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64/FBSDKCoreKit.framework/FBSDKCoreKit
当已有隐私清单文件,又已知用了哪些API,那么很容易就能知道已有隐私清单文件是否填写完整,如果不完整,会列出缺失部分,例如:
🛠️ Descriptions for the following required API reason(s) may be missing: 1
[0] NSPrivacyAccessedAPICategoryUserDefaults
通过以上这些,我想如果只是填写你自己应用代码的API声明,应该很简单了吧。所用API的原因列表选择请看:iOS问题记录 - App Store审核新政策:隐私清单 & SDK签名(持续更新)。
如果遇到疑问,欢迎评论留言私聊或提issue。项目如果对你有所帮助,给个Star🌟支持一下吧!
进阶使用
1. 第三方库怎么处理
项目第一次分析,通常第三方库会有大量的⚠️
,别慌,该升级的升级,升级不了的如果不是常用SDK(没有🎯
标记,还没被App Store重点关注),暂时不管也没什么问题。
对于常用SDK,大可放心,大部分都已经适配,实在不行,自己添加一个隐私清单也不难,用了什么API都已经给你分析出来了。
2. 为什么应用用的API全部已声明还收到警告邮件
这就不得不提到前面一开始的那个难题,如果第三方库是静态链接库又用了这些API,由于项目打包后静态链接库是会和你的程序一起合并到应用的可执行文件,所以你需要在应用的隐私清单中也声明这些第三方库使用的API。
声明很简单,难的是不知道哪个库在哪里用了。这有个办法,打开你的应用程序包(*.app文件),找到里面的Frameworks
目录,和项目全部的库对比,排除掉Frameworks
目录中的动态链接库,剩下的就是会静态链接到应用可执行文件的库。再结合脚本分析结果,你就知道是哪个库在哪里用的了。
感觉也挺麻烦的对不对,所以我花时间帮你做了这部分工作。分析结束后,最后会列出可能影响应用隐私清单的API使用分析结果,类似这样:
🔔 If the directory you are analyzing is the app project directory, your app's privacy manifest may be affected by these analysis results: 20
[0] NSPrivacyAccessedAPICategoryFileTimestamp:.modificationDate:./Pods/DKImagePickerController/Sources/DKImagePickerController/DKImageAssetExporter.swift
[1] NSPrivacyAccessedAPICategoryFileTimestamp:NSURLContentModificationDateKey,NSURLCreationDateKey:./Pods/SDWebImage/SDWebImage/Core/SDDiskCache.m
[2] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults,NSUserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/FLTSharedPreferencesPlugin.m
[3] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/messages.g.h
[4] NSPrivacyAccessedAPICategoryUserDefaults:UserDefaults:./.symlinks/plugins/shared_preferences_ios/ios/Classes/messages.g.m
...
虽然分析结果已经很准确,但是项目多种多样,还不能完全覆盖所有情况,所以也只是说可能影响,需要你再简单确认一下。
项目打包后,强烈建议再用脚本分析一遍*.app
文件,查缺补漏:
sh analyser.sh <*.app>
最后
如果这篇文章对你有所帮助,点赞👍收藏🌟支持一下吧,谢谢~
本篇文章由@crasowas发布于优快云。