├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── styles.xml
│ │ │ ├── dimens.xml
│ │ │ ├── colors.xml
│ │ │ └── text_styles.xml
│ │ ├── drawable-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xxhdpi
│ │ │ └── ic_launcher.png
│ │ └── layout
│ │ │ ├── activity_webview_video.xml
│ │ │ ├── activity_init.xml
│ │ │ ├── activity_main.xml
│ │ │ └── activity_webview.xml
│ │ ├── java
│ │ └── com
│ │ │ └── zcolin
│ │ │ └── zx5webview
│ │ │ └── demo
│ │ │ ├── app
│ │ │ └── App.java
│ │ │ ├── InitActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── WebViewVideoActivity.java
│ │ │ └── WebViewActivity.java
│ │ ├── assets
│ │ ├── bridgewebview_js_demo.js
│ │ └── bridgewebview_html_demo.html
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── libZX5WebView
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── zx5webview_styles.xml
│ │ ├── drawable-xhdpi
│ │ │ └── zwebview_error.png
│ │ ├── drawable
│ │ │ ├── zx5webview_progressbar_circle_bg.xml
│ │ │ └── zx5webview_progressbar_horizontal.xml
│ │ └── layout
│ │ │ ├── zx5webview_view_webview_horizontal_progressbar.xml
│ │ │ ├── zx5webview_view_progressbar_webview.xml
│ │ │ ├── zx5webview_view_webview_video_progress.xml
│ │ │ ├── zx5webview_view_webview_circle_progressbar.xml
│ │ │ └── zx5webview_view_webview_error.xml
│ │ ├── AndroidManifest.xml
│ │ ├── jniLibs
│ │ ├── armeabi
│ │ │ └── liblbs.so
│ │ └── armeabi-v7a
│ │ │ └── liblbs.so
│ │ ├── java
│ │ └── com
│ │ │ └── zcolin
│ │ │ └── zx5webview
│ │ │ ├── IPickFile.java
│ │ │ ├── jsbridge
│ │ │ ├── CallBackFunction.java
│ │ │ ├── BridgeHandler.java
│ │ │ ├── WebViewJavascriptBridge.java
│ │ │ ├── DefaultHandler.java
│ │ │ ├── BridgeUtil.java
│ │ │ ├── BridgeWebViewClient.java
│ │ │ ├── Message.java
│ │ │ └── BridgeWebView.java
│ │ │ ├── ZX5ChooseFileWebChromeClientWrapper.java
│ │ │ ├── ZX5VideoFullScreenWebChromeClient.java
│ │ │ ├── ZX5WebViewClientWrapper.java
│ │ │ ├── ZX5WebChromeClientWrapper.java
│ │ │ └── ZX5WebView.java
│ │ └── assets
│ │ └── WebViewJavascriptBridge.js
├── libs
│ └── tbs_sdk_thirdapp_v4.3.0.39_43939_sharewithdownloadwithfile_withoutGame_obfs_20200713_223411.jar
├── javadoc.gradle
├── build.gradle
└── proguard-rules.pro
├── settings.gradle
├── .idea
├── dictionaries
│ ├── ZColin.xml
│ └── fosung.xml
├── encodings.xml
├── vcs.xml
├── copyright
│ └── colin.xml
├── runConfigurations.xml
├── modules.xml
├── gradle.xml
└── misc.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/libZX5WebView/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app',':libZX5WebView'
--------------------------------------------------------------------------------
/libZX5WebView/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
12 |
16 |
20 | 21 |
22 |23 | 24 |
25 |26 | 28 |
29 |30 | 32 |
33 |34 | 36 |
37 |38 | 39 |
40 |41 | 42 |
43 | 44 | 114 | 115 | -------------------------------------------------------------------------------- /app/src/main/java/com/zcolin/zx5webview/demo/WebViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.zcolin.zx5webview.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import androidx.fragment.app.FragmentActivity; 7 | import androidx.appcompat.app.AlertDialog; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.widget.Button; 11 | 12 | import com.zcolin.frame.util.GsonUtil; 13 | import com.zcolin.zx5webview.ZX5WebView; 14 | import com.zcolin.zx5webview.jsbridge.DefaultHandler; 15 | 16 | 17 | /** 18 | * 带JsBridge的webview的Demo 19 | */ 20 | public class WebViewActivity extends FragmentActivity implements OnClickListener { 21 | private ZX5WebView webView; 22 | private Button button; 23 | private Activity mActivity; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_webview); 29 | mActivity = this; 30 | 31 | webView = findViewById(R.id.webView); 32 | button = findViewById(R.id.button); 33 | button.setOnClickListener(this); 34 | 35 | initWebView(); 36 | loadUrl(); 37 | 38 | getUserDataFrom_xx(); 39 | } 40 | 41 | public void initWebView() { 42 | webView.setSupportJsBridge(); 43 | webView.setSupportChooseFile(mActivity); 44 | // 如果JS调用send方法,会走到DefaultHandler里 45 | webView.setDefaultHandler(new DefaultHandler()); 46 | webView.registerHandler("submitFromWeb", 47 | (data, function) -> new AlertDialog.Builder(WebViewActivity.this).setMessage( 48 | "监听到网页传入数据:" + data) 49 | .setPositiveButton( 50 | "确定", 51 | (dialog, which) -> function 52 | .onCallBack( 53 | "java 返回数据!!!")) 54 | .create() 55 | .show()); 56 | } 57 | 58 | public void loadUrl() { 59 | webView.loadUrl("file:///android_asset/bridgewebview_html_demo.html"); 60 | } 61 | 62 | public void callJsFunc(String funcName, String strParam) { 63 | webView.callHandler(funcName, 64 | strParam, 65 | data -> new AlertDialog.Builder(WebViewActivity.this).setMessage("网页返回数据:" + data) 66 | .create() 67 | .show()); 68 | //webView.send("hello"); 69 | } 70 | 71 | 72 | @Override 73 | public void onActivityResult(int requestCode, int resultCode, Intent intent) { 74 | super.onActivityResult(requestCode, resultCode, intent); 75 | webView.processResult(requestCode, resultCode, intent); 76 | } 77 | 78 | @Override 79 | public void onClick(View v) { 80 | if (button.equals(v)) { 81 | callJsFunc("functionInJs", "java 调用传入数据"); 82 | } 83 | } 84 | 85 | public void getUserDataFrom_xx() { 86 | User user = new User(); 87 | Location location = new Location(); 88 | location.address = "SDU"; 89 | user.location = location; 90 | user.name = "大头鬼"; 91 | 92 | callJsFunc("functionInJs", GsonUtil.beanToString(user)); 93 | } 94 | 95 | 96 | static class Location { 97 | String address; 98 | } 99 | 100 | static class User { 101 | String name; 102 | Location location; 103 | String testStr; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /libZX5WebView/src/main/java/com/zcolin/zx5webview/jsbridge/BridgeUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ********************************************************* 3 | * author colin 4 | * company telchina 5 | * email wanglin2046@126.com 6 | * date 18-1-9 上午8:51 7 | * ******************************************************** 8 | */ 9 | package com.zcolin.zx5webview.jsbridge; 10 | 11 | import android.content.Context; 12 | 13 | import com.tencent.smtt.sdk.WebView; 14 | 15 | import java.io.BufferedReader; 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.io.InputStreamReader; 19 | 20 | public class BridgeUtil { 21 | final static String IOS_SCHEME = "wvjbscheme://__BRIDGE_LOADED__"; 22 | final static String YY_OVERRIDE_SCHEMA = "yy://"; 23 | /** 格式为 yy://return/{function}/returncontent */ 24 | final static String YY_RETURN_DATA = YY_OVERRIDE_SCHEMA + "return/"; 25 | final static String YY_FETCH_QUEUE = YY_RETURN_DATA + "_fetchQueue/"; 26 | final static String EMPTY_STR = ""; 27 | final static String UNDERLINE_STR = "_"; 28 | final static String SPLIT_MARK = "/"; 29 | 30 | final static String CALLBACK_ID_FORMAT = "JAVA_CB_%s"; 31 | final static String JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge" + 32 | "._handleMessageFromNative('%s');"; 33 | final static String JS_FETCH_QUEUE_FROM_JAVA = "javascript:WebViewJavascriptBridge._fetchQueue();"; 34 | public final static String JAVASCRIPT_STR = "javascript:"; 35 | 36 | public static String parseFunctionName(String jsUrl) { 37 | return jsUrl.replace("javascript:WebViewJavascriptBridge.", "").replaceAll("\\(.*\\);", ""); 38 | } 39 | 40 | 41 | public static String getDataFromReturnUrl(String url) { 42 | if (url.startsWith(YY_FETCH_QUEUE)) { 43 | return url.replace(YY_FETCH_QUEUE, EMPTY_STR); 44 | } 45 | 46 | String temp = url.replace(YY_RETURN_DATA, EMPTY_STR); 47 | String[] functionAndData = temp.split(SPLIT_MARK); 48 | 49 | if (functionAndData.length >= 2) { 50 | StringBuilder sb = new StringBuilder(); 51 | for (int i = 1; i < functionAndData.length; i++) { 52 | sb.append(functionAndData[i]); 53 | } 54 | return sb.toString(); 55 | } 56 | return null; 57 | } 58 | 59 | public static String getFunctionFromReturnUrl(String url) { 60 | String temp = url.replace(YY_RETURN_DATA, EMPTY_STR); 61 | String[] functionAndData = temp.split(SPLIT_MARK); 62 | if (functionAndData.length >= 1) { 63 | return functionAndData[0]; 64 | } 65 | return null; 66 | } 67 | 68 | 69 | /** 70 | * js 文件将注入为第一个script引用 71 | */ 72 | public static void webViewLoadJs(WebView view, String url) { 73 | String js = "var newscript = document.createElement(\"script\");"; 74 | js += "newscript.src=\"" + url + "\";"; 75 | js += "document.scripts[0].parentNode.insertBefore(newscript,document.scripts[0]);"; 76 | view.loadUrl("javascript:" + js); 77 | } 78 | 79 | public static void webViewLoadLocalJs(WebView view, String path) { 80 | String jsContent = assetFile2Str(view.getContext(), path); 81 | view.loadUrl("javascript:" + jsContent); 82 | } 83 | 84 | public static String assetFile2Str(Context c, String urlStr) { 85 | InputStream in = null; 86 | try { 87 | in = c.getAssets().open(urlStr); 88 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in)); 89 | String line = null; 90 | StringBuilder sb = new StringBuilder(); 91 | do { 92 | line = bufferedReader.readLine(); 93 | if (line != null && !line.matches("^\\s*\\/\\/.*")) { 94 | sb.append(line); 95 | } 96 | } while (line != null); 97 | 98 | bufferedReader.close(); 99 | in.close(); 100 | 101 | return sb.toString(); 102 | } catch (Exception e) { 103 | e.printStackTrace(); 104 | } finally { 105 | if (in != null) { 106 | try { 107 | in.close(); 108 | } catch (IOException e) { 109 | } 110 | } 111 | } 112 | return null; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /libZX5WebView/src/main/java/com/zcolin/zx5webview/jsbridge/BridgeWebViewClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ********************************************************* 3 | * author colin 4 | * company telchina 5 | * email wanglin2046@126.com 6 | * date 18-1-9 上午8:51 7 | * ******************************************************** 8 | */ 9 | package com.zcolin.zx5webview.jsbridge; 10 | 11 | import android.graphics.Bitmap; 12 | import android.os.Build; 13 | import androidx.annotation.RequiresApi; 14 | 15 | import com.tencent.smtt.export.external.interfaces.WebResourceError; 16 | import com.tencent.smtt.export.external.interfaces.WebResourceRequest; 17 | import com.tencent.smtt.sdk.WebView; 18 | import com.tencent.smtt.sdk.WebViewClient; 19 | 20 | import java.io.UnsupportedEncodingException; 21 | import java.net.URLDecoder; 22 | 23 | /** 24 | * 和网页js通讯的webViewClient 25 | */ 26 | public class BridgeWebViewClient extends WebViewClient { 27 | private boolean isSupportJsBridge; 28 | private boolean isReceiveError; 29 | private boolean isInjectJSBridge; 30 | private OnInjectFinishListener injectFinishListener; 31 | 32 | /** 33 | * 支持JsBridge 34 | */ 35 | public void setSupportJsBridge() { 36 | isSupportJsBridge = true; 37 | } 38 | 39 | /** 40 | * 设置注入完成监听 41 | */ 42 | public void setOnInjectFinishListener(OnInjectFinishListener listener) { 43 | this.injectFinishListener = listener; 44 | } 45 | 46 | @Override 47 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 48 | if (isSupportJsBridge) { 49 | try { 50 | url = URLDecoder.decode(url, "UTF-8"); 51 | } catch (UnsupportedEncodingException e) { 52 | e.printStackTrace(); 53 | } 54 | 55 | if (view instanceof BridgeWebView) { 56 | BridgeWebView webView = (BridgeWebView) view; 57 | // 如果是返回数据 58 | if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { 59 | webView.handlerReturnData(url); 60 | return true; 61 | } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { 62 | webView.flushMessageQueue(); 63 | return true; 64 | } else if (url.startsWith(BridgeUtil.IOS_SCHEME)) { 65 | return true; 66 | } 67 | } 68 | } 69 | return super.shouldOverrideUrlLoading(view, url); 70 | } 71 | 72 | @Override 73 | public void onPageStarted(WebView view, String url, Bitmap favicon) { 74 | super.onPageStarted(view, url, favicon); 75 | } 76 | 77 | @Override 78 | public void onPageFinished(WebView view, String url) { 79 | super.onPageFinished(view, url); 80 | if (isSupportJsBridge) { 81 | if (!isReceiveError) { 82 | BridgeUtil.webViewLoadLocalJs(view, BridgeWebView.TO_LOAD_JS); 83 | isInjectJSBridge = true; 84 | if (injectFinishListener != null) { 85 | injectFinishListener.onInjectFinish(true); 86 | } 87 | } else { 88 | if (injectFinishListener != null) { 89 | injectFinishListener.onInjectFinish(false); 90 | } 91 | } 92 | 93 | if (view instanceof BridgeWebView) { 94 | BridgeWebView webView = (BridgeWebView) view; 95 | if (webView.getStartupMessage() != null) { 96 | for (Message m : webView.getStartupMessage()) { 97 | webView.dispatchMessage(m); 98 | } 99 | webView.setStartupMessage(null); 100 | } 101 | } 102 | } 103 | } 104 | 105 | @Override 106 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { 107 | isReceiveError = true; 108 | } 109 | 110 | @RequiresApi(api = Build.VERSION_CODES.M) 111 | @Override 112 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 113 | if (request.isForMainFrame()) { 114 | isReceiveError = true; 115 | } 116 | } 117 | 118 | public boolean isInjectJSBridge() { 119 | return isInjectJSBridge; 120 | } 121 | 122 | public void reset() { 123 | isReceiveError = false; 124 | isInjectJSBridge = false; 125 | } 126 | 127 | public interface OnInjectFinishListener { 128 | void onInjectFinish(boolean success); 129 | } 130 | } -------------------------------------------------------------------------------- /libZX5WebView/src/main/java/com/zcolin/zx5webview/jsbridge/Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * ********************************************************* 3 | * author colin 4 | * company telchina 5 | * email wanglin2046@126.com 6 | * date 18-1-9 上午8:51 7 | * ******************************************************** 8 | */ 9 | package com.zcolin.zx5webview.jsbridge; 10 | 11 | import org.json.JSONArray; 12 | import org.json.JSONException; 13 | import org.json.JSONObject; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * data of bridge 20 | * 21 | * @author haoqing 22 | */ 23 | public class Message { 24 | 25 | private String callbackId; 26 | private String responseId; 27 | private String responseData; 28 | private String data; 29 | private String handlerName; 30 | 31 | private final static String CALLBACK_ID_STR = "callbackId"; 32 | private final static String RESPONSE_ID_STR = "responseId"; 33 | private final static String RESPONSE_DATA_STR = "responseData"; 34 | private final static String DATA_STR = "data"; 35 | private final static String HANDLER_NAME_STR = "handlerName"; 36 | 37 | public String getResponseId() { 38 | return responseId; 39 | } 40 | 41 | public void setResponseId(String responseId) { 42 | this.responseId = responseId; 43 | } 44 | 45 | public String getResponseData() { 46 | return responseData; 47 | } 48 | 49 | public void setResponseData(String responseData) { 50 | this.responseData = responseData; 51 | } 52 | 53 | public String getCallbackId() { 54 | return callbackId; 55 | } 56 | 57 | public void setCallbackId(String callbackId) { 58 | this.callbackId = callbackId; 59 | } 60 | 61 | public String getData() { 62 | return data; 63 | } 64 | 65 | public void setData(String data) { 66 | this.data = data; 67 | } 68 | 69 | public String getHandlerName() { 70 | return handlerName; 71 | } 72 | 73 | public void setHandlerName(String handlerName) { 74 | this.handlerName = handlerName; 75 | } 76 | 77 | public String toJson() { 78 | JSONObject jsonObject = new JSONObject(); 79 | try { 80 | jsonObject.put(CALLBACK_ID_STR, getCallbackId()); 81 | jsonObject.put(DATA_STR, getData()); 82 | jsonObject.put(HANDLER_NAME_STR, getHandlerName()); 83 | jsonObject.put(RESPONSE_DATA_STR, getResponseData()); 84 | jsonObject.put(RESPONSE_ID_STR, getResponseId()); 85 | return jsonObject.toString(); 86 | } catch (JSONException e) { 87 | e.printStackTrace(); 88 | } 89 | return null; 90 | } 91 | 92 | public static Message toObject(String jsonStr) { 93 | Message m = new Message(); 94 | try { 95 | JSONObject jsonObject = new JSONObject(jsonStr); 96 | m.setHandlerName(jsonObject.has(HANDLER_NAME_STR) ? jsonObject.getString(HANDLER_NAME_STR) : null); 97 | m.setCallbackId(jsonObject.has(CALLBACK_ID_STR) ? jsonObject.getString(CALLBACK_ID_STR) : null); 98 | m.setResponseData(jsonObject.has(RESPONSE_DATA_STR) ? jsonObject.getString(RESPONSE_DATA_STR) : null); 99 | m.setResponseId(jsonObject.has(RESPONSE_ID_STR) ? jsonObject.getString(RESPONSE_ID_STR) : null); 100 | m.setData(jsonObject.has(DATA_STR) ? jsonObject.getString(DATA_STR) : null); 101 | return m; 102 | } catch (JSONException e) { 103 | e.printStackTrace(); 104 | } 105 | return m; 106 | } 107 | 108 | public static List
27 | * webview默认的chromeClient是{@link ZX5WebChromeClientWrapper}
28 | */
29 | public class ZX5ChooseFileWebChromeClientWrapper extends ZX5WebChromeClientWrapper {
30 | private static final int REQUEST_CODE = 5200;
31 |
32 | private ValueCallback
140 | * 默认值支持单选
141 | */
142 | public boolean processResult(int requestCode, int resultCode, Intent intent) {
143 | if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE && intent != null) {
144 | processResult(intent.getData());
145 | return true;
146 | }
147 | processResult((Uri) null);
148 | return false;
149 | }
150 | }
--------------------------------------------------------------------------------
/libZX5WebView/src/main/java/com/zcolin/zx5webview/ZX5VideoFullScreenWebChromeClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * *********************************************************
3 | * author colin
4 | * company telchina
5 | * email wanglin2046@126.com
6 | * date 18-1-9 上午8:51
7 | * ********************************************************
8 | */
9 |
10 | package com.zcolin.zx5webview;
11 |
12 | import android.app.Activity;
13 | import android.content.pm.ActivityInfo;
14 | import androidx.appcompat.app.ActionBar;
15 | import androidx.appcompat.app.AppCompatActivity;
16 | import android.view.View;
17 | import android.view.WindowManager;
18 | import android.widget.FrameLayout;
19 |
20 | import com.tencent.smtt.export.external.interfaces.IX5WebChromeClient;
21 | import com.tencent.smtt.sdk.WebChromeClient;
22 | import com.tencent.smtt.sdk.WebView;
23 |
24 | /**
25 | * 支持视频播放的WebChormeClient
26 | *
27 | * webview默认的chromeClient是{@link ZX5WebChromeClientWrapper}
28 | */
29 | public class ZX5VideoFullScreenWebChromeClient extends ZX5WebChromeClientWrapper {
30 |
31 | private View videoProgressView;
32 | private View customView;
33 | private WebView webView;
34 | private FrameLayout customViewContainer;
35 | private IX5WebChromeClient.CustomViewCallback customViewCallback;
36 | private CustomViewShowStateListener customViewShowStateListener;
37 | private Activity activity;
38 |
39 | ZX5VideoFullScreenWebChromeClient(WebChromeClient webChromeClient, Activity activity, WebView webView,
40 | FrameLayout customViewContainer, View videoProgressView) {
41 | super(webChromeClient);
42 | this.webView = webView;
43 | this.videoProgressView = videoProgressView;
44 | this.customViewContainer = customViewContainer;
45 | this.activity = activity;
46 | }
47 |
48 | public void setCustomViewShowStateListener(CustomViewShowStateListener customViewShowStateListener) {
49 | this.customViewShowStateListener = customViewShowStateListener;
50 | }
51 |
52 | public boolean isCustomViewShow() {
53 | return customView != null;
54 | }
55 |
56 | @Override
57 | public void onShowCustomView(View view, int requestedOrientation, IX5WebChromeClient.CustomViewCallback callback) {
58 | onShowCustomView(view, callback);
59 | }
60 |
61 | @Override
62 | public void onShowCustomView(View view, IX5WebChromeClient.CustomViewCallback callback) {
63 | super.onShowCustomView(view, callback);
64 | webView.setVisibility(View.INVISIBLE);
65 | if (customView != null) {
66 | callback.onCustomViewHidden();
67 | return;
68 | }
69 |
70 | customView = view;
71 | customViewContainer.setVisibility(View.VISIBLE);
72 | customViewContainer.addView(customView);
73 | customViewCallback = callback;
74 |
75 | toggleFullScreen(true);
76 |
77 | if (customViewShowStateListener != null) {
78 | customViewShowStateListener.show();
79 | }
80 | }
81 |
82 | @Override
83 | public View getVideoLoadingProgressView() {
84 | return videoProgressView;
85 | }
86 |
87 | @Override
88 | public void onHideCustomView() {
89 | super.onHideCustomView();
90 |
91 | if (customView == null) {
92 | return;
93 | }
94 |
95 | webView.setVisibility(View.VISIBLE);
96 | customViewContainer.setVisibility(View.GONE);
97 | customViewContainer.removeView(customView);
98 | customView = null;
99 |
100 | customViewCallback.onCustomViewHidden();
101 |
102 | toggleFullScreen(false);
103 |
104 | if (customViewShowStateListener != null) {
105 | customViewShowStateListener.hide();
106 | }
107 | }
108 |
109 | private void toggleFullScreen(boolean isShowCustomView) {
110 | //横竖屏状态
111 | activity.setRequestedOrientation(isShowCustomView ?
112 | ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE :
113 | ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
114 |
115 | //actionBar显示状态
116 | if (activity instanceof AppCompatActivity) {
117 | ActionBar supportActionBar = ((AppCompatActivity) this.activity).getSupportActionBar();
118 | if (supportActionBar != null) {
119 | if (isShowCustomView) {
120 | supportActionBar.hide();
121 | } else {
122 | supportActionBar.show();
123 | }
124 | }
125 | } else if (activity instanceof Activity) {
126 | android.app.ActionBar actionBar = activity.getActionBar();
127 | if (actionBar != null) {
128 | if (isShowCustomView) {
129 | actionBar.hide();
130 | } else {
131 | actionBar.show();
132 | }
133 | }
134 | }
135 |
136 | //设置全屏状态
137 | WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();
138 | if (isShowCustomView) {
139 | attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
140 | attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
141 | } else {
142 | attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
143 | attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
144 | }
145 | activity.getWindow().setAttributes(attrs);
146 |
147 | //activity.getWindow()
148 | // .getDecorView()
149 | // .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
150 | }
151 |
152 |
153 | public interface CustomViewShowStateListener {
154 | void show();
155 |
156 | void hide();
157 | }
158 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
180 | *
181 | * 需要在Activity的onActivityResult中调用:
182 | *
191 | * pickFile参考如下
192 | * Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
193 | * chooserIntent.setType(acceptType);
194 | * if (fragment != null) {
195 | * fragment.startActivityForResult(chooserIntent, REQUEST_CODE);
196 | * } else if (activity != null) {
197 | * activity.startActivityForResult(chooserIntent, REQUEST_CODE);
198 | * }
199 | */
200 | public ZX5WebView setSupportChooseFile(Activity activity, IPickFile pickFile) {
201 | webChromeClientWrapper = new ZX5ChooseFileWebChromeClientWrapper(webChromeClientWrapper.getWebChromeClient(),
202 | activity,
203 | pickFile);
204 | setWebChromeClient(webChromeClientWrapper.getWebChromeClient());
205 | return this;
206 | }
207 |
208 | /**
209 | * 支持文件选择
210 | *
211 | *
212 | * 需要在Activity的onActivityResult中调用:
213 | *
227 | *
228 | * 需要在Fragment的onActivityResult中调用:
229 | *
237 | * pickFile参考如下
238 | * Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
239 | * chooserIntent.setType(acceptType);
240 | * if (fragment != null) {
241 | * fragment.startActivityForResult(chooserIntent, REQUEST_CODE);
242 | * } else if (activity != null) {
243 | * activity.startActivityForResult(chooserIntent, REQUEST_CODE);
244 | * }
245 | */
246 | public ZX5WebView setSupportChooseFile(Fragment fragment, IPickFile pickFile) {
247 | webChromeClientWrapper = new ZX5ChooseFileWebChromeClientWrapper(webChromeClientWrapper.getWebChromeClient(),
248 | fragment,
249 | pickFile);
250 | setWebChromeClient(webChromeClientWrapper.getWebChromeClient());
251 | return this;
252 | }
253 |
254 | /**
255 | * 支持文件选择
256 | *
257 | *
258 | * 需要在Activity的onActivityResult中调用:
259 | *
273 | * 必须在Activity的manifest文件中指定 android:configChanges="keyboardHidden|orientation|screenSize"
274 | *
275 | *
477 | * 需要声明权限
478 | *
479 | *
74 |
79 |
84 |
89 |
122 |
124 |
134 |
136 |
145 |
147 |
183 | * public void onActivityResult(int requestCode, int resultCode, Intent intent) {
184 | * super.onActivityResult(requestCode, resultCode, intent);
185 | * webView.processResult(requestCode, resultCode, intent);
186 | * }
187 | *
188 | *
189 | * @param pickFile 文件选择自定义处理方式
190 | *
214 | * public void onActivityResult(int requestCode, int resultCode, Intent intent) {
215 | * super.onActivityResult(requestCode, resultCode, intent);
216 | * webView.processResult(requestCode, resultCode, intent);
217 | * }
218 | *
219 | */
220 | public ZX5WebView setSupportChooseFile(Activity activity) {
221 | return this.setSupportChooseFile(activity, null);
222 | }
223 |
224 | /**
225 | * 支持文件选择
226 | *
230 | * public void onActivityResult(int requestCode, int resultCode, Intent intent) {
231 | * webView.processResult(requestCode, resultCode, intent);
232 | * }
233 | *
234 | *
235 | * @param pickFile 文件选择自定义处理方式
236 | *
260 | * public void onActivityResult(int requestCode, int resultCode, Intent intent) {
261 | * super.onActivityResult(requestCode, resultCode, intent);
262 | * webView.processResult(requestCode, resultCode, intent);
263 | * }
264 | *
265 | */
266 | public ZX5WebView setSupportChooseFile(Fragment fragment) {
267 | return this.setSupportChooseFile(fragment, null);
268 | }
269 |
270 | /**
271 | * 支持视频全屏
272 | *
276 | * 在Activity的OnKeyDown中如下:
277 | * public boolean onKeyDown(int keyCode, KeyEvent event) {
278 | * if (keyCode == KeyEvent.KEYCODE_BACK) {
279 | * if (webView.hideCustomView()) {
280 | * return true;
281 | * } else if (webView.canGoBack()) {
282 | * webView.goBack();
283 | * return true;
284 | * }
285 | * }
286 | * return super.onKeyDown(keyCode, event);
287 | * }
288 | *
289 | */
290 | public ZX5WebView setSupportVideoFullScreen(Activity activity) {
291 | ViewGroup group = (ViewGroup) this.getParent();
292 | FrameLayout container = new FrameLayout(getContext());
293 | int index = group.indexOfChild(this);
294 |
295 | //将原来的布局之间添加一层,用来盛放webView和视频全屏控件
296 | group.removeView(this);
297 | group.addView(container, index, this.getLayoutParams());
298 | container.addView(this,
299 | new FrameLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT,
300 | ViewGroup.LayoutParams.MATCH_PARENT));
301 |
302 | //添加视频ViewContainer
303 | FrameLayout flCustomContainer = new FrameLayout(getContext());
304 | flCustomContainer.setVisibility(View.INVISIBLE);
305 | container.addView(flCustomContainer,
306 | new FrameLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT,
307 | ViewGroup.LayoutParams.MATCH_PARENT));
308 |
309 | View videoProgressView = LayoutInflater.from(activity)
310 | .inflate(R.layout.zx5webview_view_webview_video_progress, null);
311 | webChromeClientWrapper = new ZX5VideoFullScreenWebChromeClient(webChromeClientWrapper.getWebChromeClient(),
312 | activity,
313 | this,
314 | flCustomContainer,
315 | videoProgressView);
316 | setWebChromeClient(webChromeClientWrapper.getWebChromeClient());
317 | return this;
318 | }
319 |
320 | public void setCustomViewShowStateListener(
321 | ZX5VideoFullScreenWebChromeClient.CustomViewShowStateListener customViewShowStateListener) {
322 | if (webChromeClientWrapper != null && webChromeClientWrapper instanceof ZX5VideoFullScreenWebChromeClient) {
323 | ((ZX5VideoFullScreenWebChromeClient) webChromeClientWrapper).setCustomViewShowStateListener(
324 | customViewShowStateListener);
325 | }
326 | }
327 |
328 | /**
329 | * 设置js通讯组件注入完成监听
330 | */
331 | public void setOnInjectFinishListener(BridgeWebViewClient.OnInjectFinishListener listener) {
332 | this.injectFinishListener = listener;
333 | webViewClientWrapper.setOnInjectFinishListener(injectFinishListener);
334 | }
335 |
336 | /**
337 | * 支持显示圆形进度条
338 | */
339 | public ZX5WebView setSupportCircleProgressBar() {
340 | setSupportProgressBar(R.layout.zx5webview_view_webview_circle_progressbar);
341 | return this;
342 | }
343 |
344 | /**
345 | * 支持自定义的圆形进度
346 | */
347 | public ZX5WebView setSupportProgressBar(@LayoutRes int resId) {
348 | setSupportProgressBar(LayoutInflater.from(getContext()).inflate(resId, null));
349 | return this;
350 | }
351 |
352 | /**
353 | * 显示自定义的进度条
354 | */
355 | public ZX5WebView setSupportProgressBar(View view) {
356 | ViewGroup group = (ViewGroup) this.getParent();
357 | RelativeLayout container = new RelativeLayout(getContext());
358 | int index = group.indexOfChild(this);
359 | group.removeView(this);
360 | group.addView(container, index, this.getLayoutParams());
361 | container.addView(this,
362 | new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
363 | ViewGroup.LayoutParams.MATCH_PARENT));
364 | customProBar = view;
365 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
366 | ViewGroup.LayoutParams.MATCH_PARENT);
367 | params.addRule(RelativeLayout.CENTER_IN_PARENT);
368 | container.addView(customProBar, params);
369 | webViewClientWrapper.setCustomProgressBar(customProBar);
370 | return this;
371 | }
372 |
373 | /**
374 | * 支持显示进度条
375 | */
376 | public ZX5WebView setSupportHorizontalProgressBar() {
377 | ViewGroup group = (ViewGroup) this.getParent();
378 | FrameLayout container = new FrameLayout(getContext());
379 | int index = group.indexOfChild(this);
380 | group.removeView(this);
381 | group.addView(container, index, this.getLayoutParams());
382 | container.addView(this,
383 | new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
384 | ViewGroup.LayoutParams.MATCH_PARENT));
385 | horizontalProBar = (ProgressBar) LayoutInflater.from(getContext())
386 | .inflate(R.layout.zx5webview_view_webview_horizontal_progressbar,
387 | null);
388 | container.addView(horizontalProBar,
389 | new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, dip2px(getContext(), 3)));
390 | webChromeClientWrapper.setHorizontalProgressBar(horizontalProBar);
391 | webViewClientWrapper.setHorizontalProgressBar(horizontalProBar);
392 | return this;
393 | }
394 |
395 | /**
396 | * 支持显示加载失败view
397 | */
398 | public ZX5WebView setSupportErrorView() {
399 | View errorView = LayoutInflater.from(getContext()).inflate(R.layout.zx5webview_view_webview_error, null);
400 | errorView.findViewById(R.id.ll_container).setOnClickListener(v -> {
401 | reload();
402 | });
403 | setSupportErrorView(errorView);
404 | return this;
405 | }
406 |
407 |
408 | /**
409 | * 支持显示加载失败view
410 | */
411 | public ZX5WebView setSupportErrorView(View view) {
412 | ViewGroup group = (ViewGroup) this.getParent();
413 | RelativeLayout container = new RelativeLayout(getContext());
414 | int index = group.indexOfChild(this);
415 | group.removeView(this);
416 | group.addView(container, index, this.getLayoutParams());
417 | container.addView(this,
418 | new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
419 | ViewGroup.LayoutParams.MATCH_PARENT));
420 | errorView = view;
421 | errorView.setVisibility(GONE);
422 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
423 | ViewGroup.LayoutParams.MATCH_PARENT);
424 | params.addRule(RelativeLayout.CENTER_IN_PARENT);
425 | container.addView(errorView, params);
426 | webViewClientWrapper.setErrorView(errorView);
427 | return this;
428 | }
429 |
430 | /**
431 | * 隐藏errorview
432 | */
433 | public void hideErrorView() {
434 | if (errorView != null) {
435 | errorView.setVisibility(GONE);
436 | }
437 | }
438 |
439 |
440 | @Override
441 | public void reload() {
442 | webViewClientWrapper.reset();
443 | hideErrorView();
444 | super.reload();
445 | }
446 |
447 | /**
448 | * 将dip或dp值转换为px值,保证尺寸大小不变
449 | */
450 | private int dip2px(Context context, float dipValue) {
451 | final float scale = context.getResources().getDisplayMetrics().density;
452 | return (int) (dipValue * scale + 0.5f);
453 | }
454 |
455 | /**
456 | * 设置是否支持JsBridge
457 | */
458 | public void setSupportJsBridge() {
459 | isSupportJsBridge = true;
460 | webViewClientWrapper.setSupportJsBridge();
461 | }
462 |
463 | /**
464 | * 设置是否支持自动缩放
465 | */
466 | public void setSupportAutoZoom() {
467 | WebSettings webSettings = getSettings();
468 | webSettings.setUseWideViewPort(true);//关键点
469 | webSettings.setLoadWithOverviewMode(true);
470 | webSettings.setBuiltInZoomControls(true);
471 | webSettings.setSupportZoom(true);
472 | }
473 |
474 | /**
475 | * 设置是否支持H5定位
476 | *