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); } } /** * 匹配链接协议,并匹配冒号间是否带空格 *
tel: *
tel : */ private static boolean matchSchemes(String url) { return url != null && ( url.startsWith("mailto:") || url.startsWith("mailto :") || url.startsWith("tel:") || url.startsWith("tel :") ); } }