android webview与js简单的交互方案
最近研究webview与js交互,看了几个开源库实现,感觉不尽如人意,存在主要问题是,耦合较高,使用不够简洁,后来参考Uri设定规则,格局Uri类似协议自定义了类似的js交互协议
比较简洁,自定义协议内容样式如:jsbridge://android-app/method123?a=123&b=345#jsMethod1(p1,p2)
协议说明:
scheme定义为jsbridge,用于区分别的网络请求(http),
authority定义为android-app,区分不同平台处理
path定义为 调用本地方法名称 method123
Query定义为调用本地方法参数 a=123&b=345
Fragment定义为回调js方法 #jsMethod1(p1,p2)
这样就可以做到精简,灵活,良好的可扩展,灵活使用的特点。再看解析实现·
- public boolean parseJsBridge(String url,WebAppInterface webNative){//WebAppInterface为被调用本地方法类实例
- if(!isProtocol(url)) return false;
- int i = -1;
- Uri uri = Uri.parse(url);//借助URI解析协议
- String methodName = uri.getPath();//调用本地方法,method123
- methodName = methodName.replace("/", "");
- String params = uri.getQuery();//调用本地方法参数。a=123&b=345
- String callback = uri.getFragment();//解析js回调方法,#jsMethod1(p1,p2)
- i = callback.lastIndexOf('(');
- String jsMethod = callback.substring(0,i);
- String jsParams = callback.substring(i+1,callback.length()-1);
- //将解析的结果封装为JsResponse,便于后续使用
- mJsRes = new JsResponse(methodName,jsMethod);
- mJsRes.parseJsCallbackParams(jsParams);
- mJsRes.parseNativeParams(params);
//这里通过反射方式调用本地方法- String[] args = mJsRes.getMethodArgs();
- if(null==args){//使用反射调用无参数方法
- jsCallNoParamMethod(webNative,methodName);
- }else{//调用反射有参数方法
- int count = args.length;
- Class[] javaParamsType = new Class[count];
- for(int t=0;t<count;t++){
- javaParamsType[t] = String.class;
- }
- jsCallParamMethod(webNative,methodName,javaParamsType,mJsRes.getMethodArgs());
- }
- return true;
- }
协议解析完整实现类:
- public class JsProcessor {
- // private JsProcessor(){}
- private JsResponse mJsRes;
- public JsResponse getJsResponse(){
- return mJsRes;
- }
- public static boolean isProtocol(String url) {
- return !TextUtils.isEmpty(url) && url.startsWith("jsbridge://");
- }
- // jsbridge://android-app/method123?a=123&b=345#jsMethod1(p1,p2)"
- public boolean parseJsBridge(String url,WebAppInterface webNative){
- if(!isProtocol(url)) return false;
- int i = -1;
- Uri uri = Uri.parse(url);
- String methodName = uri.getPath();//method1
- methodName = methodName.replace("/", "");
- String params = uri.getQuery();//a=123&b=345
- String callback = uri.getFragment();//#jsMethod1(p1,p2)
- i = callback.lastIndexOf('(');
- String jsMethod = callback.substring(0,i);
- String jsParams = callback.substring(i+1,callback.length()-1);
- mJsRes = new JsResponse(methodName,jsMethod);
- mJsRes.parseJsCallbackParams(jsParams);
- mJsRes.parseNativeParams(params);
- String[] args = mJsRes.getMethodArgs();
- if(null==args){
- jsCallNoParamMethod(webNative,methodName);
- }else{
- int count = args.length;
- Class[] javaParamsType = new Class[count];
- for(int t=0;t<count;t++){
- javaParamsType[t] = String.class;
- }
- jsCallParamMethod(webNative,methodName,javaParamsType,mJsRes.getMethodArgs());
- }
- return true;
- }
- public boolean jsCallNoParamMethod(Object obj,String mName){
- boolean success = false;
- try {
- Method method=obj.getClass().getMethod(mName);
- method.invoke(obj);
- success = true;
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }catch (Exception ex){
- ex.printStackTrace();
- }
- return success;
- }
- //getMethod("sayHello", String.class,int.class);
- public boolean jsCallParamMethod(Object obj,String mName,Class<?>[] parameterTypes,Object[] args){
- if(parameterTypes.length!=args.length) return false;
- boolean success = false;
- try {
- Method method = obj.getClass().getMethod(mName,parameterTypes);
- method.invoke(obj, args);
- success = true;
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }catch (Exception ex){
- ex.printStackTrace();
- }
- return success;
- }
- }
JSResponse解析后的封装实体类
- public class JsResponse {
- //call native
- public String methodName;
- private Map<String,String> nativeParams = new HashMap<>();
- //callback js method
- public String callJsMethod;
- // public Map<String,String> jsParams = new HashMap<>();
- private int jsParamCount;
- public JsResponse(String javaMethod,String jsMethod){
- this.methodName = javaMethod;
- this.callJsMethod = jsMethod;
- }
- public String[] getMethodArgs(){
- if(0==nativeParams.size()) return null;
- String[] params = new String[nativeParams.size()];
- int n = 0;
- for(Map.Entry<String,String> entry:nativeParams.entrySet()){
- params[n] = entry.getValue();
- n++;
- }
- return params;
- }
- public void parseNativeParams(String params){
- // int i = 0,len = params.length();
- if(!nativeParams.isEmpty())
- nativeParams.clear();
- String[] eles = params.split("&");
- for(String ele:eles){
- int eq = ele.indexOf('=');
- String value = ele.substring(eq + 1);
- String name = ele.substring(0,eq);
- nativeParams.put(name,value);
- }
- }
- public void parseJsCallbackParams(String jsparams){
- String[] eles = jsparams.split(",");
- jsParamCount = eles.length;
- }
- }
js使用规则协议,触发调用本地方法如下,即可
- function startRequest()
- {
- var iframe = document.createElement('iframe');
- iframe.setAttribute('src', 'jsbridge://android-app/showHello?a=hello-&b=i_from_js&#callbackHello(p1,p2)');
- document.body.appendChild(iframe);
- iframe.parentNode.removeChild(iframe);
- iframe = null;
- }
本地调用js回调方法
- void executeJsCmd(String jsCmd){
- Log.d(TAG,"pending execute js command="+jsCmd);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- //async execute
- mWebView.evaluateJavascript(jsCmd, new ValueCallback<String>() {
- @Override
- public void onReceiveValue(String value) {
- Log.d(TAG,"async execute result="+value);
- }
- });
- }else {
- // This code is BAD and will block the UI thread
- mWebView.loadUrl(jsCmd);
- }
- }
下面就是js与本地通信了,通过WebViewClient的shouldOverrideUrlLoading拦截内容判断处理
- private class MonitorWebClient extends WebViewClient {
- WebAppInterface webCallapp = new WebAppInterface(activity);
- .......
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- boolean handle = super.shouldOverrideUrlLoading(view, url);
- JsProcessor jsPro = null;
- if (!handle) {
- jsPro = new JsProcessor();
- handle = jsPro.parseJsBridge(url,webCallapp);
- }
- if(handle){
- handleJsCallback(jsPro,"hello","callback js method");
- }
- return handle;
- }
- @Override
- public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
- //如果需要传文件,拦截WebView的资源请求,将文件以流的形式进行通讯
- //return new WebResourceResponse("image/jpeg", "UTF-8", new FileInputStream(new File("xxxx");
- return super.shouldInterceptRequest(view, request);
- }
- }
- void handleJsCallback(JsProcessor jsPro,String... args){
//javascript:showJavaMessage('javaResult')"
//拼接js要执行方法名字与参数规则,如上样例- String jsM = jsPro.getJsResponse().callJsMethod;
- if(!TextUtils.isEmpty(jsM)){
- // String jsCmd = new StringBuilder().append("javascript:").append(jsM).
- // append('(').append("\'java\'").append(',').append("\'hello\'").append(')').toString();
- StringBuilder buf = new StringBuilder().append("javascript:").append(jsM).append('(');
- if(args!=null && args.length>0){
- // int pos = buf.length()-1;
- for(String p:args) {
- buf.append('\'').append(p).append('\'').append(',');
- }
- buf.deleteCharAt(buf.length()-1);
- }
- buf.append(')');
- executeJsCmd(buf.toString());
- }
- }
除了上面shouldOverrideUrlLoading方法拦截处理外,js也可以通过调用 alert,prompt 方法的方式传递数据 ,我们需要重写WebChromeClient 通过回调本地方法onJsAlert(), onJsPrompt()方法即可收到对应函数回调,进行数据处理
- private class AppWebChromeClient extends WebChromeClient {
- @Override
- public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
- quotaUpdater.updateQuota(spaceNeeded * 2);
- }
- @Override
- public boolean onConsoleMessage(ConsoleMessage cm) {
- Log.d("MyApplication", cm.message() + " -- From line "
- + cm.lineNumber() + " of "
- + cm.sourceId() );
- return true;
- }
- @Override
- public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
- if("1001".equals(message)){
- //解析参数defaultValue,调用java方法并得到结果
- //textexeJs();
- }
- //给js返回处理结果
- result.confirm("result");
- return false;
- }
- @Override
- public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
- Log.d("MyApplication",url);
- AlertDialog alertDialog = new AlertDialog.Builder(activity).create();
- // Setting Dialog Title
- alertDialog.setTitle("JS come message");
- // Setting Dialog Message
- alertDialog.setMessage(message);
- alertDialog.show();
- return false;
- }
- }
调用本地方法类对象
- public class WebAppInterface {
- Context mContext;
- /** Instantiate the interface and set the context */
- WebAppInterface(Context c) {
- mContext = c;
- }
- /** Show a toast from the web page */
- @JavascriptInterface
- public void showToast(String toast) {
- Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
- }
- @JavascriptInterface
- public void showDialog(String dialogMsg){
- AlertDialog alertDialog = new AlertDialog.Builder(mContext).create();
- // Setting Dialog Title
- alertDialog.setTitle("JS triggered Dialog");
- // Setting Dialog Message
- alertDialog.setMessage(dialogMsg);
- alertDialog.show();
- }
- public void showHello(String title,String msg){
- ToastUtils.showLong(mContext,title+msg);
- }
- }
js示例内容
- <html>
- <head>
- <style>
- body{
- background-color: #FA5858;
- color:#fff;
- }
- input{
- background-color: #F7D358;
- width: 300px;
- padding:10px;
- color: #000;
- }
- div#content{
- padding:20px;
- background-color: #F7D358;
- color: #000;
- }
- </style>
- <script type="text/javascript">
- function showAndroidToast(toastmsg) {
- Android.showToast(toastmsg);
- }
- function showAndroidDialog(dialogmsg) {
- Android.showDialog(dialogmsg);
- }
- function moveToScreenTwo() {
- Android.moveToNextScreen();
- }
- function showPromptToJava()
- {
- var ret = prompt( "1001", "defaultMessage001" );
- //ret值即为java传回的”result”
- //根据返回内容作相应处理
- }
- function showJavaMessage(result)
- {
- alert("hello!"+result);
- }
- function startRequest()
- {
- var iframe = document.createElement('iframe');
- iframe.setAttribute('src', 'jsbridge://android-app/showHello?a=hello-&b=i_from_js&#callbackHello(p1,p2)');
- document.body.appendChild(iframe);
- iframe.parentNode.removeChild(iframe);
- iframe = null;
- }
- function callbackHello(p1,p2)
- {
- console.log("receive callback from app");
- alert("receive callback "+p1+p2);
- }
- </script>
- </head>
- <body>
- <center>
- <h3>Binding JavaScript code to Android code</h3>
- <div id="content">
- //some content here
- </div>
- <div>
- Here are few examples:
- </div>
- <div>
- <input type="button" value="Make Toast" onClick="showAndroidToast('Toast made by Javascript')" /><br/>
- <input type="button" value="Trigger Dialog" onClick="showAndroidDialog('This dialog is triggered by Javascript ')" /><br/>
- <input type="button" value="Take me to Next Screen" onClick="showPromptToJava()" /><br/>
- <input type="button" value="jsBridgeHandle" onClick="startRequest()" /><br/>
- </div>
- </center>
- </body>
- </html>
本地显示
mWebView.loadUrl("file:///android_asset/sample1.html");
以上就是整个js与本地方法调用整体流程
备注问题:
js与本地调用会产生的问题:
1,调用js函数参数注意
string 使用'' 需要单引号拼接,直接value或"value"则无法正常匹配
直接value为整数类型
2,onJsPrompt,onJsAlert,返回true,js默认不处理,导致下次无法调用(即无反应事件)
android webview与js简单的交互方案的更多相关文章
- [android] WebView与Js交互
获取WebView对象 调用WebView对象的getSettings()方法,获取WebSettings对象 调用WebSettings对象的setJavaScriptEnabled()方法,设置j ...
- Android中webview和js之间的交互(转)
http://www.cnblogs.com/leizhenzi/archive/2011/06/29/2093636.html 1.android中利用webview调用网页上的js代码. Andr ...
- Android Webview 与JS交互
Android中 WebView控件支持JS与本地代码的交互. // 是否允许在webview中执行javascript webSettings.setJavaScriptEnabled(true); ...
- android控件之webview和js与java交互
首先添加权限:<uses-permission android:name="android.permission.INTERNET"/> 布局文件: <Relat ...
- Android WebView 总结 —— Java和JavaScript交互
交互如何实现 实现Java和js交互十分便捷.通常只需要以下几步. WebView开启JavaScript脚本执行 WebView设置供JavaScript调用的交互接口. 客户端和网页端编写调用对方 ...
- android Webview 实现js调用java代码实现Activity跳转
今天有了一个需求,在android里webview加载的html页面,要求点击html页面的按钮实现Activity的跳转. 咱是是菜鸟,webview的接触不多,于是就和度娘来了次亲密接触.在其中也 ...
- android WebView中js的alert()失效
WebView的设置代码 wv = (WebView) findViewById(R.id.webView1); wv.getSettings().setJavaScriptEnabled(true) ...
- android webview 中 js 模板引擎的使用
最近在项目中要求用 webview 展示几个界面, 而后台返回的不是 html 而是 json 数据. 起初用 StringBuilder 一个一个拼 html, 后来感觉太繁琐,拼一个还行,拼多了就 ...
- Android Webview 调用JS跳转到指定activity
JAVA: WebView wv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(save ...
- Xamarin Android Webview中JS调用App中的C#方法
参考链接:https://github.com/xamarin/recipes/tree/master/Recipes/android/controls/webview/call_csharp_fro ...
随机推荐
- vue 组件之间传值(父传子,子传父)
1.父传子 基本就用一个方式,props Father.vue(用v-bind(简写 : ) 将父组件传的值绑定到子组件上) <template> <div> 我是爸爸:{{ ...
- pyCharm中下载包的速度慢的解决方案
1.解决方案 使用阿里镜像 2.具体步骤 1.在项目里面新建一个xxx.py文件 2.然后将下面的代码复制进xxx.py文件 import os ini = "[global]\nindex ...
- cs231n学习笔记——lecture6 Training Neural Networks
该博客主要用于个人学习记录,部分内容参考自:[基础]斯坦福cs231n课程视频笔记(三) 训练神经网络.[cs231n笔记]10.神经网络训练技巧(上).CS231n学习笔记-训练神经网络.整理学习之 ...
- 使用idea进行gitee代码管理
目录 1.在idea插件市场安装gitee插件 2.把本地仓库的release分支上的代码合到dev分支上 3.把本地dev分支上的代码合到远程dev分支上去 1.在idea插件市场安装gitee插件 ...
- VSCode运行C/C++配置
将MinGw安装目录下的 1.安装 VSCode 2.安装 MinGW 链接:点击跳转 3.MinGW 内安装两个模块 1.右键 Mark for Installation 勾选 (此处已安装好,所以 ...
- 迁移学习(IIMT)——《Improve Unsupervised Domain Adaptation with Mixup Training》
论文信息 论文标题:Improve Unsupervised Domain Adaptation with Mixup Training论文作者:Shen Yan, Huan Song, Nanxia ...
- ORM执行原生SQL语句、双下划线数据查询、ORM外键字段的创建、外键字段的相关操作、ORM跨表查询、基于对象的跨表查询、基于双下划线的跨表查询、进阶查询操作
今日内容 ORM执行SQL语句 有时候ROM的操作效率可能偏低 我们是可以自己编写sql的 方式1: models.User.objects.raw('select * from app01_user ...
- vue3实现一个抽奖小项目
前言 在公司年会期间我做了个抽奖小项目,我把它分享出来,有用得着的可以看下. 浏览链接:http://xisite.top/original/luck-draw/index.html 项目链接:htt ...
- JS控制台打印星星,总有你要的那一款~呐~给你小心心哦~~~❤
用JS语句,在控制台中打印星星,你要的是哪一款呢~来认领吧~ 1.左直角星星 效果: 代码: let readline=require("readline-sync"); cons ...
- 通俗易懂angular搭建