Android 开发过程中经常会有 H5 页面和 Native 的交互,比如为了在浏览的网页上推广 APP 或改善用户体验,会有类似于天猫、京东的 Banner 条悬浮在网页底部,当手机上已经安装了对应的 APP 时,点击 Banner 条直接唤起 APP 并打开对应的 Native 页面,否则引导用户至 APP 下载页面。用户点击下载 APP 按钮时,网页再通过 JS 判断 User-Agent 对安卓和苹果平台进行区分,达到精准推广的目的。通过 URL 协议打开页面的应用场景大致有以下几种:
- 从 H5 页面打开 APP 的某个页面
- 从其他应用打开 APP 的某个页面
- 服务器下发数据,跳转至某个页面
- 点击消息推送,跳转至某个页面
Android URL Scheme 概念
Android 中的 URL 和我们通常了解的 URL 十分相似,也有类似 协议://授权/路径?查询
的格式。我们可以通过定义自己的 scheme 协议,告知手机我们的应用可以处理哪些协议的 URL,通过解析 URL 就可以知道其携带的资源路径和参数,拿到这些信息后就可以非常方便的跳转 APP 中的各个页面了。
Android URL Scheme 格式
1 | Scheme://Host:Port/Path?Query=Value |
参数名称 | 描述 | 案例 | 是否可省略 |
---|---|---|---|
Scheme | 协议 | sunzn | 否 |
Host | 地址 | baidu | 是 |
Port | 端口 | 8888 | 是 |
Path | 页面 | router | 是 |
Query | 参数 | token | 是 |
Android URL Scheme 使用
1. 配置清单文件
1 | <activity android:name=".RouterActivity"> |
2. 获取 Scheme 参数
1 | Uri uri = getIntent().getData(); |
输出字段 | 输出结果 | 备注 |
---|---|---|
Url | sunzn://baidu:8888/router?token=master&id=4625 | 无 |
Scheme | sunzn | 无 |
Host | baidu | 无 |
Port | 8888 | 无 |
Path | /router | 无 |
Query | token=master&id=4625 | 无 |
Authority | baidu:8888 | 无 |
Token | master | 无 |
Segments | [router] | 无 |
QueryParameterNames | [token, id] | 无 |
SchemeSpecificPart | //baidu:8888/router?token=master&id=4625 | 无 |
3. 网页调用
1 | <a href="sunzn://baidu:8888/router?token=master&id=4625">打开APP页面</a> |
4. 原生调用
1 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("sunzn://baidu:8888/router?token=master&id=4625")); |
5. 如何判断一个 Scheme 是否有效
1 | PackageManager packageManager = getPackageManager(); |
Android URL Scheme 在项目中的应用
知道了 Android URL Scheme 的简单使用,接下来我们看看如何在实际项目中进行使用。从上面的内容中我们知道:想让一个 Activity 响应并实现跳转,需要在清单文件里对该 Activity 的 <intent-filter>
节点进行设置。在跳转单一页面的情况下,这种方式的实现是可行的。那么,问题来了,如果要跳转多个页面呢?难道也要在每个跳转的 Activity 都设置 <intent-filter>
节点并定义不同的 scheme
吗?我们当然不希望通过这种冗余的方式来实现响应跳转,并且这种方式的扩展性也不高。我们理想的状态是定义一个专门的 Activity 来响应所有的网页调用和原生调用,在这个 Activity 里处理跳转逻辑,然后关闭这个 Activity。具体实现如下:
1. 约定一个可扩展协议
1 | sunzn://baidu:8888/router?token=A001&id=4625 |
2. 约定跳转标签和页面
跳转标签 | 跳转页面 | 备注 |
---|---|---|
A001 | A001_Activity | 无 |
A002 | A002_Activity | 无 |
A003 | A003_Activity | 无 |
A004 | A004_Activity | 无 |
A005 | A005_Activity | 无 |
3. 创建一个路由页面
创建路由页面 RouterActivity 并在清单文件中为该页面加入 <intent-filter>
节点设置。
1 | <activity android:name=".RouterActivity"> |
4. 在路由页面响应跳转
1 | public class RouterActivity extends AppCompatActivity { |
这样,就可以通过一个单一页面来响应请求,并将结果路由到指定的页面了。如果要增加新的页面跳转只需要增加对应的跳转标签和页面即可;如果要增加响应模块,可以在原来的路由协议基础上增加一个新的标签键
即可,比如在sunzn://baidu:8888/router?token
的基础上增加一个event
键,这个页面就能响应以sunzn://baidu:8888/router?token
和sunzn://baidu:8888/router?event
开头的 URL 了。