Android 抛弃原生WebView,使用腾讯X5内核、并加入广告拦截。

大家都不知道原生的WebView 存在各种坑。各种适配问题。

最近在使用,总会出现DNS被拦截的情况。预览了各个大神的论坛与博客。

发现可以更改WebView内核。找到了比较火的两个。


分别是:腾讯X5内核 和 crosswalk  

     crosswalk : 据说很强大,但缺点就是会让你的APK包增大很多。(我还没试过,都是看大神们的博客说的)

     大家可以参考这篇文章 如何轻松搞定Crosswalk之嵌入模式

    相对crosswalk呢,腾讯X5 比较适合我目前的项目。至少包不会一下子给我 增大那么多  

     TBS腾讯浏览服务(点击跳转官网)

    

  腾讯X5的好处我就不再说了,官网解释的肯定比我到位,我怎么做的吧。

扫描二维码关注公众号,回复: 1098869 查看本文章


第一步:那肯定是下载官方的SDK 包啦(腾讯浏览服务-SDK下载) 我这里下载的是上面这个



第二步:根据SDK 提供的jar包和so 包拷贝到自己的项目下。

    (注意:我这里和官方提供的so,放的位置可能有点区别,这个就需要看的项目情况了)


    

官方的Demo ,so包是放在 src\main\jniLibs  下这个可以看一下官方包。就知道了

在Demo 中的build.gradle,中有说到 so 包的目录位置





第三步:接下来就开始被配置,初始化X5了,在APP的 ApplicationonCreate()  去初始化


    private void initX5() {
        //如果没有这个内核,允许在WIFI情况下去下载内核
        QbSdk.setDownloadWithoutWifi(true);
        //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
        QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
            @Override
            public void onViewInitFinished(boolean arg0) {
                //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
                Log.d("app", " onViewInitFinished is " + arg0);
            }
            @Override
            public void onCoreInitFinished() {

            }
        };
        //x5内核初始化接口
        QbSdk.initX5Environment(getApplicationContext(),  cb);
    }


第四步 :继承  com.tencent.smtt.sdk.WebView  自定义 WebView (这里根据自己的情况定义)


public class SimpleWebView extends com.tencent.smtt.sdk.WebView {

    public SimpleWebView(Context context) {
        super(context);
        init();
    }

    public SimpleWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public SimpleWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @SuppressLint("SetJavaScriptEnabled")
    private void init() {
		
		WebSettings webSetting = this.getSettings();
        webSetting.setJavaScriptEnabled(true);
        webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
        webSetting.setAllowFileAccess(true);
        webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
        webSetting.setSupportZoom(true);
        webSetting.setBuiltInZoomControls(true);
        webSetting.setUseWideViewPort(true);
        webSetting.setSupportMultipleWindows(true);
        // webSetting.setLoadWithOverviewMode(true);
        webSetting.setAppCacheEnabled(true);
        // webSetting.setDatabaseEnabled(true);
        webSetting.setDomStorageEnabled(true);
        webSetting.setGeolocationEnabled(true);
        webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
        // webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
        webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
        // webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
        webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);

        this.setWebViewClient(new SimpleWebViewClient());

