同时该类还有把一个json转化为参数值的功能,和把参数值转化为json的功能
28 | *
29 | * Created by niuxiaowei on 16/7/14.
30 | */
31 | public class Params {
32 |
33 | /**
34 | * 解析出来的所有注解item
35 | */
36 | private BaseParamItem[] mParamItems;
37 | private static SimpleJavaJsBridge sSimpleJavaJsBridge;
38 |
39 | Params() {
40 | }
41 |
42 | /**
43 | * 初始化方法
44 | *
45 | * @param simpleJavaJsBridge
46 | */
47 | public static void init(SimpleJavaJsBridge simpleJavaJsBridge) {
48 | sSimpleJavaJsBridge = simpleJavaJsBridge;
49 | }
50 |
51 | /**
52 | * 把json转化为参数值
53 | * @param requestResponseBuilder 包含了一系列的json数据,json数据是request或者response
54 | * @return
55 | */
56 | public Object[] convertJson2ParamValues(RequestResponseBuilder requestResponseBuilder) {
57 | if (requestResponseBuilder == null || mParamItems == null) {
58 | return null;
59 | }
60 | Object[] result = new Object[mParamItems.length];
61 | BaseParamItem paramItem = null;
62 | for (int i = 0; i < mParamItems.length; i++) {
63 | paramItem = mParamItems[i];
64 | if (paramItem != null) {
65 |
66 | result[i] = paramItem.convertJson2ParamValue(requestResponseBuilder);
67 | }
68 | }
69 | return result;
70 |
71 | }
72 |
73 | /**
74 | * 把参数值转化为json
75 | * @param requestResponseBuilder
76 | * @param paramValues 参数值
77 | */
78 | public void convertParamValues2Json(RequestResponseBuilder requestResponseBuilder, Object[] paramValues) {
79 | if (requestResponseBuilder == null || paramValues == null) {
80 | return;
81 | }
82 | BaseParamItem paramItem = null;
83 | for (int i = 0; i < mParamItems.length; i++) {
84 | paramItem = mParamItems[i];
85 | if (paramItem != null) {
86 | paramItem.convertParamValue2Json(requestResponseBuilder, paramValues[i]);
87 | }
88 | }
89 | }
90 |
91 |
92 | /**
93 | * 基础类,定义了一些基础的数据
94 | */
95 | private static abstract class BaseParamItem {
96 | /**
97 | * 参数所对应的类型{@link Class}
98 | */
99 | protected Class paramType;
100 | /**
101 | * 因为参数是由{@link Param},{@link ParamCallback},{@link ParamResponseStatus}其中的一个注解标注的,
102 | * 注解标注的参数,会以{key:value}的格式存入json中,key值就是注解的value()值,因此{@link #paramKey}来代表key值
103 | */
104 | protected String paramKey;
105 |
106 | public BaseParamItem(Class paramType, String paramKey) {
107 | this.paramType = paramType;
108 | this.paramKey = paramKey;
109 | }
110 |
111 | /**
112 | * json的格式{key:value},该方法会从json中把value给解析出来,作为参数值
113 | * @param requestResponseBuilder
114 | * @return
115 | */
116 | public abstract Object convertJson2ParamValue(RequestResponseBuilder requestResponseBuilder);
117 |
118 | /**
119 | * 该方法会把参数值以{key:value}的格式存入json中
120 | * @param requestResponseBuilder
121 | * @param obj
122 | */
123 | public abstract void convertParamValue2Json(RequestResponseBuilder requestResponseBuilder, Object obj);
124 | }
125 |
126 | /**
127 | * 对应{@link Param}注解标注的参数
128 | */
129 | private static class ParamItem extends BaseParamItem {
130 |
131 |
132 | public ParamItem(String paramKey, Class paramClass) {
133 | super(paramClass, paramKey);
134 | }
135 |
136 | protected void onReceiveKeyValue(RequestResponseBuilder requestResponseBuilder, String key, Object value) {
137 | requestResponseBuilder.putValue(key, value);
138 | }
139 |
140 | protected JSONObject getJson(RequestResponseBuilder requestResponseBuilder) {
141 | return requestResponseBuilder.getValues();
142 | }
143 |
144 | @Override
145 | public Object convertJson2ParamValue(RequestResponseBuilder requestResponseBuilder) {
146 | if (requestResponseBuilder == null || requestResponseBuilder.getValues() == null) {
147 | return null;
148 | }
149 | JSONObject jsonObject = getJson(requestResponseBuilder);
150 | if (jsonObject != null) {
151 | if (!isObjectDirectPut2Json(paramType)) {
152 | try {
153 | JSONObject value = !TextUtils.isEmpty(paramKey) ? (JSONObject) jsonObject.opt(paramKey) : jsonObject;
154 | if (value == null) {
155 | return null;
156 | }
157 | Object instance = paramType.newInstance();
158 | Field[] fields = paramType.getDeclaredFields();
159 | for (Field field : fields
160 | ) {
161 | Param p = field.getAnnotation(Param.class);
162 | if (p != null) {
163 | /*可以访问不可以访问的变量*/
164 | field.setAccessible(true);
165 | field.set(instance, value.opt(p.value()));
166 | }
167 | }
168 | return instance;
169 | } catch (InstantiationException e) {
170 | e.printStackTrace();
171 | } catch (IllegalAccessException e) {
172 | e.printStackTrace();
173 | }
174 | } else {
175 | return jsonObject.opt(paramKey);
176 | }
177 | }
178 | return null;
179 | }
180 |
181 | @Override
182 | public void convertParamValue2Json(RequestResponseBuilder requestResponseBuilder, Object obj) {
183 |
184 | if (requestResponseBuilder == null || obj == null) {
185 | return;
186 | }
187 | if (!isObjectDirectPut2Json(obj)) {
188 | JSONObject json = convertObjectFileds2Json(obj);
189 | if (json == null) {
190 | return;
191 | }
192 | if (!TextUtils.isEmpty(paramKey)) {
193 | onReceiveKeyValue(requestResponseBuilder, paramKey, json);
194 | } else {
195 | Iterator 生成{@link SimpleJavaJsBridge}的实例: 调用js接口的例子: 例子: 例子: 例子: 把参数值转化为json格式 例子1: 例子2: 例子3:参数是{@link org.json.JSONObject}不可以直接存放的,{@link #value()}设置了值 例子4:参数是{@link org.json.JSONObject}不可以直接存放的 把json转化为参数值 例子1:简单类型 例子2:{@link org.json.JSONObject}不能直接存放的类型 {@link #value()}就代表key,key1这些值,@Param标注的参数或类的实例属性代表value或value1这些值; 例子1:java主动调用js,提供给js的回调方法 例子2:js主动调用java,提供给java的回调方法 因此该注解是用来对responseStatus进行标注的,responseStatus格式({status:1, msg:"ok"}。{@link #value()}就是status或msg这些key值 例子: 例子:
63 | * {
64 | * "handlerName":"test",
65 | * "callbackId":"c_111111",
66 | * "params":{
67 | * ....
68 | * }
69 | * }
70 | *
71 | * hanlerName 代表java与js之间给对方暴漏的接口的名称,
72 | * callbackId 代表对方在发起请求时,会为回调方法生产一个唯一的id值,它就代表这个唯一的id值
73 | * params 代表传递的数据
74 | *
75 | * }
76 | */
77 | private static class Request {
78 |
79 | private static String sRequestInterfaceName = "handlerName";
80 | private static String sRequestCallbackIdName = "callbackId";
81 | private static String sRequestValuesName = "params";
82 |
83 | /*request相关的属性*/
84 | private String interfaceName;
85 | private String callbackId;
86 | private JSONObject requestValues;
87 | private IJavaCallback2JS iJavaCallback2JS;
88 |
89 | private static void init(String requestInterfaceName, String requestCallbackIdName, String requestValuesName) {
90 | if (!TextUtils.isEmpty(requestCallbackIdName)) {
91 | Request.sRequestCallbackIdName = requestCallbackIdName;
92 | }
93 |
94 | if (!TextUtils.isEmpty(requestValuesName)) {
95 | Request.sRequestValuesName = requestValuesName;
96 | }
97 | if (!TextUtils.isEmpty(requestInterfaceName)) {
98 | Request.sRequestInterfaceName = requestInterfaceName;
99 | }
100 | }
101 |
102 | private void parseRequest(JSONObject json) {
103 | if (json != null) {
104 | callbackId = json.optString(sRequestCallbackIdName);
105 | interfaceName = json.optString(sRequestInterfaceName);
106 | requestValues = json.optJSONObject(sRequestValuesName);
107 | }
108 | }
109 |
110 | @Override
111 | public String toString() {
112 | JSONObject jsonObject = new JSONObject();
113 | try {
114 | jsonObject.put(sRequestCallbackIdName, callbackId);
115 | jsonObject.put(sRequestInterfaceName, interfaceName);
116 | if (requestValues != null) {
117 | jsonObject.put(sRequestValuesName, requestValues);
118 | }
119 | } catch (JSONException e) {
120 | e.printStackTrace();
121 | }
122 | return "'" + jsonObject.toString() + "'";
123 | }
124 | }
125 |
126 | /**
127 | *
128 | * response数据格式:
129 | *
130 | * {
131 | * "responseId":"iii",
132 | * "data":{
133 | * "status":"1",
134 | * "msg":"ok",
135 | * "values":{
136 | * ......
137 | * }
138 | * }
139 | * }
140 | *
141 | * responseId 代表request中的callbackId
142 | * data 代表响应的数据
143 | * status 代表响应状态
144 | * msg 代表响应状态对应的消息
145 | * values 代表响应数据包含的值
146 | *
147 | */
148 | private static class Response {
149 | private static String sResponseIdName = "responseId";
150 | private static String sResponseValuesName = "values";
151 | private static String sResponseName = "data";
152 |
153 | private String responseId;
154 | private JSONObject response = new JSONObject();
155 | private JSONObject responseValues;
156 |
157 | private static void init(String responseIdName, String responseName, String responseValuesName) {
158 | if (!TextUtils.isEmpty(responseValuesName)) {
159 |
160 | Response.sResponseValuesName = responseValuesName;
161 | }
162 | if (!TextUtils.isEmpty(responseIdName)) {
163 | Response.sResponseIdName = responseIdName;
164 | }
165 |
166 | if (!TextUtils.isEmpty(responseName)) {
167 |
168 | Response.sResponseName = responseName;
169 | }
170 |
171 | }
172 |
173 | private void parseResponse(JSONObject json) {
174 | if (json != null) {
175 | responseId = json.optString(sResponseIdName);
176 | response = json.optJSONObject(sResponseName);
177 | if (response != null) {
178 | responseValues = response.optJSONObject(sResponseValuesName);
179 | }
180 | }
181 | }
182 |
183 | @Override
184 | public String toString() {
185 | JSONObject jsonObject = new JSONObject();
186 | try {
187 | jsonObject.put(sResponseIdName, responseId);
188 | if (responseValues != null) {
189 | response.put(sResponseValuesName, responseValues);
190 | }
191 | jsonObject.put(sResponseName, response);
192 | } catch (JSONException e) {
193 | e.printStackTrace();
194 | }
195 |
196 | return "'" + jsonObject.toString() + "'";
197 | }
198 | }
199 |
200 | /**
201 | * 获取请求时为回调函数生成的 callbackId
202 | * @return
203 | */
204 | public String getCallbackId(){
205 | return mRequest == null?null: mRequest.callbackId;
206 | }
207 |
208 | /**
209 | * 获取请求的接口的名字
210 | * @return
211 | */
212 | public String getInterfaceName() {
213 | return mRequest == null ? null : mRequest.interfaceName;
214 | }
215 |
216 | public void setRequestCallback(IJavaCallback2JS callback) {
217 | initRequest();
218 | this.mRequest.iJavaCallback2JS = callback;
219 | }
220 |
221 | private void initRequest() {
222 | if (mRequest == null) {
223 | mRequest = new Request();
224 | }
225 | }
226 |
227 | /**
228 | * 设置请求的接口的名字
229 | * @param interfaceName
230 | */
231 | public void setInterfaceName(String interfaceName) {
232 | initRequest();
233 | this.mRequest.interfaceName = interfaceName;
234 | }
235 |
236 | /**
237 | * 为回调方法设置回调id
238 | * @param callbackId
239 | */
240 | public void setCallbackId(String callbackId) {
241 | initRequest();
242 | this.mRequest.callbackId = callbackId;
243 | }
244 |
245 |
246 | /**
247 | * 获取request或者response的 values值
248 | * @return
249 | */
250 | public JSONObject getValues() {
251 | if (mIsBuildRequest) {
252 | return mRequest == null ? null : mRequest.requestValues;
253 | } else {
254 | return mResponse == null ? null : mResponse.responseValues;
255 | }
256 | }
257 |
258 | /**
259 | * 往request或者response中存放 数据
260 | * @param key
261 | * @param value
262 | */
263 | public void putValue(String key, Object value) {
264 | if(TextUtils.isEmpty(key) || value == null){
265 | return;
266 | }
267 | JSONObject values = null;
268 | if (mIsBuildRequest) {
269 | initRequest();
270 | if (mRequest.requestValues == null) {
271 | mRequest.requestValues = new JSONObject();
272 | }
273 | values = mRequest.requestValues;
274 | } else {
275 | initResponse();
276 | if (mResponse.responseValues == null) {
277 | mResponse.responseValues = new JSONObject();
278 | }
279 | values = mResponse.responseValues;
280 | }
281 |
282 | try {
283 | values.put(key, value);
284 | } catch (JSONException e) {
285 | e.printStackTrace();
286 | }
287 |
288 | }
289 |
290 | public IJavaCallback2JS getCallback() {
291 | return mRequest == null ? null : mRequest.iJavaCallback2JS;
292 | }
293 |
294 | /**
295 | * @param responseIdName
296 | * @param responseName
297 | * @param responseValuesName
298 | */
299 | public static void init(String responseIdName, String responseName, String responseValuesName, String requestInterfaceName, String requestCallbackIdName, String requestValuesName) {
300 | Response.init(responseIdName, responseName, responseValuesName);
301 | Request.init(requestInterfaceName, requestCallbackIdName, requestValuesName);
302 | }
303 |
304 |
305 | private void initResponse() {
306 | if (mResponse == null) {
307 | mResponse = new Response();
308 | }
309 | }
310 |
311 | public String getResponseId() {
312 | return mResponse == null ? null : mResponse.responseId;
313 | }
314 |
315 | public void setResponseId(String responseId) {
316 | initResponse();
317 | this.mResponse.responseId = responseId;
318 | }
319 |
320 | /**
321 | * 获取response的 状态数据
322 | * @return
323 | */
324 | public JSONObject getResponseStatus() {
325 | return mResponse == null ? null : mResponse.response;
326 | }
327 |
328 | /**
329 | * 往response中存放 数据
330 | * @param key
331 | * @param value
332 | */
333 | public void putResponseStatus(String key, Object value) {
334 | if(TextUtils.isEmpty(key) || value == null){
335 | return;
336 | }
337 | initResponse();
338 | try {
339 | mResponse.response.put(key, value);
340 | } catch (JSONException e) {
341 | e.printStackTrace();
342 | }
343 | }
344 |
345 |
346 | /**
347 | * 从json中创建一个{@link RequestResponseBuilder}对象,其实最终创建的是一个 request或者response
348 | * @param json
349 | * @return
350 | */
351 | static RequestResponseBuilder create(JSONObject json) {
352 | if (json == null) {
353 | return null;
354 | }
355 | RequestResponseBuilder requestResponseBuilder = null;
356 | /*响应数据*/
357 | if (json.has(Response.sResponseIdName)) {
358 | requestResponseBuilder = new RequestResponseBuilder(false, json);
359 | } else {
360 | requestResponseBuilder = new RequestResponseBuilder(true, json);
361 | }
362 |
363 | return requestResponseBuilder;
364 | }
365 |
366 | /**
367 | * 是否构建的时request数据
368 | * @return
369 | */
370 | public boolean isBuildRequest() {
371 | return mIsBuildRequest;
372 | }
373 |
374 | @Override
375 | public String toString() {
376 | if (mIsBuildRequest) {
377 | return mRequest == null ? super.toString() : mRequest.toString();
378 | } else {
379 | return mResponse == null ? super.toString() : mResponse.toString();
380 | }
381 | }
382 | }
383 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/java/com/simplejsjavabridge/lib/SimpleJavaJSWebChromeClient.java:
--------------------------------------------------------------------------------
1 | package com.simplejsjavabridge.lib;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.os.Message;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.webkit.ConsoleMessage;
9 | import android.webkit.GeolocationPermissions;
10 | import android.webkit.JsPromptResult;
11 | import android.webkit.JsResult;
12 | import android.webkit.PermissionRequest;
13 | import android.webkit.WebChromeClient;
14 | import android.webkit.WebStorage;
15 | import android.webkit.WebView;
16 |
17 | import java.io.BufferedReader;
18 | import java.io.IOException;
19 | import java.io.InputStream;
20 | import java.io.InputStreamReader;
21 |
22 |
23 | /**
24 | *该类的主要作用是在{@link #onJsPrompt(WebView, String, String, String, JsPromptResult)}对js传递的数据交给{@link SimpleJavaJsBridge}进行
25 | * 处理 并且在{@link #onProgressChanged(WebView, int)}方法里把内嵌的js文件注入h5页面中,这样就省得使用者在关心这些环节了。
26 | * {@link #mWebChromeClient}的主要作用是使用者直接把自己生成的{@link WebChromeClient}传递进来,该类负责调用相应的方法
27 | */
28 | public class SimpleJavaJSWebChromeClient extends WebChromeClient {
29 |
30 |
31 | private WebChromeClient mWebChromeClient;
32 |
33 | public boolean mIsInjectedJS;
34 |
35 | private SimpleJavaJsBridge mSimpleJavaJsBridge;
36 |
37 | SimpleJavaJSWebChromeClient(WebChromeClient webChromeClient, SimpleJavaJsBridge simpleJavaJsBridge) {
38 | mWebChromeClient = webChromeClient;
39 | mSimpleJavaJsBridge = simpleJavaJsBridge;
40 | }
41 |
42 | private static void webViewLoadLocalJs(WebView view, String path) {
43 | String jsContent = assetFile2Str(view.getContext(), path);
44 | view.loadUrl("javascript:" + jsContent);
45 | }
46 |
47 | private static String assetFile2Str(Context c, String urlStr) {
48 | InputStream in = null;
49 | try {
50 | in = c.getAssets().open(urlStr);
51 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
52 | String line = null;
53 | StringBuilder sb = new StringBuilder();
54 | do {
55 | line = bufferedReader.readLine();
56 | if (line != null) {
57 | line = line.replaceAll("\\t", " ");
58 | if (!line.matches("^\\s*\\/\\/.*")) {
59 | sb.append(line);
60 | }
61 | }
62 | } while (line != null);
63 |
64 | bufferedReader.close();
65 | in.close();
66 |
67 | return sb.toString();
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | } finally {
71 | if (in != null) {
72 | try {
73 | in.close();
74 | } catch (IOException e) {
75 | }
76 | }
77 | }
78 | return null;
79 | }
80 |
81 | @Override
82 | public void onProgressChanged(WebView view, int newProgress) {
83 |
84 | Log.i("test", "--new pro=" + newProgress);
85 |
86 | // if (newProgress <= 98) {
87 | // mIsInjectedJS = false;
88 | // } else if (!mIsInjectedJS) {
89 | // mIsInjectedJS = true;
90 | // webViewLoadLocalJs(view, "js_native_bridge.js");
91 | // }
92 | //
93 | if (checkObjectNotNull(mWebChromeClient)) {
94 | mWebChromeClient.onProgressChanged(view, newProgress);
95 | }
96 | super.onProgressChanged(view, newProgress);
97 |
98 |
99 | }
100 |
101 | private boolean checkObjectNotNull(Object object) {
102 | return object != null;
103 | }
104 |
105 | @Override
106 | public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
107 | // result.cancel();
108 | if (checkObjectNotNull(mWebChromeClient)) {
109 | return mWebChromeClient.onJsAlert(view, url, message, result);
110 | }
111 | return super.onJsAlert(view, url, message, result);
112 | }
113 |
114 |
115 | @Override
116 | public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
117 | if (mSimpleJavaJsBridge.parseJsonFromJs(message)) {
118 | /*必须得有这行代码,否则会阻塞当前h5页面*/
119 | result.cancel();
120 | return true;
121 | }
122 |
123 | if (checkObjectNotNull(mWebChromeClient)) {
124 | return mWebChromeClient.onJsPrompt(view, url, message, defaultValue, result);
125 | }
126 |
127 | return super.onJsPrompt(view, url, message, defaultValue, result);
128 | }
129 |
130 | @Override
131 | public void onReceivedTitle(WebView view, String title) {
132 | if (checkObjectNotNull(mWebChromeClient)) {
133 | mWebChromeClient.onReceivedTitle(view, title);
134 | }
135 | super.onReceivedTitle(view, title);
136 | }
137 |
138 | @Override
139 | public void onReceivedIcon(WebView view, Bitmap icon) {
140 | if (checkObjectNotNull(mWebChromeClient)) {
141 | mWebChromeClient.onReceivedIcon(view, icon);
142 | }
143 | super.onReceivedIcon(view, icon);
144 | }
145 |
146 | @Override
147 | public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) {
148 | if (checkObjectNotNull(mWebChromeClient)) {
149 | mWebChromeClient.onReceivedTouchIconUrl(view, url, precomposed);
150 | }
151 | super.onReceivedTouchIconUrl(view, url, precomposed);
152 | }
153 |
154 | @Override
155 | public void onShowCustomView(View view, CustomViewCallback callback) {
156 | if (checkObjectNotNull(mWebChromeClient)) {
157 | mWebChromeClient.onShowCustomView(view, callback);
158 | }
159 | super.onShowCustomView(view, callback);
160 | }
161 |
162 | @Override
163 | public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) {
164 | if (checkObjectNotNull(mWebChromeClient)) {
165 | mWebChromeClient.onShowCustomView(view, requestedOrientation, callback);
166 | }
167 | super.onShowCustomView(view, requestedOrientation, callback);
168 | }
169 |
170 | @Override
171 | public void onHideCustomView() {
172 | if (checkObjectNotNull(mWebChromeClient)) {
173 | mWebChromeClient.onHideCustomView();
174 | }
175 | super.onHideCustomView();
176 | }
177 |
178 | @Override
179 | public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
180 | if (checkObjectNotNull(mWebChromeClient)) {
181 | return mWebChromeClient.onCreateWindow(view, isDialog, isUserGesture, resultMsg);
182 | }
183 | return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg);
184 | }
185 |
186 | @Override
187 | public void onRequestFocus(WebView view) {
188 | if (checkObjectNotNull(mWebChromeClient)) {
189 | mWebChromeClient.onRequestFocus(view);
190 | }
191 | super.onRequestFocus(view);
192 | }
193 |
194 | @Override
195 | public void onCloseWindow(WebView window) {
196 | if (checkObjectNotNull(mWebChromeClient)) {
197 | mWebChromeClient.onCloseWindow(window);
198 | }
199 | super.onCloseWindow(window);
200 | }
201 |
202 | @Override
203 | public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
204 | if (checkObjectNotNull(mWebChromeClient)) {
205 | return mWebChromeClient.onJsConfirm(view, url, message, result);
206 | }
207 | return super.onJsConfirm(view, url, message, result);
208 | }
209 |
210 | @Override
211 | public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
212 | if (checkObjectNotNull(mWebChromeClient)) {
213 | return mWebChromeClient.onJsBeforeUnload(view, url, message, result);
214 | }
215 | return super.onJsBeforeUnload(view, url, message, result);
216 | }
217 |
218 | @Override
219 | public void onExceededDatabaseQuota(String url, String databaseIdentifier, long quota, long estimatedDatabaseSize, long totalQuota, WebStorage.QuotaUpdater quotaUpdater) {
220 | if (checkObjectNotNull(mWebChromeClient)) {
221 | mWebChromeClient.onExceededDatabaseQuota(url, databaseIdentifier, quota, estimatedDatabaseSize, totalQuota, quotaUpdater);
222 | }
223 | super.onExceededDatabaseQuota(url, databaseIdentifier, quota, estimatedDatabaseSize, totalQuota, quotaUpdater);
224 | }
225 |
226 | @Override
227 | public void onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater) {
228 | if (checkObjectNotNull(mWebChromeClient)) {
229 | mWebChromeClient.onReachedMaxAppCacheSize(requiredStorage, quota, quotaUpdater);
230 | }
231 | super.onReachedMaxAppCacheSize(requiredStorage, quota, quotaUpdater);
232 | }
233 |
234 | @Override
235 | public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
236 | if (checkObjectNotNull(mWebChromeClient)) {
237 | mWebChromeClient.onGeolocationPermissionsShowPrompt(origin, callback);
238 | }
239 | super.onGeolocationPermissionsShowPrompt(origin, callback);
240 | }
241 |
242 | @Override
243 | public void onGeolocationPermissionsHidePrompt() {
244 | if (checkObjectNotNull(mWebChromeClient)) {
245 | mWebChromeClient.onGeolocationPermissionsHidePrompt();
246 | }
247 | super.onGeolocationPermissionsHidePrompt();
248 | }
249 |
250 | @Override
251 | public void onPermissionRequest(PermissionRequest request) {
252 | if (checkObjectNotNull(mWebChromeClient)) {
253 | mWebChromeClient.onPermissionRequest(request);
254 | }
255 | super.onPermissionRequest(request);
256 | }
257 |
258 | @Override
259 | public void onPermissionRequestCanceled(PermissionRequest request) {
260 | if (checkObjectNotNull(mWebChromeClient)) {
261 | mWebChromeClient.onPermissionRequestCanceled(request);
262 | }
263 | super.onPermissionRequestCanceled(request);
264 | }
265 |
266 | @Override
267 | public boolean onJsTimeout() {
268 | if (checkObjectNotNull(mWebChromeClient)) {
269 | mWebChromeClient.onJsTimeout();
270 | }
271 | return super.onJsTimeout();
272 | }
273 |
274 | @Override
275 | public void onConsoleMessage(String message, int lineNumber, String sourceID) {
276 | if (checkObjectNotNull(mWebChromeClient)) {
277 | mWebChromeClient.onConsoleMessage(message, lineNumber, sourceID);
278 | }
279 | super.onConsoleMessage(message, lineNumber, sourceID);
280 | }
281 |
282 | @Override
283 | public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
284 | if (checkObjectNotNull(mWebChromeClient)) {
285 | mWebChromeClient.onConsoleMessage(consoleMessage);
286 | }
287 | return super.onConsoleMessage(consoleMessage);
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/java/com/simplejsjavabridge/lib/SimpleJavaJsBridge.java:
--------------------------------------------------------------------------------
1 | package com.simplejsjavabridge.lib;
2 |
3 | import android.net.Uri;
4 | import android.os.Handler;
5 | import android.os.Looper;
6 | import android.text.TextUtils;
7 | import android.util.Log;
8 | import android.webkit.WebChromeClient;
9 | import android.webkit.WebView;
10 |
11 |
12 | import com.simplejsjavabridge.lib.annotation.InvokeJSInterface;
13 | import com.simplejsjavabridge.lib.annotation.JavaCallback4JS;
14 | import com.simplejsjavabridge.lib.annotation.JavaInterface4JS;
15 | import com.simplejsjavabridge.lib.exception.SimpleJSBridgeException;
16 |
17 | import org.json.JSONObject;
18 |
19 | import java.lang.reflect.InvocationHandler;
20 | import java.lang.reflect.Method;
21 | import java.lang.reflect.Proxy;
22 | import java.util.ArrayList;
23 | import java.util.HashMap;
24 |
25 | /**
26 | * 该类是本库的核心类,看例子
27 | *
29 | * SimpleJavaJsBridge instance = new SimpleJavaJsBridge.Builder().addJavaInterface4JS(javaInterfaces4JS)
30 | .setWebView(mWebView)
31 | .setJSMethodName4Java("_JSBridge._handleMessageFromNative")
32 | .setProtocol("didiam://__QUEUE_MESSAGE__/?").create();
33 | *
34 | * 这样可以创建一个SimpleJavaJsBridge的实例,当然还可以设置其他参数,但是上面的几个参数是必须设定的,
35 | * 发送给对方的数据,我给起了个名字叫request(请求数据),
36 | * request的格式是:
37 | *
65 | *
66 | *
38 | * {
39 | * "handlerName":"test",
40 | * "callbackId":"c_111111",
41 | * "params":{
42 | * ....
43 | * }
44 | * }
45 | *
46 | * request里面的这三个关键的key值的名字是可以重新定义的,比如"handlerName"可以使用 new SimpleJavaJsBridge.Builder().setHandlerName("interfaceName")
47 | * 来进行自定义。
48 | *
49 | * 接收到对方的数据,我给起个名字叫response(响应数据),
50 | * response的格式是:
51 | *
52 | * {
53 | * "responseId":"iii",
54 | * "data":{
55 | * "status":"1",
56 | * "msg":"ok",
57 | * "values":{
58 | * ......
59 | * }
60 | * }
61 | * }
62 | *
63 | * 同理response里面的"responseId","data","values"这三个关键的key值的名字也是可以调用SimpleJavaJsBridge.Builder进行自定义的
64 | *
68 | * //声明一个调用js的interface
69 | * interface IInvokeJS{
70 | * //声明一个调用js的 exam4 的接口,该接口不需要传递参数
71 | * :@InvokeJSInterface("exam4")
72 | * void exam4(@ParamCallback IJavaCallback2JS iJavaCallback2JS);
73 | * }
74 | *
75 | * //开始调用js的接口
76 | * IInvokeJs invokeJs = mSimpleJavaJsBridge.createInvokJSCommand(IInvokeJs.class);
77 | * invokeJS.exam4(new IJavaCallback2JS{
78 | * :@JavaCallback4JS
79 | * public void callback(@ParamResponseStatus("status") String status){
80 | *
81 | * }
82 | * });
83 | *
84 | * 以上就是一个调用js的exam4接口的例子,其实该过程是模仿了retrofit的。这样做的好处是上层使用者完全不需要关心从json中解析数据这
85 | * 一繁琐的重复的体力劳动了
86 | *
87 | *
88 | *
89 | * Created by niuxiaowei on 16/6/15.
90 | */
91 | public class SimpleJavaJsBridge {
92 |
93 | private static final String TAG = SimpleJavaJsBridge.class.getSimpleName();
94 |
95 | private static final String JAVASCRIPT = "javascript:";
96 | /**
97 | * java调用js的功能时,java会为js提供回调函数,但是不可能把回调函数传递给js,
98 | * 所以为回调函数提供一个唯一的id,
99 | */
100 | private static int sUniqueCallbackId = 1;
101 |
102 |
103 | /**
104 | * 保证发送给js数据时在ui线程中执行
105 | */
106 | private Handler mMainHandler = new Handler(Looper.getMainLooper());
107 |
108 | /**
109 | * 缓存java为js提供的接口
110 | */
111 | private HashMap
194 | * response格式:
195 | * {
196 | * "responseId":"iii",
197 | * "data":{
198 | * "status":"1",
199 | * "msg":"ok",
200 | * "values":{
201 | * ......
202 | * }
203 | * }
204 | * }
205 | * responseId 代表request中的callbackId
206 | * data 代表响应的数据
207 | * status 代表响应状态
208 | * msg 代表响应状态对应的消息
209 | * values 代表响应数据包含的值
210 | *
211 | *
212 | *
213 | * responseName的默认名字是"data",可以对这个名字进行设置
214 | *
215 | *
216 | * @param responseName
217 | * @return
218 | */
219 | public Builder setResponseName(String responseName) {
220 | mResponseName = responseName;
221 | return this;
222 | }
223 |
224 | /**
225 | * responseValuesName的默认名字是"values",可以对这个名字进行设置
226 | *
227 | * @param responseValuesName
228 | * @return
229 | * @see #setResponseName(String)
230 | */
231 | public Builder setResponseValuesName(String responseValuesName) {
232 | mResponseValuesName = responseValuesName;
233 | return this;
234 | }
235 |
236 | /**
237 | * response中responseIdName的默认名字是"responseId",可以对起进行设置
238 | * @param responseIdName
239 | * @return
240 | * @see #setResponseName(String)
241 | */
242 | public Builder setResponseIdName(String responseIdName) {
243 | mResponseIdName = responseIdName;
244 | return this;
245 | }
246 |
247 | /**
248 | *
249 | * {
250 | * "handlerName":"test",
251 | * "callbackId":"c_111111",
252 | * "params":{
253 | * ....
254 | * }
255 | * }
256 | *
257 | * hanlerName 代表java与js之间给对方暴漏的接口的名称,
258 | * callbackId 代表对方在发起请求时,会为回调方法生产一个唯一的id值,它就代表这个唯一的id值
259 | * params 代表传递的数据
260 | *
261 | *
262 | * requestInterfaceName的默认值是"handlerName",可以进行设置它
263 | *
264 | *
265 | * @param requestInterfaceName
266 | * @return
267 | */
268 | public Builder setRequestInterfaceName(String requestInterfaceName) {
269 | mRequestInterfaceName = requestInterfaceName;
270 | return this;
271 | }
272 |
273 | /**
274 | *
275 | * 同理requestCallbackIdName的默认值是"callbackId",可以对它进行设置
276 | *
277 | * @param requestCallbackIdName
278 | * @return
279 | * @see #setRequestInterfaceName(String)
280 | */
281 | public Builder setRequestCallbackIdName(String requestCallbackIdName) {
282 | mRequestCallbackIdName = requestCallbackIdName;
283 | return this;
284 | }
285 |
286 | /**
287 | * 同理requestValuesName的默认值是"params",可以对它进行设置
288 | *
289 | * @param requestValuesName
290 | * @return
291 | * @see #setRequestInterfaceName(String)
292 |
293 | */
294 | public Builder setRequestValuesName(String requestValuesName) {
295 | mRequestValuesName = requestValuesName;
296 | return this;
297 | }
298 |
299 | /**
300 | * 设置js为java暴漏的方法的名字,只需要提供方法名字即可,具体的关于"()"和参数不需要提供,因为该方法接收的是一个json字符串
301 | *
302 | * @param JSMethodName 方法名字 比如:handleMsgFromJava
303 | * @return
304 | */
305 | public Builder setJSMethodName4Java(String JSMethodName) {
306 | mJSMethodName4Java = JSMethodName;
307 | if (!TextUtils.isEmpty(mJSMethodName4Java) && !mJSMethodName4Java.startsWith(JAVASCRIPT)) {
308 | mJSMethodName4Java = JAVASCRIPT + mJSMethodName4Java ;
309 | if(!mJSMethodName4Java.contains("%s")){
310 | mJSMethodName4Java = mJSMethodName4Java + "(%s)";
311 | }
312 | }
313 | return this;
314 | }
315 |
316 | /**
317 | * 设置协议,协议格式:scheme://host?,协议是必须进行设置的,否则报错
318 | *
319 | * @param scheme 比如 file或http等
320 | * @param host
321 | * @return
322 | */
323 | public Builder setProtocol(String scheme,String host) {
324 | if(TextUtils.isEmpty(scheme) || TextUtils.isEmpty(host)){
325 | return this;
326 | }
327 | mProtocol = scheme+"://"+host+"?";
328 | return this;
329 | }
330 |
331 | public Builder setWebChromeClient(WebChromeClient webChromeClient) {
332 | mWebChromeClient = webChromeClient;
333 | return this;
334 | }
335 |
336 | /**
337 | * 添加java提供给js的接口
338 | * @param javaMethod4JS
339 | * @return
340 | */
341 | public Builder addJavaInterface4JS(Object javaMethod4JS) {
342 | if (javaMethod4JS == null) {
343 | return this;
344 | }
345 | if (mJavaMethod4JS == null) {
346 | mJavaMethod4JS = new ArrayList();
347 | }
348 | mJavaMethod4JS.add(javaMethod4JS);
349 | return this;
350 | }
351 |
352 | /**
353 | * 必须进行设置
354 | *
355 | * @param webView
356 | * @return
357 | */
358 | public Builder setWebView(WebView webView) {
359 | mWebView = webView;
360 | return this;
361 | }
362 |
363 | /**
364 | * 检测协议是否符合要求
365 | *
366 | * @return
367 | * @throws SimpleJSBridgeException
368 | */
369 | private void checkProtocol() {
370 | if (TextUtils.isEmpty(mProtocol)) {
371 | throw new SimpleJSBridgeException("必须调用setProtocol(String)设置协议");
372 | }
373 | Uri uri = Uri.parse(mProtocol);
374 | if (TextUtils.isEmpty(uri.getScheme()) || TextUtils.isEmpty(uri.getHost()) || !mProtocol.endsWith("?")) {
375 | throw new IllegalArgumentException("协议的格式必须是 scheme://host? 这种格式");
376 | }
377 | }
378 |
379 | private void checkJSMethod() {
380 | if (TextUtils.isEmpty(mJSMethodName4Java)) {
381 | throw new IllegalArgumentException("必须调用 setJSMethodName4Java(String) 方法对给js发送消息的方法进行设置");
382 | }
383 |
384 | }
385 |
386 | public SimpleJavaJsBridge create() {
387 | /*检查协议是否设置,并设置正确了*/
388 | checkProtocol();
389 | checkJSMethod();
390 | if (mWebView == null) {
391 | throw new IllegalArgumentException("必须调用 setWebView(WebView) 方法设置Webview");
392 | }
393 | return new SimpleJavaJsBridge(this);
394 | }
395 | }
396 |
397 |
398 | /**
399 | * 生成调用js的命令,在调用js之前必须得调用该方法,该模式是模仿retrofit的
400 | * @param tClass 必须是一个interface
401 | * @param
16 | * :@InvokeJSInterface("exam")
17 | * public void exam():
18 | *
19 | * 该例子表明java会调用js提供的{@code exam}这样的接口
20 | *
21 | */
22 | @Target(ElementType.METHOD)
23 | @Retention(RetentionPolicy.RUNTIME)
24 | @Documented
25 | @Inherited
26 | public @interface InvokeJSInterface {
27 | String value();
28 | }
29 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/java/com/simplejsjavabridge/lib/annotation/JavaCallback4JS.java:
--------------------------------------------------------------------------------
1 | package com.simplejsjavabridge.lib.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Inherited;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 |
11 | /**
12 | * java在主动调用js的时候,同时会给js传递一个回调,该回调的作用就是为了监听js的返回结果,
13 | * 该注解的主要作用是为了标记java为js提供的回调方法.
14 | *
16 | *
17 | * new Object{
18 | * ;@JavaCallback4JS
19 | * public void callback4JS()
20 | * }
21 | *
22 | * 上面的例子表明{@code callback4JS}方法是提供给js的回调方法
23 | *
24 | *
25 | *
26 | */
27 | @Target(ElementType.METHOD)
28 | @Retention(RetentionPolicy.RUNTIME)
29 | @Documented
30 | @Inherited
31 | public @interface JavaCallback4JS {
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/java/com/simplejsjavabridge/lib/annotation/JavaInterface4JS.java:
--------------------------------------------------------------------------------
1 | package com.simplejsjavabridge.lib.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Inherited;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * 该注解是用来标注java为js提供的接口,{@link #value()}的值是代表java与js之间约定好的接口名字。
12 | *
14 | *
15 | * :@JavaInterface4JS("test")
16 | * public void test(@Param("msg") String msg);
17 | *
18 | * 上面的例子,表明java为js提供一个名字为{@code test}的接口
19 | *
20 | * Created by niuxiaowei on 2015/10/27.
21 | * @see Param
22 | */
23 | @Target(ElementType.METHOD)
24 | @Retention(RetentionPolicy.RUNTIME)
25 | @Documented
26 | @Inherited
27 | public @interface JavaInterface4JS {
28 | /**
29 | * 代表java与js之间约定好的接口名字
30 | * @return
31 | */
32 | String value();
33 | }
34 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/java/com/simplejsjavabridge/lib/annotation/Param.java:
--------------------------------------------------------------------------------
1 | package com.simplejsjavabridge.lib.annotation;
2 |
3 | import org.json.JSONArray;
4 |
5 | import java.lang.annotation.Documented;
6 | import java.lang.annotation.ElementType;
7 | import java.lang.annotation.Inherited;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 | import java.lang.annotation.Target;
11 |
12 |
13 | /**
14 | * 该注解用来标注方法中的一个参数或者一个类的实例属性。
15 | * java与js之间传递参数的格式是json,因为对于json的封装和解析是一件繁琐的重复的体力劳动,
16 | * 因此通过注解来解决此问题。
17 | *
20 | * :@InvokeJSInterface("test")
21 | * public void test(@Param("msg") String content);
22 | *
23 | * test方法主要是让使用者来调用js暴露的test接口时,最终会把{@code @Param("msg") String content}转化为{msg:"content"}的json
24 | *
25 | *
26 | *
28 | * :@InvokeJSInterface("test")
29 | * public void test(@Param String content);
30 | *
31 | * 最终把参数转化为{"content"}的json
32 | *
33 | *
34 | *
36 | *
37 | * class User{
38 | * :@Param("userId")
39 | * String userId;
40 | *
41 | * :@Param("name")
42 | * String userName;
43 | * }
44 | *
45 | * :@InvokeJSInterface("test")
46 | * public void test(@Param(value="userInfo") User userInfo);
47 | *
48 | * 最终把参数转化为{userInfo:{userId:"userId", name:"userName"}}的json
49 | *
50 | *
51 | *
53 | *
54 | * class User{
55 | * :@Param("userId")
56 | * String userId;
57 | *
58 | * :@Param("name")
59 | * String userName;
60 | * }
61 | *
62 | * :@InvokeJSInterface("test")
63 | * public void test(@Param User userInfo);
64 | *
65 | * 最终把参数转化为{userId:"userId", name:"userName"}的json
66 | *
67 | *
68 | *
71 | *
72 | * :@JavaInterface4JS("exam")
73 | * public void test(@Param("msg") String content){
74 | *
75 | * }
76 | *
77 | * test方法是java提供给js的接口,js调用该接口时,假如传递的json是{msg:"你好java"},那会把该json中的"你好java"赋值给test方法的content参数
78 | *
79 | *
81 | *
82 | * class User{
83 | * :@Param("userId")
84 | * String userId;
85 | *
86 | * :@Param("name")
87 | * String userName;
88 | * }
89 | * :@JavaInterface4JS("exam")
90 | * public void test(@Param("userInfo") User userInfo){
91 | *
92 | * }
93 | *
94 | * 假如传递的json是{userInfo:{userId:"11", name:"nihao"}},那会把该json中的userInfo:{userId:"11", name:"nihao"}赋值给test方法的userInfo参数
95 | *
96 | */
97 | @Target(value = {ElementType.PARAMETER, ElementType.FIELD})
98 | @Retention(RetentionPolicy.RUNTIME)
99 | @Documented
100 | @Inherited
101 | public @interface Param {
102 | /**
103 | * json中一般是以{key:value, key1:value1}的格式组织数据,
104 | *
16 | *
17 | * :@InvokeJSInterface("test")
18 | * public void invokeJSTest(@ParamCallback Object callback);
19 | *
20 | * 使用:invokeJSTest(new Object(){
21 | * :@JavaCallback4JS
22 | * public void callback(){
23 | *
24 | * }
25 | * });
26 | *
27 | *
28 | *
30 | * //声明一个回调接口
31 | * interface IExamCallback{
32 | * void examCallback();
33 | * }
34 | *
35 | * :@JavaInterface4JS("exam")
36 | * public void examInterface4JS(@ParamCallback IExamCallback iExamCallback){
37 | * iExamCallback.examCallback();
38 | * }
39 | *
40 | *
41 | * @see JavaCallback4JS,JavaInterface4JS,InvokeJSInterface
42 | */
43 | @Target(ElementType.PARAMETER)
44 | @Retention(RetentionPolicy.RUNTIME)
45 | @Documented
46 | @Inherited
47 | public @interface ParamCallback {
48 | }
49 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/java/com/simplejsjavabridge/lib/annotation/ParamResponseStatus.java:
--------------------------------------------------------------------------------
1 | package com.simplejsjavabridge.lib.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Inherited;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | *
12 | * 不管是java还是js主动调用对方的数据我们称作request,返回给对方的数据我们称作response。
13 | * response数据又包含responsestatus(响应状态数据)和其他数据组成。
14 | *
17 | *
18 | * public void receiveResponse(@ParamResponseStatus("status") int status, @ParamResponseStatus("msg") String msg){
19 | *
20 | * }
21 | *
22 | *
23 | *
24 | *
26 | * :@AllFiledsConvert
27 | * public enum ResponseStatus{
28 | * private int status;
29 |
30 | private String msg;
31 |
32 | ResponseStatus(int status, String msg) {
33 | this.status = status;
34 | this.msg = msg;
35 | }
36 |
37 | public int getStatus() {
38 | return status;
39 | }
40 |
41 | public String getMsg() {
42 | return msg;
43 | }
44 | * }
45 | *
46 | * public void receiveResponse(@ParamResponseStatus ResponseStatus responseStatus){
47 | *
48 | * }
49 | *
50 | *
51 | *
52 | * Created by niuxiaowei on 2015/10/27.
53 | */
54 | @Target(ElementType.PARAMETER)
55 | @Retention(RetentionPolicy.RUNTIME)
56 | @Documented
57 | @Inherited
58 | public @interface ParamResponseStatus {
59 | /**
60 | * responseStatus格式({status:1, msg:"ok"}。{@link #value()}就是status或msg这些key值
61 | * @return
62 | */
63 | String value() default "";
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/java/com/simplejsjavabridge/lib/exception/SimpleJSBridgeException.java:
--------------------------------------------------------------------------------
1 | package com.simplejsjavabridge.lib.exception;
2 |
3 | /**
4 | * Created by niuxiaowei on 16/9/10.
5 | */
6 | public class SimpleJSBridgeException extends RuntimeException {
7 |
8 | public SimpleJSBridgeException() {
9 | }
10 |
11 | public SimpleJSBridgeException(String detailMessage) {
12 | super(detailMessage);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/simplejsjavabridgeLib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |