WebView实战与设计

WebView实战与设计

1、简述

现在纯Native的应用越来越少,即使一个使用Native开发的应用,有些模块也需要用WebView加载h5页面,比如新年活动之类生命周期很短的模块,那么使用WebView+H5的模式开发将成为首选,一来可以节约成本,再者,h5页面可以频繁更改,非常适合做活动类的模块。当然hybrid应用中,WebView的使用更是频繁。

WebView是Android SDK中内置的一个控件,可以理解为内置的浏览器。

WebView:Android SDK中内置的一个控件,可以理解为浏览器。常用的API有:

加载一个页面:

/**
     * Loads the given URL.
     *
     * @param url the URL of the resource to load
     */
    public void loadUrl(String url) {
      //
    }
给Js注入对象,在注入对象中,可以写方法让Js调用Native的逻辑,实现Js与Native的交互:

/**
         * Injects the supplied Java object into this WebView. The object is
         * injected into the JavaScript context of the main frame, using the
         * supplied name. This allows the Java object's methods to be
         * accessed from JavaScript. 
         * @param object the Java object to inject into this WebView's JavaScript
         *               context. Null values are ignored.
         * @param name the name used to expose the object in JavaScript
         */
        public void addJavascriptInterface(Object object, String name) {
           //
        }
设置WebViewClient:

/**
     * Sets the WebViewClient that will receive various notifications and
     * requests. This will replace the current handler.
     *
     * @param client an implementation of WebViewClient
     */
    public void setWebViewClient(WebViewClient client) {
        checkThread();
        mProvider.setWebViewClient(client);
    }
设置WebChromeClient:

 /**
     * Sets the chrome handler. This is an implementation of WebChromeClient for
     * use in handling JavaScript dialogs, favicons, titles, and the progress.
     * This will replace the current handler.
     *
     * @param client an implementation of WebChromeClient
     */
    public void setWebChromeClient(WebChromeClient client) {
        checkThread();
        mProvider.setWebChromeClient(client);
    }

CookieManager:WebView的Cookie管理类,可以把Native的登录态传给WebView,让H5页面也是登录态:

/**
     * 设置Cookie
     */
    private void setCookie4WebView() {
        //获取Cookie
        List<Cookie> cookies = NetUtil.getInstance().getCookieStore().getCookies();
        if (cookies != null) {
            //The CookieSyncManager is used to synchronize the browser cookie store
            // between RAM and permanent storage. To get the best performance, browser cookies are
            //saved in RAM. A separate thread saves the cookies between, driven by a timer.
            CookieSyncManager.createInstance(this);
            //Manages the cookies used by an application's {@link WebView} instances.
            // Cookies are manipulated according to RFC2109.
            CookieManager cookieManager = CookieManager.getInstance();
            cookieManager.setAcceptCookie(true);
            for (int i = 0; i < cookies.size(); i++) {
                Cookie cookie = cookies.get(i);
                String cookieString = cookie.getName() + "=" + cookie.getValue();
                //Sets a cookie for the given URL. Any existing cookie with the same host,
                //path and name will be replaced with the new cookie. The cookie being set
                //will be ignored if it is expired.
                cookieManager.setCookie(NetUrlConstant.Url_Base + "/", cookieString);
            }
            //sync() forces sync manager to sync now
            CookieSyncManager.getInstance().sync();
        }
    }

WebChromeClient:主要辅助WebView处理JavaScript的对话框、网站图标、网站title、加载进度条等:

 public class WebChromeClient extends android.webkit.WebChromeClient {
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            //页面加载中进度条的变化
            if (newProgress == 100) {
                progressBar.setVisibility(View.GONE);
            } else {
                if (progressBar.getVisibility() == View.GONE)
                    progressBar.setVisibility(View.VISIBLE);
                progressBar.setProgress(newProgress);
            }
            super.onProgressChanged(view, newProgress);
        }

    

