简介
我们都知道苹果手机中的APP都有一个沙盒,APP就是一个信息孤岛,相互是不可以进行通信的。但是iOS的APP可以注册自己的URL Scheme,URL Scheme是为方便app之间互相调用而设计的。我们可以通过系统的OpenURL来打开该app,并可以传递一些参数
URL Scheme必须能唯一标识一个APP,如果你设置的URL Scheme与别的APP的URL Scheme冲突时,你的APP不一定会被启动起来。因为当你的APP在安装的时候,系统里面已经注册了你的URL Scheme。 一般情况下,是会调用先安装的app。但是iOS的系统app的URL Scheme肯定是最高的。所以我们定义URL Scheme的时候,尽量避开系统app已经定义过的URL Scheme。
注册URL Scheme
-
方法一
在TARGETS
->Info
->URL Types
点击添加
-
方法二
在info.plist中右击,选中
- Add Row选项,然后输入URL types,类型为 Array
URL Identifier
是自定义的URL scheme
的名字,一般采用反转域名的方法保证该名字的唯一性,比如com.DemoB.www
,不过在iOS中打开一个应用程序只需要拿到这个应用程序的协议头(URL Scheme
)即可,所以我们只需配置应用程序的协议头即可。一个应用是可以有多个URL Schemes
的。
使用
1. 应用A跳转到应用B
这里创建了两个应用:DemoA 和DemoB
,DemoB
注册了Scheme
为"DemoBScheme"
,下面来实现DemoA→DemoB
的跳转
#pragma mark - DemoA -> DemoB
- (IBAction)jumpToDemoB:(id)sender {
NSString *urlString = @"DemoBScheme://";//没有参数
NSURL *url = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
}];
}
else {
[self showMessage:@"没有该应用"];
}
}
-
这里使用的是模拟器来运行,分别运行下两个应用,然后在
DemoA
中点击相应的按钮跳转到DemoB
,会发现并不能跳转,因为在iOS9
以后,如果使用canOpenURL:
方法,该方法所涉及到的URL Schemes
必须在"Info.plist"
中将它们列为白名单,否则不能使用,
在 Info.plist
中添加LSApplicationQueriesSchemes
字段,该字段对应的是数组类型,然后添加键值为DemoBScheme
(DemoB的Scheme)
然后运行,点击按钮就可以跳转到DemoB
2. 跳转到指定页面
有的时候我们需要跳转到某个应用的特定页面,比如分享的时候需要分享到朋友圈页面
- 首先在DemoB中创建PageOne和PageTwo页面
- 在
DemoA
中的点击事件中,我们可以修改urlString
为DemoBScheme://page1
,其中DemoBScheme://
是DemoB
应用的scheme
,page1
是与DemoB
约定好的跳转到PageOne
页面的标识符
#pragma mark - 跳转到pageOne页面
- (IBAction)jumpToPageOne:(id)sender {
NSString *urlString = @"DemoBScheme://page1?DemoAScheme";// DemoBScheme:// 是DemoB应用的scheme page1是与DemoB约定好的跳转到PageOne页面的标识符 ?是分割符(当然也可以用其他符号作分割),在DemoB中通过分隔符来截取DemoA的scheme, DemoAScheme是自己的scheme,用来从DemoB跳转回来
NSURL *url = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
}];
}
else {
[self showMessage:@"没有该应用"];
}
}
2.在 DemoB
的appdelegatete
中实现application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary
方法
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
// 1.获取导航栏控制器
UINavigationController *rootNav = (UINavigationController *)self.window.rootViewController;
// 2.获得主控制器
UIViewController *mainVc = [rootNav.childViewControllers firstObject];
// 3.每次跳转前必须是在跟控制器(细节)
[rootNav popToRootViewControllerAnimated:NO];
if ([url.absoluteString containsString:@"page1"]) {//与DemoA约定好的字符
PageOneViewController *page = [[PageOneViewController alloc] init];
page.urlString = url.absoluteString;
[mainVc.navigationController pushViewController:page animated:YES];
}
else if ([url.absoluteString containsString:@"page2"]) {
PageOneViewController *page = [[PageOneViewController alloc] init];
page.urlString = url.absoluteString;
[mainVc.navigationController pushViewController:page animated:YES];
}
else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"打开啦"
message:[NSString stringWithFormat:@"scheme - %@,\n host -- %@,\n query -- %@",url.scheme,url.host,url.query]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
NSLog(@"query -- %@", url.query);
[alertView show];
}
return YES;
}
这样就实现了DemoA跳转到DemoB中某个特定页面
iOS 9.0
之前应在- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
方法中设置,这里就不再列出了,以下同上
3. 从DemoB返回到DemoA
上面讲了从DemoA跳转到DemoB,有的时候在跳转完之后需要再跳回到原本的app,比如分享完成之后会让选择返回到原来的app还是留在微信
- 从某个应用跳转到另一个应用上面已经讲过了,现在要从DemoB回到DemoA的话首先也是为DemoA注册URL Scheme,然后再DemoB的Info.plist中设置白名单,把DemoA的scheme添加进去
- 在我们从DemoA跳转到DemoB的时候,我们应该顺便把DemoA的Scheme传递过去
#pragma mark - 跳转到pageOne页面
- (IBAction)jumpToPageOne:(id)sender {
//我们想要从应用B再跳转回应用A,那么在跳转到应用B的时候,还应将应用A的URL Schemes传递过来。这样我们才能判断应该跳转回哪个应用程序。
// 这样我们指定一个传递URL的规则:协议头://应用B的URL Schemes?应用A的URL Schemes。即:AppB://Page1?AppA。
NSString *urlString = @"DemoBScheme://page1?DemoAScheme";// DemoBScheme:// 是DemoB应用的scheme page1是与DemoB约定好的跳转到PageOne页面的标识符 ?是分割符(当然也可以用其他符号作分割),在DemoB中通过分隔符来截取DemoA的scheme, DemoAScheme是自己的scheme,用来从DemoB跳转回来
NSURL *url = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
}];
}
else {
[self showMessage:@"没有该应用"];
}
}
- 在
DemoB
中的- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary
方法中我们把收到的*)options url
传递给PageOne
页面
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options {
// 1.获取导航栏控制器
UINavigationController *rootNav = (UINavigationController *)self.window.rootViewController;
// 2.获得主控制器
UIViewController *mainVc = [rootNav.childViewControllers firstObject];
// 3.每次跳转前必须是在跟控制器(细节)
[rootNav popToRootViewControllerAnimated:NO];
if ([url.absoluteString containsString:@"page1"]) {//与DemoA约定好的字符
PageOneViewController *page = [[PageOneViewController alloc] init];
page.urlString = url.absoluteString;
[mainVc.navigationController pushViewController:page animated:YES];
}
else if ([url.absoluteString containsString:@"page2"]) {
PageOneViewController *page = [[PageOneViewController alloc] init];
page.urlString = url.absoluteString;
[mainVc.navigationController pushViewController:page animated:YES];
}
else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"打开啦"
message:[NSString stringWithFormat:@"scheme - %@,\n host -- %@,\n query -- %@",url.scheme,url.host,url.query]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
NSLog(@"query -- %@", url.query);
[alertView show];
}
return YES;
}
4.在DemoB
的pageOne
页面的点击事件中通过约定好的切割符号截取DemoA
的Scheme
#pragma mark - 返回DemoA
- (IBAction)backDemoA:(id)sender {
// 1.拿到对应应用程序的URL Scheme 通过约定好的分割符?切割
NSString *urlSchemeString = [[self.urlString componentsSeparatedByString:@"?"] lastObject];
NSString *urlString = [urlSchemeString stringByAppendingString:@"://"];
// 2.获取对应应用程序的URL
NSURL *url = [NSURL URLWithString:urlString];
// 3.判断是否可以打开
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
}
}
4. 通过URL传参
- 有的时候我们跳转到另一个app的时候需要传递一些参数,让另一个app根据我们传递的参数作出相应的行为
传参的格式如下:
"DemoBScheme://?name=lwy&phone=110"
- 可以发现跟我们用get请求的接口是一样的
- 跳转的时候传参
#pragma mark - DemoA -> DemoB
- (IBAction)jumpToDemoB:(id)sender {
// NSString *urlString = @"DemoBScheme://";//没有参数
NSString *urlString = @"DemoBScheme://?name=lwy&phone=110";//后面拼接参数
NSURL *url = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
}];
}
else {
[self showMessage:@"没有该应用"];
}
}
2.在demoB
中的- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary
方法可以获取到参数
NSString *query = url.query;
我们打印query
2017-02-20 15:39:58.723 DemoB[3537:184333] query -- name=lwy&phone=110
5. 通过网址打开app
- 网页打开app也是根据app的协议头(URL scheme)来区分打开的是哪一个app的,我们直接在浏览器上复制粘贴我们的url scheme ,系统会自动弹框提醒是否打开本应用,跟DemoA跳转到DemoB的跳转是一样的, 当然网页传参跟app跳转传参都是一样的格式,
最后一点:
- 在
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary
方法中打印*)options url
的scheme
的时候,发现scheme
是小写的,如图所示
- 而实际上设置的
scheme
为DemoB
, 然而当我重新创建一个应用的时候输出scheme又是正确的大小写了,不知道是不是系统原因造成的,所以笔者建议如果要在应用里判断scheme
是否为某一个值的时候应该是app
的scheme
的纯小写字符串和原本字符串同时判断一下
if ([url.schemeisEqualToString:@"app的scheme的纯小写字符串" ] || [url.schemeisEqualToString:@"app的scheme的原本字符串" ]){
}
Demo地址:Github下载