共计 4100 个字符,预计需要花费 11 分钟才能阅读完成。
阅读本文完本文请看一下推荐 可以进去交流
什么是 URL Scheme?
android 中的 scheme 是一种页面内跳转协议,是一种非常好的实现机制,通过定义自己的 scheme 协议,可以非常方便跳转 app 中的各个页面;通过 scheme 协议,服务器可以定制化告诉 App 跳转那个页面,可以通过通知栏消息定制化跳转页面,可以通过 H5 页面跳转页面等。
URL Scheme 应用场景:
客户端应用可以向操作系统注册一个 URL scheme,该 scheme 用于从浏览器或其他应用中启动本应用。通过指定的 URL 字段,可以让应用在被调起后直接打开某些特定页面,比如商品详情页、活动详情页等等。也可以执行某些指定动作,如完成支付等。也可以在应用内通过 html 页来直接调用显示 app 内的某个页面。综上 URL Scheme 使用场景大致分以下几种:
服务器下发跳转路径,客户端根据服务器下发跳转路径跳转相应的页面
H5 页面点击锚点,根据锚点具体跳转路径 APP 端跳转具体的页面
APP 端收到服务器端下发的 PUSH 通知栏消息,根据消息的点击跳转路径跳转相关页面
APP 根据 URL 跳转到另外一个 APP 指定页面
URL Scheme 协议格式:
先来个完整的 URL Scheme 协议格式:
xl://goods:8888/goodsDetail?goodsId=10011002
通过上面的路径 Scheme、Host、port、path、query 全部包含,基本上平时使用路径就是这样子的。
xl 代表该 Scheme 协议名称
goods 代表 Scheme 作用于哪个地址域
goodsDetail 代表 Scheme 指定的页面
goodsId 代表传递的参数
8888 代表该路径的端口号
URL Scheme 如何使用:
1.)在 AndroidManifest.xml 中对 <activity /> 标签增加 <intent-filter /> 设置 Scheme
<activity
android:name=".GoodsDetailActivity"
android:theme="@style/AppTheme">
<!-- 要想在别的 App 上能成功调起 App,必须添加 intent 过滤器 -->
<intent-filter>
<!-- 协议部分,随便设置 -->
<data android:scheme="xl" android:host="goods" android:path="/goodsDetail" android:port="8888"/>
<!-- 下面这几行也必须得设置 -->
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
2.)获取 Scheme 跳转的参数
Intent i_getvalue = getIntent();
String action = i_getvalue.getAction();
if(Intent.ACTION_VIEW.equals(action)){
Uri uri =
i_getvalue
.getData();
if (uri != null) {
// 完整的 url 信息 String url = uri.toString(); Log.e(TAG, “url: ” + uri); // scheme 部分 String scheme = uri.getScheme(); Log.e(TAG, “scheme: ” + scheme); // host 部分 String host = uri.getHost(); Log.e(TAG, “host: ” + host); //port 部分 int port = uri.getPort(); Log.e(TAG, “host: ” + port); // 访问路劲 String path = uri.getPath(); Log.e(TAG, “path: ” + path); List<String> pathSegments = uri.getPathSegments(); // Query 部分 String query = uri.getQuery(); Log.e(TAG, “query: ” + query); // 获取指定参数值 String goodsId = uri.getQueryParameter(“goodsId”); Log.e(TAG, “goodsId: ” + goodsId);}
}
3.)调用方式
网页上
打开商品详情
4.)如何判断一个 Scheme 是否有效
PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(“xl://goods:8888/goodsDetail?goodsId=10011002”));
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isValid = !activities.isEmpty();
if (isValid) {
startActivity(intent);
}
二:JS 和安卓互相调用
下面上代码:(js_webView.html)
html 里面的代码也比较简单,整个 html 中就一个 Button,点击这个 Button 的时候去执行 javascript 中的 jsCallAndroid() 方法。
网页中有关 javascript 的代码也比较简单,整个 js 就 2 个方法,一个是 jsCallAndroid(),一个是 androidCallJs()。看方法名就知道了,分别是 js 调用 Android 的和 Android 调用 js 的。
先不要去管 jsCallAndroid() 里面做的是什么,待会会解释,来看看 androidCallJs() 这个方法里面做的就是弹出一个信息提示框,具体提示什么信息都不重要了,随便。
再来看看代码部分(WebViewActivity 的布局文件):
整个布局文件也很简单,一个按钮和一个 WebView,按钮是用来测试 Android 调用 js 用的,js 调用 Android 就当然是 webview 加载的网页里面的按钮了。
再来看看 Java 代码部分(WebViewActivity):
下面来看看代码部分:
37-42 行:这几行就是 android 中的按钮的点击事件,没什么好解释的,来看看点击事件做的是什么?点击事件做的是:调用 webview 的 loadurl 方法去调用 js 中的方法;调用的方式是:前面是 javascript 中间用:分隔 最后是 要调用的 js 的方法名。
45-55 行:这几行就是有关于 Webview 的设置等,46-51 这几行是指支持弹窗,也就是支持 html 网页弹框,因为前面的 html 代码中,有我们 Android 调用 js 的时候,调用成功就 js 弹窗,所以这里要加上这个设置。接下来是 53 行,53 行指的是支持 javascript 这里指的是支持 html 中的 javascript 解析,不管是不是 js 和 Android 交互,只要网页中含有 js,都要。最关键的就是 54 行,54 行就是 javascript 和 Android 交互的了,addJavascriptInterface 方法需要接受两个参数,第一个是与之相对应的 js 调用 Android 本地的类的对象,这个例子中的就是 58-63 行这个类的对象,第二个参数就是和前面网页中的 js 代码中的 jsCallAndroid 方法中的 wv.sayHello(), 这里的 wv 就和这个参数 (wv) 与之相对应,而 sayHello() 就是对应的第一个参数的对象里面的方法。
最后是 58-63 行,这几行没什么好解释的了,只是如果调用成功就打印一行日志。仅此检验是否调用成功而已。
整个 demo 代码到此完毕,好激动,赶紧运行试试看。
运行的结果会让很多人失望,只是 android 调用 js 成功了,但 js 调用 android 不成功。
#### 这是为什么呢?这里要涉及到的是有关于 webview 和 js 的安全性的问题。js 可以通过这种方式下载恶意代码在 android 上执行,具体有兴趣的可以去 Google 一下,所以上面这种写法只是对于 Api16 以前的 android 手机是适用的,16 以后,谷歌对这个安全性问题进行了修复。将其注解到 android 自带的一个 javascriptInterfface 类中。下面就来看看 16 以后的写法是咋样的?
有了注解,简直如虎添翼,非常方便。还是原来的配方,还是原来的味道,原汁原味。除了 Activity 中的代码需要修改,其他都不动。
改动的代码有 55 行,直接传一个 this(Context) 对象就可以了,那么,原来的 JsInterface 就可以不要了。不要那我 sayHello 方法写到哪里呢?既然你传递的是 this,当然是写到 this 里面咯(59-62 行)。不同的是,这个 sayHello() 方法必须加上一个 JavascriptInterface 的注解。
OK 了,16 以前和 16 以后的都有了,不就 OK 了么。在添加 javascript 的时候判断一下 Api 版本就可以了,哈哈。。。
不不不,肯定不是这样子做。指需要在 onCreate() 方法上添加 @SuppressLint(“JavascriptInterface”) 注解即可。
看下面的就是终极代码了。
对,没错,就是这样子。大功告成。
最后需要提一点的是,上面的例子是可以执行,正常情况下都没什么问题,但你看看网上的 demo,很多在 android 调用 js 的时候是开一个子线程去调用,没错,实际开发中,是必须要这样子做的。好处就不言而喻了。这一点看最后一张代码图,这里也有给出,直接调用 webview 的 post,里面就是 Android 调用 js 了。
推荐
点击进群密码:111