这个话题的起因来自 2023 年 WWDC 之后苹果发布的「App Store 提交隐私更新」政策,政策主要提出了两点:第三方 SDK 隐私清单和签名和需要提供必要理由的 API 流程。
其实先简单总结,就是 Apple 想通过隐私清单来进一步提升用户数据收集和使用的透明度,包括 required reason API 也是算是属于隐私清单里的内容。
那这个和标题里的 Flutter 有什么关系?因为跟随此次隐私清单升级, Apple 上线了一个**对用户隐私产生重大影响的第三方 SDK 列表** ,而在这列表恰好就有 Flutter 的存在,并且里面接近 1/3 是和 Flutter 相关的 Plugin ,例如 connectivity_pulus
、device_info_plus
、fluttertoast
、shared_preferences_ios
、sqflite
、webview_flutter_wkwebview
、url_launcher
等等。
列表地址:https://developer.apple.com/support/third-party-SDK-requirements/
这就很懵逼了,是 Flutter 做了什么「天怒人怨」的问题,还是 Apple 故意针对 Flutter 呢?那在聊这个问题之前,我们首先需要简单了解下,这次的隐私标签里主要涉及的是什么?
这个问题不只是对 Flutter ,其实对于 iOS 来说 2024 在 Xcode15 上也属于最重要的适配需求。
隐私清单
**聊隐私清单,首先最主要是就是第三方隐私清单(privacy manifest) **,属于让 SDK 开发人员提供他们 SDK 的一些数据收集行为,然后 App 开发者在集成各种 SDK 之后,可以得到一份详细的隐私清单,如下图是 SDK 里声明的隐私清单。
隐私清单的作用是帮助开发者了解第三方 SDK 如何使用数据,这样开发者在向 App Store 提交审核时,Xcode 可以将第三方 SDK 中的隐私清单合并,然后导出一个 PDF 报告汇总。
通过这份隐私清单报告,开发者就可以在 App Store 提交审核时,更方便地提供「隐私标签」,如下图所示就是 iOS 14 时 App Store 推出的功能,当时就要求 App 开发者在 App Store 后台声明应用的数据收集和使用场景,让用户在应用详情页面知道 App 收集了什么和做了什么。
那么首先可以知道,SDK 隐私清单的作用,就是让 App 开发者可以根据生成的清单,更好精确和方便地管理自己 App 的隐私标签,一般情况下大概会有:
-
收集的数据类型
-
数据是否能关联到用户
-
数据是否用于跟踪活动
-
收集此数据的理由
其中关于数据类型可见:https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests
那如果我不需要隐私清单来管理隐私标签,就可以理会这次的隐私清单的事情了呢?那答案肯定不是,因为隐私标签还包含了其他东西,比如必要理由的 API 声明、声明跟踪域名和第三方 SDK 签名等。
必要理由的 API 声明
首先这个主要是 Apple 新搞了一个 API 分类, 使用这一个 API 分类你需要在隐私清单里说明使用理由, Apple 这么做的目的是主要是想规范 App 随意通过这些 API 做 fingerprinting 识别的行为,相关的 API 也不多,大概涉及:
- File timestamp APIs
- System boot time APIs
- Disk space APIs
- Active keyboard APIs
- User defaults APIs
如果 SDK 和 App 里用到了分类里的这些 API ,你就需要在隐私列表里填写原因,例如:
使用了 Disk space APIs 的
systemFreeSize
,在写入前判断磁盘空间大小,那么就需要引用列表里的E174.1
条款,如下图写明使用的原因。
从目前看,类似 UserDefaults
、stat
等 API 还是很容易被使用到,所以 Required Reason API 这部分应该都是跑不掉的。
条款列表可见:https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
声明跟踪域名
隐私清单其实一定程度也算是应用跟踪透明度 (ATT) 的内容之一,而本次更新,如果用户未通过 App Tracking Transparency (ATT) 授予权限, Apple 就会阻止对追踪域(Tracking Domains)的网络请求。
简单来说,就是需要定义一个 NSPrivacyTrackingDomains
列表,这样但用户不同意 ATT 权限时, 系统就会阻止这些域名的任何调用,所以 SDK 上如果有类似相关跟踪的域名调用,也需要区分声明好跟踪域名和非跟踪域名。
当然,不管你是否利用 ATT 的定义进行跟踪,你都必须在隐私清单中列出收集的数据类型和原因,因为这个和 ATT 没有必然关系,只是如果使用了 ATT 的域名,在这里需要额外声明来符合权限, ATT 在 iOS 17 上实际并没有什么变化。
这里的跟踪定义是:能狗将你收集的数据与其他公司 App 收集的数据相关联,比如使用了 IDFV 也算跟踪,。
只是这里我有个疑问,如果我不把 ATT 的相关收集域名放到 NSPrivacyTrackingDomains
列表,其实 Apple 是审核是不是也无法明确发现呢?那么我不做是不是也是可以?
第三方 SDK 签名
本次跟随隐私清单而来的还有第三方 SDK 签名,这是我们以前一直忽略的东西,而 Apple 的目的也很直接,就是希望通过签名认证的方式来确保 SDK 不会被篡改,简单的说就是 SDK 发布时带有 _CodeSignature
。
需要签名,肯定是 SDK 包含了二进制依赖,没有二进制依赖其实并不需要考虑签名问题。
这里的签名其实分 Apple Developer Program 签名和自签名,如果你的 SDK 使用的是 Apple Developer Program ,简单来说就是可以得到更安全可靠的认知加持,安全性拉满,但是如果你采用的是 codesign 自签名,那么也不是不行,就是你自己保管好签名认证的方式。
echo "Build Archive Device Slice"
xcodebuild clean archive -sdk iphoneos -destination 'generic/platform=iOS'[...]
echo "Build Archive Simulator Slice"
xcodebuild clean archive -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' [...]
echo "Create XCFramework"
xcodebuild -create-xcframework [...] -output <YOUR.xcframework>
echo "Codesign XCFramework"
codesign --timestamp -v --sign "<YOUR CERTIFICATE (ABCXYZ)>" "<YOUR.xcframework>"
经过签名认证后的 SDK ,在 Xcode15 会显示对应的 Signature 信息,如果一旦发现本次前面和上次不一致,那么Xcode 就会让编译失败并弹出警告。
当然,如果 SDK 的签名变更符合你预期,比如 SDK 维护人员发生了变化,从而导致证书发生变化,那么你也可以通过接受变更的方式也同意更改。总的来说目前这个阶段签名并不是一定要官方,甚至不一定就强制要签名,Apple 「鼓励】所有 SDK 使用签名,但影响隐私的 SDK 一定要签名,特别是前面提到列表里的。
目前来说,App Store 已经开始检查最近提交的 App 是否包含影响隐私的 SDK ,如果影响隐私的 SDK 不包含签名和隐私清单,Apple 将向应用开发人员发送提醒邮件,包括提供必要理由的 API 部分,最后会在 2024 年春季开始要求审核。
更多官方资料:
- https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api#4278397
- https://developer.apple.com/documentation/Xcode/verifying-the-origin-of-your-xcframeworks
- https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests?language=objc
Flutter
那本次隐私清单对于 Flutter 来说,最大的影响就是大量 Flutter Plugin 被挂上了 Apple 官方的用户隐私产生重大影响的第三方 SDK 列表,因为上了列表,就被认定为是影响隐私的 SDK,那么隐私清单是跑不了的了,另外如果有二进制依赖还需要满足签名条件,所以这对于 Flutter 来说在 iOS 17的适配上无疑「雪上加霜」,可以看到目前官方开了很多关于官方 package 的 iOS 隐私清单适配 issue 。
对于 Flutter Engine 部分,其实官方适配隐私清单难度并不大,目前调查完 iOS 上 Flutter Engine 主要需要适配的有:
-
File timestamps :
C617.1
用于FlutterAppDelegate.mm
里的应用状态恢复0A2A.1
用于实施相关File
包装器
-
System boot time:
35F9.1
用于各种事件计时和经过时间的计算
目前官方在 #131494 已经表示,会将 PrivacyInfo.xcprivacy
包含在未来 Flutter.framework
中,所以这部分并不需要担心。
而在 flutter/packages 部分目前却是有棘手的问题,例如 shared_preferences
,它被列入影响隐私 SDK 列表的原因是因为 NSUserDefaults
,但是 shared_preferences
它本身只是 API 的封装,为了方便 Flutter 开发者调用,它本身是不知道如何/为什么使用它,在 SDK 层面很难在隐私清单描述给出所谓的「收集原因」。
另外第三方 Plugin 也可能使用 shared_preferences
,但是 App 开发并不知道它用来做什么,那么如果让 pub 的 Plugin 能描述好隐私清单的内容?
目前官方文档提及:
If you use the API in your third-party SDK’s code, then you need to report the API in your third-party SDK’s privacy manifest file
这听起来像是只要拥有它的代码就需要标记出它的原因,但是实际上 Plugin 不知道该层存储的数据是什么或如何被使用。
对于 “收集” 的定义目前很模糊,类似的还有 webview_flutter
,webview_flutter
本身不收集任何内容,但是App 可以用来 webview_flutter
收集浏览历史记录,然后这如何在 SDK 的隐私清单里去体现?
感觉目前的 iOS 要求没有很明确,适配方向不够清晰。
最后,目前文档说他们「鼓励」每个人都采用该清单,而对于在隐私列表的 SDK 看起来是强制的,但是如何选择这些 SDK 的规则目前也看不到,所以只能等待后续和 Apple 的沟通回复。
更多进度可见:
- https://github.com/flutter/flutter/issues/131940
- https://github.com/flutter/flutter/issues/131495
- https://github.com/flutter/flutter/issues/131494
最后
总结一下,本次 iOS 隐私清单主要覆盖的有:
- SDK 提供隐私清单的数据收集类型、使用描述和用途
- 必要理由的 API 需要提供使用“代码”和原因
- ATT 跟踪添加域名区分
- 第三方 SDK 签名
这里面 SDK 提供的隐私清单,我个人理解:
- 首要是用来给 App 打包后,通过导出的 pdf 参考管理隐私标签
- 其次对于必要理由的 API 的使用附带使用说明
- 关于 ATT 收集相关的数据域名添加到清单进行区分,至于你不写是否会被抓住不好说
- 第三方 SDK 签名不是强制,也可以自签名,前提是你不是在官方影响隐私 SDK 列表中
- 如果你 SDK 没有二进制,没有使用必要理由的 API,理论上其实甚至可以不管什么隐私清单和签名,因为你正常也进不去官方的影响隐私 SDK 列表。
本次更多是探讨,因为官方的描述和文档内容上其实并不严谨,甚至有很多模糊的地方。