如何自定义 URL Scheme 进行跳转

一、URL Scheme 简介和作用

相信大家都知道 URL,例如 http://www.jianshu.com/ 就是一个URL。

:// 之前的部分就称为 URL Scheme。

也就是说 http://www.jianshu.com/ 的 URL Scheme 就是 http 。

更多关于 URL参数介绍:NSURL简介

由于苹果的app都是在沙盒中,相互是不能访问数据的。但是苹果还是给出了一个可以在app之间跳转的方法:URL Scheme

简单的说,URL Scheme 就是一个可以让 app 相互之间可以跳转的协议(例如上面的 http)。

每个app的 URL Scheme 都是不一样的,如果存在一样的 URL Scheme,那么系统就会响应先安装那个app的 URL Scheme,因为后安装的app的 URL Scheme 被覆盖掉了,是不能被调用的。

那么app之间的跳转有什么作用呢?我们所使用的每一个app就相当于一个功能,app的跳转可以使得每个app就像一个功能组件一样,帮助我们完成需要做的事情,比如三方支付,搜索,导航,分享等。

二、使用URL Scheme 跳转到系统

要跳转到别人的app,就要知道别人的app的跳转协议是什么,需要传入什么参数,我们常见的跳转到系统有下面这些:

// 1.打开Mail
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto:frank@wwdcdemo.example.com"]]
// 2.打开电话
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel:1-408-555-5555"]];
// 3.打开SMS
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms:1-408-555-1212"]];

有关系统支持的URL Scheme的详细信息,请参阅 Apple URL Scheme ReferenceiOS10如何跳转到系统设置

三、自定义 URL Scheme 进行跳转

1、注册自定义 URL Scheme

如果我们希望别人打开我们的 app(名字叫做 SchemeDemo),需要注册自定义 URL Scheme,通过 info.plist --> URL Types --> item0 --> URL Schemes --> 你的TestScheme 来设置,详细步骤如下:

  • 1、点击工程中的 info.plist 文件,当该文件显示在如下窗口时,在列表顶部鼠标选中 Information Property List,选择 +,然后向下滚动弹出的列表并选择 URL types,类型为 NSArray

    添加 URL types

  • 2、点击 URL types 左边剪头打开列表,可以看到 Item 0,一个字典实体。展开 Item 0,可以看到 URL Identifier,一个字符串对象。该字符串是你自定义的 URL scheme 的名字。建议采用反转域名的方法保证该名字的唯一性,比如 com.yourCompany.yourApp

    设置 URL Identifier

  • 3、点击 Item 0 新增一行,从下拉列表中选择 URL Schemes,敲击键盘回车键完成插入。注意 URL Schemes 是一个数组,允许应用定义多个 URL schemes

    添加 URL Schemes

    URL Schemes 是一个数组

  • 4、展开 URL Schemes 该数据并点击 Item 0。你将在这里定义自定义 URL scheme 的名字。只需要名字,不要在后面追加 ://,比如,如果你输入 iOSDevApp,你的自定义 url 就是 iOSDevApp://

    添加 URL Scheme 名字

此时,整个定义如下图:


完整定义
2、从 Safari 中调用自定义 URL Scheme

使用模拟器调用应用的步骤:

  • 在 Xcode 中运行应用

  • 一旦应用被安装,自定义 URL scheme 就会被注册

  • 通过模拟器的硬件菜单中选择 Home 来关闭应用

  • 启动 Safari

  • 在浏览器地址栏输入之前定义的 URL scheme (如下)

在 Safari 中调用自定义 URL Scheme
  • 点击回车,弹出提示框 (如下)
弹窗提示
  • 点击 打开 此时 Safari 将会进入后台,应用会被带回到前台。

祝贺你刚刚使用自定义 URL scheme 调用了一个 iPhone 应用。

3、从另一个应用( NewDemo )中调用( SchemeDemo中的 )自定义 URL Scheme

新建一个应用 NewDemo,来调用 SchemeDemo 中自定义的 URL scheme

新建应用 NewDemo 只有一个 UIButton,点击这个按钮则会通过应用(SchemeDemo)自定义的 URL scheme 来调用应用(SchemeDemo)。

点击按钮通过自定义 URL scheme 进行跳转

在按钮点击方法 clickBtn 中代码处理 URL 调用:

- (void)clickBtn {
    
    NSString *urlString = @"iOSDevApp://";
    // 若有中文传输需要进行转义
    NSString *customURL = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    // 检查自定义 URL 是否被定义,如果定义了,则使用 shared application 实例来打开 URL
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:customURL]]) {
        // openURL: 方法启动应用并将 URL 传入应用,在此过程中,当前的应用进入后台
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
        
    } else {
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"URL error" message:[NSString stringWithFormat:@"No custom URL defined for %@", customURL] delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
        [alert show];
    }
}

如果你的系统版本低于 iOS 9,那么已经可以进行调用了,但是如果是在 iOS 9及以后的系统版本中仍会出现无法调用,并在控制台输出如下错误:

-canOpenURL: failed for URL: "iOSDevApp://" - error: "This app is not allowed to query for scheme iosdevapp"

原因:因为从 iOS 9 开始系统引入了 LSApplicationQueriesSchemes,就是白名单。

用意:当前App允许访问的App有哪些,需要通信双方均设置为对方的 scheme,否则当调用对方App时,系统会告诉你 This app is not allowed to query for scheme

调用者和被调用者均需要设置白名单,一方想调用,另一方需要也知道将被你调用 ,更为安全。

解决办法:此时需要在 NewDemo 和 SchemeDemo 中的 info.plist 里面相互设置为白名单(LSApplicationQueriesSchemes)。详情如下:This app is not allowed to query for scheme

设置好之后重新运行就可以了:点击打开就可以跳转到 SchemeDemo 中了。

点击跳转提示
4、通过自定义 URL Scheme 向应用传递参数

有时你需要通过自定义 URL 向应用中传递参数。让我们看看该如何完成这个工作。

NSURL 作为从一个应用调用另一个的基础,遵循 RFC 1808 (Relative Uniform Resource Locators) 标准。 因此你所熟悉的基于网页内容的 URL 格式在这里也适用。

在自定义了 URL scheme 的应用中,AppDelegate 必须实现以下方法:

// iOS 9.0前方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation;

// iOS 9.0后方法
- (BOOL)application:(UIApplication *)app openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;

从一个应用传递参数到另一个的诀窍是通过 URL。例如,假设我们使用以下的 URL scheme,想传递一个名为 “token”的参数和一个标识注册状态的标志,我们可以像这样创建一个 URL:

// 若有中文传输需要进行转义
NSString *customURL = @"iOSDevTips://?token=123abct&registered=1";

在 web 开发中,字符串 ?token=123abct&registered=1 被称作查询字符串(query string)。

在被调用(设置了自定义 URL)的应用的 AppDelegate 中,获取参数的代码如下:

// iOS 9.0前方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {

    NSLog(@"Calling Application Bundle ID: %@", sourceApplication);
    NSLog(@"URL scheme: %@", [url scheme]);
    NSLog(@"URL query: %@", [url query]);

    return YES;
}

// iOS 9.0后方法
- (BOOL)application:(UIApplication *)app openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    
    NSLog(@"options: %@", options);
    NSLog(@"Calling Application Bundle ID: %@", [options objectForKey:@"UIApplicationOpenURLOptionsSourceApplicationKey"]);
    NSLog(@"URL scheme: %@", [url scheme]);
    NSLog(@"URL query: %@", [url query]);
    
    return YES;
}

在 iOS 9.0 之后,以上代码在应用被调用时的输出如下:

options: {
    UIApplicationOpenURLOptionsOpenInPlaceKey = 0;
    UIApplicationOpenURLOptionsSourceApplicationKey = "--.NewDemo";
}
Calling Application Bundle ID: --.NewDemo
URL scheme: iOSDevApp
URL query: token=123abct&registered=1

注意 “Calling Application Bundle ID”,你可以用这个来确保只有你定义的应用可以与你的应用直接交互。

让我们改变一下代码,来验证发起调用的应用的 Bundle ID 是否合法:

// iOS 9.0前方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    
    NSLog(@"Calling Application Bundle ID: %@", sourceApplication);
    NSLog(@"URL scheme: %@", [url scheme]);
    NSLog(@"URL query: %@", [url query]);
    
    // Check the calling application Bundle ID
    if ([sourceApplication isEqualToString:@"--.NewDemo"]) {
        
        return YES;
    }
    
    return NO;
}

// iOS 9.0后方法
- (BOOL)application:(UIApplication *)app openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

    NSLog(@"options: %@", options);
    NSLog(@"Calling Application Bundle ID: %@", [options objectForKey:@"UIApplicationOpenURLOptionsSourceApplicationKey"]);
    NSLog(@"URL scheme: %@", [url scheme]);
    NSLog(@"URL query: %@", [url query]);
    
    // Check the calling application Bundle ID
    if ([[options objectForKey:@"UIApplicationOpenURLOptionsSourceApplicationKey"] isEqualToString:@"--.NewDemo"]) {
        
        return YES;
    }
    
    return NO;
}

有一点要特别注意,你不能阻止其他应用通过自定义 URL scheme 调用你的应用,然而你可以跳过后续的操作并返回 NO,就像上面的代码那样。也就是说,如果你想阻止其它应用调用你的应用,创建一个与众不同的 URL scheme。尽管这不能保证你的应用不会被调用,但至少大大降低了这种可能性。

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

推荐阅读更多精彩内容