原文鏈接 淘系技術(shù):iOS14 隱私適配及部分解決方案
簡介: 在剛剛結(jié)束的線上 WWDC 2020 發(fā)布會上蘋果向我們展示了新的 iOS14 系統(tǒng)。iOS14 的適配,很重要的一環(huán)就集中在用戶隱私和安全方面。 最近在調(diào)研 iOS14的適配方案,本文主要分享一下 iOS14 上對于隱私授權(quán)的變更和部分適配方案,歡迎補(bǔ)充指正。

在剛剛結(jié)束的線上 WWDC 2020 發(fā)布會上蘋果向我們展示了新的 iOS14 系統(tǒng)。iOS14 的適配,很重要的一環(huán)就集中在用戶隱私和安全方面。
在 iOS13 及以前,當(dāng)用戶首次訪問應(yīng)用程序時,會被要求開放大量權(quán)限,比如相冊、定位、聯(lián)系人,實(shí)際上該應(yīng)用可能僅僅需要一個選擇圖片功能,卻被要求開放整個照片庫的權(quán)限,這確實(shí)是不合理的。對于相冊,在 iOS14 中引入了 “LimitedPhotos Library” 的概念,用戶可以授予應(yīng)用訪問其一部分的照片,對于應(yīng)用來說,僅能讀取到用戶選擇讓應(yīng)用來讀取的照片,讓我們看到了 Apple 對于用戶隱私的尊重。這僅僅是一部分,在iOS14 中,可以看到諸多類似的保護(hù)用戶隱私的措施,也需要我們升級適配。
最近在調(diào)研 iOS14的適配方案,本文主要分享一下 iOS14 上對于隱私授權(quán)的變更和部分適配方案,歡迎補(bǔ)充指正。
適配點(diǎn)
? 相冊
? iOS14 新增了“Limited Photo Library Access” 模式,在授權(quán)彈窗中增加了 Select Photo 選項(xiàng)。用戶可以在 App 請求調(diào)用相冊時選擇部分照片讓 App 讀取。從 App 的視?來看,你的相冊里就只有這幾張照片,App 無法得知其它照片的存在。

? iOS14 中當(dāng)用戶選擇
“PHAuthorizationStatusLimited” 時,如果未進(jìn)行適配,有可能會在每次觸發(fā)相冊功能時都進(jìn)行彈窗詢問用戶是否需要修改照片權(quán)限。
? 對于這種情況可通過在 Info.plist 中設(shè)置
“PHPhotoLibraryPreventAutomaticLimitedAccessAlert”的值為 YES 來阻止該彈窗反復(fù)彈出,并且可通過下面這個 API 來主動控制何時彈出PHPickerViewController 進(jìn)行照片選擇。
[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];
? 在 iOS14 中官方推薦使用 PHPicker 來替代原 API 進(jìn)行圖片選擇。PHPicker 為獨(dú)立進(jìn)程,會在視圖最頂層進(jìn)行展示,應(yīng)用內(nèi)無法對其進(jìn)行截圖也無法直接訪問到其內(nèi)的數(shù)據(jù)。
- UIImagePickerController -> PHPickerViewController, UIImagePickerViewController 功能受限,每次只能選擇一張圖片,將逐漸被廢棄。

-
PHPicker 支持多選,支持搜索,支持按 image,video,livePhotos 等進(jìn)行選擇。
image.png
? 新API及遷移demo:

