Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2fe0245

Browse files
author
lemon
committed
添加jsbridge注入的重试机制,尽可能确保注入成功
1 parent f20ad60 commit 2fe0245

File tree

6 files changed

+145
-41
lines changed

6 files changed

+145
-41
lines changed
0 Bytes
Binary file not shown.

‎.idea/misc.xml‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎easybridge/src/main/assets/easybridge.js‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@
3030
}
3131
//the name '_easybridge' is an java object that mapping to a javascript object,using addJavaInterface in Java code
3232
if (window._easybridge) {
33-
setTimeout(function () {
34-
//the function enqueue is the pubic method from Java Code,using to call Java logic
35-
_easybridge.enqueue(handlerName, location.href, parameters, callbackId);
36-
}, 0);
33+
//the function enqueue is the pubic method from Java Code,using to call Java logic
34+
_easybridge.enqueue(handlerName, location.href, parameters, callbackId);
3735
} else {
3836
console.error(bridgeName + ':' + "the mapping object '_easybridge' had not been added any more");
3937
}
@@ -111,6 +109,8 @@
111109
_dispatchResult: _dispatchResult,
112110

113111
};
112+
//notify to native that the bridge had been injected finished
113+
window[bridgeName].callHandler('rejectFinished');
114114
//notify to javascript that the bridge had been init
115115
var doc = document;
116116
var readyEvent = doc.createEvent('Events');

‎easybridge/src/main/java/tech/easily/easybridge/lib/EasyBridge.java‎

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.os.Build;
44
import android.os.Handler;
5+
import android.os.Looper;
56
import android.text.TextUtils;
67
import android.webkit.JavascriptInterface;
78
import android.webkit.ValueCallback;
@@ -25,16 +26,12 @@
2526
*/
2627
final class EasyBridge {
2728

28-
private static class CallBackHandler extends Handler {
29-
}
30-
31-
private static final String JAVA_SCRIPT_PROTOCOL = "javascript:";
3229
private static final String CALLBACK_FUNCTION = "%s._dispatchResult(\"%s\",\'%s\')";
3330
private static final String EXECUTE_SCRIPT = "%s._executeScript(\'%s\',\'%s\',\'%s\')";
3431

3532
private Map<String, BridgeHandler> registerHandlerMap;
3633
private Map<String, ResultCallBack> jsCallbackMap;
37-
private CallBackHandler callBackHandler;
34+
private Handler callBackHandler;
3835
private SoftReference<EasyBridgeWebView> bridgeWebView;
3936
private String bridgeName;
4037
private static long uniqueId = 1;
@@ -44,7 +41,7 @@ private static class CallBackHandler extends Handler {
4441
registerHandlerMap = new HashMap<>();
4542
jsCallbackMap = new HashMap<>();
4643
this.bridgeWebView = new SoftReference<>(webView);
47-
this.callBackHandler = new CallBackHandler();
44+
this.callBackHandler = new Handler(Looper.getMainLooper());
4845
}
4946

5047

@@ -138,28 +135,21 @@ private void dispatchResult(String callbackId, String parameters) {
138135
return;
139136
}
140137
final String callBackScript = String.format(CALLBACK_FUNCTION, bridgeName, callbackId, parameters);
138+
139+
}
140+
141+
private void executeScriptInMain(final String script) {
142+
if (bridgeWebView == null || bridgeWebView.get() == null) {
143+
return;
144+
}
141145
callBackHandler.post(new Runnable() {
142146
@Override
143147
public void run() {
144-
executeScriptInMain(callBackScript);
148+
bridgeWebView.get().evaluateJavascript(script);
145149
}
146150
});
147151
}
148152

149-
private void executeScriptInMain(String script) {
150-
// 如果系统版本在android4.4及以上,则使用evaluateJavascript,这个方法可以拿到js执行的返回值,否则使用loadUrl
151-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
152-
bridgeWebView.get().evaluateJavascript(script, new ValueCallback<String>() {
153-
@Override
154-
public void onReceiveValue(String value) {
155-
156-
}
157-
});
158-
} else {
159-
bridgeWebView.get().loadUrl(String.format("%s%s", JAVA_SCRIPT_PROTOCOL, script));
160-
}
161-
}
162-
163153
/**
164154
* find the suitable handler
165155
*
Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
package tech.easily.easybridge.lib;
22

3+
import android.os.Handler;
4+
import android.os.Looper;
5+
import android.text.TextUtils;
6+
import android.util.Log;
37
import android.webkit.WebChromeClient;
48
import android.webkit.WebView;
59

10+
import java.util.Date;
11+
612
/**
713
* Created by lemon on 2018年4月2日.
814
*/
915
public class EasyBridgeWebChromeClient extends WebChromeClient {
1016

1117
private static final String BRIDGE_SCRIPT_PATH = "easybridge.js";
12-
private static final String JAVA_SCRIPT_PROTOCOL = "javascript:";
1318
public static final String SECURITY_CHECK_PARAMETERS = "inject bridge script";
14-
private boolean isInjected;
19+
private boolean hasCalled;
1520
private EasyBridgeWebView easyBridgeWebView;
21+
private String injectScript;
22+
private InjectBridgeTask injectBridgeTask;
23+
1624

1725
public EasyBridgeWebChromeClient(EasyBridgeWebView webView) {
1826
this.easyBridgeWebView = webView;
@@ -21,32 +29,92 @@ public EasyBridgeWebChromeClient(EasyBridgeWebView webView) {
2129
@Override
2230
public void onProgressChanged(WebView view, int newProgress) {
2331
super.onProgressChanged(view, newProgress);
32+
if (injectBridgeTask == null) {
33+
injectBridgeTask = new InjectBridgeTask(this);
34+
}
2435
// inject the bridge code when the progress above 25% to make sure it worked
2536
if (newProgress <= 25) {
26-
isInjected = false;
37+
hasCalled = false;
2738
return;
2839
}
29-
if (!isInjected) {
40+
if (!hasCalled) {
41+
hasCalled = true;
42+
// reset the injected status label before injecting a new bridge to the page
43+
if (easyBridgeWebView != null) {
44+
easyBridgeWebView.setInjected(false);
45+
}
3046
// TODO: 2018年4月3日 it seems that the url received here possibly not the same as the real page url we look forward to
3147
if (easyBridgeWebView.checkSecurityGlobally(view.getUrl(), SECURITY_CHECK_PARAMETERS)) {
32-
isInjected = true;
33-
injectBridge(view);
48+
injectBridgeTask.start();
3449
} else {
35-
deleteBridge(view);
50+
deleteBridge();
3651
}
3752
}
3853
}
3954

40-
private void injectBridge(WebView view) {
41-
String bridgeScript = Utils.readAssetFile(view.getContext(), BRIDGE_SCRIPT_PATH);
42-
String executeScript = "var bridgeName = " + "\"" + easyBridgeWebView.getBridgeName() + "\"" + ";" + bridgeScript;
43-
view.loadUrl(String.format("%s%s", JAVA_SCRIPT_PROTOCOL, executeScript));
55+
private void injectBridge() {
56+
if (easyBridgeWebView == null) {
57+
return;
58+
}
59+
if (TextUtils.isEmpty(injectScript)) {
60+
injectScript = Utils.readAssetFile(easyBridgeWebView.getContext(), BRIDGE_SCRIPT_PATH);
61+
injectScript = "var bridgeName = " + "\"" + easyBridgeWebView.getBridgeName() + "\"" + ";" + injectScript;
62+
}
63+
easyBridgeWebView.evaluateJavascript(injectScript);
4464
}
4565

46-
private void deleteBridge(WebView view) {
47-
// execute script below to remove the bridge had set before :
48-
// delete _easybridge;
66+
67+
private boolean isInjected() {
68+
return easyBridgeWebView != null && easyBridgeWebView.isInjected();
69+
}
70+
71+
/**
72+
* as EasyBridge will inject an object named '_easybridge' into JavaScript context using addJavaScriptInterface()
73+
* we need to removed it when security forbidden
74+
*/
75+
private void deleteBridge() {
76+
if (easyBridgeWebView == null) {
77+
return;
78+
}
4979
String script = "delete " + EasyBridgeWebView.MAPPING_JS_INTERFACE_NAME + ";";
50-
view.loadUrl(String.format("%s%s", JAVA_SCRIPT_PROTOCOL, script));
80+
easyBridgeWebView.evaluateJavascript(script);
81+
}
82+
83+
/**
84+
* a task using to inject bridge ,
85+
* it will try to re-inject the bridge every 300ms(at most 5 times) if the status of bridgeInjected is false
86+
*/
87+
private static class InjectBridgeTask implements Runnable {
88+
89+
private static final int RETRY_COUNT = 5;
90+
private static final long RETRY_DELAY_INTERVAL = 300;
91+
private int retryCount;
92+
private EasyBridgeWebChromeClient webChromeClient;
93+
private Handler mainHandler;
94+
95+
InjectBridgeTask(EasyBridgeWebChromeClient webChromeClient) {
96+
this.webChromeClient = webChromeClient;
97+
this.mainHandler = new Handler(Looper.getMainLooper());
98+
}
99+
100+
@Override
101+
public void run() {
102+
if (!webChromeClient.isInjected() && retryCount <= RETRY_COUNT) {
103+
webChromeClient.injectBridge();
104+
retryCount++;
105+
mainHandler.postDelayed(this, RETRY_DELAY_INTERVAL);
106+
} else {
107+
reset();
108+
}
109+
}
110+
111+
private void reset() {
112+
mainHandler.removeCallbacks(this);
113+
retryCount = 0;
114+
}
115+
116+
public void start() {
117+
mainHandler.post(this);
118+
}
51119
}
52120
}

‎easybridge/src/main/java/tech/easily/easybridge/lib/EasyBridgeWebView.java‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@
33
import android.annotation.SuppressLint;
44
import android.content.Context;
55
import android.content.res.TypedArray;
6+
import android.os.Build;
7+
import android.os.Handler;
8+
import android.os.Looper;
9+
import android.support.annotation.Nullable;
610
import android.util.AttributeSet;
11+
import android.util.Log;
12+
import android.webkit.ValueCallback;
713
import android.webkit.WebSettings;
814
import android.webkit.WebView;
915

16+
import java.util.BitSet;
1017
import java.util.HashMap;
1118
import java.util.Map;
1219

20+
import tech.easily.easybridge.lib.handler.BaseBridgeHandler;
1321
import tech.easily.easybridge.lib.handler.BridgeHandler;
1422

1523
/**
@@ -26,11 +34,15 @@
2634
*/
2735
public class EasyBridgeWebView extends WebView {
2836

37+
private static final String JAVA_SCRIPT_PROTOCOL = "javascript:";
2938
static final String MAPPING_JS_INTERFACE_NAME = "_easybridge";
3039
private static final String DEFAULT_BRIDGE_NAME = "easyBridge";
40+
private static final String REGISTER_INJECT_FINISHED = "rejectFinished";
3141
private final EasyBridge easyBridge;
3242
private String bridgeName = DEFAULT_BRIDGE_NAME;
3343
protected SecurityPolicyChecker policyChecker;
44+
// whether the bridge had been injected to the currentPage
45+
private volatile boolean isInjected;
3446

3547
public EasyBridgeWebView(Context context, String bridgeName) {
3648
this(context, (AttributeSet) null);
@@ -60,6 +72,13 @@ private void initWebView() {
6072
addJavascriptInterface(easyBridge, MAPPING_JS_INTERFACE_NAME);
6173
EasyBridgeWebChromeClient webChromeClient = new EasyBridgeWebChromeClient(this);
6274
setWebChromeClient(webChromeClient);
75+
//register a default handler to subscribe the event of bridge injected
76+
registerHandler(new BaseBridgeHandler(REGISTER_INJECT_FINISHED, this) {
77+
@Override
78+
public void onCall(String parameters, ResultCallBack callBack) {
79+
setInjected(true);
80+
}
81+
});
6382
}
6483

6584
public void registerHandler(BridgeHandler handler) {
@@ -98,6 +117,14 @@ public String getBridgeName() {
98117
return bridgeName;
99118
}
100119

120+
public boolean isInjected() {
121+
return isInjected;
122+
}
123+
124+
void setInjected(boolean injected) {
125+
isInjected = injected;
126+
}
127+
101128
public boolean checkSecurityGlobally(String url, String parameters) {
102129
return policyChecker == null || policyChecker.check(url, parameters);
103130
}
@@ -112,9 +139,28 @@ public void setPolicyChecker(SecurityPolicyChecker policyChecker) {
112139
this.policyChecker = policyChecker;
113140
}
114141

142+
public void evaluateJavascript(String script) {
143+
evaluateJavascript(script, new ValueCallback<String>() {
144+
@Override
145+
public void onReceiveValue(String value) {
146+
147+
}
148+
});
149+
}
150+
151+
@Override
152+
public void evaluateJavascript(String script, @Nullable ValueCallback<String> resultCallback) {
153+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
154+
super.evaluateJavascript(script, resultCallback);
155+
} else {
156+
loadUrl(String.format("%s%s", JAVA_SCRIPT_PROTOCOL, script));
157+
}
158+
}
159+
115160
@Override
116161
protected void onDetachedFromWindow() {
117162
super.onDetachedFromWindow();
163+
policyChecker = null;
118164
if (easyBridge != null) {
119165
easyBridge.destroy();
120166
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /