iOS上App都是沙盒隔离的,如何做广告效果跟踪、用户拉新邀请奖励?
本文将介绍一种可以跨开发商App进行数据共享的方法,基本原理是通过与Safari共享Cookie来实现。已实现放到github。
更新:据闻iOS新版本不支持了,请自行测试确认。
写在前面
说下实际需求场景:
项目组开发的一个系列app,包括一个主应用(暂且称之为AppM)以及一系列子应用(暂且称之为AppX),AppM包含全部功能,而AppX则是另一个代码模板生成的多个应用,上线时AppM使用了公司开发者帐号Acc1,AppX则用了另外的多个帐号Accx。问题来了,产品功能合并,AppM中部分功能(比如攻略资讯)同步到AppC中了,原先分开的业务推送,现在也合并了,(可能)出现的问题是,假如需要对AppX及AppM同时推送同一条资讯,对于安装了多个这样应用的设备而言,用户有可能是接收到多条一模一样的推送消息。
原始需求就是要解决这个,服务端要过滤设备令牌,必须客户端能提供设备识别码。场景虽然不普遍,但有些公司在App Store上上架的多款app,确实会以不同开发者帐号提交的,每个帐号就是独立的开发商。
解决方案,一是能否在不同app中获取/生成相同的设备识别码?二是绕一下弯路,我们提供一个唯一码,但要求能在各个App间共享。我们分别来讨论两种方案。
设备识别码
其实广告商也很关心这个事情。
设备识别码,要求稳定、唯一,通俗讲就是今天跟昨天取到的是一致的、你的设备跟我的设备是不一样的。
MAC地址 && UDID
传统的获取方式,包括其他平台设备中使用的,比如说mac地址啊,确实可以!获取方法就是调用系统库网络相关接口:
1 | #include <sys/sysctl.h> |
但是Apple家不开心了啊!为什么我家的东西你们知道的一清二楚!所以基于mac地址的几种方案,在Apple屏蔽mac地址获取的高版本系统中都失效了,基于mac地址的OpenUDID都无效
Twolow-level networking APIs that used to return a MAC address now return thefixed value 02:00:00:00:00:00. The APIs in question are sysctl(NET_RT_IFLIST) and ioctl(SIOCGIFCONF).
同样的还有苹果自身提供的UDID:[[UIDevice currentDevice] uniqueIdentifier]
,40个字符的设备码,在iOS7之后被换成了prefix+IDFV。
IDFV
iOS6之后提供的,同一开发商在同一设备上的不同app能共享相同的IDFV,但对不同开发商是不一致的。获取方法:[[[UIDevice currentDevice] identifierForVendor] UUIDString]
。同一开发商的app全部卸载后将重置。
IDFA
这是个提供给广告商的设备识别码,获取方法:[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
,问题是,苹果继续加强隐私权限,用户可以手动关闭广告跟踪了,这时候拿到的IDFA也是非法值。
以上这些都是适用条件下理论唯一的识别码,除此之外,还有几个开源的设备识别码,不唯一(具体看碰撞率)不稳定但是可以应用在特定条件下,如OpenIDFA、SimuIateIDFA,详细可以看这篇介绍,但在实际业务上操作会复杂。比如OpenIDFA是有日期的加成,每天都变动,SimulateIDFA有启动日期及设备名称等信息加成,重启会变动。
单一的获取设备唯一码,都不太理想,对吧?再来看下数据共享的方案。
iOS应用间通信/数据共享
iOS应用间数据共享有许多应用场景,但实现方式却是屈指可数。首先,iOS中每个app都是独立的单一进程,且受限于iOS的沙盒隔离机制,app进程的访问权限是有限的。我们先看下目前进程间通信及数据共享的几种方式。
传统的IPC方式
- 管道、共享内存、信号量
- 本地socket
传统的共享内存(shmget等)等方式,苹果会允许?socket要求两端在线,普通应用进入后台后存活时间很短,现实意义不大。
URLScheme
这是常用的通信方式,目前也广泛使用在各大平台App的授权及OAuth2/SSO登录上。通过URL链接的形式调用,系统可以启动相关配置的应用,参数可以通过URL传递,或者下面介绍的粘贴板。目前的常用形式是,通过URLScheme发起调用,通过粘贴板共享数据。
粘贴板(UIPasteboard)
提供了三种粘贴板:
1 | //获取系统级别的剪切板 |
第1种粘贴板是系统级别,各应用均可访问修改;第2种,可以在同一开发者开发的其他应用程序中共享数据;第3种是第2中特例。有个关键方法:- (void)setData:(NSData *)data forPasteboardType:(NSString *)pasteboardType;
,支持现有UTI类型数据或任意二进制,往粘贴板的第一个item写入数据。
这样的话,岂不是可以利用keychain(下文介绍)+ pasteboard的方式实现应用间数据共享?试了一下,使用keychain持久化,使用pasteboard共享,差点就完美了,
但存在问题:
- 微信、微博、QQ等平台分享会导致粘贴板清空,共享失效
- 即使粘贴板未被清空,【VendorA_APP_A】将数据共享到粘贴板(及keychain)后,设备重启,下次启动直接使用【VendorB_APP_B】,无法拿到共享数据,将提供与【VendorA_APP_A】完全不一致的设备标识信息
没有保证的,一口老血。
Keychain(Access Group)
Keychain是Apple提供的又一套数据共享、数据持久化的方案,实质上是对存放在/private/var/Keychains/keychain-2.db上的一个sqlite数据库的操作。当然这么好用的东西,苹果怎么可能没有权限控制。 苹果通过内置到app中的权限文件限制应用可访问的共享数据,还有所有访问自然都是限制在同一开发商中的。
之前我们也通过Keychain提供了一个设备识别码获取保存的框架,主要思路是,将IDFV及设备参数等发到后台获取一个GUID,将GUID写入keychain特定Access-Group中,这样同一个开发商便能够通过配置相同的Access-Group在设备上始终获取到同一个设备码,即使是原先所有app都被卸载后(IDFV会重置,见上文描述)。
可以通过Security框架进行keychain中内容的CURD操作,具体配置及操作其实已经有很多文章介绍就不啰嗦了。
实际上可以通过组合以上的几种方式来实现自己的需求的。微信、微博平台的授权登录、分享等是URLScheme+UIPasteboard组合的经典。在下面的介绍的SFCookie中,同样是多种方式组合。
SFCookie
这个方案主要是因为iOS9新增的SafariServices
框架。SafariServices
新增类SFSafariViewController
允许app内使用Safari访问Web页面,数据互通(关于Safari数据互通,还有个“共享Web凭证”)。我们将通过访问Safari的Cookie来实现数据共享。
但是它也是受限的,SFSafariViewController
不允许访问本地html(所以必须将html配置到服务端站点),且iOS10之后应用审核规范中冒出了一条,明确不允许隐藏Safari视图。实际测试发现,如果SFSafariViewController
的视图被hidden
或者alpha
值过小,它是不会加载页面内容的,其他方面限制暂未发现。适当规避这个还是可以利用它来实现我们的功能的。
SFCookie
提供的是,通过SFCookie
来访问存放在Safari中的Cookie,至于Cookie内容是什么根据业务而定。就文章开头所举的例子的话,可以是一个简单的设备令牌。提供的接口如下:
1 | // 设置appScheme及web页面路径 |
以上调用均为异步回调,默认回调到主线程。
SFCookie
实现比较简单,仅提供了UIApplication+SafariCookie
这样一个拓展方法分类,以及一个简单的包含内嵌JS处理Cookie的html文件“sfc.html”。给项目加入SFCookie
的支持,需要
- 将“sfc.html”放到服务端站点上,并使用
setNTL_SafariCookie_WebURL
配置好加载的地址 - 配置appScheme,以确保能从
SFSafariViewController
得到回调 - 将UIApplication+SafariCookie分类拓展的代码加入项目,或使用pod的方式亦可
回调正是通过URLScheme的方式实现。AppScheme是可以各个客户端动态配置的,并作为参数传递给Web页面来保证正确的回调。需注意的几点:
- 参数尽量不要掺杂特殊符号,虽然内部已经做了URL编解码处理;如果有特殊符号需测试检验;
- AppScheme在设备上唯一(默认是
safaricookie
),否则从Web页面发起调用后,由系统决定跳转;
回到文章开头所提的需求,我们可以结合keychain,基本流程是:
- 从
SFCookie
获取特定键的cookie,若能取到并检验有效,便是所需要的设备码,结束 - 获取keychain保存的共享的设备码,若存在便是所需设备码,并将结果写入
SFCookie
,结束 - 生成/获取设备码,写入keychain及
SFCookie
,结束
具体查看源码。
Author: Jason
Permalink: http://blog.knpc21.com/ios/ios-safari-cookie/
文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。
Comments