1. Android中调用
参考: http://stackoverflow.com/questions/10389572/call-java-function-from-javascript-over-android-webview ,
通过消息传递来修改视图的文章: http://blog.csdn.net/veryitman/article/details/6384641
Android 调用 js代码其实很简单. 直接 使用 evaluateJavascript 就可以:
webview.evaluateJavascript("get_right_button_text()", new ValueCallback() {
@Override
public void onReceiveValue(String value) {
setTextFromHtml(buttonRight, value);
Log.d(TAG, "get_right_button_text value=" + value);
}
});
但是, 这个情况只适用于 普通的HTML( 传统的PHP, JSP,RAILS 所生成的HTML页面) .
不适用于: Angular, Vuejs 这样, 使用 js引擎对页面再次渲染生成的页面.在这样的页面中, Android的一些方法都会失效(onPageFinished 等等) 往往会报错, 找不到方法.
所以, 我们要想一个办法. 能够让Android 能够在 合适的时间( js 引擎渲染完HTML页面后) , 执行JS代码.
试过一些方法, 不过都不行. IOS 下适用的方法,不适合android . 所以, 走的通的方法是: 使用javascript interface.
步骤:
1. 声明一个java class:
package com.tuling.Fragment;
import android.app.Activity;
import android.app.Fragment;
import android.os.Message;
import android.util.Log;
import android.webkit.JavascriptInterface;
import com.tuling.Fragment.html.WebViewFragmentBase;
/**
* 在 js中调用的 java对象.
* refer to: http://stackoverflow.com/questions/10389572/call-java-function-from-javascript-over-android-webview
*/
public class AndroidObjectInJavascript {
private Activity activity;
private WebViewFragmentBase fragment;
public AndroidObjectInJavascript(Activity activity, WebViewFragmentBase fragment){
this.activity = activity;
this.fragment = fragment;
}
/**
* 设置 对应fragment的标题. 通过 消息机制来实现.
*/
@JavascriptInterface
public String setTitle(String title){
Log.d("AndroidObjectInJs", "== setting title: " + title);
Message message = fragment.get_title_handler().obtainMessage();
message.what = 1; // 这个东西没有意义, 认为它一直是1好了.
message.obj = title;
message.sendToTarget();
Log.d("AndroidObjectInJs", " == 触发了message");
fragment.set_title(title);
return "title set in java code.";
}
}
2. 在调用打开某个Webview的 Activity 或者 Fragment中, 增加如下内容( 下面以fragment为例子):
public abstract class WebViewFragmentBase extends Fragment implements View.OnClickListener {
/**
* 页面链接
*/
protected String pageUrl;
protected WebView webview;
private TextView title;
// 通过消息机制来修改 某个View的属性. 否则会出现 异常: "Only the original thread that created a view hierarchy can touch its views"
Handler title_handler = new Handler(){
@Override
public void handleMessage(Message message){
// 目前只设置title. TODO 将来可以设置 各种其他变量常量字符串.
title.setText((String)message.obj);
}
};
// 这个方法给 AndroidObjectInJavascript 使用.
public Handler get_title_handler(){
return title_handler;
}
public void set_title(String title){
this.title.setText(title);
this.title.setVisibility(View.VISIBLE);
}
/**
* 设置当前页面的标题.
* @param title
*/
public void set_title(String title){
this.title.setText(title);
this.title.setVisibility(View.VISIBLE);
}
// 打开这个页面, 注意其中的 "android" js变量, 就是android在js中的对象.
public View onCreateView(){
webview = (WebView) view.findViewById(R.id.web_view);
// 大师添加: 向webview中注入 android object in js:
AndroidObjectInJavascript android = new AndroidObjectInJavascript(getActivity(), this);
webview.addJavascriptInterface(android, "android");
webview.loadUrl(pageUrl);
}
3. 在对应的 Vuejs 页面中, 直接调用 android 这个变量:
...
<script>
export default {
data() {
return {
// 这里定义初始化变量
}
},
route: {
this.$http.get('..../interface...').then(function(){
// 获取 titile 变量
title = this.article.title
try{
android.setTitle(title)
}catch(e) {
console.warn("== 出现错误, 如果在非android环境下访问, 出现该警告是正常的.")
console.warn(e)
}
})
}
}
</script>
2. IOS 中调用 Vue
..
<template>
<!-- 这里是 template的内容 -->
</template>
<script>
export default {
data () {
return {
article: {}
}
},
route: {
data (transition) {
this.showLoading()
this.$http.get(this.$config.API + '/interface/shoppings/article_details', {article_id: this.$route.params.aid}).then(function (response) {
this.$set('article', response.data.article)
var title = this.article.heading
// IOS语法糖开始. 暴露给 ios 的方法, 要写到这个setTimeout 里面.
setTimeout(function () {
// 利用iframe的onload事件刷新页面
// 注意: 这里的 window.get_title() 方法, 就是要暴露给 IOS的方法.
window.get_title = function (){
return document.title
}
// 暴露给 ios的方法, 要写在这个方法之前.
// 下面代码是废代码(boilerplate code) 没它不行, 写它只为了能让ios知道 上面的 js 方法.
var iframe = document.createElement('iframe')
iframe.style.visibility = 'hidden'
iframe.style.width = '1px'
iframe.style.height = '1px'
iframe.onload = function () {
setTimeout(function () {
document.body.removeChild(iframe)
}, 0)
}
document.body.appendChild(iframe)
}, 0)
// ios 语法糖,结束
}, function (response) {
console.log('response.data.error' + response.data.error)
})
this.hideLoading()
}
},
methods: {
},
components: {
XHeader
}
}
</script>