软件编程
位置:首页>> 软件编程>> Android编程>> Android WebView基础应用详解

Android WebView基础应用详解

作者:红日666  发布时间:2023-09-30 07:36:46 

标签:Android,WebView,应用

附GitHub源码:WebViewExplore

一、WebView的基础配置


WebSettings ws = getSettings();
ws.setBuiltInZoomControls(true);// 隐藏缩放按钮
ws.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);// 排版适应屏幕

ws.setUseWideViewPort(true);// 可任意比例缩放
ws.setLoadWithOverviewMode(true);// setUseWideViewPort方法设置webview推荐使用的窗口。setLoadWithOverviewMode方法是设置webview加载的页面的模式。

ws.setSaveFormData(true);// 保存表单数据
ws.setJavaScriptEnabled(true); // 是否能与JS交互【如果业务中无JS交互,建议将此项关闭】
ws.setGeolocationEnabled(true);// 启用地理定位【如果业务中无此业务,建议将此项关闭】
ws.setDomStorageEnabled(true);
ws.setJavaScriptCanOpenWindowsAutomatically(true);//允许JS Alert对话框等打开【如果业务中无此业务,建议将此项关闭】
ws.setSupportMultipleWindows(true);// 新加

二、WebView支持播放音乐


//是否支持播放音乐
ws.setPluginState(WebSettings.PluginState.ON);
ws.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

//是否需要用户点击才播放
ws.setMediaPlaybackRequiresUserGesture(true);

三、WebView支持视频播放

Android WebView播放视频(包括全屏播放)

四、WebChromeClient


/**
* WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等
*/
setWebChromeClient(new XWebChromeClient());

其具体覆盖方法如下: 


   public static class XWebChromeClient extends WebChromeClient {

/**
        * 获取网页加载进度
        * @param view
        * @param newProgress
        */
       @Override
       public void onProgressChanged(WebView view, int newProgress) {
           super.onProgressChanged(view, newProgress);
           Log.d(TAG, "onProgressChanged---> newProgress:" + newProgress);
       }

/**
        * 获取网站标题 (Android 6.0 以下通过title获取【捕捉HTTP ERROR】)
        *
        * @param view
        * @param title
        */
       @Override
       public void onReceivedTitle(WebView view, String title) {
           super.onReceivedTitle(view, title);
           Log.d(TAG, "onReceivedTitle---> title:" + title);
           if (webTitleCallBack != null) {
               webTitleCallBack.onReceived(title);
           }
           if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
               if (title.contains("404") || title.contains("500") || title.contains("Error")) {
                   view.loadUrl("about:blank"); // 避免出现默认的错误界面
                   // 在这里可以考虑显示自定义错误页
                   // showErrorPage();
               }
           }
       }

/**
        * 网站图标
        *
        * @param view
        * @param icon
        */
       @Override
       public void onReceivedIcon(WebView view, Bitmap icon) {
           super.onReceivedIcon(view, icon);
           Log.d(TAG, "icon:" + icon);
       }

/**
        * 拦截Alert弹框
        *
        * @param view
        * @param url
        * @param message
        * @param result
        * @return
        */
       @Override
       public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
           Log.d(TAG, "onJsAlert");
           return super.onJsAlert(view, url, message, result);
       }

/**
        * 拦截 confirm弹框
        *
        * @param view
        * @param url
        * @param message
        * @param result
        * @return
        */
       @Override
       public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
           Log.d(TAG, "onJsConfirm");
           return super.onJsConfirm(view, url, message, result);
       }

/**
        * 打印console信息
        *
        * @param consoleMessage
        * @return
        */
       @Override
       public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
           Log.d(TAG, "onConsoleMessage");
           return super.onConsoleMessage(consoleMessage);
       }

/**
        * 该方法在web页面请求某个尚未被允许或拒绝的权限时回调
        *
        * @param request
        */
       @Override
       public void onPermissionRequest(PermissionRequest request) {
           super.onPermissionRequest(request);
           Log.d(TAG, "onPermissionRequest---> request:" + request);
       }
   }

