【iOS】关于UIPasteboard应用级粘贴板的一些事

2021.04.12更新:最近发现App剪切板在App更新的时候会被清空,请慎用。
本文已不再适用。

前言

工程中用到了+ (nullable UIPasteboard *)pasteboardWithName:(NSString *)pasteboardName create:(BOOL)create;这个方法创建的一个粘贴板(一个老古董模块),最近到网上查了相关资料,对这个方法的持久化功能和应用间共享功能,我发现苹果的文档和网上的博客以及我个人的经验不太一样,所以就进行了一番测试。

苹果文档的介绍

文档链接
摘抄如下:

Call this method to create custom app pasteboards. (You can also use it to obtain the general pasteboard, but the generalPasteboard class method exists for that purpose.) App pasteboards returned by this method are not persistent, existing only until the app quits. Starting in iOS 10, persistent named pasteboards are deprecated. Instead use a shared container, as described in the overview for the UIPasteboard class.

谷歌翻译如下:

调用此方法可以创建自定义应用程序粘贴板。 (您也可以使用它来获取常规粘贴板,但是为此目的存在generalPasteboard类方法。)此方法返回的应用程序粘贴板不是持久性的,仅在应用程序退出之前存在。 从iOS 10开始,不推荐使用持久命名的粘贴板。 而是使用共享容器,如UIPasteboard类的概述中所述。

按照苹果文档所说,这个方法创建出来的粘贴板仅在应用生命周期内有效,只要退出应用,就无效的。当然,粘贴板本身是有一个- (void)setPersistent:(BOOL)persistent NS_DEPRECATED_IOS(3_0, 10_0, "Do not set persistence on pasteboards. This property is set automatically.");方法是可以让粘贴板持久化的,但是苹果在iOS10开始就将这个方法标为过时方法了,是否持久化是自动设置的。

一些博客说法

例如这篇文章
摘抄如下:

自定义的剪切板通过一个特定的名称字符串进行创建,它在应用程序内或者同一开发者开发(必须Bundle Identifier 例com.maoshaoqian.** 星号前部一样)的其他应用程序中可以进行数据共享。举个例子:比如你开发了多款应用,用户全部下载了,在A应用中用户拷贝了一些数据(为了数据安全,不用系统级别的Pasteboard),在打开B应用时就会自动识别,提高用户体验。

这个意思是有进行持久化,并且可以在同一开发者账号中拥有相同前缀的bundleID的App之间共享。

对于持久化的争议的测试

究竟这个应用内粘贴板是否做了持久化,持久化的程序如何呢?我带着这个问题做了一波测试。
测试方法:使用adhoc证书打包的一个ipa包,然后根据不同的情况做卸载、重装操作。只在第一次安装的时候,点击按钮设置一次应用内粘贴板。以后只读取粘贴板内容。在不同的设备进行测试。
核心代码如下:

//设置粘贴板
- (IBAction)onClickBtn1:(id)sender {
    
    UIPasteboard *pd = [UIPasteboard pasteboardWithName:@"com.shixueqian.pasteboard" create:YES];
    NSDictionary *dict = @{@"name":@"qianyanwangyu"};
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dict];
    [pd setData:data forPasteboardType:@"com.shixueqian.pasteboard.type"];
}
//读取粘贴板内容
- (IBAction)onClickBtn2:(id)sender {
    
    UIPasteboard *pd = [UIPasteboard pasteboardWithName:@"com.shixueqian.pasteboard" create:NO];
    NSData *data = [pd dataForPasteboardType:@"com.shixueqian.pasteboard.type"];
    NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    //在label上显示读取的结果以及persistent属性的值
    self.label.text = [NSString stringWithFormat:@"结果:%@;persistent:%d;",dict,pd.persistent];
}

以下为测试的结果:

系统 重新打开App 重启设备 卸载重装 卸载重启设备再安装
iOS9.3.2 可读取 可读取 可读取 可读取
iOS12 可读取 可读取 可读取 可读取
iOS13beta4 可读取 可读取 可读取 可读取

