iOS渠道分包2种模式之包内注入文件分包(iOS13验证签名问题)
解决问题:商业模式中会存在这样的形式1款app需要不同的运用团队(工会)去分包推广,谁推广的包下载的人数都会在服务器记录,不同渠道的标示唯一来区分。
iOS渠道分包模式有两种:着重讲第二种
一、IDFA模式
IDFA全称应该是Identifier For Advertising, 一个跟device相关的唯一标识符,可以理解为广告id,apple公司提供的用于追踪用户的广告标识符,可以用来打通不同app之间的广告。适用于对外:例如广告推广,换量等跨应用的用户追踪等。比如你在淘宝里搜索了某个商品之后,你在用浏览器去浏览网页的时候,那个网页的广告就会给你展示相应的那个商品的广告。当然你可以重置你的IDFA,使别人不能再track到你的行为。
缺点:如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。 另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成
因为IDFA是可以改变的,所以之前很多人都想拿到一个唯一不变的值比如说UDID(Unique Device Identifier, 这个是跟手机绑定的,用户不能更改),但是Apple后来禁止苹果应用获取UDID。所以现在IDFA成为了iphone用户的标识符的标准。
IDFA是一串16进制的32位串。有了IDFA之后,相当于广告追踪,你所有的浏览历史都会被别的商家利用,给你推相同或相似的广告。
另外一个apple上可以用到的标识符是UUID,Universally Unique IDentifier,在应用程序使用生命期间,这个 UUID保持不变。但如果用户重新安装,那么这个 UUID 就会发生变化。
还有一个类似的标识符叫做IDFV,Identifier for Vendor, 来自同一个开发商比如亚马逊下边的购物app和kindle app,此值是相同的。这样可以做到同一开发商下的不同app做到信息共享。
关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广 告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。
在同一个设备上的所有App都会取到相同的值,是苹果专门给各广告提供商用来追踪用户而设的,用户可以在 设置|隐私|广告追踪 里重置此id的值,或限制此id的使用,故此id有可能会取不到值,但好在Apple默认是允许追踪的,而且一般用户都不知道有这么个设置,所以基本上用来监测推广效果,是戳戳有余了。
注意:由于idfa会出现取不到的情况,故绝不可以作为业务分析的主id,来识别用户。
因此,IDFA就是用来跟踪广告推广的,而UUID虽然每次不同,但是可以自己手动存入Keychain来进行唯一性的确保,这么说来IDFA就是广告商投放的时候使用,而UUID就是自己后台来判断用户是否换了设备,或者信息不一致需要重新登录的业务。
好了, 总结一下这三个标识符:
UUID, app之内信息共享。
IDFV, 同一开发商下的不同app信息共享。
IDFA,同一设备下的不同app信息共享。
二、母包(没有种植文件的叫母包,种植完文件的叫子包,母包只有一个用来种植,子包可以多个)种植文件的形式
1、我们随便打一个ipa包;
2、然后通过后台或者window电脑注入一个文件-我们定义文件名为channel_xxxx(xxxx为渠道id);
key:关键来了我们怎么注入一个文件才能在用户打开app的时候取到这个文件名?
3、然后会有一个文件路径12345->Payload->bixinlive,然后bixinlive显示包内容:里边有一个_CodeSignature文件(这个文件是验证签名的文件),在他的路径下注入一个名字问channel_EFS89V的文件;
4、代码取到这个文件的文件名;
NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; NSString *path = [NSString stringWithFormat:@"%@/%@", bundlePath, @"_CodeSignature"]; NSFileManager *manager = [NSFileManager defaultManager]; NSString *channel = @""; if ([manager fileExistsAtPath:path]) { NSArray *allPath =[manager subpathsAtPath:path]; //4.遍历所有的子路径 for (NSString *subPath in allPath) { if ([subPath containsString:@"channel_"]) { channel = [subPath substringFromIndex:@"channel_".length]; } } }
//然后请求接口把渠道id传给后台。
iOS13签名验证这种方式会验证签名不通过;
三、解决iOS13的问题
iOS13会验签_CodeSignature的文件的所有内容文件;
所以我们要换一种方案;
偶然发现苹果在验证签名的时候不会验签文件夹。所以我们只需要在_CodeSignature同一级别文件夹(非子文件夹)种植一个文件夹channel,文件夹内同样的有一个文件夹(记住都要是文件夹)名字为channel_EFS89V通过二的方式去文件夹的名字。
然后取文件夹的名字作为渠道id
AFHTTPSessionManager *session = [AFHTTPSessionManager manager]; NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; NSString *path2 = [NSString stringWithFormat:@"%@/%@", bundlePath, @"channel"]; NSFileManager *manager = [NSFileManager defaultManager]; NSString *channel = @""; if ([NSString isEmpty:channel]) { if ([manager fileExistsAtPath:path2]) { NSArray *allPath =[manager subpathsAtPath:path2]; //4.遍历所有的子路径 for (NSString *subPath in allPath) { if ([subPath containsString:@"channel_"]) { channel = [subPath substringFromIndex:@"channel_".length]; } } } }
//取到的channel问渠道id,然后吧channel作为渠道id传给后台接口内