├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── jwkj │ │ └── demo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── jwkj │ │ │ └── demo │ │ │ ├── Main2Activity.java │ │ │ ├── MainActivity.java │ │ │ ├── MyApp.java │ │ │ ├── TranActivity.java │ │ │ └── runtimepermissions │ │ │ ├── Permissions.java │ │ │ ├── PermissionsManager.java │ │ │ └── PermissionsResultAction.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_main2.xml │ │ └── activity_tran.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── jwkj │ └── demo │ └── ExampleUnitTest.java ├── build.gradle ├── com_web.gif ├── commwebview_lib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── jwkj │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── comm_hdl_web_error.html │ │ ├── comm_hdl_web_error_us.html │ │ ├── net_error.html │ │ └── net_error_us.html │ ├── java │ │ └── com │ │ │ └── jwkj │ │ │ ├── CommWebView.java │ │ │ └── WebViewCallback.java │ └── res │ │ ├── values-zh-rCN │ │ └── strings.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── jwkj │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image.png ├── image_us.png ├── no_net_us.png ├── no_net_zh.png └── settings.gradle /README.md: -------------------------------------------------------------------------------- 1 | # CommWebView [![License](https://img.shields.io/badge/license-Apache%202-green.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![Download](https://api.bintray.com/packages/huangdali/jwkj/commwebview/images/download.svg) ](https://bintray.com/huangdali/jwkj/commwebview/_latestVersion) 2 | 通用webview 3 | - 避免API < 17 下的漏洞 4 | - 加载错误时出现默认页面 5 | - 点击默认页面可重新加载(刷新)--->两种错误提示页面 6 | - 方便获取当前在加载页面的url和title 7 | - 与js交互不变 8 | - 可设置背景透明 9 | 10 | ## 导入 11 | app/gradle中加入依赖 12 | 13 | ```java 14 | compile 'com.jwkj:commwebview:v1.2.6' 15 | ```` 16 | 17 | ## 用法 18 | 19 | ### 初始化并加载页面 20 | 21 | ```java 22 | wv_main = (CommWebView) findViewById(R.id.wv_main); 23 | wv_main.setCurWebUrl("https://www.baidu.com1") 24 | .addJavascriptInterface(new JSCallJava(), "NativeObj") 25 | .startCallback(new WebViewCallback() { 26 | @Override 27 | public void onStart() { 28 | ELog.e("开始调用了"); 29 | mProgressDialog.show(); 30 | } 31 | 32 | @Override 33 | public void onProgress(int curProgress) { 34 | ELog.e(curProgress); 35 | if (curProgress > 80) {//加载完成80%以上就可以隐藏了,防止部分网页不能 36 | mProgressDialog.dismiss(); 37 | tvTitle.setText(wv_main.getWebTitle()); 38 | } 39 | } 40 | 41 | @Override 42 | public void onError(int errorCode, String description, String failingUrl) { 43 | super.onError(errorCode, description, failingUrl); 44 | ELog.e(errorCode + " \t" + description + "\t" + failingUrl); 45 | } 46 | }); 47 | ``` 48 | 49 | ## 销毁 50 | 在avtivity销毁的时候需要将webview销毁 51 | 52 | ```java 53 | @Override 54 | protected void onDestroy() { 55 | wv_main.onDestroy(); 56 | super.onDestroy(); 57 | } 58 | ``` 59 | 60 | 效果图 61 | 62 | ![](https://github.com/huangdali/commwebview/blob/master/com_web.gif) 63 | 64 | 中文加载失败页面1(默认) 65 | 66 | 67 | ![](https://github.com/huangdali/commwebview/blob/master/no_net_zh.png) 68 | 69 | 中文加载失败页面2 70 | 71 | 72 | ![](https://github.com/huangdali/commwebview/blob/master/image.png) 73 | 74 | 英文加载失败页面1(默认) 75 | 76 | 77 | ![](https://github.com/huangdali/commwebview/blob/master/no_net_us.png) 78 | 79 | 英文加载失败页面2 80 | 81 | 82 | ![](https://github.com/huangdali/commwebview/blob/master/image_us.png) 83 | 84 | ## 版本记录 85 | 86 | v1.2.6 ( [2018.03.22]() ) 87 | 88 | - 【优化】适配Android8.0 89 | 90 | v1.2.5 ( [2018.01.25]() ) 91 | 92 | - 【优化】点击默认加载失败页面的刷新无效问题 93 | 94 | v1.2.4 ( [2017.11.23]() ) 95 | 96 | - 【优化】部分魅族手机崩溃问题 97 | 98 | v1.2.3 ( [2017.11.15]() ) 99 | 100 | - 【优化】删除清单文件中的appname,防止部分依赖时app名字被修改 101 | 102 | v1.2.2 ( [2017.11.08]() ) 103 | 104 | - 【新增】onPageFinished回调 105 | 106 | v1.2.1 ( [2017.10.25]() ) 107 | 108 | - 【新增】视频全屏与退出全屏监听 109 | 110 | v1.1.4 ( [2017.09.11]() ) 111 | 112 | - 【新增】网络错误默认页面,通过方法设置setNetErrorConfig(CommWebView.NetErrorConfig.DEFAULT_BUTTON);,默认是DEFAULT_BODY 113 | 114 | v1.1.2 ( [2017.09.08]() ) 115 | 116 | - 【修复】特殊情况抛出空指针 117 | 118 | v1.0.9 ( [2017.09.01]() ) 119 | 120 | - 【修复】中文环境无网络环境时的标题为英文 121 | 122 | v1.0.8 ( [2017.08.21]() ) 123 | 124 | - 【新增】设置是否背景透明方法setTransparent(默认不透明) 125 | 126 | v1.0.7 ( [2017.08.04]() ) 127 | - 【新增】evaluateJavascript方法 128 | - 【新增】获取原生WebView方法 129 | 130 | v1.0.6 131 | - 【修复】部分网页大不开 132 | 133 | v1.0.5 134 | - 【新增】英文版加载失败页面(带刷新功能) 135 | 136 | v1.0.4 137 | - 【新增】中文版加载失败页面(带刷新功能) 138 | 139 | v1.0.4 以前版本未记录 140 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.jwkj.demo" 8 | minSdkVersion 11 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile project(path: ':commwebview_lib') 28 | compile 'com.android.support:appcompat-v7:25.3.1' 29 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7' 30 | compile 'com.hdl:elog:v2.0.2' 31 | compile 'com.jwkj:CrashExceptioner:v2.0.3' 32 | testCompile 'junit:junit:4.12' 33 | } 34 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in F:\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/jwkj/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.jwkj.demo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.jwkj.commwebview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwkj/demo/Main2Activity.java: -------------------------------------------------------------------------------- 1 | package com.jwkj.demo; 2 | 3 | import android.content.pm.ActivityInfo; 4 | import android.content.res.Configuration; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.view.WindowManager; 9 | import android.webkit.WebChromeClient; 10 | import android.webkit.WebSettings; 11 | import android.webkit.WebView; 12 | import android.webkit.WebViewClient; 13 | import android.widget.FrameLayout; 14 | 15 | 16 | public class Main2Activity extends AppCompatActivity { 17 | private FrameLayout mFrameLayout; 18 | private WebView mWebView; 19 | private InsideWebChromeClient mInsideWebChromeClient; 20 | // private JavascriptInterface javascriptInterface; 21 | private String URL = "https://mobile.cloudlinks.cn/vas/pages/share-live/?liveId=7b7e44e3b79f11e7b1c100163e008337"; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | // 1 27 | // requestWindowFeature(Window.FEATURE_NO_TITLE); 28 | setContentView(R.layout.activity_main2); 29 | // 2 30 | mFrameLayout = (FrameLayout) findViewById(R.id.mFrameLayout); 31 | mWebView = (WebView) findViewById(R.id.mWebView); 32 | // 3 33 | initWebView(); 34 | mWebView.loadUrl(URL); 35 | } 36 | 37 | private void initWebView() { 38 | WebSettings settings = mWebView.getSettings(); 39 | settings.setJavaScriptEnabled(true); 40 | settings.setJavaScriptCanOpenWindowsAutomatically(true); 41 | settings.setPluginState(WebSettings.PluginState.ON); 42 | //settings.setPluginsEnabled(true); 43 | settings.setAllowFileAccess(true); 44 | settings.setLoadWithOverviewMode(true); 45 | settings.setUseWideViewPort(true); 46 | settings.setCacheMode(WebSettings.LOAD_NO_CACHE); 47 | settings.setCacheMode(WebSettings.LOAD_DEFAULT); 48 | mInsideWebChromeClient = new InsideWebChromeClient(); 49 | InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient(); 50 | // javascriptInterface = new JavascriptInterface(); 51 | // mWebView.addJavascriptInterface(javascriptInterface, "java2js_laole918"); 52 | mWebView.setWebChromeClient(mInsideWebChromeClient); 53 | mWebView.setWebViewClient(mInsideWebViewClient); 54 | } 55 | 56 | private class InsideWebChromeClient extends WebChromeClient { 57 | private View mCustomView; 58 | private CustomViewCallback mCustomViewCallback; 59 | 60 | @Override 61 | public void onShowCustomView(View view, CustomViewCallback callback) { 62 | super.onShowCustomView(view, callback); 63 | if (mCustomView != null) { 64 | callback.onCustomViewHidden(); 65 | return; 66 | } 67 | mCustomView = view; 68 | mFrameLayout.addView(mCustomView); 69 | mCustomViewCallback = callback; 70 | mWebView.setVisibility(View.GONE); 71 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 72 | } 73 | @Override 74 | public void onHideCustomView() { 75 | mWebView.setVisibility(View.VISIBLE); 76 | if (mCustomView == null) { 77 | return; 78 | } 79 | mCustomView.setVisibility(View.GONE); 80 | mFrameLayout.removeView(mCustomView); 81 | mCustomViewCallback.onCustomViewHidden(); 82 | mCustomView = null; 83 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 84 | super.onHideCustomView(); 85 | } 86 | } 87 | 88 | private class InsideWebViewClient extends WebViewClient { 89 | 90 | @Override 91 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 92 | // TODO Auto-generated method stub 93 | view.loadUrl(url); 94 | return true; 95 | } 96 | 97 | @Override 98 | public void onPageFinished(WebView view, String url) { 99 | super.onPageFinished(view, url); 100 | //mWebView.loadUrl(javascript); 101 | } 102 | 103 | } 104 | 105 | @Override 106 | public void onConfigurationChanged(Configuration config) { 107 | super.onConfigurationChanged(config); 108 | switch (config.orientation) { 109 | case Configuration.ORIENTATION_LANDSCAPE: 110 | getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); 111 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 112 | break; 113 | case Configuration.ORIENTATION_PORTRAIT: 114 | getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 115 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); 116 | break; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwkj/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jwkj.demo; 2 | 3 | import android.app.ProgressDialog; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.annotation.RequiresApi; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.KeyEvent; 9 | import android.view.View; 10 | import android.view.WindowManager; 11 | import android.widget.EditText; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | 15 | import com.hdl.elog.ELog; 16 | import com.jwkj.CommWebView; 17 | import com.jwkj.WebViewCallback; 18 | 19 | public class MainActivity extends AppCompatActivity { 20 | private CommWebView wv_main; 21 | private ProgressDialog mProgressDialog; 22 | private TextView tvTitle; 23 | private LinearLayout fl_full; 24 | private EditText etUrl; 25 | 26 | @RequiresApi(api = Build.VERSION_CODES.ECLAIR_MR1) 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 32 | mProgressDialog = new ProgressDialog(this); 33 | tvTitle = (TextView) findViewById(R.id.tv_title); 34 | mProgressDialog.setMessage("玩命加载中"); 35 | fl_full = (LinearLayout) findViewById(R.id.fl_full); 36 | etUrl = (EditText) findViewById(R.id.et_url); 37 | wv_main = (CommWebView) findViewById(R.id.wv_main); 38 | wv_main.setNetErrorConfig(CommWebView.NetErrorConfig.DEFAULT_BUTTON); 39 | wv_main.getWebview().getSettings().setDomStorageEnabled(true); 40 | // wv_main.setCurWebUrl("http://upg.cloudlinks.cn/demo/default.htm") 41 | wv_main.setCurWebUrl("http://39.108.193.125:8080/vas/") 42 | .startCallback(new WebViewCallback() { 43 | @Override 44 | public void onStart() { 45 | ELog.e("开始调用了"+wv_main.getCurWebUrl()); 46 | mProgressDialog.show(); 47 | } 48 | 49 | @Override 50 | public void onProgress(int curProgress) { 51 | ELog.e(curProgress); 52 | if (curProgress > 80) {//加载完成80%以上就可以隐藏了,防止部分网页不能 53 | mProgressDialog.dismiss(); 54 | tvTitle.setText(wv_main.getWebTitle()); 55 | } 56 | } 57 | 58 | @Override 59 | public void onError(int errorCode, String description, String failingUrl) { 60 | super.onError(errorCode, description, failingUrl); 61 | ELog.e(errorCode + " \t" + description + "\t" + failingUrl); 62 | } 63 | }); 64 | } 65 | 66 | /** 67 | * 监听返回键 68 | * 69 | * @param keyCode 70 | * @param event 71 | * @return 72 | */ 73 | @Override 74 | public boolean onKeyDown(int keyCode, KeyEvent event) { 75 | if (keyCode == KeyEvent.KEYCODE_BACK) { 76 | if (wv_main.canGoBack()) { 77 | wv_main.goBack();//返回上一个页面 78 | return true; 79 | } 80 | } 81 | return false; 82 | } 83 | 84 | @Override 85 | protected void onDestroy() { 86 | wv_main.onDestroy(); 87 | super.onDestroy(); 88 | } 89 | 90 | public void onGoUrl(View view) { 91 | String url = etUrl.getText().toString().trim(); 92 | wv_main.setCurWebUrl(url); 93 | wv_main.refresh();//需要调用刷新 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwkj/demo/MyApp.java: -------------------------------------------------------------------------------- 1 | package com.jwkj.demo; 2 | 3 | import android.app.Application; 4 | 5 | import com.hdl.CrashExceptioner; 6 | 7 | /** 8 | * Created by HDL on 2017/9/26. 9 | */ 10 | 11 | public class MyApp extends Application { 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | CrashExceptioner.init(this);//最好放在onCreate方法的最后 16 | //CrashExceptioner.setShowErrorDetails(false);//设置不显示详细错误按钮,默认为true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwkj/demo/TranActivity.java: -------------------------------------------------------------------------------- 1 | package com.jwkj.demo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.view.View; 6 | 7 | import com.jwkj.CommWebView; 8 | 9 | public class TranActivity extends FragmentActivity{ 10 | 11 | private CommWebView webView; 12 | private String url = "http://:8080/vas/pages/dialogs/"; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_tran); 18 | webView = (CommWebView) findViewById(R.id.cwv_view); 19 | webView.setTransparent(true); 20 | webView.setCurWebUrl(url); 21 | webView.refresh(); 22 | } 23 | boolean isTransparent=true; 24 | public void onDialog(View view) { 25 | isTransparent=!isTransparent; 26 | webView.setTransparent(isTransparent); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/jwkj/demo/runtimepermissions/Permissions.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Anthony Restaino 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | Unless required by applicable law or agreed to in writing, 9 | software distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | either express or implied. See the License for the specific language governing 12 | permissions and limitations under the License. 13 | */ 14 | package com.jwkj.demo.runtimepermissions; 15 | 16 | /** 17 | * Enum class to handle the different states 18 | * of permissions since the PackageManager only 19 | * has a granted and denied state. 20 | */ 21 | enum Permissions { 22 | GRANTED, 23 | DENIED, 24 | NOT_FOUND 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/jwkj/demo/runtimepermissions/PermissionsManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Anthony Restaino 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | Unless required by applicable law or agreed to in writing, 9 | software distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | either express or implied. See the License for the specific language governing 12 | permissions and limitations under the License. 13 | */ 14 | package com.jwkj.demo.runtimepermissions; 15 | 16 | import android.Manifest; 17 | import android.app.Activity; 18 | import android.content.Context; 19 | import android.content.pm.PackageInfo; 20 | import android.content.pm.PackageManager; 21 | import android.os.Build; 22 | import android.support.annotation.NonNull; 23 | import android.support.annotation.Nullable; 24 | import android.support.v4.app.ActivityCompat; 25 | import android.support.v4.app.Fragment; 26 | import android.util.Log; 27 | 28 | import java.lang.ref.WeakReference; 29 | import java.lang.reflect.Field; 30 | import java.util.ArrayList; 31 | import java.util.HashSet; 32 | import java.util.Iterator; 33 | import java.util.List; 34 | import java.util.Set; 35 | 36 | /** 37 | * A class to help you manage your permissions simply. 38 | */ 39 | public class PermissionsManager { 40 | 41 | private static final String TAG = PermissionsManager.class.getSimpleName(); 42 | 43 | private final Set mPendingRequests = new HashSet(1); 44 | private final Set mPermissions = new HashSet(1); 45 | private final List> mPendingActions = new ArrayList>(1); 46 | 47 | private static PermissionsManager mInstance = null; 48 | 49 | public static PermissionsManager getInstance() { 50 | if (mInstance == null) { 51 | mInstance = new PermissionsManager(); 52 | } 53 | return mInstance; 54 | } 55 | 56 | private PermissionsManager() { 57 | initializePermissionsMap(); 58 | } 59 | 60 | /** 61 | * This method uses reflection to read all the permissions in the Manifest class. 62 | * This is necessary because some permissions do not exist on older versions of Android, 63 | * since they do not exist, they will be denied when you check whether you have permission 64 | * which is problematic since a new permission is often added where there was no previous 65 | * permission required. We initialize a Set of available permissions and check the set 66 | * when checking if we have permission since we want to know when we are denied a permission 67 | * because it doesn't exist yet. 68 | */ 69 | private synchronized void initializePermissionsMap() { 70 | Field[] fields = Manifest.permission.class.getFields(); 71 | for (Field field : fields) { 72 | String name = null; 73 | try { 74 | name = (String) field.get(""); 75 | } catch (IllegalAccessException e) { 76 | Log.e(TAG, "Could not access field", e); 77 | } 78 | mPermissions.add(name); 79 | } 80 | } 81 | 82 | /** 83 | * This method retrieves all the permissions declared in the application's manifest. 84 | * It returns a non null array of permisions that can be declared. 85 | * 86 | * @param activity the Activity necessary to check what permissions we have. 87 | * @return a non null array of permissions that are declared in the application manifest. 88 | */ 89 | @NonNull 90 | private synchronized String[] getManifestPermissions(@NonNull final Activity activity) { 91 | PackageInfo packageInfo = null; 92 | List list = new ArrayList(1); 93 | try { 94 | Log.d(TAG, activity.getPackageName()); 95 | packageInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS); 96 | } catch (PackageManager.NameNotFoundException e) { 97 | Log.e(TAG, "A problem occurred when retrieving permissions", e); 98 | } 99 | if (packageInfo != null) { 100 | String[] permissions = packageInfo.requestedPermissions; 101 | if (permissions != null) { 102 | for (String perm : permissions) { 103 | Log.d(TAG, "Manifest contained permission: " + perm); 104 | list.add(perm); 105 | } 106 | } 107 | } 108 | return list.toArray(new String[list.size()]); 109 | } 110 | 111 | /** 112 | * This method adds the {@link PermissionsResultAction} to the current list 113 | * of pending actions that will be completed when the permissions are 114 | * received. The list of permissions passed to this method are registered 115 | * in the PermissionsResultAction object so that it will be notified of changes 116 | * made to these permissions. 117 | * 118 | * @param permissions the required permissions for the action to be executed. 119 | * @param action the action to add to the current list of pending actions. 120 | */ 121 | private synchronized void addPendingAction(@NonNull String[] permissions, 122 | @Nullable PermissionsResultAction action) { 123 | if (action == null) { 124 | return; 125 | } 126 | action.registerPermissions(permissions); 127 | mPendingActions.add(new WeakReference(action)); 128 | } 129 | 130 | /** 131 | * This method removes a pending action from the list of pending actions. 132 | * It is used for cases where the permission has already been granted, so 133 | * you immediately wish to remove the pending action from the queue and 134 | * execute the action. 135 | * 136 | * @param action the action to remove 137 | */ 138 | private synchronized void removePendingAction(@Nullable PermissionsResultAction action) { 139 | for (Iterator> iterator = mPendingActions.iterator(); 140 | iterator.hasNext(); ) { 141 | WeakReference weakRef = iterator.next(); 142 | if (weakRef.get() == action || weakRef.get() == null) { 143 | iterator.remove(); 144 | } 145 | } 146 | } 147 | 148 | /** 149 | * This static method can be used to check whether or not you have a specific permission. 150 | * It is basically a less verbose method of using {@link ActivityCompat#checkSelfPermission(Context, String)} 151 | * and will simply return a boolean whether or not you have the permission. If you pass 152 | * in a null Context object, it will return false as otherwise it cannot check the permission. 153 | * However, the Activity parameter is nullable so that you can pass in a reference that you 154 | * are not always sure will be valid or not (e.g. getActivity() from Fragment). 155 | * 156 | * @param context the Context necessary to check the permission 157 | * @param permission the permission to check 158 | * @return true if you have been granted the permission, false otherwise 159 | */ 160 | @SuppressWarnings("unused") 161 | public synchronized boolean hasPermission(@Nullable Context context, @NonNull String permission) { 162 | return context != null && (ActivityCompat.checkSelfPermission(context, permission) 163 | == PackageManager.PERMISSION_GRANTED || !mPermissions.contains(permission)); 164 | } 165 | 166 | /** 167 | * This static method can be used to check whether or not you have several specific permissions. 168 | * It is simpler than checking using {@link ActivityCompat#checkSelfPermission(Context, String)} 169 | * for each permission and will simply return a boolean whether or not you have all the permissions. 170 | * If you pass in a null Context object, it will return false as otherwise it cannot check the 171 | * permission. However, the Activity parameter is nullable so that you can pass in a reference 172 | * that you are not always sure will be valid or not (e.g. getActivity() from Fragment). 173 | * 174 | * @param context the Context necessary to check the permission 175 | * @param permissions the permissions to check 176 | * @return true if you have been granted all the permissions, false otherwise 177 | */ 178 | @SuppressWarnings("unused") 179 | public synchronized boolean hasAllPermissions(@Nullable Context context, @NonNull String[] permissions) { 180 | if (context == null) { 181 | return false; 182 | } 183 | boolean hasAllPermissions = true; 184 | for (String perm : permissions) { 185 | hasAllPermissions &= hasPermission(context, perm); 186 | } 187 | return hasAllPermissions; 188 | } 189 | 190 | /** 191 | * This method will request all the permissions declared in your application manifest 192 | * for the specified {@link PermissionsResultAction}. The purpose of this method is to enable 193 | * all permissions to be requested at one shot. The PermissionsResultAction is used to notify 194 | * you of the user allowing or denying each permission. The Activity and PermissionsResultAction 195 | * parameters are both annotated Nullable, but this method will not work if the Activity 196 | * is null. It is only annotated Nullable as a courtesy to prevent crashes in the case 197 | * that you call this from a Fragment where {@link Fragment#getActivity()} could yield 198 | * null. Additionally, you will not receive any notification of permissions being granted 199 | * if you provide a null PermissionsResultAction. 200 | * 201 | * @param activity the Activity necessary to request and check permissions. 202 | * @param action the PermissionsResultAction used to notify you of permissions being accepted. 203 | */ 204 | @SuppressWarnings("unused") 205 | public synchronized void requestAllManifestPermissionsIfNecessary(final @Nullable Activity activity, 206 | final @Nullable PermissionsResultAction action) { 207 | if (activity == null) { 208 | return; 209 | } 210 | String[] perms = getManifestPermissions(activity); 211 | requestPermissionsIfNecessaryForResult(activity, perms, action); 212 | } 213 | 214 | /** 215 | * This method should be used to execute a {@link PermissionsResultAction} for the array 216 | * of permissions passed to this method. This method will request the permissions if 217 | * they need to be requested (i.e. we don't have permission yet) and will add the 218 | * PermissionsResultAction to the queue to be notified of permissions being granted or 219 | * denied. In the case of pre-Android Marshmallow, permissions will be granted immediately. 220 | * The Activity variable is nullable, but if it is null, the method will fail to execute. 221 | * This is only nullable as a courtesy for Fragments where getActivity() may yeild null 222 | * if the Fragment is not currently added to its parent Activity. 223 | * 224 | * @param activity the activity necessary to request the permissions. 225 | * @param permissions the list of permissions to request for the {@link PermissionsResultAction}. 226 | * @param action the PermissionsResultAction to notify when the permissions are granted or denied. 227 | */ 228 | @SuppressWarnings("unused") 229 | public synchronized void requestPermissionsIfNecessaryForResult(@Nullable Activity activity, 230 | @NonNull String[] permissions, 231 | @Nullable PermissionsResultAction action) { 232 | if (activity == null) { 233 | return; 234 | } 235 | addPendingAction(permissions, action); 236 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 237 | doPermissionWorkBeforeAndroidM(activity, permissions, action); 238 | } else { 239 | List permList = getPermissionsListToRequest(activity, permissions, action); 240 | if (permList.isEmpty()) { 241 | //if there is no permission to request, there is no reason to keep the action int the list 242 | removePendingAction(action); 243 | } else { 244 | String[] permsToRequest = permList.toArray(new String[permList.size()]); 245 | mPendingRequests.addAll(permList); 246 | ActivityCompat.requestPermissions(activity, permsToRequest, 1); 247 | } 248 | } 249 | } 250 | 251 | /** 252 | * This method should be used to execute a {@link PermissionsResultAction} for the array 253 | * of permissions passed to this method. This method will request the permissions if 254 | * they need to be requested (i.e. we don't have permission yet) and will add the 255 | * PermissionsResultAction to the queue to be notified of permissions being granted or 256 | * denied. In the case of pre-Android Marshmallow, permissions will be granted immediately. 257 | * The Fragment variable is used, but if {@link Fragment#getActivity()} returns null, this method 258 | * will fail to work as the activity reference is necessary to check for permissions. 259 | * 260 | * @param fragment the fragment necessary to request the permissions. 261 | * @param permissions the list of permissions to request for the {@link PermissionsResultAction}. 262 | * @param action the PermissionsResultAction to notify when the permissions are granted or denied. 263 | */ 264 | @SuppressWarnings("unused") 265 | public synchronized void requestPermissionsIfNecessaryForResult(@NonNull Fragment fragment, 266 | @NonNull String[] permissions, 267 | @Nullable PermissionsResultAction action) { 268 | Activity activity = fragment.getActivity(); 269 | if (activity == null) { 270 | return; 271 | } 272 | addPendingAction(permissions, action); 273 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 274 | doPermissionWorkBeforeAndroidM(activity, permissions, action); 275 | } else { 276 | List permList = getPermissionsListToRequest(activity, permissions, action); 277 | if (permList.isEmpty()) { 278 | //if there is no permission to request, there is no reason to keep the action int the list 279 | removePendingAction(action); 280 | } else { 281 | String[] permsToRequest = permList.toArray(new String[permList.size()]); 282 | mPendingRequests.addAll(permList); 283 | fragment.requestPermissions(permsToRequest, 1); 284 | } 285 | } 286 | } 287 | 288 | /** 289 | * This method notifies the PermissionsManager that the permissions have change. If you are making 290 | * the permissions requests using an Activity, then this method should be called from the 291 | * Activity callback onRequestPermissionsResult() with the variables passed to that method. If 292 | * you are passing a Fragment to make the permissions request, then you should call this in 293 | * the {@link Fragment#onRequestPermissionsResult(int, String[], int[])} method. 294 | * It will notify all the pending PermissionsResultAction objects currently 295 | * in the queue, and will remove the permissions request from the list of pending requests. 296 | * 297 | * @param permissions the permissions that have changed. 298 | * @param results the values for each permission. 299 | */ 300 | @SuppressWarnings("unused") 301 | public synchronized void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) { 302 | int size = permissions.length; 303 | if (results.length < size) { 304 | size = results.length; 305 | } 306 | Iterator> iterator = mPendingActions.iterator(); 307 | while (iterator.hasNext()) { 308 | PermissionsResultAction action = iterator.next().get(); 309 | for (int n = 0; n < size; n++) { 310 | if (action == null || action.onResult(permissions[n], results[n])) { 311 | iterator.remove(); 312 | break; 313 | } 314 | } 315 | } 316 | for (int n = 0; n < size; n++) { 317 | mPendingRequests.remove(permissions[n]); 318 | } 319 | } 320 | 321 | /** 322 | * When request permissions on devices before Android M (Android 6.0, API Level 23) 323 | * Do the granted or denied work directly according to the permission status 324 | * 325 | * @param activity the activity to check permissions 326 | * @param permissions the permissions names 327 | * @param action the callback work object, containing what we what to do after 328 | * permission check 329 | */ 330 | private void doPermissionWorkBeforeAndroidM(@NonNull Activity activity, 331 | @NonNull String[] permissions, 332 | @Nullable PermissionsResultAction action) { 333 | for (String perm : permissions) { 334 | if (action != null) { 335 | if (!mPermissions.contains(perm)) { 336 | action.onResult(perm, Permissions.NOT_FOUND); 337 | } else if (ActivityCompat.checkSelfPermission(activity, perm) 338 | != PackageManager.PERMISSION_GRANTED) { 339 | action.onResult(perm, Permissions.DENIED); 340 | } else { 341 | action.onResult(perm, Permissions.GRANTED); 342 | } 343 | } 344 | } 345 | } 346 | 347 | /** 348 | * Filter the permissions list: 349 | * If a permission is not granted, add it to the result list 350 | * if a permission is granted, do the granted work, do not add it to the result list 351 | * 352 | * @param activity the activity to check permissions 353 | * @param permissions all the permissions names 354 | * @param action the callback work object, containing what we what to do after 355 | * permission check 356 | * @return a list of permissions names that are not granted yet 357 | */ 358 | @NonNull 359 | private List getPermissionsListToRequest(@NonNull Activity activity, 360 | @NonNull String[] permissions, 361 | @Nullable PermissionsResultAction action) { 362 | List permList = new ArrayList(permissions.length); 363 | for (String perm : permissions) { 364 | if (!mPermissions.contains(perm)) { 365 | if (action != null) { 366 | action.onResult(perm, Permissions.NOT_FOUND); 367 | } 368 | } else if (ActivityCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) { 369 | if (!mPendingRequests.contains(perm)) { 370 | permList.add(perm); 371 | } 372 | } else { 373 | if (action != null) { 374 | action.onResult(perm, Permissions.GRANTED); 375 | } 376 | } 377 | } 378 | return permList; 379 | } 380 | 381 | } -------------------------------------------------------------------------------- /app/src/main/java/com/jwkj/demo/runtimepermissions/PermissionsResultAction.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Anthony Restaino 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | Unless required by applicable law or agreed to in writing, 9 | software distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | either express or implied. See the License for the specific language governing 12 | permissions and limitations under the License. 13 | */ 14 | package com.jwkj.demo.runtimepermissions; 15 | 16 | import android.content.pm.PackageManager; 17 | import android.os.Handler; 18 | import android.os.Looper; 19 | import android.support.annotation.CallSuper; 20 | import android.support.annotation.NonNull; 21 | import android.util.Log; 22 | 23 | import java.util.Collections; 24 | import java.util.HashSet; 25 | import java.util.Set; 26 | 27 | /** 28 | * This abstract class should be used to create an if/else action that the PermissionsManager 29 | * can execute when the permissions you request are granted or denied. Simple use involves 30 | * creating an anonymous instance of it and passing that instance to the 31 | * requestPermissionsIfNecessaryForResult method. The result will be sent back to you as 32 | * either onGranted (all permissions have been granted), or onDenied (a required permission 33 | * has been denied). Ideally you put your functionality in the onGranted method and notify 34 | * the user what won't work in the onDenied method. 35 | */ 36 | public abstract class PermissionsResultAction { 37 | 38 | private static final String TAG = PermissionsResultAction.class.getSimpleName(); 39 | private final Set mPermissions = new HashSet(1); 40 | private Looper mLooper = Looper.getMainLooper(); 41 | 42 | /** 43 | * Default Constructor 44 | */ 45 | public PermissionsResultAction() {} 46 | 47 | /** 48 | * Alternate Constructor. Pass the looper you wish the PermissionsResultAction 49 | * callbacks to be executed on if it is not the current Looper. For instance, 50 | * if you are making a permissions request from a background thread but wish the 51 | * callback to be on the UI thread, use this constructor to specify the UI Looper. 52 | * 53 | * @param looper the looper that the callbacks will be called using. 54 | */ 55 | @SuppressWarnings("unused") 56 | public PermissionsResultAction(@NonNull Looper looper) {mLooper = looper;} 57 | 58 | /** 59 | * This method is called when ALL permissions that have been 60 | * requested have been granted by the user. In this method 61 | * you should put all your permissions sensitive code that can 62 | * only be executed with the required permissions. 63 | */ 64 | public abstract void onGranted(); 65 | 66 | /** 67 | * This method is called when a permission has been denied by 68 | * the user. It provides you with the permission that was denied 69 | * and will be executed on the Looper you pass to the constructor 70 | * of this class, or the Looper that this object was created on. 71 | * 72 | * @param permission the permission that was denied. 73 | */ 74 | public abstract void onDenied(String permission); 75 | 76 | /** 77 | * This method is used to determine if a permission not 78 | * being present on the current Android platform should 79 | * affect whether the PermissionsResultAction should continue 80 | * listening for events. By default, it returns true and will 81 | * simply ignore the permission that did not exist. Usually this will 82 | * work fine since most new permissions are introduced to 83 | * restrict what was previously allowed without permission. 84 | * If that is not the case for your particular permission you 85 | * request, override this method and return false to result in the 86 | * Action being denied. 87 | * 88 | * @param permission the permission that doesn't exist on this 89 | * Android version 90 | * @return return true if the PermissionsResultAction should 91 | * ignore the lack of the permission and proceed with exection 92 | * or false if the PermissionsResultAction should treat the 93 | * absence of the permission on the API level as a denial. 94 | */ 95 | @SuppressWarnings({"WeakerAccess", "SameReturnValue"}) 96 | public synchronized boolean shouldIgnorePermissionNotFound(String permission) { 97 | Log.d(TAG, "Permission not found: " + permission); 98 | return true; 99 | } 100 | 101 | @SuppressWarnings("WeakerAccess") 102 | @CallSuper 103 | protected synchronized final boolean onResult(final @NonNull String permission, int result) { 104 | if (result == PackageManager.PERMISSION_GRANTED) { 105 | return onResult(permission, Permissions.GRANTED); 106 | } else { 107 | return onResult(permission, Permissions.DENIED); 108 | } 109 | 110 | } 111 | 112 | /** 113 | * This method is called when a particular permission has changed. 114 | * This method will be called for all permissions, so this method determines 115 | * if the permission affects the state or not and whether it can proceed with 116 | * calling onGranted or if onDenied should be called. 117 | * 118 | * @param permission the permission that changed. 119 | * @param result the result for that permission. 120 | * @return this method returns true if its primary action has been completed 121 | * and it should be removed from the data structure holding a reference to it. 122 | */ 123 | @SuppressWarnings("WeakerAccess") 124 | @CallSuper 125 | protected synchronized final boolean onResult(final @NonNull String permission, Permissions result) { 126 | mPermissions.remove(permission); 127 | if (result == Permissions.GRANTED) { 128 | if (mPermissions.isEmpty()) { 129 | new Handler(mLooper).post(new Runnable() { 130 | @Override 131 | public void run() { 132 | onGranted(); 133 | } 134 | }); 135 | return true; 136 | } 137 | } else if (result == Permissions.DENIED) { 138 | new Handler(mLooper).post(new Runnable() { 139 | @Override 140 | public void run() { 141 | onDenied(permission); 142 | } 143 | }); 144 | return true; 145 | } else if (result == Permissions.NOT_FOUND) { 146 | if (shouldIgnorePermissionNotFound(permission)) { 147 | if (mPermissions.isEmpty()) { 148 | new Handler(mLooper).post(new Runnable() { 149 | @Override 150 | public void run() { 151 | onGranted(); 152 | } 153 | }); 154 | return true; 155 | } 156 | } else { 157 | new Handler(mLooper).post(new Runnable() { 158 | @Override 159 | public void run() { 160 | onDenied(permission); 161 | } 162 | }); 163 | return true; 164 | } 165 | } 166 | return false; 167 | } 168 | 169 | /** 170 | * This method registers the PermissionsResultAction object for the specified permissions 171 | * so that it will know which permissions to look for changes to. The PermissionsResultAction 172 | * will then know to look out for changes to these permissions. 173 | * 174 | * @param perms the permissions to listen for 175 | */ 176 | @SuppressWarnings("WeakerAccess") 177 | @CallSuper 178 | protected synchronized final void registerPermissions(@NonNull String[] perms) { 179 | Collections.addAll(mPermissions, perms); 180 | } 181 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 25 | 26 | 28 | 29 | 30 | 38 | 39 | -------------------------------------------------------------------------------- /commwebview_lib/src/main/assets/net_error_us.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | Network error 11 | 12 | 19 | 20 | 21 |
22 |
24 |
25 |

