我们做项目经常会用到Android 嵌套网页,然后就会有互相调用的情况,但是之前没有总结,懂的人懂了,换了一批开发人员就又要研究了,所以现在把相关知识点总结一下。
先上前端代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Android 与JS互相调用示例</title>
</head>
<body class="bg_gray">
<input type="submit" id="collect" οnclick="collect()" value="收藏"></a>
<input type="submit" οnclick="dialogSelectType()" value="选择"></a>
<a id="url", href="http://www.baidu.com">百度</a>
<input type="submit" οnclick="getContent(1)" value="修改内容1"></a>
<input type="submit" οnclick="getContent(2)" value="修改内容2"></a>
<h2 >啦啦啦内容</h2>
</body>
<script type="text/javascript">
function collect()
{
window.Js_Interactive.collection(1);
}
function getContent(id)
{
var content = window.Js_Interactive.getContent(id);
document.getElementsByTagName('h2')[0].innerHTML = content;
}
function changeUrl(url, name)
{
var el = document.getElementById('url');
el.setAttribute('href', url);
el.innerHTML = name;
}
function dialogSelectType()
{
window.Js_Interactive.dialogSelectType();
}
function changeBtnColor()
{
var el = document.getElementById('collect');
el.style.background = "#22AAEE";
}
</script>
</html>
一、 JS 调用Android 原生
1、接口定义
window.Js_Interactive.getContent(id);
window 是api固定的,Js_Interactive 是可以根据不同项目改变的,但是一个项目,不建议有多个名字,也就是整个项目这个定义好了也不会改变,
getContent 是方法名,不同地方调用的方法名、参数都不一致,参数数据类型也不一样,有些js传参id传的时候看起来是Int,但是有可能在移动端这边接收的是String,所以建议都传String类型
在Android 端需要定义一个JavascriptInterface 来接收来自JS的调用
webView.addJavascriptInterface(new JavascriptInterface(this), "Js_Interactive");
后面的参数Js_Interactive与JS定义的Js_Interactive要一致,整个工程最好固定这个属性定定义,JavascriptInterface 类需写好前端定义好的方法名,具体代码如下
/**js通信接口*/
public class JavascriptInterface {
private Context context;
public JavascriptInterface(Context context) {
this.context = context;
}
@android.webkit.JavascriptInterface
public void dialogSelectType(){
//javascript 从子线程调用
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "javascript调用了popwindow", Toast.LENGTH_SHORT).show();
//接到web里面的javascript传来的命令,调用显示dialog
shareDialog.show();
}
});
}
@android.webkit.JavascriptInterface
public String collection(long id){
LogUtil.e("collection("+id+")");
Toast.makeText(context, "javascript传来的商品id:"+id, Toast.LENGTH_SHORT).show();
return "哈哈哈";
}
@android.webkit.JavascriptInterface
public String collection(String id){
Toast.makeText(context, "javascript传来的商品String id:"+id, Toast.LENGTH_SHORT).show();
return "返回返回";
}
//这是网页控制跳去一个新的Activity
@android.webkit.JavascriptInterface
public void comment(String id){
Toast.makeText(context, "javascript传来的商品id:"+id, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(WebActivity.this,WebStartActivity.class);
startActivity(intent);
}
@android.webkit.JavascriptInterface
public void business_go(String bussID){
Toast.makeText(context, "javascript传来的商家id:"+bussID, Toast.LENGTH_SHORT).show();
}
@android.webkit.JavascriptInterface
public String getContent(String id){
int type = 0;
try{
type = Integer.parseInt(id);
} catch (NumberFormatException e){
e.printStackTrace();
}
switch (type){
case 1:
return "内容11111111111111111111111111";
case 2:
return "内容2222222222";
default:
return "内容333333333333333333333333";
}
}
}
2、需要允许加载JS ,所以代码需要加上如下语句:
webview.getSettings().setJavaScriptEnabled(true); |
3、每个方法上要加注解@android.webkit.JavascriptInterface
4、部分情况前端传过来的有可能是子线程的,处理UI相关时就需要转到主线程调用。
5、返回值
当JS调用Android 时希望带着返回值回去,那么我们可以定义方法成有返回值的就可以了,比如上面的public String getContent(String id)方法,但是Android调JS时是用webview,loadUrl的形式调用,所以不存在返回值的情况。
6、混淆
这些方法定义好后,打包上架时需要混淆,然后你就发现调用失效了,那么我们还需要对这些
JavascriptInterface 类进行防止混淆,但是每个有WebView的页面都要检查一遍是很麻烦的,所以我们应该定义一个父类,所有
JavascriptInterface 类全部继承至这个父类,然后混淆就好写很多了。
public class JavascriptInterface extends BaseJavascriptInterface { //... } |
混淆时加上
-keep public class * extends com.aiitec.technicalreserve.interfaces .BaseJavascriptInterface {* ;} |
就可以了。
二、 Android 调用 JS
Android 调用JS就更简单了,首先JS 必须事先定义好方法,如
function changeBtnColor() { var el = document.getElementById( 'collect' ); el.style.background = "#22AAEE" ; } |
然后Android 调用
webView.loadUrl( "javascript:changeBtnColor()" ); |
就这么简单,但是需要再网页加载完成才能调用,有的人实例化好立即调用是无效的,所以想一开始就调用的必须在WebViewClient的onPageFinished(WebView view, String url) 里调用。
我看有的人多加一个冒号javascript::,但是结果都一样 。
三、 WebViewClient 常见问题
1、 加载菊花
如果想做加载监时增加选中菊花可以在
onPageStarted(WebView view, String url, Bitmap favicon) 弹出加载菊花
onPageFinished(WebView view, String url) 取消加载菊花
2、 https加载http图片
如果在https里面加载http的图片需要用到下面这句,否则可能加载不出来。
if (Build.VERSION.SDK_INT >= 21) { webview.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW } |
3、 加载部分网友时莫名唤起浏览器加载
有时候加载百度等网站时会自动唤起浏览器打开,这个是我们不希望有的,那么在WebViewClient里加上这么一句,返回true 就好了。
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器 view.loadUrl(url); return true; } |