Android 中通过 URI 实现 Web 页面调用本地 App
HTML 5 和本地 App 各有所长,现在公司的项目中也大量采用 HTML 5 做活动页面,这样本地代码和 HTML 5 的交互就是必须的。
说到 Android 端 Java 代码和 Web 端 HTML / JS 代码的交互,你可能最先想到的就是 WebView
的这两个方法:
loadUrl(String url)
;addJavascriptInterface(Object object, String name)
;
前者可以实现 native 代码直接执行 JS 代码,而后者可以将 native 代码实现的接口暴露给 Web 页面,这样 Web 页面可以像调用普通 JS function 一样调用这个 native 接口。
但其实还有一种更直接的方式:那就是 URL,准确的说是 URI。
因为 shouldOverrideUrlLoading(WebView view, String url)
等回调方法本身就可以看作 Web 页面通过 URL 和本地应用进行数据交互,因此只要 Web 页面按照 URI 规范将数据传递过来,本地 App 就能在相关回调方法中调用相关 URI 的 API 解析数据,实现数据交互。
事实上,Android 很多内部组件正是通过 URI 传递数据的,特别是在调用系统服务和使用 ContentProvider
时经常用到。例如:
//调用地图应用显示地理位置
Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent it = new Intent(Intent.Action_VIEW, uri);
startActivity(it);
//调用拨号程序
Uri uri = Uri.parse("tel:18616612345");
Intent it = new Intent(Intent.ACTION_DIAL, uri);
startActivity(it);
假设 Web 页面采用一个超链接将数据以 URI 形式传递过来:
<a href="MY_SCHEME:\\MY_HOST:MY_PORT\MY_PATH\?arg0=0&arg1=1">Open App</a>
则 Android 端数据解析代码如下:
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri uri=Uri.parse(url);
if(uri.getScheme().equals(MY_SCHEME)
&& uri.getHost().equals(MY_HOST)
&& uri.getPort() == MY_PORT
&& uri.getPath().equals(MY_PATH)){
String arg0 = uri.getQueryParameter("arg0");
String arg1 = uri.getQueryParameter("arg1");
//TODO
} else {
view.loadUrl(url);
}
return true;
}
});
以上是在 WebView
中加载 Web 页面的情况,如果要使外部浏览器中的 Web 页面也能够调用,则需要在 AndroidManifest.xml
中为指定 Activity
注册 intent-filter
:
<activity
android:name=".activity.UriActivity"
android:exported="true">
<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:scheme="MY_SCHEME"
android:host="MY_HOST"
android:port="MY_PORT"
android:path="MY_PATH"/>
</intent-filter>
</activity>
对应的在处理 URI 的 Activity
中只需要调用 getIntent().getData()
方法即可读取 URI 数据。