@interface ViewController () <PHPickerViewControllerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (nonatomic, strong) NSArray<NSItemProvider *> *itemProviders;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)button:(id)sender {
// 以下 API 僅為 iOS14 only
PHPickerConfiguration *configuration = [[PHPickerConfiguration alloc] init];
configuration.filter = [PHPickerFilter videosFilter]; // 可配置查詢用戶相冊中文件的類型,支持三種
configuration.selectionLimit = 0; // 默認(rèn)為1,為0時表示可多選。
PHPickerViewController *picker = [[PHPickerViewController alloc] initWithConfiguration:configuration];
picker.delegate = self;
// picker vc,在選完圖片后需要在回調(diào)中手動 dismiss
[self presentViewController:picker animated:YES completion:^{
}];
}
#pragma mark - Delegate
- (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results {
[picker dismissViewControllerAnimated:YES completion:nil];
if (!results || !results.count) {
return;
}
NSItemProvider *itemProvider = results.firstObject.itemProvider;
if ([itemProvider canLoadObjectOfClass:UIImage.class]) {
__weak typeof(self) weakSelf = self;
[itemProvider loadObjectOfClass:UIImage.class completionHandler:^(__kindof id<NSItemProviderReading> _Nullable object, NSError * _Nullable error) {
if ([object isKindOfClass:UIImage.class]) {
__strong typeof(self) strongSelf = weakSelf;
dispatch_async(dispatch_get_main_queue(), ^{
strongSelf.imageView.image = (UIImage *)object;
});
}
}];
}
}
? 需要注意的是,在 limit Photo 模式下,AssetsLibrary 訪問相冊會失??;在 writeOnly 模式下,AssetLibrary 也會有顯示問題。建議還在使用 AssetsLibrary 的同學(xué)盡快遷移到新 API。
? 授權(quán)相關(guān):舊 API 廢棄,增加 PHAccessLevel 參數(shù)。如果再使用以前的API來獲取權(quán)限狀態(tài),
PHAuthorizationStatusLimited 狀態(tài)下也會返回
PHAuthorizationStatusAuthorized

typedef NS_ENUM(NSInteger, PHAccessLevel) {
PHAccessLevelAddOnly = 1, // 僅允許添加照片
PHAccessLevelReadWrite = 2, // 允許訪問照片,limitedLevel 必須為 readWrite
} API_AVAILABLE(macos(10.16), ios(14), tvos(14));
// 查詢權(quán)限
PHAccessLevel level = PHAccessLevelReadWrite;
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatusForAccessLevel:level];
switch (status) {
case PHAuthorizationStatusLimited:
NSLog(@"limited");
break;
case PHAuthorizationStatusDenied:
NSLog(@"denied");
break;
case PHAuthorizationStatusAuthorized:
NSLog(@"authorized");
break;
default:
break;
}
// 請求權(quán)限,需注意 limited 權(quán)限盡在 accessLevel 為 readAndWrite 時生效
[PHPhotoLibrary requestAuthorizationForAccessLevel:level handler:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusLimited:
NSLog(@"limited");
break;
case PHAuthorizationStatusDenied:
NSLog(@"denied");
break;
case PHAuthorizationStatusAuthorized:
NSLog(@"authorized");
break;
default:
break;
}
}];
? 定位
? 在 iOS13 及以前,App 請求用戶定位授權(quán)時為如下形態(tài):一旦用戶同意應(yīng)用獲取定位信息,當(dāng)前應(yīng)用就可以獲取到用戶的精確定位。

? iOS14 新增用戶大致位置選項(xiàng)可供用戶選擇,原因是大多數(shù) App 實(shí)際上并不需要獲取用戶到用戶最準(zhǔn)確的定位信息。iOS14 授權(quán)彈窗新增的 Precise的開關(guān)默認(rèn)會選中精確位置。用戶通過這個開關(guān)可以進(jìn)行更改,當(dāng)把這個值設(shè)為 On 時,地圖上會顯示精確位置;切換為Off時,將顯示用戶的大致位置。
? 對于對用戶位置敏感度不高的 App 來說,這個似乎無影響,但是對于強(qiáng)依賴精確位置的 App 適配工作就顯得非常重要了。可以通過用戶在 “隱私設(shè)置” 中設(shè)置來開啟精確定位,但是可能用戶寧可放棄使用這個應(yīng)用也不愿意開啟。這個時候,iOS14 在 CLLocationManager 新增兩個方法可用于向用戶申請臨時開啟一次精確位置權(quán)限。

使用方式也很簡單,需要首先在 Info.plist 中配置“NSLocationTemporaryUsageDescriptionDictionary”字典中需要配置 key 和 value 表明使用位置的原因,以及具體的描述。

在本例中,key 即為獲取用戶權(quán)限時傳的 "purposeKey",最終呈現(xiàn)給用戶的就是左圖,右圖為當(dāng)App主動關(guān)閉精確定位權(quán)限申請。

