14

iOS14隐私权限适配及其他

 3 years ago
source link: https://xnxy.github.io/xnxy.github.io/2020/09/14/iOS14%E9%9A%90%E7%A7%81%E6%9D%83%E9%99%90%E9%80%82%E9%85%8D%E5%8F%8A%E5%85%B6%E4%BB%96/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Overview

WWDC2020发布会上苹果展示了新的iOS14系统。对于iOS开发工程师来说,适配iOS14其重点在于隐私权限的适配。具体内容可以观看WWDC2020中:建立更好的隐私信任的视频进行了解。

note:截止目前,适配iOS14需要更新mac系统到11 beta 6、xcode需要更新到12 beta 6、手机需要更新到14 beta 8,相关版本可以到苹果官网下载;更新beta版本打包可能会影响正常上架,该问题未进行测试,但需要引起注意。

广告标识符的获取

广告标识符(Identity for Advertisers)简称IDFA,主要用来标记用户。在iOS14系统中,系统会默认关闭广告标跟踪权限。如果在开发中使用,需要向用户请求权限,步骤如下:

1、info.plist配置

选中info.plist右键Open As->Source Code 然后将下方配置和描述信息添加进去。

1
2
<key>NSUserTrackingUsageDescription</key>
<string>“太平通宝”需要您允许访问广告标识符权限,以便于追踪广告和信息的推送</string>

2、头文件引入

为了适配低版本Xcode编译,需要使用预编译命令,所以头文件引入方式如下所示:

1
2
3
#if defined(__IPHONE_14_0)
#import <AppTrackingTransparency/AppTrackingTransparency.h>//适配iOS14
#endif

3、获取IDFA

iOS14及以上系统,需要先请求跟踪权限,用户同意后才能获取广告标识。获取方法标识符的代码iOS14之前一样。示例代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
+ (NSString *)idfaString {
__block NSString *idfa;
#if defined(__IPHONE_14_0)
if (@available(iOS 14, *)) {
// iOS14及以上版本需要先请求权限
ATTrackingManagerAuthorizationStatus status = ATTrackingManager.trackingAuthorizationStatus;
if (status == ATTrackingManagerAuthorizationStatusNotDetermined) { //用户未做选择或未弹窗
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
// 获取到权限后,依然使用老方法获取idfa
if (status == ATTrackingManagerAuthorizationStatusAuthorized) { //用户允许
idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
ICLog(@"--iOS14----%@----",idfa);
}
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}else if(status == ATTrackingManagerAuthorizationStatusAuthorized){//用户允许
idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
}else{
ICLog(@"请在设置-隐私-Tracking中允许App请求跟踪");
}
}
#else
// iOS14以下版本依然使用老方法
// 判断在设置-隐私里用户是否打开了广告跟踪
if ([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]) {
idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
ICLog(@"---iOS14以下系统----%@-----",idfa);
} else {
ICLog(@"请在设置-隐私-广告中打开广告跟踪功能");
}
#endif
idfa = (idfa ? : @"");
return idfa;
}

iOS14中新增了个有限的图片库访问模式,在授权弹窗的时候会新增个Select Photo选项,用户可以选择一部分图片供App读取,而App无法获取相册中的所有图片信息。

如果用户使用了有限图片库访问(Limited Photo Library Access)的模式, 如果App不进行适配,权限提示框会在每次冷启动打开相册的时候重新弹出,我们需要在info.plist中进行配置,关闭弹窗。

1、info.plist配置

选中info.plist右键Open As->Source Code 然后将下方配置和描述信息添加进去。

1
2
<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
<true/>

当然,我们也可以通过相应API来控制何时弹出图片选择的弹出。API如下所示:

1
[[PHPhotoLibrary sharedPhotoLibrary] presentLimitedLibraryPickerFromViewController:self];

同时,在iOS14中官方推荐使用苹果推荐使用PHPicker来代替原API来选择图片。

关于PHPicker的介绍可以参看WWDC2020:认识新的照片选择器的相关介绍。

在iOS14中,苹果新增了模糊定位的概念。原因是苹果认为很多APP并不需要获取用户的精准定位。所以在iOS14授权弹窗的时候新增了Precise的精准开关,默认会选中精准位置,用户可以通过这个开关进行更改。

对于地理位置敏感的APP

1、info.plist配置

不过对于需要精准定位的App需要在info.plist中设置NSLocationTemporaryUsageDescriptionDictionary字典,key为purposeKey,value为对应获取精准定位的原因。

示例如下:

1
2
3
4
5
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>punchTheClock</key>
<string>“太平通宝”需要您允许精准定位,以便于使用打卡功能</string>
</dict>

2、获取单次精准定位

同时需要调用相应API,获取精准定位。代码如下:

