App间跳转

iOS篇

schema

schema是iOS9之前比较主流的一种跳转方案了, 更多的是用在了两个APP相互跳转中。也可以在Safari中输入 schema:// 跳转到App内部
比如在浏览器输入 wechat:// 就可以跳到微信

使用URL Scheme 跳转到系统

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

1
2
3
4
5
6
// 1.打开Mail
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto:[email protected]"]]
// 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 进行跳转

1. 注册自定义 URL Scheme

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

  • (1)、点击工程中的 info.plist 文件,当该文件显示在如下窗口时,在列表顶部鼠标选中 Information Property List,选择 +,然后向下滚动弹出的列表并选择 URL types,类型为 NSArray。
    upload successful
  • (2)、点击 URL types 左边剪头打开列表,可以看到 Item 0,一个字典实体。展开 Item 0,可以看到 URL Identifier,一个字符串对象。该字符串是你自定义的 URL scheme 的名字。建议采用反转域名的方法保证该名字的唯一性,比如 com.yourCompany.yourApp。
    upload successful
  • (3)、点击 Item 0 新增一行,从下拉列表中选择 URL Schemes,敲击键盘回车键完成插入。注意 URL Schemes 是一个数组,允许应用定义多个 URL schemes。
    upload successful
    upload successful
  • (4)、展开 URL Schemes 该数据并点击 Item 0。你将在这里定义自定义 URL scheme 的名字。只需要名字,不要在后面追加 ://,比如,如果你输入 iOSDevApp,你的自定义 url 就是 iOSDevApp://。
    upload successful

此时,整个定义如下图:
upload successful

2. 从 Safari 中调用自定义 URL Scheme

在浏览器地址栏输入之前定义的 URL scheme,然后跳转 (如下)
upload successful
点击 打开 此时 Safari 将会进入后台,应用会被带回到前台。

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (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及以后的系统版本中仍会出现无法调用,并在控制台输出如下错误:

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

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

解决方案:
在 info.plist 增加 key:LSApplicationQueriesSchemes,类型为NSArray。
添加需要支持的白名单,类型为String。
upload successful

4、通过自定义 URL Scheme 向应用传递参数

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/ 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;
}

缺点:

手机没安装要跳转 app 不会提示下载

参考1

参考2

Universal Links(通用链接)是iOS9.0出的新技术。如果我们的应用支持通用链接,那么就可以通过https链接来打开APP(手机中已经安装此APP),或者跳转到https链接(手机中没有安装此APP)。

使用条件

1.有一个注册的域名。
2.支持https请求,并且CA证书是有效的,这个需要与后端同事进行确认。
3.可上传一个json文件到web服务器
4.APP版本至少为iOS9及以上
5.Xcode版本为7以上

通用链接使用说明

1.Xcode配置
upload successful

2.创建apple-app-site-association文件,格式如下

1
2
3
4
5
6
7
8
9
10
11
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMIDSHSAUX.com.test.bundle",
"paths": [ "*" ]
}
]
}
}

相关参数说明
appID:由TeamID.BundleID组成。TeamID可在开发者中心查看,BundleID可在Xcode中查看。
paths:设定一个App的路径支持列表,只有这些指定的路径链接才会被App所处理。(paths是大小写敏感,*是通配符表示任意路径,一般填写这个就可以)

3.上传apple-app-site-association文件
将上面生成好的apple-app-site-association上传到web server
这里一定要跟你的后端&前端小伙伴沟通, 自己是做不出来的哦

apple-app-site-association文件保存的位置
根目录下。etc.https://test.com/apple-app-site-association
.well-known文件夹下(推荐,苹果在iOS9.3更改了通用链接的请求文件的位置,但是仍然支持上面的路径)。在根目录新建.well-known文件夹(不要忘记前面的.)。etc.https://test.com/.well-known/apple-app-site-association

4.检查
(1)使用浏览器打开我们上传的文件路径,应该可以直接看到刚刚上传的json文件,或者是会自动下载到电脑。
(2)苹果也提供了一个官方网页供我们开发者来验证https://test.com/apple-app-site-association是否有效。验证地址:https://search.developer.apple.com/appsearch-validation-tool/
成功的情况应该如下图
upload successful