五、WebViewClient


/**
* WebViewClient就是帮助WebView处理各种通知、请求事件的
*/
setWebViewClient(new XWebViewClient());

其具体覆盖方法如下: 


   public class XWebViewClient extends WebViewClient {

@Override
       public void onPageStarted(WebView view, String url, Bitmap favicon) {
           super.onPageStarted(view, url, favicon);
           Log.d(TAG, "onPageStarted---> url:" + url);
       }

@Override
       public void onPageFinished(WebView view, String url) {
           super.onPageFinished(view, url);
           Log.d(TAG, "onPageFinished---> url:" + url);
       }

/**
        * WEB页面加载错误时回调,这些错误通常都是由无法与服务器正常连接引起的。
        *
        * @param view
        * @param errorCode
        * @param description
        * @param failingUrl
        */
       //Android6.0之前的方法 【在新版本中也可能被调用,所以加上一个判断,防止重复显示】
       @Override
       public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
           super.onReceivedError(view, errorCode, description, failingUrl);
           if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
               // 断网或者网络连接超时
               showReceivedErrorPage(view, errorCode, description, failingUrl);
           }
       }

/**
        * 当服务器返回错误码时回调
        *
        * @param view
        * @param request
        * @param errorResponse
        */
       //6.0新增方法
       @RequiresApi(api = Build.VERSION_CODES.M)
       @Override
       public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
           super.onReceivedHttpError(view, request, errorResponse);
           // 这个方法在6.0才出现
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               int statusCode = 0;
               if (errorResponse != null) {
                   statusCode = errorResponse.getStatusCode();
               }
               Log.d(TAG, "onReceivedHttpError---> code = " + statusCode);
               if (404 == statusCode || 500 == statusCode) {
                   view.loadUrl("about:blank");// 避免出现默认的错误界面
                   // 在这里可以考虑显示自定义错误页
                   // showErrorPage();
               }
           }
       }
   }

还有如下方法,在使用时尤其要注意:

1、重定向问题

在 shouldOverrideUrlLoading 方法可进行重定向的判断跟处理:


       /**
        * 重定向分析:
        *
        * @param view
        * @param request
        * @return true: 表示当前url已经加载完成,即使url还会重定向都不会再进行加载
        * false: 表示此url默认由系统处理,该重定向还是重定向,直到加载完成
        */
       //Android7.0之后的方法
       @RequiresApi(api = Build.VERSION_CODES.N)
       @Override
       public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
           Log.d(TAG, "shouldOverrideUrlLoading new---> url:" + request.getUrl());

analysisRequest(request);

String url = (request.getUrl()).toString();
           boolean hasGesture = request.hasGesture();
           boolean isRedirect = request.isRedirect();

return shouldOverride(view, url);
       }

其WebView重定向需要考虑的case如下:

1、是最普通的http url【不含.doc .apk等下载url】

2、下载的http url【如.doc .apk等】

3、非http或https自定义url 【如 "weixin:// alipays://等】

【deprecated】如果期望打开web页时不自动唤起app,可通过 request.hasGesture()【是否】点击来判断,如果是true才唤起第三方app。(此种方案有时不太准确,故可采用下面方案)

【recommend】定义一个boolean值如:isClickWeb = false,在onTouchEvent DOWN方法中,将其赋值为true。在必要位置添加判断即可【具体可参考代码】


       /**
        * 自定义重定向处理方法
        * @param view
        * @param url
        * @return
        */
       private boolean shouldOverride(WebView view, final String url) {
           //业务需要可做处理
           redirectionJudge(view, url);

if (SchemeUtil.isHttpProtocol(url) && !SchemeUtil.isDownloadFile(url)) {
               return false;
           }

if (SchemeUtil.isHttpProtocol(url) && SchemeUtil.isDownloadFile(url)) {
               if (isClickWeb) {
                   openDialog(url);
                   return true;
               }
           }

if (!SchemeUtil.isHttpProtocol(url)) {
               boolean isValid = SchemeUtil.isSchemeValid(context, url);
               if (isValid && isClickWeb) {
                   openDialog(url);
               } else {
                   Log.d(TAG, "此scheme无效[比如手机中未安装该app]");
               }
               return true;
           }
           return false;
       }

