使用Android, IOS 与Vuejs 做结合的注意点: 调用js 方法
访问量: 6432
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>