其中,iOS9.3.2中的persistent属性一直打印NO,其他系统测试的时候一直显示为YES。

从结果中可以看出,实际上写入粘贴板的内容是会持久化到本地磁盘里面的,不管之后是重启手机还是卸载重装,依然可以读取到粘贴板中的内容。就这个特性来说,跟keychain的特性基本一致。

对于App共享之间的争议的测试

这个争议在于,有些博客认为,必须在同一个开发者账号下,并且需要bundleID前缀相同的App才能共享这个粘贴板的内容。而苹果的文档说的是拥有同一个teamID的应用就可以共享粘贴板内容。
于是我又做了一个测试。4个ipa包,一个bundleID为com.demo.aaa,一个为com.demo.bbb,一个位com.shixueqian.ccc。这3个bundleID是在同一个开发者账号下的。还有另外一个com.demo.ddd是在另外一个开发者账号下的。
先安装com.demo.aaa,设置粘贴板,然后进行卸载。以后安装的ipa包都直接读取粘贴板对应内容,得出结果后就进行卸载。
以下为测试记录:

系统 com.demo.aaa com.demo.bbb com.shixueqian.ccc com.demo.ddd
iOS12 开始进行设置 可读取 可读取 无法读取

就只测试了iOS12的设备,其他的就懒得测试了,2333
从测试结果可以得出结论:苹果文档中说的同一个teamID的App可以共享粘贴板内容这个是没问题的。不管这些App的bundleID是什么都没有关系。当然了,我测试的都是Explicit类型的bundleID。

那么一个主开发者账号就对应着一个teamID吗?之前找到一篇文章说是粘贴板共享是在同一个App ID Prefix的App才能生效,而App ID Prefix可能会有多个。WTF,问题是我从来就没有看到有多个的情况,苹果的文档也没找到这种情况,如果有了解的大佬可以说一下。
所以,结论是只要是同一个开发者账号下的App,都能共享粘贴板内容。(虽然根据现有资料来看这个结论不是那么严谨......)

App转让的问题

做过App转让操作的童鞋都知道,App转让之后,再次打包上传送审的时候苹果会发一个警告邮件:

ITMS-90076: Potential Loss of Keychain Access - The previous version of software has an application-identifier value of ['2VFRxxxx.com.demo.aaa'] and the new version of software being submitted has an application-identifier of ['2DBAxxxx.com.demo.aaa']. This will result in a loss of keychain access.

可以看下苹果对这个问题的解释
看起来有点懵逼。首先,从我多次转让App的经验来看,App ID Prefix这个确实是会改变的,会变成当前账号下的teamID。至于转让之后keychain会不会无法读取,这个没做过测试(这个一点都不好测试),不好确认。但是按照苹果的说法,一些依靠App ID Prefix的技术,比如keychain access,UIPasteboard sharing,都是会受到影响的。
所以,用了keychain或者UIPasteboard的App,如果可以的话,尽量考虑到转让的情况。一个可行的方案是,将写入keychain或者Pasteboard的数据,同时用NSUserDefault存一份,如果找不到,就从NSUserDefault里面找,应该可以在一定程序上缓解这个问题。

谦言忘语

苹果并不建议使用UIPasteboard的应用内粘贴板功能来让同一个开发者账号上面的App共享数据,虽然它现在确实能够做到。所以我们尽量还是少用为好,省得哪天苹果改了规则那得跪。话说还想吐槽的是,keychain这个功能苹果本身的意思是建议只用作存储账号和密码使用的,结果现在简直是八仙过海各显神通,五花八门的使用方式都有,也没见苹果吭过一声。

参考

https://yq.aliyun.com/articles/608584?utm_content=m_1000005468
https://developer.apple.com/documentation/uikit/uipasteboard?language=objc
https://www.jianshu.com/p/a6d2e46329f8
https://blog.csdn.net/shengpeng3344/article/details/51404708
https://stackoverflow.com/questions/32492119/how-where-to-define-an-app-id-prefixes-in-xcode

你可能感兴趣的:(【iOS】关于UIPasteboard应用级粘贴板的一些事)