2、实现预加载

在 shouldInterceptRequest 方法中可实现资源预加载:


       /**
        * 【实现预加载】
        * 有时候一个页面资源比较多,图片,CSS,js比较多,还引用了JQuery这种庞然巨兽,
        * 从加载到页面渲染完成需要比较长的时间,有一个解决方案是将这些资源打包进APK里面,
        * 然后当页面加载这些资源的时候让它从本地获取,这样可以提升加载速度也能减少服务器压力。
        */
       @Nullable
       @Override
       public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
           if (request == null) {
               return null;
           }
           String url = request.getUrl().toString();
           Log.d(TAG, "shouldInterceptRequest---> " + url);
           return getWebResourceResponse(url);
       }

       protected WebResourceResponse getWebResourceResponse(String url) {
           //此处[tag]等需要跟服务端协商好,再处理
           if (url.contains("[tag]")) {
               try {
                   String localPath = url.replaceFirst("^http.*[tag]\\]", "");
                   InputStream is = getContext().getAssets().open(localPath);
                   Log.d(TAG, "shouldInterceptRequest: localPath " + localPath);
                   String mimeType = "text/javascript";
                   if (localPath.endsWith("css")) {
                       mimeType = "text/css";
                   }
                   return new WebResourceResponse(mimeType, "UTF-8", is);
               } catch (IOException e) {
                   e.printStackTrace();
                   return null;
               }
           } else {
               return null;
           }
       }

3、增加错误页面展示限制

在onReceivedError方法中,通过 request.isForMainFrame() || url.equals(getUrl() 判断来尽可能少的减少错误页面的展示。即当错误页面是主页面时才展示错误页,避免整个页面中如某个icon等展示错误,导致影响整个页面的情况【如网易音乐的某些URL,就曾有出现这种情况,通过这种方式可以避免错误页面展示】。


       /**
        * 此方法中加载错误页面的时候,需要判断下 isForMainFrame 是否为true 亦或者 当前url跟加载的url是否为同一个url。
        *
        * @param view
        * @param request
        * @param error
        */
       //Android6.0之后的方法
       @RequiresApi(api = Build.VERSION_CODES.M)
       @Override
       public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
           super.onReceivedError(view, request, error);
           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
               String url = request.getUrl().toString();
               int errorCode = error.getErrorCode();
               String description = error.getDescription().toString();
               Log.d(TAG, "onReceivedError---> " + " url:" + url + "errorCode:" + errorCode + " description:" + description + " failingUrl:" + url + " request.isForMainFrame():" + request.isForMainFrame());
               // 如果当前网络请求是为main frame创建的,则显示错误页
               if (request.isForMainFrame() || url.equals(getUrl())) {
                   showReceivedErrorPage(view, error.getErrorCode(), error.getDescription().toString(), request.getUrl().toString());
               }
           }
       }

4、解决页面白屏问题

当SSL证书无效时,会导致白屏问题,可在 onReceivedSslError 方法中添加 handler.proceed();

可解决白屏问题: 


       /**
        * 【解决白屏问题】
        * 如SSL证书无效时调用
        *
        * @param view
        * @param handler
        * @param error
        */
       @Override
       public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
           //此处处理可避免SSL证书无效的页面白屏
           handler.proceed();
           super.onReceivedSslError(view, handler, error);
           Log.d(TAG, "onReceivedSslError---> error = " + error);
       }

来源:https://blog.csdn.net/u012440207/article/details/121758583

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com