1
[CALocationMnanger requestTemporaryFullAccuracyAuthorizationWithPurposeKey:@"punchTheClock"]

对于地理位置不敏感的App

对定位信息不敏感的APP,iOS14中可以直接在info.plist中添加NSLocationDefaultAccuracyReducedtrue,默认请求模糊定位

选中info.plist右键Open As->Source Code 然后将下方配置和描述信息添加进去。

1
2
<key>NSLocationDefaultAccuracyReduced</key>
<true/>

Local Network

iOS14中新增了Local Network权限提示,具体关于Local Network的相关信息可以查看苹果官网的视频或者少数派的关于iOS14新增的本地网络权限,要开给第三方App吗?等相关资料。

在iOS14中,如果APP读取剪切版的内容时,手机会弹出提示,提示哪个APP在获取剪切板内容。

相机和麦克风

在iOS14中APP如果使用相机和麦克风,手机的的上方会有绿色和黄色的提示,同时也可以查看是哪个APP在使用相机和麦克风。

关于该功能开发人员无法控制。

UIDatePicker更新UI样式

在iOS14中,UIDatePicker的样式新增了UIDatePickerStyleInline,而且为默认值。如果项目中使用了UIDatePicker,而且希望使用原来的样式,需要设置其样式。

1
self.pickerView.preferredDatePickerStyle = UIDatePickerStyleWheels;

UITableViewCell适配

UITableViewCell无法点击

在Xcode12、iOS14中,如果在UITableViewCell渲染前没有调用self.contentView,系统会在渲染完UITableViewCell上的控件后在其上方添加contentView,这会使contentView拦截住UITableViewCell控件的响应事件。

其解决方式是将UITableViewCell上的控件添加到self.contentView

1
2
3
[self addSubview:view];
改为:
[self.contentView addSubview:view];

hook修复UITableViewCell无法点击问题

虽然上方的方法可以修复UITableViewCell无法点击问题,但对于一个很庞大的项目来说,不确定是否有遗漏,尤其是一些组件。所以在项目中需要用到修改+hook的方式。

方法也很简单,直接hook住UITableViewCell中的addSubview:方法,全局修复下即可,同时后期写代码也要注意代码规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import "UITableViewCell+TB.h"
#import <objc/runtime.h>

@implementation UITableViewCell (TB)

+ (void)load {
Method method1 = class_getInstanceMethod([self class], NSSelectorFromString(@"addSubview:"));
Method method2 = class_getInstanceMethod([self class], @selector(tb_addSubview:));
method_exchangeImplementations(method1, method2);
}

- (void)addSubview:(UIView *)view{
[super addSubview:view];
}

- (void)tb_addSubview:(UIView *)view {
if ([view isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]) {
[self tb_addSubview:view];
} else {
[self.contentView addSubview:view];
}
}

@end

UITableViewCell 背景色变成灰色

灰色为self.contentView的背景色,在init方法中共添加即可。

YYAnimatedImageView 无法加载图片

因为项目中用到YYImage第三方库。

解决方式:
修复:YYAnimatedImageView.m 529行的函数修改如下:

1
2
3
4
5
6
7
8
9
- (void)displayLayer:(CALayer *)layer {
if (_curFrame) {
layer.contents = (__bridge id)_curFrame.CGImage;
}else {
if (@available(iOS 14.0, *)) {
[super displayLayer:layer];
}
}
}

但在项目中,并不会这些修复,毕竟是第三方库,我们可以直接替换这个类的该方法。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#import "YYAnimatedImageView+TB.h"
#import <objc/runtime.h>

@implementation YYAnimatedImageView (TB)

+ (void)load {
Method method1 = class_getInstanceMethod([self class], NSSelectorFromString(@"displayLayer:"));
Method method2 = class_getInstanceMethod([self class], @selector(tb_displayLayer:));
method_exchangeImplementations(method1, method2);
}

- (void)tb_displayLayer:(CALayer *)layer{
Ivar ivar = class_getInstanceVariable(self.class, "_curFrame");
UIImage *_curFrame = object_getIvar(self, ivar);
if (_curFrame) {
layer.contents = (__bridge id)_curFrame.CGImage;
}else{
if (@available(iOS 14.0, *)) {
[super displayLayer:layer];
}
}
}

@end

关于真机调试

最新Xcode 12 beta版本31G,而且还不稳定,如果需要使用低版本Xcode运行到iOS14的真机上可以下载iOS14的DeviceSupport,存放的路径为:

1
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

关于更新iOS14系统

关于更新iOS14 beta版的系统,我在百度经验上水了篇文章,可以点击百度经验查看,当然经验水的有些粗糙,还有错别字。

也可能是好久没写了,写完后,竟然还给了0.3元的红包……


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK