creator-webview与Android交互
creator-webview与Android交互
前篇
- Android:你要的WebView与 JS 交互方式 都在这里了 - https://cloud.tencent.com/developer/article/1394361
java 调用 js
使用
WebView.evaluateJavascript
执行 js 代码1
2String callStr = String.format("window['java2js'](`%s`, `%s`)", funcName, jsonMsg);
WebViewIns.evaluateJavascript(callStr, null);如果要透传数据结构或 json, 最好用 base64 加密一下, 然后在 js 中再解密出来, 以保证这些数据不会破会 js 代码的结构
一般跨语言的交互中, 我都会使用 base64 去加密数据使之变成正常的字符串
js 调用 java
使用
WebView.addJavascriptInterface(Object, String);
映射对象和方法到 js 中一个变量, 例如:1
2
3
4
5
6
7
8public static class JsUtils {
public void call(String funcName, String jsonMsg) { // 具体多少个参数对上 js 即可
...
}
}
WebViewIns.addJavascriptInterface(new JsUtils(), "gJavaObj");直接使用 gJavaObj 对象即可
1
gJavaObj.call(funcName, jsonMsg);
加载 js 代码
使用
WebView.loadUrl
1
2String bdg = "js 代码";
WebView.loadUrl("javascript:" + bdg);js 代码书写有严格的要求, 例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 1. 一定要以这种 执行方法 的方式初始化
// 2. 语句结尾要加 ;, 不然报错 Invalid left-hand side expression in postfix operation
// 3. 注释必须清楚掉
(function() {
window.cm = {};
window.java2js = function(f, m) {
var oldCb = window.cm[f];
if (oldCb) oldCb(window.atob(m));
window.cm[f] = null;
};
window.WebViewJavascriptBridge = {
init: function() { },
registerHandler: function() { },
callHandler: function(f, m, c) {
window.cm[f] = c;
gJavaObj.call(f, m);
},
};
document.dispatchEvent(new Event("WebViewJavascriptBridgeReady"));
})()可以使用 uglyjs 把代码压缩成一行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157String bdg = "window.cm={},window.java2js=function(f,m){var oldCb=window.cm[f];oldCb&&oldCb(window.atob(m)),window.cm[f]=null},window.WebViewJavascriptBridge={init:function(){},registerHandler:function(){},callHandler:function(f,m,c){window.cm[f]=c,gJavaObj.call(f,m)}},document.dispatchEvent(new Event(\"WebViewJavascriptBridgeReady\"));"
---
### 完整的 java, html 代码
#### java
- 代码
```json
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.net.http.SslError;
import android.util.Base64;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.SslErrorHandler;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
public class WebviewHelper {
public static WebviewHelper instance = null;
private RelativeLayout mLayoutRoot;
private WebView mWebview;
private static Map<String, BridgeHandler> mJsCb = new HashMap<>();
public static void showWebview(final Activity activity, final String url, final ActivityMgr.CodeRunnable task) {
closeWebview(activity, () -> {
instance = new WebviewHelper();
instance.show(activity, url);
if (task != null) {
task.run(ActivityMgr.Ok, "");
}
});
}
public static void closeWebview(final Activity activity, final Runnable task) {
activity.runOnUiThread(() -> {
if (instance != null) {
instance.destroy();
}
if (task != null) {
task.run();
}
});
}
public static boolean goBack() {
ActivityMgr.Act.moveTaskToBack(true);
return false;
}
@SuppressLint("SetJavaScriptEnabled")
public void show(Activity activity, final String url) {
final RelativeLayout rLayout = new RelativeLayout(activity);
mLayoutRoot = rLayout;
RelativeLayout.LayoutParams rParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
final WebView wv = new WebView(activity);
wv.setWebViewClient(new WebviewClientHelper());
mWebview = wv;
wv.setLayoutParams(lParams);
rLayout.addView(wv);
activity.addContentView(rLayout, rParams);
mWebview.addJavascriptInterface(new JsUtils(), "gJavaObj");//AndroidtoJS类对象映射到js的test对象
wv.loadUrl(url);
// 设置webview
WebSettings settings = wv.getSettings();
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); // 有缓存就使用缓存
settings.setSupportZoom(false);
settings.setBuiltInZoomControls(true);
}
public static void regHandler(String name, BridgeHandler bh) {
mJsCb.put(name, bh);
}
private void destroy() {
if (mWebview != null) {
mWebview.destroy();
mWebview = null;
}
if (mLayoutRoot != null) {
ViewGroup vg = (ViewGroup) mLayoutRoot.getParent();
vg.removeView(mLayoutRoot);
mLayoutRoot = null;
}
instance = null;
}
public interface BridgeHandler {
void handler(String var1, Consumer<String> var2);
}
public static class JsUtils {
@JavascriptInterface
public void call(String funcName, String jsonMsg) {
BridgeHandler bh = mJsCb.get(funcName);
if (bh == null) {
ActivityMgr.E("no func: %s", funcName);
return;
}
bh.handler(jsonMsg, (result) -> {
try {
// 交互是需要 base64 处理一下
result = Base64.encodeToString((result != null ? result : "").getBytes(StandardCharsets.UTF_8), Base64.DEFAULT);
String callStr = String.format("window['java2js'](`%s`, `%s`)", funcName, result);
instance.mWebview.evaluateJavascript(callStr, null);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
public static class WebviewClientHelper extends WebViewClient {
public boolean isLoadBdg = false;
@Override
public void onPageFinished(WebView view, String url) {
if (!isLoadBdg) {
String bdg = "window.cm={},window.java2js=function(f,m){var oldCb=window.cm[f];oldCb&&oldCb(window.atob(m)),window.cm[f]=null},window.WebViewJavascriptBridge={init:function(){},registerHandler:function(){},callHandler:function(f,m,c){window.cm[f]=c,gJavaObj.call(f,m)}},document.dispatchEvent(new Event(\"WebViewJavascriptBridgeReady\"));";
view.loadUrl("javascript:" + bdg);
isLoadBdg = true;
}
super.onPageFinished(view, url);
}
}
}
html
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<html>
<head>
<script>
document.addEventListener(
'WebViewJavascriptBridgeReady'
, function() {
console.log("--- WebViewJavascriptBridgeReady");
},
false
);
function js2java() {
console.log("--- js2java");
// gJavaObj.hello("Hello Terry")
var funcName = "StartInfo"
var jsonMsg = "World 002"
window.WebViewJavascriptBridge.callHandler(funcName, jsonMsg, function(responseData) {
console.log("--- responseData:", responseData);
})
}
console.log("--- web loaded");
</script>
<title>Test Webview</title>
</head>
<body>
<div id="mydiv">
<br /><br /><button onclick="js2java()"> js2java </button>
</div>
</body>
</html>