您的位置:首页 > 移动开发 > Android开发

android与js交互-jsbridge

2016-10-09 16:27 190 查看
完整项目:https://github.com/snailycy/android_jsbridge

1.1 配置WebView

public void configWebView() {
try {
WebSettings settings = this.mWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setDatabaseEnabled(true);
settings.setBuiltInZoomControls(false);
settings.setDomStorageEnabled(true);
settings.setAppCacheEnabled(true);
//设置localStorage存储路径
String localStorageDBPath = this.mWebView.getContext().getFilesDir().getAbsolutePath();
settings.setDatabasePath(localStorageDBPath);

this.mWebView.setWebViewClient(new JSWebViewClient(this));
this.mWebView.setWebChromeClient(new JSWebChromeClient(this));
} catch (Exception e) {
LogUtils.e(TAG, "configWebView error.");
}
}


1.2 安卓端拦截js的请求在WebChromeClient类中的onJsAlert方法中处理

注:如果是用addJavascriptInterface的方式接受js请求,那么在android 4.2系统以下版本有js注入漏洞(在4.2及以上系统时引入@JavascriptInterface可避免)

@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
if (message.startsWith(JS_REQUEST_PREFIX)) {
if (this.jsBridge == null) {
result.cancel();
return true;
}
parseJSProtocol(message);
result.cancel();
return true;
}

return super.onJsAlert(view, url, message, result);
}


1.3 自定义JS 请求协议:myjsbridge:///request?class=指定调用的类名&method=指定调用的方法名¶ms=指定的参数&callId=指定的请求ID

解析时按照协议格式分别解析出类名,方法名,参数,callId

/**
* 解析JS协议
*
* @param message: myjsbridge:///request?class=指定调用的类名&method=指定调用的方法名¶ms=指定的参数&callId=指定的请求ID
*/
private void parseJSProtocol(String message) {
String[] tokens = message.substring(JS_REQUEST_PREFIX.length()).split("&");
String target = null;
String method = null;
String params = null;
long callID = -1;

for (String token : tokens) {
String[] pair = token.split("=");

if (pair.length != 2) {
continue;
}

try {
String key = pair[0];
String value = Uri.decode(pair[1]);

if (JS_REQUEST_CLASS_KEY.equals(key)) {
target = value;
} else if (JS_REQUEST_METHOD_KEY.equals(key)) {
method = value;
} else if (JS_REQUEST_PARAMETERS_KEY.equals(key)) {
params = value;
} else if (JS_REQUEST_CALL_ID_KEY.equals(key)) {
callID = Long.parseLong(value);
}
} catch (Exception e) {
// Ignores.
}
}

if (target != null && method != null && callID >= 0) {
this.jsBridge.requestAndroid(target, method, params, callID);
}
}


1.4 拿到对应的类名,方法名,参数后通过发射调用对应的jsapi

/**
* 由JS发起的对android端的请求
*
* @param className  类名
* @param methodName 方法名
* @param params     参数
* @param callID     请求ID
*/
public void requestAndroid(final String className, final String methodName,
final String params, final long callID) {
this.mWebView.post(new Runnable() {
@Override
public void run() {
try {
//拼接全类名: 包名.jsapi.className
String fullClassName = mWebView.getContext().getPackageName() + ".jsapi" + "." + className;
Class<?> cls = Class.forName(fullClassName);
//JSAPI 方法形参为(JSBridge jsbridge,long callId,JSONObject params)
Method declaredMethod = cls.getDeclaredMethod(methodName, JSBridge.class,
Long.class, JSONObject.class);
Object instance = cls.newInstance();
//将请求参数转换成JSONObject
JSONObject requestParams;
try {
requestParams = new JSONObject(params);
} catch (JSONException e) {
requestParams = new JSONObject();
}
//反射调用JSAPI
declaredMethod.invoke(instance, JSBridge.this, callID, requestParams);
} catch (Exception e) {
reportError(callID);
}
}
});

LogUtils.d(TAG, "requestAndroid : " + className + " , " + methodName + " , " + params);
}


1.5 jsapi demo

public class JSUIControl {

public void showToast(JSBridge jsBridge, Long callId, JSONObject requestParams) {
String content = requestParams.optString("content");
Toast.makeText(jsBridge.getActivity(), content, Toast.LENGTH_LONG).show();
//回调JS
jsBridge.reportSuccess(callId);
}
}


1.6 jsapi处理完逻辑后,将结果回调给js

/**
* 回调JS
*
* @param callID 请求ID (由JS请求android端时带过来的请求ID)
* @param type   JSAPI执行成功与否
* @param params 回传参数
*/
private void callbackJS(long callID, JSCallbackType type, String params) {
try {
if (callID < 0) {
return;
}
//组装回调js
StringBuilder js = new StringBuilder("javascript:");
js.append(MY_JS_BRIDGE);
js.append(".callbackFromNative(");
js.append(callID);
js.append(",");
js.append(type.getValue());

if (TextUtils.isEmpty(params)) {
js.append(",{});");
} else {
js.append(",");
js.append(params);
js.append(");");
}
String callbackJS = js.toString();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//4.4及以上使用evaluateJavascript
this.mWebView.evaluateJavascript(callbackJS, null);
} else {
this.mWebView.loadUrl(callbackJS);
}
LogUtils.d(TAG, "callbackJS : " + callbackJS);
} catch (Exception e) {
//ignore
}
}


1.7 js端使用alert方式调用android接口:

var json = JSON.stringify({"content":"js call native!"});
alert("myjsbridge:///request?class=JSUIControl&method=showToast¶ms="+
encodeURIComponent(json)+"&callId=1");


使用:

//1.实例化JSBridge,配置WebView
JSBridge jsBridge = new JSBridge(this, webview);
jsBridge.configWebView();

//2.WebView 加载网页资源
webview.loadUrl("file:///android_asset/demo.html");


然后结合业务,自定义jsapi

完整项目:https://github.com/snailycy/android_jsbridge
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  webview jsbridge android