CommonWebView.java
· 7.4 KiB · Java
Raw
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.webkit.*;
import android.widget.EditText;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import java.io.Serializable;
import java.util.Locale;
/**
* Created by hp on 2017/8/31.
* 通用WebView
*/
public class CommonWebView extends WebView implements Serializable {
private static String tag = "CommonWebView";
private static boolean DEBUG = false;
public CommonWebView(Context context) {
this(context, null);
}
public CommonWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CommonWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
// Generic
setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
setVerticalScrollBarEnabled(false);
setHorizontalScrollBarEnabled(false);
// WebSettings
WebSettings settings = this.getSettings();
settings.setDefaultTextEncodingName("utf-8");
settings.setJavaScriptEnabled(true);//支持js
settings.setDomStorageEnabled(true);
settings.setLoadsImagesAutomatically(true);
setWebViewClient(new DefaultWebViewClient(getContext()));
setWebChromeClient(new DefaultWebChromeClient());
}
@Override
public WebSettings getSettings() {
return super.getSettings();
}
/**
* @param object 供JS调用的实例
* @param name 内部写定为 {@code "android"}
*/
@SuppressLint("JavascriptInterface")
@Override
public void addJavascriptInterface(Object object, String name) {
super.addJavascriptInterface(object, name);
}
public void registerJSO(Object object) {
addJavascriptInterface(object, "android");
}
@Override
public void loadUrl(String url) {
super.loadUrl(url);
System.out.println("loadUrl=" + url);
}
@Override
public void goBack() {
if (canGoBack()) {
super.goBack();
}
}
@Override
public void goForward() {
if (canGoForward()) {
super.goForward();
}
}
@Override
public void goBackOrForward(int steps) {
super.goBackOrForward(steps);
}
public void setDebug(boolean isDebug) {
DEBUG = isDebug;
}
public static class DefaultWebViewClient extends WebViewClient {
private Context context;
public DefaultWebViewClient(@NonNull Context context) {
this.context = context;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
// New API
// 拦截'tel:'链接
String targetUrl = request.getUrl().getScheme();
if (matchSchemes(targetUrl) && context != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
context.startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, request);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String targetUrl) {
// Old API
// 拦截'tel:'链接
if (matchSchemes(targetUrl) && context != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(targetUrl));
context.startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, targetUrl);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
String msg = "onReceivedError api-old";
msg += String.format(
Locale.CHINESE,
": (%d) %s, %s",
errorCode,
failingUrl,
description
);
if (DEBUG) Log.e(tag, msg);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
String msg = "onReceivedError api-new";
if (Build.VERSION.SDK_INT >= 23) {
msg += String.format(
Locale.CHINESE,
": (%d) %s, %s",
error.getErrorCode(),
request.getUrl().toString(),
error.getDescription()
);
}
if (DEBUG) Log.e(tag, msg);
}
@Override
public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) {
LinearLayout linearView = new LinearLayout(this.context);
linearView.setOrientation(LinearLayout.VERTICAL);
final EditText nameEdit = new EditText(this.context);
nameEdit.setHint("用户名");
linearView.addView(nameEdit);
final EditText passEdit = new EditText(this.context);
passEdit.setHint("密码");
linearView.addView(passEdit);
new AlertDialog.Builder(this.context).setTitle(host)
.setMessage(realm)
.setView(linearView)
.setNegativeButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
handler.proceed(nameEdit.getText().toString().trim(), passEdit.getText().toString().trim());
}
})
.setPositiveButton("", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
handler.cancel();
}
})
.create()
.show();
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();
}
}
public static class DefaultWebChromeClient extends WebChromeClient {
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
if (DEBUG) {
System.out.println(String.format(Locale.CHINESE, "%s---> [%s:Line(%d)] %s", tag, consoleMessage.messageLevel(), consoleMessage.lineNumber(), consoleMessage.message()));
}
return super.onConsoleMessage(consoleMessage);
}
}
/**
* 匹配链接协议,并匹配冒号间是否带空格
* <br/><code>tel:</code>
* <br/><code>tel :</code>
*/
private static boolean matchSchemes(String url) {
return url != null && (
url.startsWith("mailto:")
|| url.startsWith("mailto :")
|| url.startsWith("tel:")
|| url.startsWith("tel :")
);
}
}
| 1 | import android.annotation.SuppressLint; |
| 2 | import android.content.Context; |
| 3 | import android.content.DialogInterface; |
| 4 | import android.content.Intent; |
| 5 | import android.net.Uri; |
| 6 | import android.net.http.SslError; |
| 7 | import android.os.Build; |
| 8 | import android.util.AttributeSet; |
| 9 | import android.util.Log; |
| 10 | import android.view.View; |
| 11 | import android.webkit.*; |
| 12 | import android.widget.EditText; |
| 13 | import android.widget.LinearLayout; |
| 14 | import androidx.annotation.NonNull; |
| 15 | import androidx.appcompat.app.AlertDialog; |
| 16 | |
| 17 | import java.io.Serializable; |
| 18 | import java.util.Locale; |
| 19 | |
| 20 | /** |
| 21 | * Created by hp on 2017/8/31. |
| 22 | * 通用WebView |
| 23 | */ |
| 24 | public class CommonWebView extends WebView implements Serializable { |
| 25 | private static String tag = "CommonWebView"; |
| 26 | private static boolean DEBUG = false; |
| 27 | |
| 28 | public CommonWebView(Context context) { |
| 29 | this(context, null); |
| 30 | } |
| 31 | |
| 32 | public CommonWebView(Context context, AttributeSet attrs) { |
| 33 | super(context, attrs); |
| 34 | init(); |
| 35 | } |
| 36 | |
| 37 | public CommonWebView(Context context, AttributeSet attrs, int defStyleAttr) { |
| 38 | super(context, attrs, defStyleAttr); |
| 39 | init(); |
| 40 | } |
| 41 | |
| 42 | private void init() { |
| 43 | // Generic |
| 44 | setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); |
| 45 | setVerticalScrollBarEnabled(false); |
| 46 | setHorizontalScrollBarEnabled(false); |
| 47 | |
| 48 | // WebSettings |
| 49 | WebSettings settings = this.getSettings(); |
| 50 | settings.setDefaultTextEncodingName("utf-8"); |
| 51 | settings.setJavaScriptEnabled(true);//支持js |
| 52 | settings.setDomStorageEnabled(true); |
| 53 | settings.setLoadsImagesAutomatically(true); |
| 54 | |
| 55 | setWebViewClient(new DefaultWebViewClient(getContext())); |
| 56 | setWebChromeClient(new DefaultWebChromeClient()); |
| 57 | } |
| 58 | |
| 59 | @Override |
| 60 | public WebSettings getSettings() { |
| 61 | return super.getSettings(); |
| 62 | } |
| 63 | |
| 64 | /** |
| 65 | * @param object 供JS调用的实例 |
| 66 | * @param name 内部写定为 {@code "android"} |
| 67 | */ |
| 68 | @SuppressLint("JavascriptInterface") |
| 69 | @Override |
| 70 | public void addJavascriptInterface(Object object, String name) { |
| 71 | super.addJavascriptInterface(object, name); |
| 72 | } |
| 73 | |
| 74 | public void registerJSO(Object object) { |
| 75 | addJavascriptInterface(object, "android"); |
| 76 | } |
| 77 | |
| 78 | @Override |
| 79 | public void loadUrl(String url) { |
| 80 | super.loadUrl(url); |
| 81 | System.out.println("loadUrl=" + url); |
| 82 | } |
| 83 | |
| 84 | @Override |
| 85 | public void goBack() { |
| 86 | if (canGoBack()) { |
| 87 | super.goBack(); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | @Override |
| 92 | public void goForward() { |
| 93 | if (canGoForward()) { |
| 94 | super.goForward(); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | @Override |
| 99 | public void goBackOrForward(int steps) { |
| 100 | super.goBackOrForward(steps); |
| 101 | } |
| 102 | |
| 103 | public void setDebug(boolean isDebug) { |
| 104 | DEBUG = isDebug; |
| 105 | } |
| 106 | |
| 107 | public static class DefaultWebViewClient extends WebViewClient { |
| 108 | private Context context; |
| 109 | |
| 110 | public DefaultWebViewClient(@NonNull Context context) { |
| 111 | this.context = context; |
| 112 | } |
| 113 | |
| 114 | @Override |
| 115 | public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { |
| 116 | // New API |
| 117 | // 拦截'tel:'链接 |
| 118 | String targetUrl = request.getUrl().getScheme(); |
| 119 | if (matchSchemes(targetUrl) && context != null) { |
| 120 | Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); |
| 121 | context.startActivity(intent); |
| 122 | return true; |
| 123 | } |
| 124 | return super.shouldOverrideUrlLoading(view, request); |
| 125 | } |
| 126 | |
| 127 | @Override |
| 128 | public boolean shouldOverrideUrlLoading(WebView view, String targetUrl) { |
| 129 | // Old API |
| 130 | // 拦截'tel:'链接 |
| 131 | if (matchSchemes(targetUrl) && context != null) { |
| 132 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(targetUrl)); |
| 133 | context.startActivity(intent); |
| 134 | return true; |
| 135 | } |
| 136 | return super.shouldOverrideUrlLoading(view, targetUrl); |
| 137 | } |
| 138 | |
| 139 | @Override |
| 140 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { |
| 141 | String msg = "onReceivedError api-old"; |
| 142 | msg += String.format( |
| 143 | Locale.CHINESE, |
| 144 | ": (%d) %s, %s", |
| 145 | errorCode, |
| 146 | failingUrl, |
| 147 | description |
| 148 | ); |
| 149 | if (DEBUG) Log.e(tag, msg); |
| 150 | } |
| 151 | |
| 152 | @Override |
| 153 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { |
| 154 | String msg = "onReceivedError api-new"; |
| 155 | if (Build.VERSION.SDK_INT >= 23) { |
| 156 | msg += String.format( |
| 157 | Locale.CHINESE, |
| 158 | ": (%d) %s, %s", |
| 159 | error.getErrorCode(), |
| 160 | request.getUrl().toString(), |
| 161 | error.getDescription() |
| 162 | ); |
| 163 | } |
| 164 | if (DEBUG) Log.e(tag, msg); |
| 165 | } |
| 166 | |
| 167 | @Override |
| 168 | public void onReceivedHttpAuthRequest(final WebView view, final HttpAuthHandler handler, final String host, final String realm) { |
| 169 | LinearLayout linearView = new LinearLayout(this.context); |
| 170 | linearView.setOrientation(LinearLayout.VERTICAL); |
| 171 | final EditText nameEdit = new EditText(this.context); |
| 172 | nameEdit.setHint("用户名"); |
| 173 | linearView.addView(nameEdit); |
| 174 | final EditText passEdit = new EditText(this.context); |
| 175 | passEdit.setHint("密码"); |
| 176 | linearView.addView(passEdit); |
| 177 | new AlertDialog.Builder(this.context).setTitle(host) |
| 178 | .setMessage(realm) |
| 179 | .setView(linearView) |
| 180 | .setNegativeButton("确定", new DialogInterface.OnClickListener() { |
| 181 | @Override |
| 182 | public void onClick(DialogInterface dialog, int which) { |
| 183 | handler.proceed(nameEdit.getText().toString().trim(), passEdit.getText().toString().trim()); |
| 184 | } |
| 185 | }) |
| 186 | .setPositiveButton("", new DialogInterface.OnClickListener() { |
| 187 | @Override |
| 188 | public void onClick(DialogInterface dialog, int which) { |
| 189 | handler.cancel(); |
| 190 | } |
| 191 | }) |
| 192 | .create() |
| 193 | .show(); |
| 194 | } |
| 195 | |
| 196 | @Override |
| 197 | public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { |
| 198 | handler.proceed(); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | public static class DefaultWebChromeClient extends WebChromeClient { |
| 203 | @Override |
| 204 | public boolean onConsoleMessage(ConsoleMessage consoleMessage) { |
| 205 | if (DEBUG) { |
| 206 | System.out.println(String.format(Locale.CHINESE, "%s---> [%s:Line(%d)] %s", tag, consoleMessage.messageLevel(), consoleMessage.lineNumber(), consoleMessage.message())); |
| 207 | } |
| 208 | return super.onConsoleMessage(consoleMessage); |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | /** |
| 213 | * 匹配链接协议,并匹配冒号间是否带空格 |
| 214 | * <br/><code>tel:</code> |
| 215 | * <br/><code>tel :</code> |
| 216 | */ |
| 217 | private static boolean matchSchemes(String url) { |
| 218 | return url != null && ( |
| 219 | url.startsWith("mailto:") |
| 220 | || url.startsWith("mailto :") |
| 221 | || url.startsWith("tel:") |
| 222 | || url.startsWith("tel :") |
| 223 | ); |
| 224 | } |
| 225 | } |
| 226 |