? 對于地理位置不敏感的App 來說,iOS14 也可以通過直接在 info.plist 中添加 NSLocationDefaultAccuracyReduced 為 true 默認(rèn)請求大概位置。

? 這樣設(shè)置之后,即使用戶想要為該 App 開啟精確定位權(quán)限,也無法開啟。
? 也可以直接通過API來根據(jù)不同的需求設(shè)置不同的定位精確度。

? 需要注意的是,當(dāng) App 在 Background 模式下,如果并未獲得精確位置授權(quán),那么 Beacon 及其他位置敏感功能都將受到限制。
? Local Network
? iOS14 當(dāng) App 要使用 Bonjour 服務(wù)時或者訪問本地局域網(wǎng),使用 mDNS 服務(wù)等,都需要授權(quán),開發(fā)者需要在 Info.plist 中詳細(xì)描述使用的為哪種服務(wù)以及用途。下圖為需要無需申請權(quán)限與需要授權(quán)的服務(wù):

? 在 "隱私設(shè)置" 中也可以查看和修改具體有哪些 App 正在使用 LocalNetwork

? 如果應(yīng)用中需要使用 LocalNetwork 需要在 Info.plist 中配置兩個選項(xiàng),詳細(xì)描述為什么需要使用該權(quán)限,以及需要列出具體使用 LocalNetwork 的服務(wù)列表。

? 對于使用了下列包含 Bonjour 的 framework,都需要更新描述.

? Wi-Fi Address
? iOS8 - iOS13 ,用戶在不同的網(wǎng)絡(luò)間切換和接入時,mac 地址都不會改變,這也就使得網(wǎng)絡(luò)運(yùn)營商還是可以通過 mac 地址對用戶進(jìn)行匹配和用戶信息收集,生成完整的用戶信息。iOS14 提供 Wifi 加密服務(wù),每次接入不同的 WiFi 使用的 mac 地址都不同。每過 24 小時,mac 地址還會更新一次。需要關(guān)注是否有使用用戶網(wǎng)絡(luò) mac 地址的服務(wù)。
? 下圖為 iOS13 及之前用戶接入網(wǎng)絡(luò)時 mac 地址并不會進(jìn)行改變

? 下圖為 iOS14 用戶接入 Wi-Fi 時 mac 地址的變化情況

? 并且用戶也可以自行選擇是否開啟 private Wi-Fi address

? 剪切板
? 在 iOS14 中,讀取用戶剪切板的數(shù)據(jù)會彈出提示。

? 彈出提示的原因是使用 UIPasteboard 訪問用戶數(shù)據(jù),訪問以下數(shù)據(jù)都會彈出 toast 提示。

? 兼容方案:如果應(yīng)用訪問剪切板僅僅用于判斷是否為URL格式,則 iOS14 新增了兩個 API 可以用于規(guī)避該提示。如果應(yīng)用想直接訪問剪切板的數(shù)據(jù),暫時可能無法做到規(guī)避該提示。iOS14 新增兩種
UIPasteboardDetectionPattern。

? 上面的兩個 API 可用于規(guī)避提示,但只能用于判斷剪切板中是否有 URL,并不是真正的訪問剪貼板數(shù)據(jù),也拿不到剪切板的真實(shí)數(shù)據(jù)。下面兩個 API 可以獲得具體的 URL 信息,但是會觸發(fā)剪切板提示。并且實(shí)測當(dāng)用戶剪切板中包含多個 URL 時只會返回第一個。

? 使用示例
NSSet *patterns = [[NSSet alloc] initWithObjects:UIPasteboardDetectionPatternProbableWebURL, nil];
[[UIPasteboard generalPasteboard] detectPatternsForPatterns:patterns completionHandler:^(NSSet<UIPasteboardDetectionPattern> * _Nullable result, NSError * _Nullable error) {
if (result && result.count) {
// 當(dāng)前剪切板中存在 URL
}
}];
? 相機(jī)和麥克風(fēng)
? iOS14 中 App 使用相機(jī)和麥克風(fēng)時會有圖標(biāo)提示以及綠點(diǎn)和黃點(diǎn)提示,并且會顯示當(dāng)前是哪個 App 在使用此功能。我們無法控制是否顯示該提示。

