iOS16適配之剪貼板

背景

Apple從iOS14后,增加了對剪貼板內容的隱私保護


131217723881.jpeg

iOS16的剪貼板彈窗。


936be07d1526176.jpg

問題

雖然用戶的隱私被更好的保護了,但用戶體驗也在下降。
在iOS16中,只要讀取了[UIPasteboard generalPasteboard].string
就會彈出是否允許的彈窗,且彈窗沒有暴露api來控制,也沒有記錄上次的點擊結果。如果拒絕,下次讀取還是會彈出。

解決方案

針對剪貼版的問題。有兩種解決方案

1.用戶主動讀取剪貼板

使用iOS16 UIKit的新組件 UIPasteControl,來讀取剪貼板內容,則不會觸發彈窗

用法

  1. 初始化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);
}
  1. 配置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的實現。大家有更好的方案也可以一起討論。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容