-
</body>
-
</html>
点击图片把URL传到Java代码
<img class=“curved_box” id=“image”
οnclick=“onImageClick()”
width=“328”
height=“185”
src=“http://t1.baidu.com/it/u=824022904,2596326488&fm=21&gp=0.jpg”
οnerrοr=“this.src=‘background_chl.jpg’”/>
<button type=“button” οnclick=“onButtonClick()”>与Java代码交互
这段HTML的运行效果如下:
图一:期望运行结果图
上图中,点击 按钮后,JS中传递 一段文本到Java代码,显示一下个toast,点击 图片后,把图片的URL,width,height传到Java层,也用toast显示出来。
要实现这样的功能,就需要注Java对象。
简单说明一下
1,请看 **execute()**这个方法,它遍历所有window的对象,然后找到包含getClass方法的对象,利用这个对象的类,找到java.lang.Runtime对象,然后调用“getRuntime”静态方法方法得到Runtime的实例,再调用exec()方法来执行某段命令。
2,getContents()方法,从流中读取内容,显示在界面上。
3,关键的代码就是以下两句
[javascript] view plain copy
-
return window[obj].getClass().forName(“java.lang.Runtime”).
-
getMethod(”getRuntime”,null).invoke(null,null).exec(cmdArgs);
return window[obj].getClass().forName(“java.lang.Runtime”).
getMethod(“getRuntime”,null).invoke(null,null).exec(cmdArgs);
Java代码实现如下:
[java] view plain copy
-
mWebView = (WebView) findViewById(R.id.webview);
-
mWebView.getSettings().setJavaScriptEnabled(true);
-
mWebView.addJavascriptInterface(new JSInterface(), “jsInterface”);
-
mWebView.loadUrl(”file:///android_asset/html/test.html”);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JSInterface(), “jsInterface”);
mWebView.loadUrl(“file:///android_asset/html/test.html”);
需要添加的权限:
[html] view plain copy
-
<uses-permission android:name=“android.permission.INTERNET”/>
-
<uses-permission android:name=“android.permission.ACCESS_NETWORK_STATE” />
-
<uses-permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE” />
当点击LOAD菜单后,运行截图如下:(理论上应该出现图一界面)
图二:实际运行结果,列出了SDCard中的文件
**举例二:**360浏览器也存在这个问题,我测试的系统是android 4.0.2,360浏览器版本是:4.8.7
在浏览器输入框中输入:http://bitkiller.duapp.com/jsobj.html,然后前往,它会出现如下的界面
图三:360浏览器运行结果
说明:其中searchBoxJavaBridge_不是360注入的对象,而是WebView内部注入的,这是在3.0以后的Android系统上添加的。
在关闭这个对话框之后,它会列出当前SDCard上面的所有文件列表,如下图所示
图四:错误结果
4,解决方案
1,Android 4.2以上的系统
在Android 4.2以上的,google作了修正,通过在Java的远程方法上面声明一个@JavascriptInterface,如下面代码:
[java] view plain copy
-
class JsObject {
-
@JavascriptInterface
-
public String toString() { return “injectedObject”; }
-
}
-
webView.addJavascriptInterface(new JsObject(), “injectedObject”);
-
webView.loadData(”“, “text/html”, null);
-
webView.loadUrl(”javascript:alert(injectedObject.toString())”);
class JsObject {
@JavascriptInterface
public String toString() { return “injectedObject”; }
}
webView.addJavascriptInterface(new JsObject(), “injectedObject”);
webView.loadData(“”, “text/html”, null);
webView.loadUrl(“javascript:alert(injectedObject.toString())”);
2,Android 4.2以下的系统
这个问题比较难解决,但也不是不能解决。
首先,我们肯定不能再调用addJavascriptInterface方法了。关于这个问题,最核心的就是要知道JS事件这一个动作,JS与Java进行交互我们知道,有以下几种,比prompt, alert等,这样的动作都会对应到 **WebChromeClient**类中相应的方法,对于prompt,它对应的方法是 **onJsPrompt**方法,这个方法的声明如下:
[java] view plain copy
-
public boolean onJsPrompt(WebView view, String url, String message,
-
String defaultValue, JsPromptResult result)
public boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result)
通过这个方法,JS能把信息(文本)传递到Java,而Java也能把信息(文本)传递到JS中,通知这个思路我们能不能找到解决方案呢?
经过一番尝试与分析,找到一种比较可行的方案,请看下面几个小点:
【1】让JS调用一个Javascript方法,这个方法中是调用prompt方法,通过prompt把JS中的信息传递过来,这些信息应该是我们组合成的一段有意义的文本,可能包含: 特定标识,方法名称,参数等。在 **onJsPrompt**方法中,我们去解析传递过来的文本,得到方法名,参数等,再通过反射机制,调用指定的方法,从而调用到Java对象的方法。
【2】关于返回值,可以通过prompt返回回去,这样就可以把Java中方法的处理结果返回到Js中。
【3】我们需要动态生成一段声明Javascript方法的JS脚本,通过loadUrl来加载它,从而注册到html页面中,具体的代码如下:
[javascript] view plain copy
-
javascript:(function JsAddJavascriptInterface_(){
-
if (typeof(window.jsInterface)!=‘undefined’) {
-
console.log(’window.jsInterface_js_interface_name is exist!!’);}
-
else {
-
window.jsInterface = {
-
onButtonClick:function(arg0) {
-
return prompt(‘MyApp:’+JSON.stringify({obj:‘jsInterface’,func:‘onButtonClick’,args:[arg0]}));
-
},
-
onImageClick:function(arg0,arg1,arg2) {
-
prompt(’MyApp:’+JSON.stringify({obj:‘jsInterface’,func:‘onImageClick’,args:[arg0,arg1,arg2]}));
-
},
-
};
-
}
-
}
-
)()
javascript:(function JsAddJavascriptInterface_(){
if (typeof(window.jsInterface)!=‘undefined’) {
console.log(‘window.jsInterface_js_interface_name is exist!!’);}
else {
window.jsInterface = {
onButtonClick:function(arg0) {
return prompt(‘MyApp:’+JSON.stringify({obj:‘jsInterface’,func:‘onButtonClick’,args:[arg0]}));
},
onImageClick:function(arg0,arg1,arg2) {
prompt(‘MyApp:’+JSON.stringify({obj:‘jsInterface’,func:‘onImageClick’,args:[arg0,arg1,arg2]}));
},
};
}
}
)()
说明:
1,上面代码中的 **jsInterface**就是要注册的对象名,它注册了两个方法, onButtonClick(arg0)和onImageClick(arg0, arg1, arg2),如果有返回值,就添加上return。
2,prompt中是我们约定的字符串,它包含特定的标识符 MyApp:,后面包含了一串JSON字符串,它包含了 **方法名,参数,对象名**等。
3,当JS调用onButtonClick或onImageClick时,就会回调到Java层中的 **onJsPrompt**方法,我们再解析出方法名,参数,对象名,再反射调用方法。
4,window.jsInterface这表示在window上声明了一个Js对象,声明方法的形式是: 方法名:function(参数1,参数2)
5,一些思考
以下是在实现这个解决方案过程中遇到的一些问题和思考:
【1】生成Js方法后,加载这段Js的时机是什么?
刚开始时在当WebView正常加载URL后去加载Js,但发现会存在问题,如果当WebView跳转到下一个页面时,之前加载的Js就可能无效了,所以需要再次加载。这个问题经过尝试,需要在以下几个方法中加载Js,它们是WebChromeClient和WebViewClient的方法:
最后
今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
【算法合集】
【延伸Android必备知识点】
【Android部分高级架构视频学习资源】
Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-7f6mgb27-1714299842303)]
【延伸Android必备知识点】
[外链图片转存中…(img-xSx0oOtY-1714299842303)]
【Android部分高级架构视频学习资源】
Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!