Network error, please click the button to reload

26 |
27 | 28 |
29 |
30 | 38 | 39 | -------------------------------------------------------------------------------- /commwebview_lib/src/main/java/com/jwkj/CommWebView.java: -------------------------------------------------------------------------------- 1 | package com.jwkj; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Color; 8 | import android.net.ConnectivityManager; 9 | import android.net.NetworkInfo; 10 | import android.net.http.SslError; 11 | import android.os.Build; 12 | import android.text.TextUtils; 13 | import android.util.AttributeSet; 14 | import android.view.View; 15 | import android.view.ViewGroup; 16 | import android.webkit.JavascriptInterface; 17 | import android.webkit.SslErrorHandler; 18 | import android.webkit.ValueCallback; 19 | import android.webkit.WebChromeClient; 20 | import android.webkit.WebSettings; 21 | import android.webkit.WebView; 22 | import android.webkit.WebViewClient; 23 | import android.widget.LinearLayout; 24 | 25 | 26 | /** 27 | * 通用webview 28 | * Created by HDL on 2017/6/23. 29 | * 30 | * @author hdl 31 | */ 32 | 33 | public class CommWebView extends LinearLayout { 34 | /** 35 | * 是否可以返回上一个页面,默认可以返回上一个页面 36 | */ 37 | private boolean isCanBack = true; 38 | /** 39 | * 当前网页的标题 40 | */ 41 | private String webTitle = ""; 42 | /** 43 | * 当前url 44 | */ 45 | private String curWebUrl = ""; 46 | /** 47 | * 回调器 48 | */ 49 | private WebViewCallback callback; 50 | /** 51 | * 采用addview(webview)的方式添加到线性布局,可以及时销毁webview 52 | */ 53 | private WebView webview; 54 | 55 | private Context context; 56 | /** 57 | * 是否背景透明 58 | */ 59 | private boolean isTransparent = false; 60 | /** 61 | * 网络加载出错时显示的界面,默认NetErrorConfig.DEFAULT_BODY 62 | */ 63 | private NetErrorConfig netErrorConfig = NetErrorConfig.DEFAULT_BODY; 64 | 65 | public CommWebView(Context context) { 66 | this(context, null); 67 | } 68 | 69 | public CommWebView(Context context, AttributeSet attrs) { 70 | this(context, attrs, 0); 71 | } 72 | 73 | public CommWebView(Context context, AttributeSet attrs, int defStyle) { 74 | super(context, attrs, defStyle); 75 | setLayerType(View.LAYER_TYPE_SOFTWARE, null); 76 | this.context = context; 77 | initConfig(context); 78 | } 79 | 80 | /** 81 | * 判断网络是否可用网络状态 82 | * 83 | * @param context 84 | * @return 85 | */ 86 | public boolean isNetworkConnected(Context context) { 87 | if (context != null) { 88 | ConnectivityManager mConnectivityManager = (ConnectivityManager) context 89 | .getSystemService(Context.CONNECTIVITY_SERVICE); 90 | NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); 91 | if (mNetworkInfo != null) { 92 | return mNetworkInfo.isAvailable(); 93 | } 94 | } 95 | return false; 96 | } 97 | 98 | /** 99 | * 初始化参数配置 100 | * 101 | * @param context 102 | */ 103 | private void initConfig(final Context context) { 104 | webview = new WebView(context.getApplicationContext()); 105 | transparent(); 106 | WebSettings settings = webview.getSettings(); 107 | settings.setJavaScriptCanOpenWindowsAutomatically(true); 108 | settings.setPluginState(WebSettings.PluginState.ON); 109 | settings.setAllowFileAccess(true); 110 | settings.setLoadWithOverviewMode(true); 111 | settings.setDomStorageEnabled(true); 112 | settings.setUseWideViewPort(true); 113 | settings.setSupportMultipleWindows(true);// 新加 114 | //开启硬件加速 115 | this.setLayerType(View.LAYER_TYPE_HARDWARE, null); 116 | webview.setLayerType(View.LAYER_TYPE_HARDWARE, null); 117 | settings.setJavaScriptEnabled(true);//设置是否支持与js互相调用 118 | settings.setCacheMode(WebSettings.LOAD_NO_CACHE);//不使用网络缓存,开启的话容易导致app膨胀导致卡顿 119 | webview.setWebViewClient(new WebViewClient() {//设置webviewclient,使其不会由第三方浏览器打开新的url 120 | 121 | @Override 122 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 123 | if (shouldLoadingUrl()) { 124 | loadWebUrl(url); 125 | return true; 126 | } 127 | return false;//设置为false才有效哦 128 | } 129 | 130 | public boolean shouldLoadingUrl() { 131 | /** 132 | * 低于android 8.0的需要手动loadURL,大于等于android 8.0直接返回false,否则无法重定向 133 | */ 134 | return Build.VERSION.SDK_INT < 26; 135 | } 136 | 137 | @Override 138 | public void onPageStarted(WebView view, String url, Bitmap favicon) { 139 | if (callback != null) { 140 | callback.onStart(); 141 | } 142 | } 143 | 144 | @Override 145 | public void onPageFinished(WebView view, String url) { 146 | super.onPageFinished(view, url); 147 | webTitle = view.getTitle(); 148 | if (callback != null) { 149 | callback.onPageFinished(); 150 | } 151 | } 152 | 153 | @Override 154 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { 155 | super.onReceivedError(view, errorCode, description, failingUrl); 156 | if (NetErrorConfig.DEFAULT_BODY.equals(netErrorConfig)) { 157 | webview.loadUrl(context.getResources().getString(R.string.comm_hdl_web_url_default)); 158 | } else { 159 | webview.loadUrl(context.getResources().getString(R.string.comm_hdl_web_url_default2)); 160 | } 161 | if (callback != null) { 162 | callback.onError(errorCode, description, failingUrl); 163 | } 164 | } 165 | 166 | @Override 167 | public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 168 | super.onReceivedSslError(view, handler, error); 169 | handler.proceed();//接受证书 170 | } 171 | }); 172 | webview.setWebChromeClient(new WebChromeClient() {//监听加载的过程 173 | private View mCustomView; 174 | private CustomViewCallback mCustomViewCallback; 175 | 176 | /** 177 | * 显示自定义视图,无此方法视频不能播放 178 | */ 179 | @Override 180 | public void onShowCustomView(View view, CustomViewCallback callback) { 181 | super.onShowCustomView(view, callback); 182 | ViewGroup parent = (ViewGroup) webview.getParent(); 183 | parent.removeView(webview); 184 | // 设置背景色为黑色 185 | view.setBackgroundColor(Color.BLACK); 186 | parent.addView(view); 187 | if (onVedioFullScreenListener != null) { 188 | onVedioFullScreenListener.onSetFullScreen(); 189 | } 190 | if (mCustomView != null) { 191 | callback.onCustomViewHidden(); 192 | return; 193 | } 194 | mCustomView = view; 195 | mCustomViewCallback = callback; 196 | } 197 | 198 | @Override 199 | public void onHideCustomView() { 200 | super.onHideCustomView(); 201 | webview.setVisibility(View.VISIBLE); 202 | if (mCustomView == null) { 203 | return; 204 | } 205 | ViewGroup parent = (ViewGroup) mCustomView.getParent(); 206 | parent.removeView(mCustomView); 207 | parent.addView(webview); 208 | mCustomView.setVisibility(View.GONE); 209 | mCustomViewCallback.onCustomViewHidden(); 210 | mCustomView = null; 211 | if (onVedioFullScreenListener != null) { 212 | onVedioFullScreenListener.onQuitFullScreen(); 213 | } 214 | } 215 | 216 | @Override 217 | public void onProgressChanged(WebView view, int newProgress) { 218 | if (!"file:".equals(view.getUrl().substring(0, 5))) { 219 | curWebUrl = view.getUrl(); 220 | } 221 | webTitle = view.getTitle(); 222 | if (callback != null) { 223 | callback.onProgress(newProgress); 224 | } 225 | } 226 | 227 | }); 228 | setVisibility(View.VISIBLE); 229 | requestFocus();//请求获取焦点,防止view不能打开输入法问题 230 | requestFocusFromTouch();//请求获取焦点,防止view不能打开输入法问题 231 | setOrientation(LinearLayout.VERTICAL); 232 | LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 233 | webview.setLayoutParams(params); 234 | webview.addJavascriptInterface(new JSCallJava(), "NativeObj"); 235 | // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {//3.0以上暂时关闭硬件加速 236 | // webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 237 | // } 238 | /** 239 | * Webview在安卓5.0之前默认允许其加载混合网络协议内容 240 | * 在安卓5.0之后,默认不允许加载http与https混合内容,需要设置webview允许其加载混合网络协议内容 241 | */ 242 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 243 | webview.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); 244 | 245 | } 246 | addView(webview); 247 | } 248 | 249 | private void transparent() { 250 | if (isTransparent) { 251 | webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 252 | setBackgroundColor(0); 253 | webview.setBackgroundColor(0); 254 | setLayerType(View.LAYER_TYPE_SOFTWARE, null); 255 | } 256 | } 257 | 258 | public void setTransparent(boolean transparent) { 259 | isTransparent = transparent; 260 | transparent(); 261 | } 262 | 263 | public void setNetErrorConfig(NetErrorConfig netErrorConfig) { 264 | this.netErrorConfig = netErrorConfig; 265 | } 266 | 267 | /** 268 | * 销毁当前的页面 269 | */ 270 | public void onDestroy() { 271 | if (webview != null) { 272 | webview.removeAllViews(); 273 | try { 274 | webview.destroy(); 275 | } catch (Throwable t) { 276 | } 277 | webview = null; 278 | } 279 | curWebUrl = ""; 280 | } 281 | 282 | /** 283 | * 开始回调 284 | * 285 | * @param callback 286 | */ 287 | public CommWebView startCallback(WebViewCallback callback) { 288 | this.callback = callback; 289 | if (isNetworkConnected(context)) { 290 | loadWebUrl(curWebUrl); 291 | } else { 292 | if (NetErrorConfig.DEFAULT_BODY.equals(netErrorConfig)) { 293 | webview.loadUrl(context.getResources().getString(R.string.comm_hdl_web_url_default)); 294 | } else { 295 | webview.loadUrl(context.getResources().getString(R.string.comm_hdl_web_url_default2)); 296 | } 297 | if (callback != null) { 298 | callback.onError(202, "No Netwark", curWebUrl); 299 | } 300 | } 301 | return this; 302 | } 303 | 304 | /** 305 | * 判断是否可以返回上一个页面 306 | * 307 | * @return 308 | */ 309 | public boolean isCanBack() { 310 | return isCanBack; 311 | } 312 | 313 | /** 314 | * 设置是否可以返回上一个页面 315 | * 316 | * @param canBack 317 | */ 318 | public CommWebView setCanBack(boolean canBack) { 319 | isCanBack = canBack; 320 | return this; 321 | } 322 | 323 | /** 324 | * 获取webview 325 | * 326 | * @return 327 | */ 328 | public WebView getWebview() { 329 | return webview; 330 | } 331 | 332 | /** 333 | * 执行js代码 334 | * 335 | * @param js 336 | * @param callback 337 | */ 338 | public void evaluateJavascript(String js, ValueCallback callback) { 339 | if (webview != null) { 340 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 341 | webview.evaluateJavascript(js, callback); 342 | } 343 | } 344 | } 345 | 346 | public String getCurWebUrl() { 347 | return curWebUrl; 348 | } 349 | 350 | /** 351 | * 设置当前需要加载的url 352 | * 353 | * @param curWebUrl 354 | */ 355 | public CommWebView setCurWebUrl(String curWebUrl) { 356 | this.curWebUrl = curWebUrl; 357 | return this; 358 | } 359 | 360 | public String getWebTitle() { 361 | return webTitle; 362 | } 363 | 364 | /** 365 | * 加载网页 366 | * 367 | * @param url 368 | */ 369 | private CommWebView loadWebUrl(String url) { 370 | if (!TextUtils.isEmpty(url)) { 371 | curWebUrl = url;//记录当前的url 372 | if (webview != null) { 373 | webview.loadUrl(curWebUrl);//webview加载url 374 | } 375 | } 376 | return this; 377 | } 378 | 379 | /** 380 | * 判断是否可以返回上一个页面 381 | * 382 | * @return 383 | */ 384 | public boolean canGoBack() { 385 | return webview.canGoBack(); 386 | } 387 | 388 | /** 389 | * 返回到上一个页面 390 | */ 391 | public void goBack() { 392 | webview.goBack(); 393 | } 394 | 395 | /** 396 | * 添加js与java互相调用类. 397 | *

398 | * SuppressLint("JavascriptInterface") 表示webview的修复漏洞 399 | * 400 | * @param mapClazz js方法与java方法映射类 401 | * @param objName 对象的名字 402 | */ 403 | @SuppressLint("JavascriptInterface") 404 | public CommWebView addJavascriptInterface(Object mapClazz, String objName) { 405 | webview.addJavascriptInterface(mapClazz, objName); 406 | return this; 407 | } 408 | 409 | /** 410 | * 刷新 411 | */ 412 | public void refresh() { 413 | loadWebUrl(curWebUrl); 414 | } 415 | 416 | public class JSCallJava { 417 | @JavascriptInterface 418 | public void refreshPager() { 419 | if (context != null) { 420 | /** 421 | * 4.4以上的webview,需要在子线程中调用js与java互相调用的代码 422 | */ 423 | ((Activity) context).runOnUiThread(new Runnable() { 424 | @Override 425 | public void run() { 426 | if (isNetworkConnected(context)) { 427 | refresh(); 428 | } else { 429 | if (NetErrorConfig.DEFAULT_BODY.equals(netErrorConfig)) { 430 | webview.loadUrl(context.getResources().getString(R.string.comm_hdl_web_url_default)); 431 | } else { 432 | webview.loadUrl(context.getResources().getString(R.string.comm_hdl_web_url_default2)); 433 | } 434 | if (callback != null) { 435 | callback.onError(202, "No Netwark", curWebUrl); 436 | } 437 | } 438 | } 439 | }); 440 | } 441 | } 442 | } 443 | 444 | /** 445 | * 网络错误页. 446 | * DEFAULT_BODY-->点击body刷新(默认) 447 | * DEFAULT_BUTTON-->点击按钮刷新 448 | */ 449 | public enum NetErrorConfig { 450 | /** 451 | * 默认加载失败页面,点击body刷新 452 | */ 453 | DEFAULT_BODY, 454 | /** 455 | * 点击按钮刷新 456 | */ 457 | DEFAULT_BUTTON 458 | } 459 | 460 | private OnVedioFullScreenListener onVedioFullScreenListener; 461 | 462 | public void setOnVedioFullScreenListener(OnVedioFullScreenListener onVedioFullScreenListener) { 463 | this.onVedioFullScreenListener = onVedioFullScreenListener; 464 | } 465 | 466 | public interface OnVedioFullScreenListener { 467 | void onSetFullScreen(); 468 | 469 | void onQuitFullScreen(); 470 | } 471 | 472 | } 473 | -------------------------------------------------------------------------------- /commwebview_lib/src/main/java/com/jwkj/WebViewCallback.java: -------------------------------------------------------------------------------- 1 | package com.jwkj; 2 | 3 | /** 4 | * webview回调 5 | * Created by HDL on 2017/6/23. 6 | */ 7 | 8 | public abstract class WebViewCallback { 9 | /** 10 | * 开始加载的时候调用 11 | */ 12 | public void onStart() { 13 | } 14 | 15 | /** 16 | * 加载进度回调 17 | * 18 | * @param curProgress 当前进度值[0,100] 19 | */ 20 | public void onProgress(int curProgress) { 21 | } 22 | 23 | /** 24 | * 加载错误的时候会回调 25 | * 26 | * @param errorCode 错误码 27 | * @param description 描述 28 | * @param failingUrl 加载失败的url 29 | */ 30 | public void onError(int errorCode, String description, String failingUrl) { 31 | } 32 | 33 | /** 34 | * 当页面加载完成的时候,此方法不靠谱,如果页面有跳转会回调多次 35 | */ 36 | public void onPageFinished() { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /commwebview_lib/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | CommWebView 4 | file:///android_asset/comm_hdl_web_error.html 5 | file:///android_asset/net_error.html 6 | 7 | -------------------------------------------------------------------------------- /commwebview_lib/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | CommWebView 4 | file:///android_asset/comm_hdl_web_error_us.html 5 | file:///android_asset/net_error_us.html 6 | 7 | -------------------------------------------------------------------------------- /commwebview_lib/src/test/java/com/jwkj/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.jwkj; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdali/CommWebView/249e8b26cc22bf15bc9b23f603e8f8ef31b1d40d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Feb 26 10:23:26 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdali/CommWebView/249e8b26cc22bf15bc9b23f603e8f8ef31b1d40d/image.png -------------------------------------------------------------------------------- /image_us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdali/CommWebView/249e8b26cc22bf15bc9b23f603e8f8ef31b1d40d/image_us.png -------------------------------------------------------------------------------- /no_net_us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdali/CommWebView/249e8b26cc22bf15bc9b23f603e8f8ef31b1d40d/no_net_us.png -------------------------------------------------------------------------------- /no_net_zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangdali/CommWebView/249e8b26cc22bf15bc9b23f603e8f8ef31b1d40d/no_net_zh.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':commwebview_lib' 2 | --------------------------------------------------------------------------------