需求:假设有应用A和应用B两个应用,现在需要从应用A跳转到应用B中。如果手机中没有安装跳到下载页,如果已经安装直接打开APP。
认识URL Scheme
URL Schemes是苹果给出的用来跳转到系统应用或者跳转到别人的应用的一种机制。同时还可以在应用之间传数据。所以想要打开别人的APP或者让别人打开我们的APP,那就需要通过URL Schemes了!
1、一些概念的补充
协议:双方互相遵守的一种规范,只有遵守共同的协议规范才能进行彼此的通信。比如我们最熟悉的网络协议——http协议。
URL:资源的路径或地址。在IOS中有一个专门用于包装资源路径的类——NSURL。
一个完整URL的组成
例如:http://123.0.0.1/path?page=100
“http://”:协议类型
“123.0.0.1”:服务器ip地址
“/path”:资源存放的是路径
“page=100”:请求的参数
NSURL包装一个完整地址
NSURL *url = [NSURL URLWithString:@"http://123.0.0.1/path?page=100"];
NSLog(@"scheme(协议):%@",url.scheme);
NSLog(@"host(域名):%@",url.host);
NSLog(@"path(路径):%@",url.path);
NSLog(@"query(参数):%@",url.query);
打印结果如下:
2016-12-02 14:50:38.442 TestDemo[5632:406869] scheme(协议):http
2016-12-02 14:50:38.442 TestDemo[5632:406869] host(域名):123.0.0.1
2016-12-02 14:50:38.442 TestDemo[5632:406869] path(路径):/path
2016-12-02 14:50:38.442 TestDemo[5632:406869] query(参数):page=100
2、跳转的原理
在iOS中,从一个app打开另一个app,实际上是两个app之间的交互和通信。我们知道一些跳转系统应用的用法:
//拨打系统电话
NSURL *url = [NSURL URLWithString:@"tel://10086"];
[[UIApplication sharedApplication] openURL:url];
//发送系统短信
NSURL *url = [NSURL URLWithString:@"sms://1383838438"];
[[UIApplication sharedApplication] openURL:url];
拨打系统电话、发送系统短信其实就是应用间的跳转。执行以上方法就会从你当前的应用跳转到系统的拨打电话界面、或者发送短信界面,普通的应用间的跳转只是传递的NSURL参数不一样,完成跳转到不同的应用场景。
总结:
一个应用能打开另一个应用的必然条件是:另一个应用必须配置一个scheme(协议),这样应用程序才能根据协议找到需要打开的应用。
3、实现两个app间的跳转
创建两个demo 工程:发达和ProtocolTest。现在我要从应用:发达 打开应用:ProtocolTest。
- 在被跳转的ProtocolTest配置一个协议scheme:projectB
( 名字可随意配置,当然最好是英文并且跟你项目相关)
ProtocolTest的bundleID是: com.suning.ProtocolTest
targets -> info -> URL Types ->URL Scheme ->填写协议
方法二:
以上设置是等效的,用一种设置即可。
- 在工程 发达 中实现跳转的代码,发达的bundleID是: com.suning.–
//
// ViewController.m
// 发达
//
// Created by lzz on 2019/3/8.
// Copyright © 2019 lzz. All rights reserved.
//
#import "ViewController.h"
// 这是一个未发布到AppStore的企业版应用的下载地址
#define WOHAIBAO_DOWNLOAD_URL @"https://daweb.cnsuning.com/snf-da-web/download.html"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.title = @"你哈皮";
}
- (IBAction)pushLoadBundle:(id)sender {
// ?token=123abct®istered=1 这是参数
[self openScheme:@"projectB://?token=123abct®istered=1"];
}
- (void)openScheme:(NSString *)scheme {
UIApplication *application = [UIApplication sharedApplication];
NSURL *URL = [NSURL URLWithString:scheme];
// 这里做了判断,兼容iOS 9以前的API
if ([application respondsToSelector:@selector(openURL:options:completionHandler:)]) {
[application openURL:URL options:@{}
completionHandler:^(BOOL success) {
NSLog(@"Open %@: %d",scheme,success);
if (!success) {
// 打不开,表示手机中不存在,跳到下载页
[self openScheme:WOHAIBAO_DOWNLOAD_URL];
}
}];
} else {
if ([[UIApplication sharedApplication] canOpenURL:URL]) {
[[UIApplication sharedApplication] openURL:URL];
}else{
// 打不开,表示手机中不存在,跳到下载页
[self openScheme:WOHAIBAO_DOWNLOAD_URL];
}
}
}
@end
- 在被跳转的ProtocolTest 的AppDelegate.m中添加接受参数的方法
// 公共处理方法
- (void)handleUrl:(NSURL *)url {
NSString *urlStr = [url absoluteString];
NSLog(@"urlStr---%@",urlStr);
NSString *queryStr = [url query];
NSLog(@"queryStr---%@",queryStr);
// &拼接的参数解析
NSArray *parameArr = [queryStr componentsSeparatedByString:@"&"];
NSLog(@"parameArr---%@",parameArr);
for (NSString *canshu in parameArr) {
NSArray *canshuArr = [canshu componentsSeparatedByString:@"="];
NSLog(@"canshuArr---%@",canshuArr);
}
UIAlertView *alertView=[[UIAlertView alloc] initWithTitle:@"heihie" message:urlStr delegate:self cancelButtonTitle:nil otherButtonTitles:@"hah", nil];
[alertView show];
}
// iOS 9之前代理
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation
{
// com.suning.--
if (sourceApplication) {
if (([sourceApplication isEqualToString:@"com.suning.--"])) {
[self handleUrl:url];
}
}
return YES;
}
// iOS 9之后的代理
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
if (options) {
NSString *sourceApplicationBundleId= options[@"UIApplicationOpenURLOptionsSourceApplicationKey"];
if (([sourceApplicationBundleId isEqualToString:@"com.suning.--"])) {
[self handleUrl:url];
}
}
return YES;
}
跳转后接受到的参数,以弹框的形式显示出来
这样就完成了从 **应用A** 到**应用B**的跳转了。
我用真机iOS 12.3测试了,也用模拟器iOS 8.4测试了,均能正常跳转。
4、网上说:iOS 9.0以后,需要配置协议白名单。我没有配置也能正常跳转。我把设置白名单的方法贴一下。
在ProtocolTest的info.plist文件中增加一个LSApplicationQueriesSchemes字段,把它设置为数组类型,并配置需要跳转的协议名单。
⚠️Universal Links方式跳转:请自行百度
因为在微信、QQ里打开会禁止scheme方式打开app,苹果iOS 9推出了Universal Links方式刚好可以解决这一问题。