背景
Apple从iOS14后,增加了对剪贴板内容的隐私保护

iOS16的剪贴板弹窗。

问题
虽然用户的隐私被更好的保护了,但用户体验也在下降。
在iOS16中,只要读取了[UIPasteboard generalPasteboard].string
就会弹出是否允许的弹窗,且弹窗没有暴露api来控制,也没有记录上次的点击结果。如果拒绝,下次读取还是会弹出。
解决方案
针对剪贴版的问题。有两种解决方案
1.用户主动读取剪贴板
使用iOS16 UIKit的新组件 UIPasteControl,来读取剪贴板内容,则不会触发弹窗
用法
- 初始化pasteControl
@interface ViewController ()
@property (nonatomic, strong) UIPasteControl *pasteControl;
@end
@implementation ViewController
- (void)viewDidLoad {
self.control = [[TestPasteControl alloc] init];
self.control.target = self;
[self.view addSubview:self.control];
self.control.frame = CGRectMake(0, 0, 100, 100);
}
- 配置configuration(支持类型)
- (void)viewDidLoad {
// ...
self.pasteConfiguration = [[UIPasteConfiguration alloc] initWithTypeIdentifiersForAcceptingClass:[NSString class]];
}
3.target重写pasteItemProviders:itemProviders方法,用于监听pasteControl点击后的回调
- (void)pasteItemProviders:(NSArray<NSItemProvider *> *)itemProviders {
for (NSItemProvider *provider in itemProviders) {
[provider loadObjectOfClass:NSString.class
completionHandler:^(id<NSItemProviderReading> _Nullable object, NSError * _Nullable error) {
if (object) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *result = [NSString stringWithFormat:@"复制的内容: %@", object];
NSLog(@"%@",result);
});
}
}];
}
}
2.用户无感知读取
如淘宝分享商品,虽然不能避免触发读取剪贴板的弹窗,但可以利用一些不会触发弹窗的,判断内容的api。来减少弹窗出现的概率,增大读取准确内容的命中率。
用法
使用iOS14新增的api
detectPatternsForPatterns:completionHandler:
detectPatternsForPatterns:inItemSet:completionHandler:
来提前判断
可以判断的类型
typedef NSString * UIPasteboardDetectionPattern NS_TYPED_ENUM API_AVAILABLE(ios(14.0));
/// NSString value, suitable for implementing "Paste and Go"
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternProbableWebURL API_AVAILABLE(ios(14.0));
/// NSString value, suitable for implementing "Paste and Search"
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternProbableWebSearch API_AVAILABLE(ios(14.0));
/// NSNumber value
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternNumber API_AVAILABLE(ios(14.0));
/// Array of DDMatchLink values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternLink NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
/// Array of DDMatchPhoneNumber values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternPhoneNumber NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
/// Array of DDMatchEmailAddress values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternEmailAddress NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
/// Array of DDMatchAddress values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternPostalAddress NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
/// Array of DDMatchCalendarEvent values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternCalendarEvent NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
/// Array of DDMatchShipmentTrackingNumber values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternShipmentTrackingNumber NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
/// Array of DDMatchFlightNumber values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternFlightNumber NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
/// Array of DDMatchMoneyAmount values
UIKIT_EXTERN UIPasteboardDetectionPattern const UIPasteboardDetectionPatternMoneyAmount NS_REFINED_FOR_SWIFT API_AVAILABLE(ios(15.0));
判断逻辑
UIPasteboard *board = [UIPasteboard generalPasteboard];
[board detectPatternsForPatterns:[NSSet setWithObjects:UIPasteboardDetectionPatternProbableWebURL, UIPasteboardDetectionPatternNumber, UIPasteboardDetectionPatternProbableWebSearch, nil]
completionHandler:^(NSSet<UIPasteboardDetectionPattern> * _Nullable set, NSError * _Nullable error) {
for (NSString *type in set) {
if ([type isEqualToString:UIPasteboardDetectionPatternProbableWebURL]) {
//do something
}
}
}];
总结
Apple一直是一家重视用户隐私的企业,但这次iOS16关于剪贴板的更新,苹果自己的设计师也觉得有些过量,目前的解决方案也是尽量提高下用户体验。下个版本iOS16.1不知道是否有更优雅的解决方式。后续如果有需要也可以更新一下swift的实现。大家有更好的方案也可以一起讨论。
网友评论