? 會觸發(fā)錄音小黃點(diǎn)的代碼示例:
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:recorderPath settings:nil error:nil];
[recorder record];
? 觸發(fā)相機(jī)小綠點(diǎn)的代碼示例:
AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:videoCaptureDevice error:nil];
AVCaptureSession *session = [[AVCaptureSession alloc] init];
if ([session canAddInput:videoInput]) {
[session addInput:videoInput];
}
[session startRunning];
? IDFA
? IDFA 全稱為 Identity for Advertisers ,即廣告標(biāo)識符。用來標(biāo)記用戶,目前最廣泛的用途是用于投放廣告、個性化推薦等。
? 在 iOS13 及以前,系統(tǒng)會默認(rèn)為用戶開啟允許追蹤設(shè)置,我們可以簡單的通過代碼來獲取到用戶的 IDFA 標(biāo)識符。
if ([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]) {
NSString *idfaString = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
NSLog(@"%@", idfaString);
}
? 但是在 iOS14 中,這個判斷用戶是否允許被追蹤的方法已經(jīng)廢棄。

? iOS14 中,系統(tǒng)會默認(rèn)為用戶關(guān)閉廣告追蹤權(quán)限。

? 對于這種情況,我們需要去請求用戶權(quán)限。首先需要在 Info.plist 中配置" NSUserTrackingUsageDescription " 及描述文案,接著使用 AppTrackingTransparency 框架中的 ATTrackingManager 中的 requestTrackingAuthorizationWithCompletionHandler 請求用戶權(quán)限,在用戶授權(quán)后再去訪問 IDFA 才能夠獲取到正確信息。
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <AdSupport/AdSupport.h>
- (void)testIDFA {
if (@available(iOS 14, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
NSString *idfaString = [[ASIdentifierManager sharedManager] advertisingIdentifier].UUIDString;
}
}];
} else {
// 使用原方式訪問 IDFA
}
}
對于用戶拒絕授權(quán) UserTracking 的情況,可以考慮接入蘋果的 SKAdNetwork 框架進(jìn)行廣告分析。感興趣的同學(xué)可進(jìn)一步了解:https://developer.apple.com/documentation/storekit/skadnetwork
? 上傳 AppStore
更加嚴(yán)格的隱私審核,可以讓用戶在下載 App 之前就知道此 App 將會需要哪些權(quán)限。目前蘋果商店要求所有應(yīng)用在上架時都必須提供一份隱私政策。如果引入了第三方收集用戶信息等SDK,都需要向蘋果說明是這些信息的用途。


總結(jié)
對于這次 iOS14 的隱私權(quán)限大升級和新嘗試,體現(xiàn)了蘋果對于用戶隱私的尊重。
從用戶角度來說,近年來越來越精準(zhǔn)的廣告投放讓我們越來越感覺自己被”監(jiān)視“著,此次升級后,我們有了更多保護(hù)自己隱私的方式以及避免廣告騷擾的方法,蘋果此舉無疑會加大我們對其的好感度和信任感。但從另一個角度來說,對于 IDFA 的限制,可能會導(dǎo)致之前許多依靠廣告投放收入的免費(fèi) App 難以繼續(xù)維持生計(jì),也可能也會導(dǎo)致免費(fèi) App 的數(shù)量有所降低。從開發(fā)者的角度來說,除了對 iOS14 隱私升級的積極適配外,也讓我們感受到了 iOS14 中對于用戶隱私的重視無疑會提高獲取用戶行為信息的成本。
沖擊最大的應(yīng)該就是廣告行業(yè),對于目前的推薦算法和用戶拉新都會受到影響,如何在充分尊重用戶隱私的前提下進(jìn)行廣告的精準(zhǔn)投放對于開發(fā)者和廣告商來說都是一個不小的機(jī)遇和挑戰(zhàn)。
下一期,我們聊聊 【Metal 新特性詳解|帶來的技術(shù)啟發(fā)和思考】,敬請持續(xù)關(guān)注~
參考資料
- WWDC 2020 Apple Developer
- Developer Documentation
