天天看點

猜一下淘密碼如何适配iOS14的

iOS 14 新增剪切闆權限

随着 iOS 14 的釋出,剪切闆的濫用也被大家所知曉。凡是 APP 讀取剪切闆内容,系統都會在頂部彈出提醒,而且這個提醒不能夠關閉。這樣,大家在使用 APP 的過程中就能夠看到哪些 APP 使用了剪切闆。

衆所周知,淘寶 APP 在各個社交平台傳播分享是通過淘密碼的,被分享者通過複制淘密碼打開淘寶 APP 可以定位到分享的商品,完成購買。而這個步驟就是通過讀取剪切闆内容實作的。那麼,在 iOS 14 上,隻要啟動淘寶,就會出現系統提示,淘寶讀取了剪切闆内容。

淘密碼适配 iOS 14

前段時間,淘寶釋出了新版本,并公布了新的淘密碼規則:數字+淘密碼+連結。

為什麼要這樣做呢?

因為随着 iOS 14 對剪切闆隐私的保護,新增加了兩個 API

detectPatternsForPatterns:completionHandler:

detectPatternsForPatterns:inItemSet:completionHandler:

來判斷剪切闆中的内容格式,使用這兩個 API 不會觸發系統剪切闆提示,但是也拿不到剪切闆的具體内容。

是以,淘密碼的适配使用了這兩個 API,來判斷剪切闆内容是否符合淘密碼規則。

但是這兩個 API 隻是暴露了三種規則:數字

UIPasteboardDetectionPatternNumber

、連結

UIPasteboardDetectionPatternProbableWebURL

、搜尋内容

UIPasteboardDetectionPatternProbableWebSearch

。是以淘寶也隻能使用這些規則。為了保證讀取淘密碼的精确度,便使用了數字+連結兩種方式比對,降低讀取剪切闆的錯誤率。不過,最終識别出了淘密碼,讀取内容還是需要使用其他 API,仍然會出現系統提醒。

可能很多人以為淘寶這個規則是通過正規表達式實作的。其實,蘋果這兩個 API 的判斷規則是不支援正規表達式的。而且它的比對規則具體沒法知曉,比如數字的判定,一段文字開頭是數字可以識别,中間有數字就識别不出來。又比如連結的比對,正常 http:// 的連結可以識别,其他 scheme 比如 taobao:// 也可以識别,甚至 😕 都可以識别。

如果根據目前了解的資訊來看的話,淘寶應該就是這樣實作的,但是不排除其他騷操作。不過,有一說一,淘寶對于淘密碼的适配真的是費了一番功夫的。

下面是我猜測實作的代碼,測試了不同種類的密碼,發現與淘寶效果一緻。
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);
        }];