三、检验成果
重新编译App后,就可以检验成果了。
(1).在备忘录输入你的域名,点击可直接跳转到App,长按会显示(在“AppName”中打开)。

upload successful

四、在App中进行处理
用户通过链接进入我们的App中,在AppDelegate是可以获取该链接的

1
2
3
4
5
6
7
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler
{
NSLog(@"%@", userActivity.webpageURL);

[MGJRouter openURL:[userActivity.webpageURL absoluteString]];
return YES;
}

参考

Android 篇

URL Scheme

以下场景中可以使用URL Scheme

服务器下发跳转路径,客户端根据服务器下发跳转路径跳转相应的页面
H5页面点击锚点,根据锚点具体跳转路径APP端跳转具体的页面
APP端收到服务器端下发的PUSH通知栏消息,根据消息的点击跳转路径跳转相关页面
APP根据URL跳转到另外一个APP指定页面

URL Scheme的使用方法

  1. URL Scheme的使用方法简要言之就是先在manifest中配置能接受Scheme方式启动的activity;当需要调用时,将Scheme协议的URi以Data的形式加入到Intent中,隐式调用该activity。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<activity android:name=".MainActivity">
<intent-filter> <!--正常启动-->
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter> <!--URL Scheme启动-->
<!--必有项-->
<action android:name="android.intent.action.VIEW"/>
<!--如果希望该应用可以通过浏览器的连接启动,则添加该项-->
<category android:name="android.intent.category.BROWSABLE"/>
<!--表示该页面可以被隐式调用,必须加上该项-->
<category android:name="android.intent.category.DEFAULT"/>
<!--协议部分-->
<data android:scheme="urlscheme"
android:host="auth_activity">
</intent-filter>
<intent-filter>
<action android:name="emms.intent.action.check_authorization"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="emms.intent.category.authorization"/>
</intent-filter>
</activity>

上面的设置中可以看到,MainActivity包含多个设置,第一个是正常的启动,也就是在应用列表中启动;第二个是通过URL Scheme方式启动,其本身也是隐式Intent调用的一种,不同在于添加了属性,定义了其接受URL Scheme协议格式为 urlschemel://auth_activity

  1. 使用URL启动Activity
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Uri data = Uri.parse("urlschemel://auth_activity");
    Intent intent = new Intent(Intent.ACTION_VIEW,data);
    //保证新启动的APP有单独的堆栈,如果希望新启动的APP和原有APP使用同一个堆栈则去掉该项
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    try {
    startActivityForResult(intent, RESULT_OK);
    } catch (Exception e) {
    e.printStackTrace();
    Toast.makeText(MainActivity.this, "没有匹配的APP,请下载安装",Toast.LENGTH_SHORT).show();
    }

当然可以在网页中调用

1
<a href="urlschemel://auth_activity">打开新的应用</a>

将子APP在Home Launcher中隐藏

有时候需要把一些辅助性的、较为独立的APP在Home Launcher中隐藏起来,只允许一些特定的APP调用。这个时候,我们可以利用URL Scheme协议来做到这一点,设置AndroidManifest.xml中对标签如下

1
2
3
4
5
6
7
8
9
10
11
12
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.BROWSABLE"/>
<!--表示该页面可以被隐式调用,必须加上该项-->
<category android:name="android.intent.category.DEFAULT"/>
<!--协议部分-->
<data android:scheme="urlscheme"
android:host="auth_activity">
</intent-filter>
</activity>

因为Home Launcher列出的应用图标要求必须有Activity同时满足

1
2
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>

上面的配置中有多余的category和data限制存在,所以并不匹配,不会在Home Launcher出现,但是可以使用URL Scheme来启动。

1
2
3
Uri data = Uri.parse("urlschemel://auth_activity");
Intent intent = new Intent(Intent.ACTION_MAIN,data);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

这样就可以将一组APP设置一个统一的入口,然后根据实际需要在调用不同子APP,即所谓的APP业务组件化,URL Scheme在其中有着重要的作用

参考