iOS scheme跳转机制

简介

我们都知道苹果手机中的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 点击添加

    1.png

  • 方法二
    在info.plist中右击,选中


    2.png
    • Add Row选项,然后输入URL types,类型为 Array

URL Identifier是自定义的 URL scheme 的名字,一般采用反转域名的方法保证该名字的唯一性,比如 com.DemoB.www,不过在iOS中打开一个应用程序只需要拿到这个应用程序的协议头(URL Scheme)即可,所以我们只需配置应用程序的协议头即可。一个应用是可以有多个URL Schemes的。

使用

1. 应用A跳转到应用B

这里创建了两个应用:DemoA 和DemoBDemoB注册了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)

074196E0-A963-4828-AADA-1B717D983CA3.png

然后运行,点击按钮就可以跳转到DemoB

2. 跳转到指定页面

有的时候我们需要跳转到某个应用的特定页面,比如分享的时候需要分享到朋友圈页面

  1. 首先在DemoB中创建PageOne和PageTwo页面
  • DemoA中的点击事件中,我们可以修改urlStringDemoBScheme://page1,其中DemoBScheme://DemoB应用的schemepage1是与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.在 DemoBappdelegatete中实现application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options方法

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)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还是留在微信

  1. 从某个应用跳转到另一个应用上面已经讲过了,现在要从DemoB回到DemoA的话首先也是为DemoA注册URL Scheme,然后再DemoB的Info.plist中设置白名单,把DemoA的scheme添加进去
  2. 在我们从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:@"没有该应用"];
    }
}
  1. DemoB中的- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options 方法中我们把收到的url传递给PageOne页面
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)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.在DemoBpageOne页面的点击事件中通过约定好的切割符号截取DemoAScheme

#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请求的接口是一样的
  1. 跳转的时候传参
#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<UIApplicationOpenURLOptionsKey,id> *)options方法可以获取到参数

 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跳转传参都是一样的格式,
1989C378-1DC2-4FFA-80D9-3DCCF8246719.png

最后一点:

  • - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options方法中打印urlscheme的时候,发现scheme是小写的,如图所示
粘贴图片.png
  • 而实际上设置的schemeDemoB , 然而当我重新创建一个应用的时候输出scheme又是正确的大小写了,不知道是不是系统原因造成的,所以笔者建议如果要在应用里判断scheme是否为某一个值的时候应该是appscheme的纯小写字符串和原本字符串同时判断一下
if ([url.schemeisEqualToString:@"app的scheme的纯小写字符串" ] || [url.schemeisEqualToString:@"app的scheme的原本字符串" ]){
        
}

Demo地址:Github下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容