一、背景:2023年WWDC之后苹果发布了「App store 提交隐私更新」政策,政策主要提出两点:
1. 三方SDK隐私清单和签名 从 2024 年春季开始,如果你提交的新 App 或 App 更新添加了 App Store 上的 App 中常用的第三方 SDK,那么你需要包含相应SDK 的隐私清单。将 SDK 用作二进制文件依赖项时,也需要包含签名。此功能对于所有 App 来说都是向前迈出的重要一步,我们鼓励所有 SDK 采用这项功能,以更好地支持依赖于相应 SDK 的 App。
2. 需要提供必要理由的API流程
(1) 如果你上传到 App Store Connect 的新 App 或 App 更新使用了需要必要理由API (包括第三方 SDK 使用的 API),而你没有在 App 的隐私清单(privacy manifest)中提供批准的原因,那么你会收到通知。根据我们收到的开发者反馈,批准的原因列表已扩展到包含更多用例。如果你的用例可让用户直接受益,但未在现有批准原因列表中,请提交请求以便我们添加新的原因。
从 2024 年春季开始,若要将新 App 或 App 更新上传到 App Store Connect,你需要在 App 的隐私清单中注明批准的原因,以准确反映你的 App 如何使用相应 API。
(2)若三方SDK使用了必要理由api,则必须在SDK的manifest文件中体现。 如下图:
(3)针对上面的声明必要原因的api列表,我写了一个匹配脚本,可以在项目中进行匹配是否引用了对应的API。shell脚本代码在文章末尾。
二、隐私清单(privacy manifest)的创建
- Xcode升级到Xcode15版本及以上
- 新建文件 Cmd + N
- privacy文件如下图
4. 隐私清单的作用是帮助开发者了解SDK如何使用数据
导出以后的PDF如图所示,通过隐私清单,开发者可以在appStore提交审核时更方便的提供「隐私标签」
----privacy中的相关字段说明
-
NSPrivacyTracking
- bool,指示您的应用程序或第三方 SDK 是否使用应用程序跟踪透明度框架下定义的数据进行跟踪。有关更多信息,请参阅用户隐私和数据使用。
-
NSPrivacyTrackingDomains
- array,列出您的应用或第三方 SDK 连接到的参与跟踪的互联网域。如果用户未通过应用程序跟踪透明度框架授予跟踪权限,则对这些域的网络请求将失败,并且您的应用程序会收到错误。
- 如果设置NSPrivacyTracking为true则至少需要设置一个domain,否则可以为0个or多个。
- 如果用户未通过ATT的隐私协议,则apple会阻止对追踪域(Tracking Domains)的网络请求。
- 可以通过Xcode->open developer tool->Instruments->network->points of interest。 如下图:
- NSPrivacyCollectedDataTypes
- 描述您的应用程序或第三方 SDK 收集的数据类型的字典数组。
- NSPrivacyCollectedDataType
- string,用于标识您的应用或第三方 SDK 收集的数据类型。从下面的数据类型列表中选择与您的应用或第三方 SDK 收集的数据相匹配的值。
- 链接: developer.apple.com/documentati…
- NSPrivacyCollectedDataTypeLinked
- bool,应用程序或第三方 SDK 是否将此数据类型链接到用户的身份。有关更多信息,请参阅App Store 上的应用程序隐私详细信息中链接到用户的数据
- NSPrivacyCollectedDataTypeTracking
- bool,应用程序或第三方 SDK 是否使用此数据类型进行跟踪。
- NSPrivacyCollectedDataTypePurposes
- 应用或第三方 SDK 收集数据的原因的字符串数组。从下面的目的列表中选择与您的应用或第三方 SDK 收集此数据类型的原因相匹配的值。
- 链接:
developer.apple.com/documentati… - 各个字段说明如图:
- NSPrivacyCollectedDataTypePurposes
-
dictionary,描述应用或第三方 SDK 访问的 API 类型,这些类型已被指定为需要访问原因的 API。有关字典中要使用的键和值的信息,请参阅描述必要理由API 的使用。
-
NSPrivacyAccessedAPIType
- string,标记应用程序必要理由的api类型
-
NSPrivacyAccessedAPITypeReasons
- string,应用程序使用API的原因
-
三、签名
- 签名是对于三方SDK而言的,多数三方SDK都包含了签名
-
若依赖最新版本or较新版本的sdk,都包含签名,我看了很多sdk都包含。 如FMDB的签名如下图,其中的_CodeSignature就是签名:
-
若所依赖的SDK不包含签名,则需要开发者对其进行手动签名。
-
签名所需的命令
- 搜索指定目录下是否包含_CodeSignature签名目录
- find -name -type d "_CodeSignature"
- 列出本地与代码签名相关的证书
- security find-identity -v -p codesigning
- 对SDK进行签名
- codesign --timestamp -v --sign "Your Certificate Name" </path/to/SDK.framework>
ps:WWDC2023官网签名命令
视频链接:developer.apple.com/videos/play…
----视频里有详解,视频下方code分类里有签名命令。
- codesign --timestamp -v --sign "Your Certificate Name" </path/to/SDK.framework>
- 验证签名(可以看到相关签名信息)
- codesign -dvvv </path/to/SDK.framework>
- 搜索指定目录下是否包含_CodeSignature签名目录
-
四、开发者需要做哪些工作
- 若引用的三方SDK不在苹果列出的名单里,则理论上可以不对SDK进行签名和新增manifest文件。
- 若在名单里,则需要对SDK进行签名和新增manifest文件及必要理由api、TrackingDomains的说明等。
- 若项目依赖老版本SDK(不包含manifest文件)
- 更新到最新版本,常用的三方都会在新版本适配manifest
- 若不想更新sdk,则可以
- 将对应的SDK下载到本地
- 本地新增manifest文件(可以参考最新的sdk中的manifest文件)
- 推送到自己的github上
- 通过cocoapods引入新增manifest文件的sdk
- 更改.podspec文件
- s.resource_bundles = {'fmdb' => ['src/privacy/PrivacyInfo.xcprivacy']}
- 在项目中使用cocoapods导入
- pod 'FMDB', :git => "git地址", :branch => "master"
必要理由api文件
----1.File timestamp APIs----
NSFileCreationDate
NSFileModificationDate
fileModificationDate
NSURLContentModificationDateKey
NSURLCreationDateKey
getattrlist
getattrlistbulk
fgetattrlist
st_atimespec
st_blksize
st_blocks
st_ctimespec
st_dev
st_flags
st_gen
st_gid
st_ino
st_lspare
st_mode
st_mtimespec
st_nlink
st_qspare
st_rdev
st_size
st_uid
fstat
fstatat
lstat
getattrlistat
----2.System boot time APIs----
systemUptime
mach_absolute_time
----3.Disk space APIs----
NSURLVolumeAvailableCapacityKey
NSURLVolumeAvailableCapacityForImportantUsageKey
NSURLVolumeAvailableCapacityForOpportunisticUsageKey
NSURLVolumeTotalCapacityKey
NSFileSystemFreeSize
NSFileSystemSize
statfs
statvfs
fstatfs
fstatvfs
getattrlist
fgetattrlist
getattrlistat
----4.Active keyboard APIs----
activeInputModes
----5.User defaults APIs----
NSUserDefaults
匹配脚本代码
#递归搜索当前路径下是否包含传入的文件中的字符串,若包含打印路径。
# 提示用户输入包含搜索字符串的文件路径
read -p "请输入必要理由api的文件路径:" file_path
# 检查文件是否存在
if [ ! -f "$file_path" ]; then
echo "错误:文件不存在。"
exit 1
fi
# 逐行读取文件中的搜索字符串,并执行搜索操作
while IFS= read -r search_string; do
# 检查搜索字符串是否以 "----" 开头
if [[ "$search_string" == ----* ]]; then
echo "${search_string}"
else
# 检查搜索字符串是否为空或只包含空格
if [ -n "$(echo "$search_string" | tr -d '[:space:]')" ]; then
# 指定要搜索的目录为当前目录
search_directory="."
# 对搜索字符串进行处理,确保空格被保留
# 使用 printf 格式化字符串,%s 表示字符串
formatted_search_string=$(printf "%s" "$search_string")
# 使用 find 命令查找目录下的所有文件,并使用 grep 查找包含指定字符串的文件
# -type f 表示只查找文件
# -exec grep -H -i "$formatted_search_string" {} + 表示对每个找到的文件执行 grep 命令,输出包含匹配字符串的文件路径和匹配的行
result=$(find "$search_directory" -type f -exec grep -H -i "$formatted_search_string" {} +)
# 检查结果是否为空
if [ -n "$result" ]; then
echo "找到包含${formatted_search_string}符串的文件:"
echo "$result"
echo "------------------------end------------------------"
else
echo "未找到包含${formatted_search_string}字符串的文件。"
echo "------------------------------------------------"
fi
fi
fi
done < "$file_path"
使用方法:必要理由文件命名为requestReasonApi.text文件,匹配脚本为match.shell。执行match.shell->将requestReasonApi.text文件拖入作为第一个参数即可进行匹配。
以上是我对苹果这边iOS隐私协议适配的一些见解,查了很多资料,若有不对的地方欢迎大家指正。 首篇技术博客大家多多关照!!!