        this.setWebChromeClient(new WebChromeClient(){
            //这里可以设置进度条。但我是用另外一种
            @Override
            public void onProgressChanged(WebView webView, int i) {
                super.onProgressChanged(webView, i);
            }
        });
    }

    public static class SimpleWebViewClient extends com.tencent.smtt.sdk.WebViewClient {

        private SimpleLoadingDialog loadingDialog;

        @Override
        public com.tencent.smtt.export.external.interfaces.WebResourceResponse shouldInterceptRequest(com.tencent.smtt.sdk.WebView webView, String url) {
            //做广告拦截,ADFIlterTool 为广告拦截工具类
            if (!ADFilterTool.hasAd(webView.getContext(),url)){
                return super.shouldInterceptRequest(webView, url);
            }else {
                return new WebResourceResponse(null,null,null);
            }
        }
        /**
         * 防止加载网页时调起系统浏览器
         */
        @Override
        public boolean shouldOverrideUrlLoading(com.tencent.smtt.sdk.WebView webView, String url) {
            webView.loadUrl(url);
            return true;
        }
        //在开始的时候,开始loadingDialog
        @Override
        public void onPageStarted(com.tencent.smtt.sdk.WebView webView, String s, Bitmap bitmap) {
            super.onPageStarted(webView, s, bitmap);
            try{
                loadingDialog = new SimpleLoadingDialog(webView.getContext(),true);
                loadingDialog.show();
            }catch (Exception e){}
        }
        //在页面加载结束的时候,关闭LoadingDialog
        @Override
        public void onPageFinished(com.tencent.smtt.sdk.WebView webView, String s) {
            super.onPageFinished(webView, s);
            try {
                if (loadingDialog != null) {
                    loadingDialog.dismiss();
                }
            } catch (Exception e) {}
        }

        @Override
        public void onReceivedError(com.tencent.smtt.sdk.WebView webView, com.tencent.smtt.export.external.interfaces.WebResourceRequest webResourceRequest, com.tencent.smtt.export.external.interfaces.WebResourceError webResourceError) {
            super.onReceivedError(webView, webResourceRequest, webResourceError);
        }

        @Override
        public void onReceivedSslError(com.tencent.smtt.sdk.WebView webView, com.tencent.smtt.export.external.interfaces.SslErrorHandler sslErrorHandler, com.tencent.smtt.export.external.interfaces.SslError sslError) {
            sslErrorHandler.proceed();
        }

    }
}


接下来就是使用了,和我们原生的webView 没什么区别啦。


    /**
     * 初始化webView
     */
    @SuppressLint("SetJavaScriptEnabled")
    private void initDetailsH5() {
        webView.getSettings().setJavaScriptEnabled(true);

        webView.setWebViewClient(new SimpleWebView.SimpleWebViewClient(){

            @Override
            public void onPageFinished(com.tencent.smtt.sdk.WebView webView, String url) {
                super.onPageFinished(webView, url);
                toolbarTitle.setText(webView.getTitle());//获取WebView 的标题,设置到toolbar中去
            }

            @Override
            public boolean shouldOverrideUrlLoading(com.tencent.smtt.sdk.WebView webView, String url) {
                if (url.contains("Activity/")){
                    ...

                }else if (url.contains("Share")){
                    ...
                }else {
                    webView.loadUrl(url);
                }
                return true;
            }

        });
    }


    /**
     * 监听系统返回键,判断WebView是否有上一级,有的话就返回WebView的上一级
     * 否则返回页面
     *
     * @param keyCode
     * @param event
     * @return
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (webView != null && webView.canGoBack()) {
                webView.goBack();
                return true;
            } else {
                return super.onKeyDown(keyCode, event);
            }
        }
        return super.onKeyDown(keyCode, event);
    }


第五步:这里也根据需要添加吧。就是广告拦截了。广告库加多了的话,可能就会影响性能了。

            (我觉的这种做法存在很大的问题,如果建议直接使用Https。就可以避免这个问题)

public class ADFilterTool {

    /**
     * 屏蔽广告的NoAdWebViewClient类
     *
     * @param context
     * @param url
     * @return true 为广告链接,false 为正常连接
     */
    public static boolean hasAd(Context context, String url) {
        Resources res = context.getResources();
        String[] adUrls = res.getStringArray(R.array.adBlockUrl);
        for (String adUrl : adUrls) {
            if (url.contains(adUrl)) {
                return true;
            }
        }
        return false;
    }
}

在 res \ vlaues 目录下创建 AdUrlString.xml



(注:广告库部分摘取 Android Webview广告过滤的实现

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="adBlockUrl">
        <item>ubmcmm.baidustatic.com</item>
        <item>gss1.bdstatic.com/</item>
        <item>cpro2.baidustatic.com</item>
        <item>cpro.baidustatic.com</item>
        <item>lianmeng.360.cn</item>
        <item>nsclick.baidu.com</item>
        <item>caclick.baidu.com/</item>
        <item>jieaogd.com</item>
        <item>publish-pic-cpu.baidu.com/</item>
        <item>cpro.baidustatic.com/</item>
        <item>hao61.net/</item>
        <item>cpu.baidu.com/</item>
        <item>pos.baidu.com</item>
        <item>cbjs.baidu.com</item>
        <item>cpro.baidu.com</item>
        <item>images.sohu.com/cs/jsfile/js/c.js</item>
        <item>union.sogou.com/</item>
        <item>sogou.com/</item>
        <item>5txs.cn/</item>
        <item>liuzhi520.com/</item>
        <item>yhzm.cc/</item>
        <item>jieaogd.com</item>
        <item>a.baidu.com</item>
        <item>c.baidu.com</item>
        <item>mlnbike.com</item>
        <item>alipays://platformapi</item>
        <item>alipay.com/</item>
        <item>jieaogd.com</item>
        <item>vipshop.com</item>
    </string-array>
</resources>


接下来就是  CookieUtils  ,同步WebView 的Cookie。为什么要同步Cookie ,我这就不介绍啦。

直接贴代码

/**
 * Created by Peng on 2017/7/31.
 */
public class CookieUtils {


    /**s
     * 安卓登陆与H5同步Cookie
     *
     * @param mUrl
     */
    public static void syncSession(Context context,WebView webView, String mUrl){
        HttpUrl httpUrl = HttpUrl.parse(mUrl);
        if (httpUrl != null){
            //注入session
            CookieManager cm = CookieManager.getInstance();
            cm.setAcceptCookie(true);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                cm.removeSessionCookies(new ValueCallback<Boolean>() {
                    @Override
                    public void onReceiveValue(Boolean value) {
                    }
                });
            } else {
                cm.removeSessionCookie();
            }
            cm.removeAllCookie();
            JavaNetCookieJar cookieJar = (JavaNetCookieJar) RetrofitUtil.getOkHttpClient().cookieJar();
            List<Cookie> cookies = cookieJar.loadForRequest(httpUrl);
            for (Cookie cookie : cookies) {
                cm.setCookie(mUrl, cookie.toString());
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                cm.setAcceptThirdPartyCookies(webView,true);
                CookieManager.getInstance().flush();
            } else {
                CookieSyncManager.createInstance(context).sync();
            }
        }
    }

    /**s
     * 安卓登陆与H5同步Cookie   X5内核同步
     *
     * @param mUrl
     */
    public static void syncSession(Context context, com.tencent.smtt.sdk.WebView webView, String mUrl){
        HttpUrl httpUrl = HttpUrl.parse(mUrl);
        if (httpUrl != null){
            //注入session
            com.tencent.smtt.sdk.CookieManager cm = com.tencent.smtt.sdk.CookieManager.getInstance();
            cm.setAcceptCookie(true);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                cm.removeSessionCookies(new com.tencent.smtt.sdk.ValueCallback<Boolean>() {
                    @Override
                    public void onReceiveValue(Boolean value) {
                    }
                });
            } else {
                cm.removeSessionCookie();
            }
            cm.removeAllCookie();
            JavaNetCookieJar cookieJar = (JavaNetCookieJar) RetrofitUtil.getOkHttpClient().cookieJar();
            List<Cookie> cookies = cookieJar.loadForRequest(httpUrl);
            for (Cookie cookie : cookies) {
                cm.setCookie(mUrl, cookie.toString());
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                cm.setAcceptThirdPartyCookies(webView,true);
                CookieManager.getInstance().flush();
            } else {
                CookieSyncManager.createInstance(context).sync();
            }
        }
    }

    /**
     * 同步token
     *
     * @param context
     * @param url
     * @param token
     */
    public static void syncCookie(Context context, String url,String token){
        clearCookie(context);
        try{
            CookieSyncManager.createInstance(context);
            CookieManager cookieManager = CookieManager.getInstance();
            cookieManager.setAcceptCookie(true);
            cookieManager.removeSessionCookie();// 移除
            cookieManager.removeAllCookie();
            String cookieValue = "token=" + token;
            cookieManager.setCookie(url, cookieValue);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                CookieManager.getInstance().flush();
            } else {
                CookieSyncManager.createInstance(context).sync();
            }
        }catch(Exception e){
        }
    }

    /**
     * 同步X5 token
     *
     * @param context
     * @param url
     * @param token
     */
    public static void syncX5Cookie(Context context, String url,String token){
        clearX5Cookie(context);
        try{
            com.tencent.smtt.sdk.CookieSyncManager.createInstance(context);
            com.tencent.smtt.sdk.CookieManager cookieManager = com.tencent.smtt.sdk.CookieManager.getInstance();
            cookieManager.setAcceptCookie(true);
            cookieManager.removeSessionCookie();// 移除
            cookieManager.removeAllCookie();
            String cookieValue = "token=" + token;
            cookieManager.setCookie(url, cookieValue);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                com.tencent.smtt.sdk.CookieManager.getInstance().flush();
            } else {
                com.tencent.smtt.sdk.CookieSyncManager.createInstance(context).sync();
            }
        }catch(Exception e){
        }
    }


    /**
     * 清除WebView 缓存以及Cookie
     *
     * @param context
     * @param webView
     */
    public static void clearWebViewCache(Context context, WebView webView){
        clearCookie(context);
        webView.setWebChromeClient(null);
        webView.setWebViewClient(null);
        webView.getSettings().setJavaScriptEnabled(false);
        webView.clearCache(true);
    }

    /**
     * 清除X5WebView 缓存以及Cookie
     *
     * @param context
     * @param webView
     */
    public static void clearWebViewCache(Context context, com.tencent.smtt.sdk.WebView webView){
        clearX5Cookie(context);
        webView.setWebChromeClient(null);
        webView.setWebViewClient(null);
        webView.getSettings().setJavaScriptEnabled(false);
        webView.clearCache(true);
    }


    /**
     * 清除Cookie
     *
     * @param context
     */
    public static void clearCookie(Context context){
        CookieSyncManager.createInstance(context);  //Create a singleton CookieSyncManager within a context
        CookieManager cookieManager = CookieManager.getInstance(); // the singleton CookieManager instance
        cookieManager.removeAllCookie();// Removes all cookies.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {// forces sync manager to sync now
            CookieManager.getInstance().flush();
        } else {
            CookieSyncManager.createInstance(context);
            CookieSyncManager.getInstance().sync();
        }
    }

    /**
     * 清除X5Cookie
     *
     * @param context
     */
    public static void clearX5Cookie(Context context){
        com.tencent.smtt.sdk.CookieSyncManager.createInstance(context);  //Create a singleton CookieSyncManager within a context
        com.tencent.smtt.sdk.CookieManager cookieManager = com.tencent.smtt.sdk.CookieManager.getInstance(); // the singleton CookieManager instance
        cookieManager.removeAllCookie();// Removes all cookies.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {// forces sync manager to sync now
            com.tencent.smtt.sdk.CookieManager.getInstance().flush();
        } else {
            com.tencent.smtt.sdk.CookieSyncManager.createInstance(context);
            com.tencent.smtt.sdk.CookieSyncManager.getInstance().sync();
        }
    }

    /**
     * 停止原生WebView加载,销毁WebView
     *
     * @param webView
     */
    public static void destroyWebView(WebView webView){
        if (webView != null){
            ViewParent parent = webView.getParent();
            if (parent != null) {
                ((ViewGroup) parent).removeView(webView);
            }
            webView.stopLoading();
            webView.clearHistory();
            webView.clearView();
            webView.removeAllViews();
            webView.destroy();
            webView = null;
        }
    }
    /**
     * 停止X5WebView加载,销毁WebView
     *
     * @param webView
     */
    public static void destroyWebView(com.tencent.smtt.sdk.WebView webView){
        if (webView != null){
            ViewParent parent = webView.getParent();
            if (parent != null) {
                ((ViewGroup) parent).removeView(webView);
            }
            webView.stopLoading();
            webView.clearHistory();
            webView.clearView();
            webView.removeAllViews();
            webView.destroy();
            webView = null;
        }
    }
}

最后温馨提醒一下,如果没有添加权限,注意加一下权限噢~

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <!-- 硬件加速对X5视频播放非常重要,建议开启 -->
    <uses-permission android:name="android.permission.GET_TASKS" />

好啦,到这里就全部介绍完啦。希望对你帮助。


猜你喜欢

转载自blog.csdn.net/qq_35070105/article/details/80047595