微信做为一个开放平台,各方面都是作得比较好的,推出了SDK以后,微信与使用了SDK的应用便能进行更多交互。但在iOS平台上,应用间交换数据仍是相对麻烦的,那么微信为何能直接在应用检测到其余使用了SDK的应用呢?基于这个疑问,我用了一个下午研究其原理。(当前微信版本4.5.0.54)编程
1、SDK的方法数组
我以前也没使用过微信的SDK,不过下载后,查看发现SDK接口有这么一段服务器
1 /*! @brief WXApi的成员函数,在微信终端程序中注册第三方应用。 2 * 3 * 须要在每次启动第三方应用程序时调用。第一次调用后,会在微信的可用应用列表中出现。 4 * @param appid 微信开发者ID 5 * @return 成功返回YES,失败返回NO。 6 */ 7 +(BOOL) registerApp:(NSString *) appid;
换句话来讲,若是下载包含SDK的应用后,不打开应用或应用不调用注册方法,微信是没法检测应用的。但事实上,这段注释还不完整(原理会在下文解释),第一次在本机安装的应用,不打开确实没法让微信检测。同时,若是应用删除了,微信也会及时在可添加的列表中删除这个应用。可是,若是在本机安装过一次并打开过这个应用,不管之后删除后再安装,不从新打开,微信同样能够检测到这个应用。微信
2、交互的方法网络
其实,现时在微信中添加应用这个功能仍是略无聊,只是增长了一个相似快捷方式的东西而已。固然之后发展了,这个功能确定大有做为,包括相似新浪微博SDK的SSO也是使用了URLScheme。在应用中跳转到其余应用,方法很简单,被打开的应用先设置后本身的URLScheme,例如微信开发
而后只要用相似app
1 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"wxd930ea5d5a258f4f://test"]];
“wxd930ea5d5a258f4f”为上面URLScheme,“test”改成参数,固然没有参数都是能够正常打开的。还有拨号、邮件等系统默认的URLScheme,能够本身搜索。至于第三方应用的URLScheme,则能够在应用目录下的“XXX.app”的“Info.plist”的“CFBundleURLTypes”中找到。函数
3、检测应用的方法测试
查了一下检测已安装应用的方法(可参考http://tangqiaoboy.blog.163.com/blog/static/116114258201172975359440),不外乎就这几种方法,显然最可靠的就是UIApplication的方法优化
1 - (BOOL)canOpenURL:(NSURL *)url
这也是网上大多数人认为微信检测应用所采用的方案,但显然这还不完整。首先,检测时须要知道检测对象的URLScheme,难道微信要遍历每个可能的URLScheme来进行检测??这效率确定至关低下,愈来愈多人使用微信平台的SDK,那么未来遍历URLScheme的成本也太大了吧。因而我有一种猜测,微信SDK都能像OpenUDID同样生成一个UDID,而后打开包含SDK的应用时,就同时将UDID和应用的信息上传到服务器,而后每次登录微信都利用UDID查询已安装的应用信息。
彷佛也能够实现,可是我测试后发现,即便不联网,微信依然能检测到已安装的应用。上面的猜测直接被推翻了。
后来我想起了OpenUDID的原理(可参考http://blog.csdn.net/lusonglin121/article/details/9466495),其中有利用到UIPasteboard的地方
1 UIPasteboard* slotPB = [UIPasteboard pasteboardWithName:availableSlotPBid create:YES];
UIPasteboard是建立自定义的设备剪贴板,能够用于应用间的数据交换,并且支持文字、图片、URL和颜色。最重要的是,剪贴板的数据大小彷佛不限制大小(我查到的资料没有说起数据大小的问题,具体的原理我之后会继续研究,若有错漏请包涵),还有能使用数组储存和重启后的持久化。
说了这么久,思路其实已经很清晰了,我如今就来总结一下微信实现检测的整个流程:
一、安装微信,打开微信,这很重要,由于须要微信来建立剪贴板
1 UIPasteboard *paste = [UIPasteboard pasteboardWithName:@"hello" create:YES]; 2 paste.persistent = YES;
如相似代码,persistent的属性必定要设置为YES,不然应用一退出,剪贴板就被清空了。这个文档说得很清楚的,系统的剪贴板是默认YES,自行建立的默认NO。还有剪贴板的内容若是被持久化,则应用退出后、重启后,内容一直都在,除非应用被删除。事实上,一旦微信被删除(仅删除Document和Library是不影响检测应用的),从新安装后,打开微信也没法检测已安装应用了。由于剪贴板被清空了,除非再次打开那些使用SDK的应用。这也证实了,微信确实是使用了剪贴板的方法。
二、使用SDK的应用打开后,将本身的Key、URLScheme和图标等,图标就在mainBundle那里,添加到微信的剪贴板。
三、再次打开微信,微信经过遍历剪贴板的内容,就能轻松列出用户本机上使用了SDK的应用名字和图标,点击添加也是能够当即打开。不过此处有一些地方须要注意,应用的描述介绍是须要在线加载的,因此不链接网络,第一次列出的应用介绍会变成空白。同时,图标也会在线加载,替换原来从剪贴板中拿来的图标。
四、基本全部步骤都完成了,剩下只是每次添加应用前再检查一下是否有效便可。
总结:
这样就能完整解释了微信检查应用功能的种种现象了,不过,其实有须要改进的地方:
一、应用删除后,下次打开微信遍历完成后,并未将剪贴板中的对应记录删除。其实这种作法会有出现一种状况,就是用户安装了大量包含SDK的应用后,都打开了几回后就删除。但冗余的记录仍在剪贴板,那么遍历的速度会受到很大的影响。这里须要一些优化的策略,如按期清理、达到必定数量就清理等(或者微信已经作了我不知道,可是,我发现每次点击“+”的按钮,确实有轻微卡顿)。
二、就是一旦被知道Pasteboard的name,就可以知道用户曾经安装过哪些应用,同时再经过遍历URLScheme知道现时还存在的应用。固然name确实存在被反汇编泄露出来的可能(下一步能够研究一下这个),利用微信这个特性或许能获知用户更多的私隐。固然遍历测试URLScheme的方法其实每个厂商都能作,只要积累一个足够大的“URLScheme库”也就能够了,但效率不及直接利用微信要快。同时,有一些应用确实不使用URLScheme的,就没法经过这种方法获取了。显然,微信利用这种方法着实能统计用户的安装应用行为,手法至关高明,要是将来不少应用都使用了微信SDK的话,它统计的数据就会更为准确。因此微信SDK有意封装了这些方法,仅但愿本身能获知这些信息。
经过分析微信的这种实现方法,但愿也能为你们拓展一下编程的思路,欢迎交流。我认可此次的分析仍是不够严谨,但微信检测应用的功能确实能够经过这种方法来实现,若是之后还有时间,我会考虑再深刻研究。后续更新,我已经在微信客户端发现了这个接口
- (id)getRegisterPasteboardName;
这基本能够证实个人结论大致是正确的,至于Pasteboard的name我还须要继续研究。
转载请注明Pinka-cnblogs。