WebViewClient:主要帮助WebView处理各种通知、请求事件:

        setWebChromeClient(new WebChromeClient() {
            @Override
            public void onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater) {
                quotaUpdater.updateQuota(requiredStorage * 2);
            }
        });

        setWebViewClient(new WebViewClient() {

            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                handler.proceed();  // 接受所有网站的证书
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (!url.contains("tel:")) {
                    if (url.contains(context.getPackageName())) {
                        view.loadUrl(url);
                    } else if (url.equals("local://redo")) {
                        if (!StringHelper.isEmpty(failUrl)) {
                            view.loadUrl(failUrl);
                        }
                    } else {
                        view.loadUrl("file:///android_asset/noWifi.html");
                    }
                }
                return true;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                isLoad = false;
//                if (!url.contains("noWifi.html") && !url.contains("txt.pingan.com.cn")) {
//                    activity.showLoading(true);
//                }
                if (!url.contains("http")) {
                    activity.showLoading(true);
                }
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
//                if (url.contains("noWifi.html") || url.contains("fs-txt.pingan.com.cn")) {
//                    activity.showLoading(false);
//                }
                if (url.contains("http")) {
                    activity.showLoading(false);
                }
                isLoad = true;
            }

            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                //缓存错误页面
                failUrl = failingUrl;
                view.stopLoading();
                view.clearView();
                view.loadUrl("javascript:document.body.innerHTML=\"" + "" + "\"");
                view.loadUrl("file:///android_asset/noWifi.html");
                activity.showLoading(false);
                super.onReceivedError(view, errorCode, description, failingUrl);
            }
        });

WebViewSetting:管理WebView的设置状态。官方介绍:

Manages settings state for a WebView. When a WebView is first created, it
* obtains a set of default settings. These default settings will be returned
* from any getter call. A WebSettings object obtained from
* WebView.getSettings() is tied to the life of the WebView.

 webSettings = getSettings();
        webSettings.setJavaScriptEnabled(true);//允许调用JavaScript
        webSettings.setUseWideViewPort(true); //设置内容自适应屏幕大小
        webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);//提高渲染的优先级
        webSettings.setSupportZoom(false);//页面禁止缩放
        webSettings.setDomStorageEnabled(true);//允许使用本地缓存

        int sdk = Build.VERSION.SDK_INT;

        if (sdk > 10) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        webSettings.setSaveFormData(true);
        webSettings.setAppCacheMaxSize(1024 * 5);

        //存储H5
        String appCacheDir = context.getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath() + APP_CACAHE_DIRNAME;
//        String appCacheDir = context.getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
        webSettings.setAppCachePath(appCacheDir);
        webSettings.setAllowFileAccess(true);
        webSettings.setAppCacheEnabled(true);

//       //存储url
        webSettings.setDatabaseEnabled(true);
//        String appData = context.getApplicationContext().getDir("databases", Context.MODE_PRIVATE).getPath() + APP_DB_DIRNAME;
        webSettings.setDatabasePath(appCacheDir);

WebViewJsInjection:Js注入类,该该类中,可以写方法给H5页面调用:

/**
 * the Java object to inject into this WebView's JavaScript
 */
public class WebViewJS {

    @JavascriptInterface
    public void linkRecord(int recordid) {
       //
    }
   
    @JavascriptInterface
    public void linkThing(long thingid) {
      //
    }

    @JavascriptInterface
    public void linkUser(int userid) {
       //
    }

    public void linkLogin(){
      //
    }
}

2、整体的设计:

废话不多说,先上UML类图:

WebApp1Activity:普通的Activity界面,放一个WebView,加载h5;

ProgresswebView:自定义的WebView,带进度条

MyWebChromeClient:自定义的WebChromeClient,处理页面变化过程中进度条的变化,需要风行Progressbar,作为ProgresswebView内部类出现

MyWebViewClient:自定义的WebViewClient,处理加载页面的相关事件

INativeJsInjection:Native给Js的注入类接口,抽象,让ProgressView依赖抽象,不依赖具体实现

DetailNativeJsInjection1:Native给Js注入类的具体实现

附:Github地址

参考:WebViewClient与WebChromeClient的区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值