From 935fb1149f434843f33b47d70bf2dfacb9cadf14 Mon Sep 17 00:00:00 2001 From: chenjuntao Date: Thu, 2 Jul 2020 11:03:34 +0800 Subject: [PATCH] =?UTF-8?q?DsBridge=20=E8=BD=AC=E4=B8=BA=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=EF=BC=8C=E6=9A=82=E6=97=B6=E5=81=9C=E7=94=A8?= =?UTF-8?q?chucker(jitpack=E8=BF=9E=E4=B8=8D=E4=B8=8A)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 2 - .../main/java/com/gh/common/DefaultJsApi.kt | 2 +- .../gh/common/view/NestedScrollWebView.java | 4 +- .../gh/common/view/NestedScrollWebView2.java | 3 +- .../view/dsbridge/CompletionHandler.java | 11 + .../com/gh/common/view/dsbridge/DWebView.java | 1002 +++++++++++++++++ .../common/view/dsbridge/OnReturnValue.java | 9 + .../GameResourcePolicyDialogFragment.kt | 2 +- .../gamedetail/desc/DescViewModel.kt | 2 +- .../rating/edit/RatingEditActivity.kt | 4 +- .../gamecenter/retrofit/RetrofitManager.java | 5 +- .../halo/assistant/fragment/WebFragment.java | 5 +- .../main/res/layout/activity_rating_edit.xml | 2 +- .../layout/dialog_game_resource_policy.xml | 2 +- 14 files changed, 1038 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/com/gh/common/view/dsbridge/CompletionHandler.java create mode 100644 app/src/main/java/com/gh/common/view/dsbridge/DWebView.java create mode 100644 app/src/main/java/com/gh/common/view/dsbridge/OnReturnValue.java diff --git a/app/build.gradle b/app/build.gradle index bad768c025..9303421a17 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -265,8 +265,6 @@ dependencies { }) implementation "com.shuyu:GSYVideoPlayer-exo2:$gsyVideo" - implementation "com.github.wendux:DSBridge-Android:$dsBridge" - implementation "android.arch.work:work-runtime:${workManager}" implementation "com.llew.huawei:verifier:${verifier}" diff --git a/app/src/main/java/com/gh/common/DefaultJsApi.kt b/app/src/main/java/com/gh/common/DefaultJsApi.kt index fc550cd502..0e4ecd9367 100644 --- a/app/src/main/java/com/gh/common/DefaultJsApi.kt +++ b/app/src/main/java/com/gh/common/DefaultJsApi.kt @@ -6,6 +6,7 @@ import android.webkit.JavascriptInterface import androidx.annotation.Keep import com.gh.base.CurrentActivityHolder import com.gh.common.util.* +import com.gh.common.view.dsbridge.CompletionHandler import com.gh.gamecenter.BuildConfig import com.gh.gamecenter.LoginActivity import com.gh.gamecenter.ViewImageActivity @@ -23,7 +24,6 @@ import io.reactivex.schedulers.Schedulers import okhttp3.ResponseBody import org.json.JSONObject import retrofit2.HttpException -import wendu.dsbridge.CompletionHandler class DefaultJsApi(var context: Context) { diff --git a/app/src/main/java/com/gh/common/view/NestedScrollWebView.java b/app/src/main/java/com/gh/common/view/NestedScrollWebView.java index 46b73bb3fc..5725ff27d4 100644 --- a/app/src/main/java/com/gh/common/view/NestedScrollWebView.java +++ b/app/src/main/java/com/gh/common/view/NestedScrollWebView.java @@ -1,4 +1,5 @@ package com.gh.common.view; + import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; @@ -7,7 +8,8 @@ import androidx.core.view.MotionEventCompat; import androidx.core.view.NestedScrollingChild; import androidx.core.view.NestedScrollingChildHelper; import androidx.core.view.ViewCompat; -import wendu.dsbridge.DWebView; + +import com.gh.common.view.dsbridge.DWebView; public class NestedScrollWebView extends DWebView implements NestedScrollingChild { diff --git a/app/src/main/java/com/gh/common/view/NestedScrollWebView2.java b/app/src/main/java/com/gh/common/view/NestedScrollWebView2.java index 9c2cf3ee7f..2401c20975 100644 --- a/app/src/main/java/com/gh/common/view/NestedScrollWebView2.java +++ b/app/src/main/java/com/gh/common/view/NestedScrollWebView2.java @@ -25,7 +25,8 @@ import androidx.core.view.NestedScrollingParentHelper; import androidx.core.view.ViewCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.core.view.accessibility.AccessibilityRecordCompat; -import wendu.dsbridge.DWebView; + +import com.gh.common.view.dsbridge.DWebView; /** * Copyright (c) Tuenti Technologies. All rights reserved. diff --git a/app/src/main/java/com/gh/common/view/dsbridge/CompletionHandler.java b/app/src/main/java/com/gh/common/view/dsbridge/CompletionHandler.java new file mode 100644 index 0000000000..271be1d85a --- /dev/null +++ b/app/src/main/java/com/gh/common/view/dsbridge/CompletionHandler.java @@ -0,0 +1,11 @@ +package com.gh.common.view.dsbridge; + +/** + * Created by du on 16/12/31. + */ + +public interface CompletionHandler { + void complete(T retValue); + void complete(); + void setProgressData(T value); +} diff --git a/app/src/main/java/com/gh/common/view/dsbridge/DWebView.java b/app/src/main/java/com/gh/common/view/dsbridge/DWebView.java new file mode 100644 index 0000000000..48a2fe1b20 --- /dev/null +++ b/app/src/main/java/com/gh/common/view/dsbridge/DWebView.java @@ -0,0 +1,1002 @@ +package com.gh.common.view.dsbridge; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.ConsoleMessage; +import android.webkit.CookieManager; +import android.webkit.GeolocationPermissions; +import android.webkit.JavascriptInterface; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.PermissionRequest; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebStorage; +import android.webkit.WebView; +import android.widget.EditText; +import android.widget.FrameLayout; + +import androidx.annotation.Keep; +import androidx.appcompat.app.AlertDialog; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + + +/** + * Created by du on 16/12/29. + */ + +public class DWebView extends WebView { + private static final String BRIDGE_NAME = "_dsbridge"; + private static final String LOG_TAG = "dsBridge"; + private static boolean isDebug = false; + private Map javaScriptNamespaceInterfaces = new HashMap(); + private String APP_CACHE_DIRNAME; + private int callID = 0; + private WebChromeClient webChromeClient; + + private volatile boolean alertBoxBlock = true; + private JavascriptCloseWindowListener javascriptCloseWindowListener = null; + private ArrayList callInfoList; + private InnerJavascriptInterface innerJavascriptInterface = new InnerJavascriptInterface(); + private Handler mainHandler = new Handler(Looper.getMainLooper()); + + private class InnerJavascriptInterface { + + private void PrintDebugInfo(String error) { + Log.d(LOG_TAG, error); + if (isDebug) { + evaluateJavascript(String.format("alert('%s')", "DEBUG ERR MSG:\\n" + error.replaceAll("\\'", "\\\\'"))); + } + } + + @Keep + @JavascriptInterface + public String call(String methodName, String argStr) { + String error = "Js bridge called, but can't find a corresponded " + + "JavascriptInterface object , please check your code!"; + String[] nameStr = parseNamespace(methodName.trim()); + methodName = nameStr[1]; + Object jsb = javaScriptNamespaceInterfaces.get(nameStr[0]); + JSONObject ret = new JSONObject(); + try { + ret.put("code", -1); + } catch (JSONException e) { + e.printStackTrace(); + } + if (jsb == null) { + PrintDebugInfo(error); + return ret.toString(); + } + Object arg=null; + Method method = null; + String callback = null; + + try { + JSONObject args = new JSONObject(argStr); + if (args.has("_dscbstub")) { + callback = args.getString("_dscbstub"); + } + if(args.has("data")) { + arg = args.get("data"); + } + } catch (JSONException e) { + error = String.format("The argument of \"%s\" must be a JSON object string!", methodName); + PrintDebugInfo(error); + e.printStackTrace(); + return ret.toString(); + } + + + Class cls = jsb.getClass(); + boolean asyn = false; + try { + method = cls.getMethod(methodName, + new Class[]{Object.class, CompletionHandler.class}); + asyn = true; + } catch (Exception e) { + try { + method = cls.getMethod(methodName, new Class[]{Object.class}); + } catch (Exception ex) { + + } + } + + if (method == null) { + error = "Not find method \"" + methodName + "\" implementation! please check if the signature or namespace of the method is right "; + PrintDebugInfo(error); + return ret.toString(); + } + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + JavascriptInterface annotation = method.getAnnotation(JavascriptInterface.class); + if (annotation == null) { + error = "Method " + methodName + " is not invoked, since " + + "it is not declared with JavascriptInterface annotation! "; + PrintDebugInfo(error); + return ret.toString(); + } + } + + Object retData; + method.setAccessible(true); + try { + if (asyn) { + final String cb = callback; + method.invoke(jsb, arg, new CompletionHandler() { + + @Override + public void complete(Object retValue) { + complete(retValue, true); + } + + @Override + public void complete() { + complete(null, true); + } + + @Override + public void setProgressData(Object value) { + complete(value, false); + } + + private void complete(Object retValue, boolean complete) { + try { + JSONObject ret = new JSONObject(); + ret.put("code", 0); + ret.put("data", retValue); + //retValue = URLEncoder.encode(ret.toString(), "UTF-8").replaceAll("\\+", "%20"); + if (cb != null) { + //String script = String.format("%s(JSON.parse(decodeURIComponent(\"%s\")).data);", cb, retValue); + String script = String.format("%s(%s.data);", cb, ret.toString()); + if (complete) { + script += "delete window." + cb; + } + //Log.d(LOG_TAG, "complete " + script); + evaluateJavascript(script); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } else { + retData = method.invoke(jsb, arg); + ret.put("code", 0); + ret.put("data", retData); + return ret.toString(); + } + } catch (Exception e) { + e.printStackTrace(); + error = String.format("Call failed:The parameter of \"%s\" in Java is invalid.", methodName); + PrintDebugInfo(error); + return ret.toString(); + } + return ret.toString(); + } + + } + + Map handlerMap = new HashMap<>(); + + public interface JavascriptCloseWindowListener { + /** + * @return If true, close the current activity, otherwise, do nothing. + */ + boolean onClose(); + } + + + @Deprecated + public interface FileChooser { + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + void openFileChooser(ValueCallback valueCallback, String acceptType); + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + void openFileChooser(ValueCallback valueCallback, + String acceptType, String capture); + } + + public DWebView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public DWebView(Context context) { + super(context); + init(); + } + + /** + * Set debug mode. if in debug mode, some errors will be prompted by a dialog + * and the exception caused by the native handlers will not be captured. + * + * @param enabled + */ + public static void setWebContentsDebuggingEnabled(boolean enabled) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + WebView.setWebContentsDebuggingEnabled(enabled); + } + isDebug = enabled; + } + + @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"}) + private void init() { + APP_CACHE_DIRNAME = getContext().getFilesDir().getAbsolutePath() + "/webcache"; + WebSettings settings = getSettings(); + settings.setDomStorageEnabled(true); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + CookieManager.getInstance().setAcceptThirdPartyCookies(this, true); + settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + } + settings.setAllowFileAccess(false); + settings.setAppCacheEnabled(false); + settings.setCacheMode(WebSettings.LOAD_NO_CACHE); + settings.setJavaScriptEnabled(true); + settings.setLoadWithOverviewMode(true); + settings.setAppCachePath(APP_CACHE_DIRNAME); + settings.setUseWideViewPort(true); + super.setWebChromeClient(mWebChromeClient); + addInternalJavascriptObject(); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { + super.addJavascriptInterface(innerJavascriptInterface, BRIDGE_NAME); + } else { + // add dsbridge tag in lower android version + settings.setUserAgentString(settings.getUserAgentString() + " _dsbridge"); + } + } + + + private String[] parseNamespace(String method) { + int pos = method.lastIndexOf('.'); + String namespace = ""; + if (pos != -1) { + namespace = method.substring(0, pos); + method = method.substring(pos + 1); + } + return new String[]{namespace, method}; + } + + @Keep + private void addInternalJavascriptObject() { + addJavascriptObject(new Object() { + + @Keep + @JavascriptInterface + public boolean hasNativeMethod(Object args) throws JSONException { + JSONObject jsonObject = (JSONObject) args; + String methodName = jsonObject.getString("name").trim(); + String type = jsonObject.getString("type").trim(); + String[] nameStr = parseNamespace(methodName); + Object jsb = javaScriptNamespaceInterfaces.get(nameStr[0]); + if (jsb != null) { + Class cls = jsb.getClass(); + boolean asyn = false; + Method method = null; + try { + method = cls.getMethod(nameStr[1], + new Class[]{Object.class, CompletionHandler.class}); + asyn = true; + } catch (Exception e) { + try { + method = cls.getMethod(nameStr[1], new Class[]{Object.class}); + } catch (Exception ex) { + + } + } + if (method != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + JavascriptInterface annotation = method.getAnnotation(JavascriptInterface.class); + if (annotation == null) { + return false; + } + } + if ("all".equals(type) || (asyn && "asyn".equals(type) || (!asyn && "syn".equals(type)))) { + return true; + } + + } + } + return false; + } + + @Keep + @JavascriptInterface + public String closePage(Object object) throws JSONException { + runOnMainThread(new Runnable() { + @Override + public void run() { + if (javascriptCloseWindowListener == null + || javascriptCloseWindowListener.onClose()) { + Context context = getContext(); + if (context instanceof Activity) { + ((Activity)context).onBackPressed(); + } + } + } + }); + return null; + } + + @Keep + @JavascriptInterface + public void disableJavascriptDialogBlock(Object object) throws JSONException { + JSONObject jsonObject = (JSONObject) object; + alertBoxBlock = !jsonObject.getBoolean("disable"); + } + + @Keep + @JavascriptInterface + public void dsinit(Object jsonObject) { + DWebView.this.dispatchStartupQueue(); + } + + @Keep + @JavascriptInterface + public void returnValue(final Object obj){ + runOnMainThread(new Runnable() { + @Override + public void run() { + JSONObject jsonObject = (JSONObject) obj; + Object data = null; + try { + int id = jsonObject.getInt("id"); + boolean isCompleted = jsonObject.getBoolean("complete"); + OnReturnValue handler = handlerMap.get(id); + if (jsonObject.has("data")) { + data = jsonObject.get("data"); + } + if (handler != null) { + handler.onValue(data); + if (isCompleted) { + handlerMap.remove(id); + } + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + }); + } + + }, "_dsb"); + } + + private void _evaluateJavascript(String script) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + DWebView.super.evaluateJavascript(script, null); + } else { + super.loadUrl("javascript:" + script); + } + } + + /** + * This method can be called in any thread, and if it is not called in the main thread, + * it will be automatically distributed to the main thread. + * + * @param script + */ + public void evaluateJavascript(final String script) { + runOnMainThread(new Runnable() { + @Override + public void run() { + _evaluateJavascript(script); + } + }); + } + + /** + * This method can be called in any thread, and if it is not called in the main thread, + * it will be automatically distributed to the main thread. + * + * @param url + */ + @Override + public void loadUrl(final String url) { + runOnMainThread(new Runnable() { + @Override + public void run() { + if (url != null && url.startsWith("javascript:")){ + DWebView.super.loadUrl(url); + }else{ + callInfoList = new ArrayList<>(); + DWebView.super.loadUrl(url); + } + } + }); + } + + /** + * This method can be called in any thread, and if it is not called in the main thread, + * it will be automatically distributed to the main thread. + * + * @param url + * @param additionalHttpHeaders + */ + @Override + public void loadUrl(final String url, final Map additionalHttpHeaders) { + runOnMainThread(new Runnable() { + @Override + public void run() { + if (url != null && url.startsWith("javascript:")){ + DWebView.super.loadUrl(url, additionalHttpHeaders); + }else{ + callInfoList = new ArrayList<>(); + DWebView.super.loadUrl(url, additionalHttpHeaders); + } + } + }); + } + + @Override + public void reload() { + runOnMainThread(new Runnable() { + @Override + public void run() { + callInfoList = new ArrayList<>(); + DWebView.super.reload(); + } + }); + } + + /** + * set a listener for javascript closing the current activity. + */ + public void setJavascriptCloseWindowListener(JavascriptCloseWindowListener listener) { + javascriptCloseWindowListener = listener; + } + + + private static class CallInfo { + private String data; + private int callbackId; + private String method; + + CallInfo(String handlerName, int id, Object[] args) { + if (args == null) args = new Object[0]; + data = new JSONArray(Arrays.asList(args)).toString(); + callbackId = id; + method = handlerName; + } + + @Override + public String toString() { + JSONObject jo = new JSONObject(); + try { + jo.put("method", method); + jo.put("callbackId", callbackId); + jo.put("data", data); + } catch (JSONException e) { + e.printStackTrace(); + } + return jo.toString(); + } + } + + private synchronized void dispatchStartupQueue() { + if (callInfoList != null) { + for (CallInfo info : callInfoList) { + dispatchJavascriptCall(info); + } + callInfoList = null; + } + } + + private void dispatchJavascriptCall(CallInfo info) { + evaluateJavascript(String.format("window._handleMessageFromNative(%s)", info.toString())); + } + + public synchronized void callHandler(String method, Object[] args, final OnReturnValue handler) { + + CallInfo callInfo = new CallInfo(method, callID++, args); + if (handler != null) { + handlerMap.put(callInfo.callbackId, handler); + } + + if (callInfoList != null) { + callInfoList.add(callInfo); + } else { + dispatchJavascriptCall(callInfo); + } + + } + + public void callHandler(String method, Object[] args) { + callHandler(method, args, null); + } + + public void callHandler(String method, OnReturnValue handler) { + callHandler(method, null, handler); + } + + + /** + * Test whether the handler exist in javascript + * + * @param handlerName + * @param existCallback + */ + public void hasJavascriptMethod(String handlerName, OnReturnValue existCallback) { + callHandler("_hasJavascriptMethod", new Object[]{handlerName}, existCallback); + } + + /** + * Add a java object which implemented the javascript interfaces to dsBridge with namespace. + * Remove the object using {@link #removeJavascriptObject(String) removeJavascriptObject(String)} + * + * @param object + * @param namespace if empty, the object have no namespace. + */ + public void addJavascriptObject(Object object, String namespace) { + if (namespace == null) { + namespace = ""; + } + if (object != null) { + javaScriptNamespaceInterfaces.put(namespace, object); + } + } + + /** + * remove the javascript object with supplied namespace. + * + * @param namespace + */ + public void removeJavascriptObject(String namespace) { + if (namespace == null) { + namespace = ""; + } + javaScriptNamespaceInterfaces.remove(namespace); + + } + + + public void disableJavascriptDialogBlock(boolean disable) { + alertBoxBlock = !disable; + } + + @Override + public void setWebChromeClient(WebChromeClient client) { + webChromeClient = client; + } + + private WebChromeClient mWebChromeClient = new WebChromeClient() { + + @Override + public void onProgressChanged(WebView view, int newProgress) { + if (webChromeClient != null) { + webChromeClient.onProgressChanged(view, newProgress); + } else { + super.onProgressChanged(view, newProgress); + } + } + + @Override + public void onReceivedTitle(WebView view, String title) { + if (webChromeClient != null) { + webChromeClient.onReceivedTitle(view, title); + } else { + super.onReceivedTitle(view, title); + } + } + + @Override + public void onReceivedIcon(WebView view, Bitmap icon) { + if (webChromeClient != null) { + webChromeClient.onReceivedIcon(view, icon); + } else { + super.onReceivedIcon(view, icon); + } + } + + @Override + public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) { + if (webChromeClient != null) { + webChromeClient.onReceivedTouchIconUrl(view, url, precomposed); + } else { + super.onReceivedTouchIconUrl(view, url, precomposed); + } + } + + @Override + public void onShowCustomView(View view, CustomViewCallback callback) { + if (webChromeClient != null) { + webChromeClient.onShowCustomView(view, callback); + } else { + super.onShowCustomView(view, callback); + } + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + public void onShowCustomView(View view, int requestedOrientation, + CustomViewCallback callback) { + if (webChromeClient != null) { + webChromeClient.onShowCustomView(view, requestedOrientation, callback); + } else { + super.onShowCustomView(view, requestedOrientation, callback); + } + } + + @Override + public void onHideCustomView() { + if (webChromeClient != null) { + webChromeClient.onHideCustomView(); + } else { + super.onHideCustomView(); + } + } + + @Override + public boolean onCreateWindow(WebView view, boolean isDialog, + boolean isUserGesture, Message resultMsg) { + if (webChromeClient != null) { + return webChromeClient.onCreateWindow(view, isDialog, + isUserGesture, resultMsg); + } + return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg); + } + + @Override + public void onRequestFocus(WebView view) { + if (webChromeClient != null) { + webChromeClient.onRequestFocus(view); + } else { + super.onRequestFocus(view); + } + } + + @Override + public void onCloseWindow(WebView window) { + if (webChromeClient != null) { + webChromeClient.onCloseWindow(window); + } else { + super.onCloseWindow(window); + } + } + + @Override + public boolean onJsAlert(WebView view, String url, final String message, final JsResult result) { + if (!alertBoxBlock) { + result.confirm(); + } + if (webChromeClient != null) { + if (webChromeClient.onJsAlert(view, url, message, result)) { + return true; + } + } + Dialog alertDialog = new AlertDialog.Builder(getContext()). + setMessage(message). + setCancelable(false). + setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + if (alertBoxBlock) { + result.confirm(); + } + } + }) + .create(); + alertDialog.show(); + return true; + } + + @Override + public boolean onJsConfirm(WebView view, String url, String message, + final JsResult result) { + if (!alertBoxBlock) { + result.confirm(); + } + if (webChromeClient != null && webChromeClient.onJsConfirm(view, url, message, result)) { + return true; + } else { + DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (alertBoxBlock) { + if (which == Dialog.BUTTON_POSITIVE) { + result.confirm(); + } else { + result.cancel(); + } + } + } + }; + new AlertDialog.Builder(getContext()) + .setMessage(message) + .setCancelable(false) + .setPositiveButton(android.R.string.ok, listener) + .setNegativeButton(android.R.string.cancel, listener).show(); + return true; + + } + + } + + @Override + public boolean onJsPrompt(WebView view, String url, final String message, + String defaultValue, final JsPromptResult result) { + + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) { + String prefix = "_dsbridge="; + if (message.startsWith(prefix)) { + result.confirm(innerJavascriptInterface.call(message.substring(prefix.length()), defaultValue)); + return true; + } + } + + if (!alertBoxBlock) { + result.confirm(); + } + + if (webChromeClient != null && webChromeClient.onJsPrompt(view, url, message, defaultValue, result)) { + return true; + } else { + final EditText editText = new EditText(getContext()); + editText.setText(defaultValue); + if (defaultValue != null) { + editText.setSelection(defaultValue.length()); + } + float dpi = getContext().getResources().getDisplayMetrics().density; + DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (alertBoxBlock) { + if (which == Dialog.BUTTON_POSITIVE) { + result.confirm(editText.getText().toString()); + } else { + result.cancel(); + } + } + } + }; + new AlertDialog.Builder(getContext()) + .setTitle(message) + .setView(editText) + .setCancelable(false) + .setPositiveButton(android.R.string.ok, listener) + .setNegativeButton(android.R.string.cancel, listener) + .show(); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + int t = (int) (dpi * 16); + layoutParams.setMargins(t, 0, t, 0); + layoutParams.gravity = Gravity.CENTER_HORIZONTAL; + editText.setLayoutParams(layoutParams); + int padding = (int) (15 * dpi); + editText.setPadding(padding - (int) (5 * dpi), padding, padding, padding); + return true; + } + + } + + @Override + public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) { + if (webChromeClient != null) { + return webChromeClient.onJsBeforeUnload(view, url, message, result); + } + return super.onJsBeforeUnload(view, url, message, result); + } + + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, long quota, + long estimatedDatabaseSize, + long totalQuota, + WebStorage.QuotaUpdater quotaUpdater) { + if (webChromeClient != null) { + webChromeClient.onExceededDatabaseQuota(url, databaseIdentifier, quota, + estimatedDatabaseSize, totalQuota, quotaUpdater); + } else { + super.onExceededDatabaseQuota(url, databaseIdentifier, quota, + estimatedDatabaseSize, totalQuota, quotaUpdater); + } + } + + @Override + public void onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater) { + if (webChromeClient != null) { + webChromeClient.onReachedMaxAppCacheSize(requiredStorage, quota, quotaUpdater); + } + super.onReachedMaxAppCacheSize(requiredStorage, quota, quotaUpdater); + } + + @Override + public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { + if (webChromeClient != null) { + webChromeClient.onGeolocationPermissionsShowPrompt(origin, callback); + } else { + super.onGeolocationPermissionsShowPrompt(origin, callback); + } + } + + @Override + public void onGeolocationPermissionsHidePrompt() { + if (webChromeClient != null) { + webChromeClient.onGeolocationPermissionsHidePrompt(); + } else { + super.onGeolocationPermissionsHidePrompt(); + } + } + + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public void onPermissionRequest(PermissionRequest request) { + if (webChromeClient != null) { + webChromeClient.onPermissionRequest(request); + } else { + super.onPermissionRequest(request); + } + } + + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public void onPermissionRequestCanceled(PermissionRequest request) { + if (webChromeClient != null) { + webChromeClient.onPermissionRequestCanceled(request); + } else { + super.onPermissionRequestCanceled(request); + } + } + + @Override + public boolean onJsTimeout() { + if (webChromeClient != null) { + return webChromeClient.onJsTimeout(); + } + return super.onJsTimeout(); + } + + @Override + public void onConsoleMessage(String message, int lineNumber, String sourceID) { + if (webChromeClient != null) { + webChromeClient.onConsoleMessage(message, lineNumber, sourceID); + } else { + super.onConsoleMessage(message, lineNumber, sourceID); + } + } + + @Override + public boolean onConsoleMessage(ConsoleMessage consoleMessage) { + if (webChromeClient != null) { + return webChromeClient.onConsoleMessage(consoleMessage); + } + return super.onConsoleMessage(consoleMessage); + } + + @Override + public Bitmap getDefaultVideoPoster() { + + if (webChromeClient != null) { + return webChromeClient.getDefaultVideoPoster(); + } + return super.getDefaultVideoPoster(); + } + + @Override + public View getVideoLoadingProgressView() { + if (webChromeClient != null) { + return webChromeClient.getVideoLoadingProgressView(); + } + return super.getVideoLoadingProgressView(); + } + + @Override + public void getVisitedHistory(ValueCallback callback) { + if (webChromeClient != null) { + webChromeClient.getVisitedHistory(callback); + } else { + super.getVisitedHistory(callback); + } + } + + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, + FileChooserParams fileChooserParams) { + if (webChromeClient != null) { + return webChromeClient.onShowFileChooser(webView, filePathCallback, fileChooserParams); + } + return super.onShowFileChooser(webView, filePathCallback, fileChooserParams); + } + + + @Keep + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public void openFileChooser(ValueCallback valueCallback, String acceptType) { + if (webChromeClient instanceof FileChooser) { + ((FileChooser) webChromeClient).openFileChooser(valueCallback, acceptType); + } + } + + + @Keep + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + public void openFileChooser(ValueCallback valueCallback, + String acceptType, String capture) { + if (webChromeClient instanceof FileChooser) { + ((FileChooser) webChromeClient).openFileChooser(valueCallback, acceptType, capture); + } + } + + }; + + @Override + public void clearCache(boolean includeDiskFiles) { + super.clearCache(includeDiskFiles); + CookieManager.getInstance().removeAllCookie(); + Context context = getContext(); + try { + context.deleteDatabase("webview.db"); + context.deleteDatabase("webviewCache.db"); + } catch (Exception e) { + e.printStackTrace(); + } + + File appCacheDir = new File(APP_CACHE_DIRNAME); + File webviewCacheDir = new File(context.getCacheDir() + .getAbsolutePath() + "/webviewCache"); + + if (webviewCacheDir.exists()) { + deleteFile(webviewCacheDir); + } + + if (appCacheDir.exists()) { + deleteFile(appCacheDir); + } + } + + public void deleteFile(File file) { + if (file.exists()) { + if (file.isFile()) { + file.delete(); + } else if (file.isDirectory()) { + File files[] = file.listFiles(); + for (int i = 0; i < files.length; i++) { + deleteFile(files[i]); + } + } + file.delete(); + } else { + Log.e("Webview", "delete file no exists " + file.getAbsolutePath()); + } + } + + private void runOnMainThread(Runnable runnable) { + if (Looper.getMainLooper() == Looper.myLooper()) { + runnable.run(); + return; + } + mainHandler.post(runnable); + } + + + + +} diff --git a/app/src/main/java/com/gh/common/view/dsbridge/OnReturnValue.java b/app/src/main/java/com/gh/common/view/dsbridge/OnReturnValue.java new file mode 100644 index 0000000000..16e506a738 --- /dev/null +++ b/app/src/main/java/com/gh/common/view/dsbridge/OnReturnValue.java @@ -0,0 +1,9 @@ +package com.gh.common.view.dsbridge; + +/** + * Created by du on 16/12/31. + */ + +public interface OnReturnValue { + void onValue(T retValue); +} diff --git a/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt b/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt index 089066a648..612413c89e 100644 --- a/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt @@ -11,9 +11,9 @@ import com.gh.base.fragment.BaseDialogFragment import com.gh.common.DefaultJsApi import com.gh.common.util.MtaHelper import com.gh.common.util.dip2px +import com.gh.common.view.dsbridge.DWebView import com.gh.gamecenter.BuildConfig import com.gh.gamecenter.R -import wendu.dsbridge.DWebView /** * 光环助手资源协议 diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt index e644ddb5eb..ad78d3484b 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt @@ -269,7 +269,7 @@ class DescViewModel(application: Application, hasShownCustomColumnTagsExpandHint = true } - // 手动为自定义栏目的说明添加展开分隔符 + // 将自定义栏目正文内容里低版本 android 系统不支持的 HTML Tag 转为手动处理 if (!TextUtils.isEmpty(rawItem.customColumn?.desBrief)) { rawItem.customColumn?.desFull = rawItem.customColumn?.desFull?.replaceUnsupportedHtmlTag() rawItem.customColumn?.desBrief = rawItem.customColumn?.desBrief?.replaceUnsupportedHtmlTag() diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt index 8051880a85..a343815e9e 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt @@ -20,6 +20,8 @@ import com.gh.common.AppExecutor import com.gh.common.DefaultJsApi import com.gh.common.im.ImManager import com.gh.common.util.* +import com.gh.common.view.dsbridge.DWebView +import com.gh.common.view.dsbridge.OnReturnValue import com.gh.gamecenter.* import com.gh.gamecenter.databinding.ActivityRatingEditBinding import com.gh.gamecenter.entity.* @@ -33,8 +35,6 @@ import okhttp3.MediaType import okhttp3.RequestBody import org.json.JSONObject import retrofit2.HttpException -import wendu.dsbridge.DWebView -import wendu.dsbridge.OnReturnValue class RatingEditActivity : ToolBarActivity(), KeyboardHeightObserver { diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java b/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java index db1c06e529..30f7fbe664 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/RetrofitManager.java @@ -2,9 +2,6 @@ package com.gh.gamecenter.retrofit; import android.content.Context; -import com.chuckerteam.chucker.api.ChuckerCollector; -import com.chuckerteam.chucker.api.ChuckerInterceptor; -import com.chuckerteam.chucker.api.RetentionManager; import com.gh.common.constant.Config; import com.gh.gamecenter.Injection; import com.gh.gamecenter.retrofit.service.ApiService; @@ -52,7 +49,7 @@ public class RetrofitManager { return Injection.provideRetrofitBuilder() .addInterceptor(new OkHttpCacheInterceptor(context)) .addInterceptor(new OkHttpRetryInterceptor(context)) - .addInterceptor(new ChuckerInterceptor(context, new ChuckerCollector(context, true, RetentionManager.Period.ONE_DAY))) +// .addInterceptor(new ChuckerInterceptor(context, new ChuckerCollector(context, true, RetentionManager.Period.ONE_DAY))) .addNetworkInterceptor(new OkHttpNetworkInterceptor(context)) .connectTimeout(connTimeout, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.SECONDS) diff --git a/app/src/main/java/com/halo/assistant/fragment/WebFragment.java b/app/src/main/java/com/halo/assistant/fragment/WebFragment.java index 4001cf3fcb..7249d7b048 100644 --- a/app/src/main/java/com/halo/assistant/fragment/WebFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/WebFragment.java @@ -16,6 +16,8 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.Nullable; + import com.gh.base.BaseActivity; import com.gh.common.AppExecutor; import com.gh.common.DefaultJsApi; @@ -28,6 +30,7 @@ import com.gh.common.util.EntranceUtils; import com.gh.common.util.GsonUtils; import com.gh.common.util.MtaHelper; import com.gh.common.util.ShareUtils; +import com.gh.common.view.dsbridge.DWebView; import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.MessageDetailActivity; import com.gh.gamecenter.R; @@ -50,12 +53,10 @@ import org.greenrobot.eventbus.ThreadMode; import java.util.HashMap; import java.util.List; -import androidx.annotation.Nullable; import butterknife.BindView; import butterknife.OnClick; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; -import wendu.dsbridge.DWebView; /** * TODO 整理这个类 diff --git a/app/src/main/res/layout/activity_rating_edit.xml b/app/src/main/res/layout/activity_rating_edit.xml index 20ee2a1546..01fafe46cd 100644 --- a/app/src/main/res/layout/activity_rating_edit.xml +++ b/app/src/main/res/layout/activity_rating_edit.xml @@ -136,7 +136,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - diff --git a/app/src/main/res/layout/dialog_game_resource_policy.xml b/app/src/main/res/layout/dialog_game_resource_policy.xml index d6ce6fc7e5..de8b90adda 100644 --- a/app/src/main/res/layout/dialog_game_resource_policy.xml +++ b/app/src/main/res/layout/dialog_game_resource_policy.xml @@ -23,7 +23,7 @@ android:textStyle="bold" tools:text="光环助手资源协议"/> -