iOS 14 新增剪切板權(quán)限
隨著 iOS 14 的發(fā)布,剪切板的濫用也被大家所知曉。凡是 APP 讀取剪切板內(nèi)容,系統(tǒng)都會在頂部彈出提醒,而且這個提醒不能夠關(guān)閉。這樣,大家在使用 APP 的過程中就能夠看到哪些 APP 使用了剪切板。
眾所周知,淘寶 APP 在各個社交平臺傳播分享是通過淘口令的,被分享者通過復(fù)制淘口令打開淘寶 APP 可以定位到分享的商品,完成購買。而這個步驟就是通過讀取剪切板內(nèi)容實(shí)現(xiàn)的。那么,在 iOS 14 上,只要啟動淘寶,就會出現(xiàn)系統(tǒng)提示,淘寶讀取了剪切板內(nèi)容。
淘口令適配 iOS 14
前段時間,淘寶發(fā)布了新版本,并公布了新的淘口令規(guī)則:數(shù)字+淘口令+鏈接。
為什么要這樣做呢?
因?yàn)殡S著 iOS 14 對剪切板隱私的保護(hù),新增加了兩個 API detectPatternsForPatterns:completionHandler: detectPatternsForPatterns:inItemSet:completionHandler: 來判斷剪切板中的內(nèi)容格式,使用這兩個 API 不會觸發(fā)系統(tǒng)剪切板提示,但是也拿不到剪切板的具體內(nèi)容。
所以,淘口令的適配使用了這兩個 API,來判斷剪切板內(nèi)容是否符合淘口令規(guī)則。
但是這兩個 API 只是暴露了三種規(guī)則:數(shù)字UIPasteboardDetectionPatternNumber、鏈接UIPasteboardDetectionPatternProbableWebURL、搜索內(nèi)容UIPasteboardDetectionPatternProbableWebSearch。所以淘寶也只能使用這些規(guī)則。為了保證讀取淘口令的精確度,便使用了數(shù)字+鏈接兩種方式匹配,降低讀取剪切板的錯誤率。不過,最終識別出了淘口令,讀取內(nèi)容還是需要使用其他 API,仍然會出現(xiàn)系統(tǒng)提醒。
可能很多人以為淘寶這個規(guī)則是通過正則表達(dá)式實(shí)現(xiàn)的。其實(shí),蘋果這兩個 API 的判斷規(guī)則是不支持正則表達(dá)式的。而且它的匹配規(guī)則具體沒法知曉,比如數(shù)字的判定,一段文字開頭是數(shù)字可以識別,中間有數(shù)字就識別不出來。又比如鏈接的匹配,正常 http:// 的鏈接可以識別,其他 scheme 比如 taobao:// 也可以識別,甚至 :/ 都可以識別。
如果根據(jù)目前了解的信息來看的話,淘寶應(yīng)該就是這樣實(shí)現(xiàn)的,但是不排除其他騷操作。不過,有一說一,淘寶對于淘口令的適配真的是費(fèi)了一番功夫的。
下面是我猜測實(shí)現(xiàn)的代碼,測試了不同種類的口令,發(fā)現(xiàn)與淘寶效果一致。
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
void (^checkBlock)(NSSet *set, int type) = ^(NSSet *set, int type) {
BOOL isNumber = NO, isUrl = NO;
for (NSString *s in set) {
if ([s isEqualToString:UIPasteboardDetectionPatternNumber]) {
isNumber = YES;
}
if ([s isEqualToString:UIPasteboardDetectionPatternProbableWebURL]) {
isUrl = YES;
}
if ([s isEqualToString:UIPasteboardDetectionPatternProbableWebSearch]) {
// NSLog(@"todo --- hehe");
}
}
if (isNumber && isUrl) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *s = pasteboard.string;
NSLog(@"todo -- %@", s);
if (type == 1) {
self->_label1.text = @"1";
}
else if (type == 2) {
self->_label2.text = @"2";
}
});
}
};
[pasteboard detectPatternsForPatterns:[NSSet setWithObjects:UIPasteboardDetectionPatternNumber, UIPasteboardDetectionPatternProbableWebURL, UIPasteboardDetectionPatternProbableWebSearch, nil] completionHandler:^(NSSet<UIPasteboardDetectionPattern> * _Nullable set, NSError * _Nullable error) {
checkBlock(set, 1);
}];