前言
知乎在手机浏览器打开, 会有个 App 内打开的按钮, 点击直接打开且跳转到该详情页, 是不是有点神奇, 是如何做到的呢?
效果预览
Uri Scheme
配置 intent-filter
- AndroidManifest.xml
- <activity android:name=".MainActivity">
- <!-- 需要添加下面的 intent-filter 配置 -->
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data
- android:host="myhost"
- android:path="/main"
- android:port="1024"
- android:scheme="myscheme" />
- </intent-filter>
- </activity>
测试网页
main 下新建 assets 文件, 写了简单的 html 网页用于 webView 展示, 来进行测试.
- index.html:
- <html>
- <head>
- <meta charset="UTF-8">
- </head>
- <body>
- <h1 > 这是一个 WebView</h1>
- <a href="market://details?id=com.tencent.mm">open app with market</a>
- <br/>
- <br/>
- <a href="myscheme://myhost:1024/main?key1=value1&key2=value2">open app with Uri Scheme</a>
- <br/>
- <br/>
- </body>
- </html>
Web View 加载:
webView.loadUrl("file:///android_asset/index.html");
目标页面
接受参数, 做相应的处理.
- Intent intent = getIntent();
- if (null != intent && null != intent.getData()) {
- // uri 就相当于 web 页面中的链接
- Uri uri = intent.getData();
- Log.e(TAG, "uri=" +uri);
- String scheme = uri.getScheme();
- String host = uri.getHost();
- int port = uri.getPort();
- String path = uri.getPath();
- String key1 = uri.getQueryParameter("key1");
- String key2 = uri.getQueryParameter("key2");
- Log.e(TAG, "scheme=" + scheme + ",host=" + host
- + ",port=" + port + ",path=" + path
- + ",query=" + uri.getQuery()
- + ",key1=" + key1 + ",key2=" + key2);
- }
打印消息如下:
- uri=myscheme://myhost:1024/main?key1=value1&key2=value2
- scheme=myscheme,host=myhost,port=1024,path=/main,query=key1=value1&key2=value2,key1=value1,key2=value2
原理
- myscheme://myhost:1024/main?key1=value1&key2=value2, 通过一个链接, 为什么能启动相应的 APP 呢? Web 唤起 Android app 的实现及原理 http://johnnyshieh.me/posts/web-evoke-app/ , 一文说到关键代码在 Android 6.0 的原生浏览器的 shouldOverrideUrlLoading 方法, 核心实现在 http://androidxref.com/6.0.1_r10/xref/packages/apps/Browser/src/com/android/browser/UrlHandler.java 这个类中. 代码如下:
- final static String SCHEME_WTAI = "wtai://wp/";
- final static String SCHEME_WTAI_MC = "wtai://wp/mc;";
- boolean shouldOverrideUrlLoading(Tab tab, WebView view, String url) {
- if (view.isPrivateBrowsingEnabled()) {
- // Don't allow urls to leave the browser app when in
- // private browsing mode
- return false;
- }
- if (url.startsWith(SCHEME_WTAI)) {
- // wtai://wp/mc;number
- // number=string(phone-number)
- if (url.startsWith(SCHEME_WTAI_MC)) {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(WebView.SCHEME_TEL +
- url.substring(SCHEME_WTAI_MC.length())));
- mActivity.startActivity(intent);
- // before leaving BrowserActivity, close the empty child tab.
- // If a new tab is created through JavaScript open to load this
- // url, we would like to close it as we will load this url in a
- // different Activity.
- mController.closeEmptyTab();
- return true;
- }
- //......
- }
源码
公众号吴小龙同学回复SchemeSample, 获取这次练习的完整示例.
Deep Links
如图, 在 Android M 之前, 如果点击一个链接有多个 APP 符合, 会弹出一个对话框, 询问用户使用哪个应用打开 - 包括浏览器应用. 谷歌在 Android M 上实现了一个自动认证 (auto-verify) 机制, 让开发者可以避开这个弹出框, 使用户不必去选择一个列表, 直接跳转到他们的 APP.
创建
Android M 的 App Links 实现详解 https://github.com/hehonghui/android-tech-frontier/blob/master/issue-15/Android-M的App-Links实现详解.md
Android M App Links: 实现, 缺陷以及解决办法 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0718/3200.html
我没有验证, 因为我玩不起来, 有条件更新下 Deep Links 这块内容, 可以自己搭个本地服务器.
弊端
需要 Android M
需要 Android 6.0(minSdkVersion 级别 23)及更高版本上的才能使用.
.well-known/assetlinks.json
开发者必须维护一个与 app 相关联的网站, 通过在以下位置托管数字资产链接 JSON 文件来声明您的网站与您的意图过滤器之间的关系:
https://domain.name/.well-known/assetlinks.json
参考
Android 使用 Scheme 实现从网页启动 APP https://www.jianshu.com/p/1cd02fe1810f
Deep Link 是什么 http://blog.zhaiyifan.cn/2016/02/04/deeplink-intro/
Android 移动开发者必须知道的 Deep Linking 技术 https://segmentfault.com/a/1190000006101709
Handling Android App Links https://developer.android.com/training/app-links/index.html
来源: https://juejin.im/post/5ac8d87df265da239e4e54d3