WebView学习笔记

WebView的使用大概涉及到以下几点      

a. 进度条 - WebViewClient / WebChromeClient
b. goBack 和 物理按键 - onKeyDown
c. 缓存设置等
d. 出错界面
e. 超时处理
f. 资源销毁 - onDestroy

注意事项:

1. 若要WebView loadUrl时,不调用系统浏览器,始终在WebView里打开网页,需要设置自己的WebViewClient。
mWebView.setWebViewClient(mWebViewClient);

2. 加载app/src/main/assets/目录下的xxx.html文件
webView.loadUrl("file:///android_asset/xxx.html");

3. 若打开的网页,如csdn的网页,未适配屏幕,要调用WebSettings的setJavaScriptEnabled方法,开启JS支持
WebSettings webSetting = mWebView.getSettings();
webSetting.setJavaScriptEnabled(true);// -> 是否开启JS支持
4. 网页中的图片加载不出,可能是因为WebView加载的链接为Https开头,但链接里面的图片为Http链接,此时要调用WebSettings的setMixedContentMode方法。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    webSetting.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

5. jianshu:// 、alipays://等重定向问题 - net::ERR_UNKNOWN_URL_SCHEME

        //WebViewClient shouldOverrideUrlLoading
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            /**
             * 若没有设置 WebViewClient 则由系统(Activity Manager)处理该 url,通常是使用浏览器打开或弹出浏览器选择对话框。
             * 若设置 WebViewClient 且该方法返回 true ,则说明由应用的代码处理该 url,WebView 不处理,也就是程序员自己做处理。
             * 若设置 WebViewClient 且该方法返回 false,则说明由 WebView 处理该 url,即用 WebView 加载该 url。
             */
            if (null != request && null != request.getUrl()){
                Log.d(TAG, "shouldOverrideUrlLoading: "+ request.getUrl());
                String url = request.getUrl().toString();
                if (url.startsWith("http://") || url.startsWith("https://")) { //加载的url是http/https协议地址
//                    view.loadUrl(url);
//                    return true;//返回true,说明不让WebView处理,自己在代码里处理,即自己调用了WebView的loadUrl方法
                    return false; //返回false表示由WebView处理该url。和上边两句的功能是一样的。
                } else { //加载的url是自定义协议地址,如jianshu:// alipays:// 等
                    try {
                        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                        startActivity(intent);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return true;//返回 true,说明不让WebView处理,自己在代码里处理
        }

6. net::ERR_CLEARTEXT_NOT_PERMITTED
manifest 中application节点添加 android:usesCleartextTraffic="true"

代码如下:

public class WebActivity extends BaseActivity{
    private static final String TAG = WebActivity.class.getSimpleName();

    private WebView mWebView;
    private String mUrl;
    private final String mErrorUrl = "file:///android_asset/test.html";//-> assets目录下放置文件
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web);

        Intent intent = getIntent();
        if (null != intent){
            mUrl = intent.getStringExtra(Const.WEB_VIEW_URL);
        }
        Log.d(TAG, "onCreate: url = " + mUrl);
        initView();
    }

    private ProgressBar mProgress;

    private void initView() {
        mProgress = findViewById(R.id.pb);
        mWebView = findViewById(R.id.wv);
        mWebView.setWebViewClient(mWebViewClient);
        mWebView.setWebChromeClient(chromeClient);
        mWebView.loadUrl(null == mUrl ? mErrorUrl : mUrl);

        WebSettings webSetting = mWebView.getSettings();
        webSetting.setJavaScriptEnabled(true);// -> 是否开启JS支持
        webSetting.setJavaScriptCanOpenWindowsAutomatically(true);// -> 是否允许JS打开新窗口
        webSetting.setAllowFileAccess(true);//-> 是否允许访问文件
        webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);//-> 设定WebView的HTML布局方式
        webSetting.setSupportZoom(true);//-> 是否支持缩放
        webSetting.setBuiltInZoomControls(true);// -> 是否支持缩放变焦,前提是支持缩放
        webSetting.setUseWideViewPort(true);// -> 缩放至屏幕大小
        webSetting.setLoadWithOverviewMode(true);//-> 缩放至屏幕大小
        webSetting.setAppCacheEnabled(true);//-> 是否应用缓存
        webSetting.setDatabaseEnabled(true); //-> 是否数据缓存
        webSetting.setDomStorageEnabled(true);//-> 是否节点缓存
        webSetting.setGeolocationEnabled(true);//-> 设置开启定位功能
        webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
        webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
        webSetting.setCacheMode(WebSettings.LOAD_DEFAULT);//(默认)根据cache-control决定是否从网络上取数据。

        //当WebView加载的链接为Https开头,但是链接里面的内容,比如图片为Http链接,这时候,图片就会加载不出来
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            webSetting.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
    }
    
    private WebViewClient mWebViewClient = new WebViewClient(){
        //页面开始加载时调用
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            mProgress.setVisibility(View.VISIBLE);
            Log.d(TAG, "onPageStarted: ");
        }

        @Override
        public void onLoadResource(WebView view, String url) {
            startTimer();
            super.onLoadResource(view, url);
        }

        //页面完成加载时调用
        @Override
        public void onPageFinished(WebView view, String url) {
            stopTimer();
            mProgress.setVisibility(View.GONE);
            super.onPageFinished(view, url);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {

            /**
             * 若没有设置 WebViewClient 则由系统(Activity Manager)处理该 url,通常是使用浏览器打开或弹出浏览器选择对话框。
             * 若设置 WebViewClient 且该方法返回 true ,则说明由应用的代码处理该 url,WebView 不处理,也就是程序员自己做处理。
             * 若设置 WebViewClient 且该方法返回 false,则说明由 WebView 处理该 url,即用 WebView 加载该 url。
             *
             * 链接:https://www.jianshu.com/p/3474cb8096da
             */
            if (null != request && null != request.getUrl()){
                Log.d(TAG, "shouldOverrideUrlLoading: "+ request.getUrl());
                String url = request.getUrl().toString();
                if (url.startsWith("http://") || url.startsWith("https://")) { //加载的url是http/https协议地址
//                    view.loadUrl(url);
//                    return true;//返回true,说明不让WebView处理,自己在代码里处理,即自己调用了WebView的loadUrl方法
                    return false; //返回false表示由WebView处理该url。和上边两句的功能是一样的。
                } else { //加载的url是自定义协议地址,如jianshu:// alipays:// 等
                    try {
                        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                        startActivity(intent);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return true;//返回 true,说明不让WebView处理,自己在代码里处理
        }

        @RequiresApi(api = Build.VERSION_CODES.M)
        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            stopTimer();
            super.onReceivedError(view, request, error);
            Log.e(TAG, "onReceivedError: " + request.getUrl() + ", " + error.getDescription());
//            view.loadUrl(mErrorUrl);
        }

        @Override
        public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
            stopTimer();
            super.onReceivedHttpError(view, request, errorResponse);
            Log.e(TAG, "onReceivedHttpError: " + request.getUrl() + ", " + errorResponse.toString());
//            view.loadUrl(mErrorUrl);
        }
    };

    //超时处理
    private final static int TIMEOUT_TIMER_ID = 1;
    private final static int TIMEOUT_TIME = 5*1000;
    private void startTimer() {
        mHandler.sendEmptyMessageDelayed(TIMEOUT_TIMER_ID, TIMEOUT_TIME);
    }

    private void stopTimer() {
        mHandler.removeCallbacksAndMessages(null);
    }

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if (TIMEOUT_TIMER_ID == msg.what){
                stopTimer();
                if (mProgress.getProgress() < 100 && null != mWebView){
                    mWebView.loadUrl(mErrorUrl);
                }
            }
        }
    };

    WebChromeClient chromeClient = new WebChromeClient(){
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            mProgress.setProgress(newProgress);
        }
    };

    public void onBack(View v){
        if (mWebView.canGoBack() && !mErrorUrl.equals(mWebView.getUrl())){//当前不处于error界面时
            mWebView.goBack();
        } else {
            finish();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (mWebView.canGoBack()
                && !mErrorUrl.equals(mWebView.getUrl())
                && keyCode == KeyEvent.KEYCODE_BACK){//点击返回按钮的时候判断有没有上一页
            mWebView.goBack(); // goBack()表示返回webView的上一页面
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        //释放资源
        mWebView.destroy();
        mWebView = null;
        super.onDestroy();
    }
}

参考:

WebView shouldOverrideUrlLoading功能 

Android5.0 WebView中Http和Https混合问题

关于shouldOverrideUrlLoading方法的一些考证

net::ERR_CLEARTEXT_NOT_PERMITTED Android9.0无法加载url

webview 常用方法

Android WebView

Android WebView基本使用

Android WebView使用详解及注意事项

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值