iOS是一个自闭的系统,应用之间是不能互相存储,读取文件。为了满足应用的通讯,苹果使用了URL Scheme来实现了这个功能。通过各个APP设计的符合苹果的统一规范的URL Scheme,Url Scheme 是可以用来在各种应用之间传递信息。
URLScheme在iOS中的定义和理解
URLScheme是为方便app之间互相调用而设计的。你可以通过一个类似URL的链接,通过系统的OpenURl来打开该app,并可以传递一些参数。每个URL必须能唯一标识一个APP,如果你设置的URL与别的APP的URL冲突,此时,你的APP不一定会被调用起来,原因是当APP在安装的时候就已经在系统里面注册了此APP的URL Scheme,如果你的一致但是是后安装的,那么系统不会调用你的APP,因为你的APP设置的URL scheme被覆盖了。
简单分析
以微信的为示例,大家都知道微信SDK中集成了登录,分享,支付等功能,这几个也是平时大家用到比较多的功能,都是需要跳转到微信app中进行操作,URLScheme就是作用于应用间互相通讯的,那么我们不妨看看微信在登录,分享,支付的时候分别传递了什么样的信息。
由于URLScheme会互相覆盖,后安装者会覆盖前一个安装者。我们创建一个简单的空白应用,把这个应用的URLScheme设置成**和微信一样,让系统以为后面安装的就是微信。我们可以在这个app中截取URLScheme,然后看看传递的是什么东西。
创建工程,设置工程的URLScheme
在项目里info.plist (非test里面的info.plist)并选择 右键 Open As – Source Code:
加入如下源码:
CFBundleURLTypesCFBundleURLSchemesweixin
就会生成和微信app相同的URLScheme。就是weixin。
在AppDelegate.m里面截取跳转过来的URLScheme,app接收urlScheme传值时会响应此方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
//显示截取的urlscheme
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"接收到的urlScheme" message:url.absoluteString delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
[alert show];
return YES;
}
运行手机上有微信登录,分享,支付的app,点击微信的登录,分享或者支付。看看会发生什么
在iphone找一个有微信的登录,支付,分享的工程的app,在app中做相应的操作。
我们会发现点解微信登录的时候,提示的不是打开微信,而是打开我自己创建的app(get_scheme_str),点击打开会看到我们想看到的。
能看到,在登录的过程中,实际上Scheme是携带一些参数的url。上图的url是
weixin://app/wxa932d071d0f12af2/auth/?scope=snsapi_message%2Csnsapi_userinfo%2Csnsapi_friend%2Csnsapi_contact&state=xxx&supportcontentfromwx=8191
稍微调整一下数据格式
weixin://app/wxa932d071d0f12af2/auth/?scope=snsapi_message,snsapi_userinfo,snsapi_friend,snsapi_contactstate=xxxsupportcontentfromwx=8191
接过微信sdk的朋友一定可以非常简单的看出来这里面其实传递的就是四个参数,分别的是微信后台申请的appid,scope,state,supportcontentfromwx,后面两个经实验固定形式就可以,第一个是appid参数,第二个是登录微信,需要的权限,字段是固定的,用逗号分隔开,这个可以去微信开发者中心查看。也就是说实际上我们只需要填写appid就可以跳转到微信app中进行登录操作。
同样的将你要用到微信登录的app的Scheme设置成在微信后台申请成功的appid。这样通过跳转到微信登录,点击登录后,微信同样会根据这个Scheme返回到相应的app,并携带一串auth认证返回的结果.
wxa932d071d0f12af2://oauth?code=071MME2c1SUdTr0j2B4c1k4D2c1MME2F&state=xxx
可以看到是以为wxa932d071d0f12af2://为协议的Scheme,携带code的参数。我们同样可以在AppDelegate中截取到这个code,然后根据code请求固定的api,拿到登录账号的数据。就可以完成登录。
同样的道理,微信的分享,支付也是一样的。通过以上的方式,我们可以拿到微信分享的Scheme是
weixin://app/wxa932d071d0f12af2/sendreq/?
分享回调的Scheme是
wxa932d071d0f12af2://platformId=wechat
支付的也是一样,支付的URLScheme是
weixin://app/wxa932d071d0f12af2/pay/?partnerId=1455924902&prepayId=wx20170830135454e7f54637ae0987672641&package=Sign%3DWXPay&nonceStr=dd4ftd1vdz9x36haqivffa922sn4ijei&timeStamp=1504072494&signType=SHA1&supportcontentfromwx=8191
支付回调的Scheme是
wxa932d071d0f12af2://pay/?returnKey=(null)&ret=-2
对比官方SDK
这里就以参数最多的支付为示例,首先我们看看微信开放者平台中调起支付的参数介绍和说明
上面的支付URLScheme经过简单的处理后
weixin://app/wxa932d071d0f12af2/pay/?
partnerId=1455924902
prepayId=wx20170830135454e7f54637ae0987672641
package=Sign=WXPay
nonceStr=dd4ftd1vdz9x36haqivffa922sn4ijei
timeStamp=1504072494
signType=SHA1
supportcontentfromwx=8191
我们可以很容易的看到,URLScheme中携带的数据,和微信官方的数据是一样的。url中只是多了一个签名方式和supportcontentfromwx。经测试,这两个数据基本上是固定的。那么我们可以大胆的猜测,在微信官方SDK中发起微信的支付时候,其实最底层还是通过URLScheme的方式进行数据互传的。它通过固定的协议头加上不同的参数来实现应用不同的逻辑。