WebView

WebView是一个用来展示web页面的控件。

1.WebSetting

        WebView mWebView = (WebView)findViewById(R.id.webview);

        WebSettings webSettings = mWebView.getSettings();
        //支持获取手势焦点,输入用户名、密码或其他
        mWebView.requestFocusFromTouch();
        //支持JS
        webSettings.setJavaScriptEnabled(true);
        //支持插件,没有该方法,,?
        //webSettings.setPluginsEnabled(true);

        //提高渲染的优先级
        webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);

        //设置自适应屏幕,两者合用
        webSettings.setUseWideViewPort(true);//将图片调整到合适webview的大小
        webSettings.setLoadWithOverviewMode(true);//缩放至屏幕的大小

        //支持缩放,默认为true,是下面那个的前提
        webSettings.setSupportZoom(true);
        //设置内置的缩放控件,若上面是false,则该webview不可缩放,这个不管设置什么都不能缩放
        webSettings.setBuiltInZoomControls(true);

        //隐藏原生的缩放控件
        webSettings.setDisplayZoomControls(false);

        //支持内容重新布局
        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
        //多窗口
        webSettings.supportMultipleWindows();
        //关闭webView中缓存
        webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        //设置可以访问文件
        webSettings.setAllowFileAccess(true);
        //当webView调用rewuestFocus时为webView设置节点
        webSettings.setNeedInitialFocus(true);
        //支持通过JS打开新窗口
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        //支持自动加载图片
        webSettings.setLoadsImagesAutomatically(true);
        //设置编码格式
        webSettings.setDefaultTextEncodingName("utf-8");

缓存模式:

  • LOAD_CACHE_ONLY:不适用网络,只读取本地缓存数据;
  • LOAD_DEFAULT:(默认)根据cache-control决定是否从网络上取数据;
  • LOAD_NO_CACHE:不适用缓存数据,只从网络获取数据;
  • LOAD_CACHE_ELSE_NETWORK:只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
    结合使用(理线加载):
        if (有网){
            //根据cache-control决定是否从网络上获取数据
            webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        }else {
            //没网,则从本地获取,即离线加载
            webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        }
        //开启DOM storage API功能
        webSettings.setDomStorageEnabled(true);
        //开启database storage API功能
        webSettings.setDatabaseEnabled(true);
        //开启Application Cache功能
        webSettings.setAppCacheEnabled(true);
        String cacheDirPath = getFilesDir().getAbsolutePath()+"应用缓存路径名APP_CACAHE_DIRNAME";
        //设置Application cache缓存目录
        webSettings.setAppCachePath(cacheDirPath);

注意:每个Application只调用一次WebSettings.setAppCachePath(),WebSetting.setAppCacheMaxSize()。

2.加载方式

(1)加载一个网页:

    mWebView.loadUrl("http://www.google.com/");

(2)加载apk包中的一个html页面:

    mWebView.loadUrl("file:///android_asset/test.html");

(3)加载手机本地的一个html页面的方法:

    mWebView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");

3.WebViewClient

WebViewClient就是帮助WebView处理各种通知、请求事件的。
打开网页时,不调用系统浏览器,而是在本WebView中显示:

        mWebView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });

WebViewClient的方法:

        WebViewClient mWebViewClient = new WebViewClient(){
            //最常用的,比如上面的。在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作
            //比如获取url,查看url.contains("add"),进行添加操作
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                return super.shouldOverrideUrlLoading(view, url);
            }

            //重写此方法才能够处理在浏览器中的按键事件
            @Override
            public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
                return super.shouldOverrideKeyEvent(view, event);
            }

            //这个时间就是开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }

            //在页面加载结束时调用,同样道理,我们可以关闭loading条,切换程序动作。
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
            }

            //在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次
            @Override
            public void onLoadResource(WebView view, String url) {
                super.onLoadResource(view, url);
            }

            //拦截替换网络请求数据,API 11开始引入,API 21弃用
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
                return super.shouldInterceptRequest(view, url);
            }

            //拦截替换网络请求数据,API 21开始引入
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                return super.shouldInterceptRequest(view, request);
            }

            //报告错误信息
            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                super.onReceivedError(view, errorCode, description, failingUrl);
            }
            
            //更新历史记录
            @Override
            public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
                super.doUpdateVisitedHistory(view, url, isReload);
            }

            //应用程序重新请求网页数据
            @Override
            public void onFormResubmission(WebView view, Message dontResend, Message resend) {
                super.onFormResubmission(view, dontResend, resend);
            }

            //获取返回信息授权信息
            @Override
            public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
                super.onReceivedHttpAuthRequest(view, handler, host, realm);
            }

            //重写此方法可以让webview处理https请求
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                super.onReceivedSslError(view, handler, error);
            }

            //webview发生改变时调用
            @Override
            public void onScaleChanged(WebView view, float oldScale, float newScale) {
                super.onScaleChanged(view, oldScale, newScale);
            }
            
            //key事件未被加载时调用
            @Override
            public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
                super.onUnhandledKeyEvent(view, event);
            }
        };

将上面定义的WebViewClient设置给WebView:

        mWebView.setWebViewClient(mWebViewClient);

4.WebChromeClient

WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度条等。
方法中的代码都是有Android端自己处理。

        WebChromeClient mWebChromeClient = new WebChromeClient(){
            //获得网页的加载进度
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
               if (newProgress <100){
                   String progress = newProgress+"%";
               }else {
                   
               }
            }
            
            //获取Web页中的title用来设置自己界面中的title
            //当加载出错的时候,比如无网络,这时onReceivedTitle中获取的标题为找不到该网页,
            //因此建议当触发onReceiveError时不时使用获取到的title
            @Override
            public void onReceivedTitle(WebView view, String title) {
                MainActivity.this.setTitle(title);
            }

            @Override
            public void onReceivedIcon(WebView view, Bitmap icon) {
                //
            }

            @Override
            public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
                //
                return true;
            }

            @Override
            public void onCloseWindow(WebView window) {
                //
            }
            
            //处理alert弹出框,html弹框的一种方式
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                return true;
            }

            //处理prompt弹出框
            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                return true;
            }
            
            //处理confirm弹出框
            @Override
            public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
                return true;
            }
        };

同样,将上面定义的WebChromeClient设置给WebView:

        mWebView.setWebChromeClient(mWebChromeClient);

5.WebView的其他方法

(1)前进、后退:

        mWebView.goBack();//后退
        mWebView.goForward();//前进
        //以当前的index为起始点前进或者后退到历史纪录中指定的steps,
        //如果steps为负数则后退,正数则为前进
        mWebView.goBackOrForward(steps);
        
        mWebView.canGoBack();//是否可以后退
        mWebView.canGoForward();//是否可以前进

(2)清除缓存数据:

        //清除网页访问留下的缓存,由于内核缓存是全局的,因此这个方法不仅仅针对webview而是针对整个应用程序
        mWebView.clearCache(true);
        //清除当前webView访问的历史纪录,只会清除webview访问历史纪录里的所有历史纪录除了当前访问记录
        mWebView.clearHistory();
        //这个API仅仅清除自动完成填充的表单数据,并不会清除webView清除到本地的数据
        mWebView.clearFormData();

(3)webview的状态:

        //激活WebView为活跃状态,能正常执行网页的响应
        mWebView.onResume();
        //当页面被失去焦点被切换到后台不可见状态,需要执行onPause动作,onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
        mWebView.onPause();
        当应用程序被切换到后台我们使用了webview, 这个方法不仅仅针对当前的webview而是全局的全应用程序的webview,它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
        mWebView.pauseTimers();
        恢复pauseTimers时的动作。
        mWebView.resumeTimers();
        //销毁,关闭了Activity时,音乐或视频,还在播放。就必须销毁。
        mWebView.destroy();

注意:webview调用destory时,webview仍绑定在Activity上,这是由于自定义构建时传入了该Activity的context对象,因此需要先从父容器中移除webview,然后再销毁webview。

        RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.activity_main);
        rootLayout.removeView(mWebView);
        mWebView.destroy();

(4)判断WebView是否已经滚动到页面低端或者顶端:

  • getScrollY():方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离;
  • getHeight()或者getBottom():方法都返回当前WebView这个容器的高度;
  • getContentHeight():返回的是整个html的高度,但并不等同于当前整个页面的高度,因为WebView有缩放功能,所以当前整个页面的高度实际上应该是原始html的高度再乘上缩放比例,因此,更正后的结果,准确的判断方法应该是:
        if (mWebView.getContentHeight() * mWebView.getScale() == (mWebView.getHeight() + mWebView.getScrollY())){
            //已经处于底端
        }
        
        if (mWebView.getScrollY() == 0){
            //处于顶端
        }

(5)返回键
返回上一次浏览的页面:

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()){
            mWebView.goBack();
            return true;
        }
        return  super.onKeyDown(keyCode,event);
    }

(6)调用JS代码:(待续。。。)
首先在assets文件夹下创建一个html文档:

<body>
    <a>js中调用本地方法</a>
    <script>
        function funFromjs(){
            document.getElementById("helloweb").innerHTML="Hello WebView,I'm from js"
        }

        var aTag = document.getElementsByTagName('a')[0];
        aTag.addEventListener('click', function(){
            //调用android本地方法
            myObj.fun1FromAndroid("调用android本地方法fun1FromAndroid(String name)!!");
            return false;
        }, false);

    </script>

    <p></p>
    <div id="helloweb">

    </div>
</body>

接下来是主要交互的java代码:

        Button btn = (Button) findViewById(R.id.btn);
        mWebView = (WebView) findViewById(R.id.webview);
        WebSettings webSettings = mWebView.getSettings();
        //设置编码
        webSettings.setDefaultTextEncodingName("utf-8");
        //支持JS
        webSettings.setJavaScriptEnabled(true);
        //设置背景颜色 透明
        mWebView.setBackgroundColor(Color.argb(0, 0, 0, 0));
        //设置本地调用对象及其接口
        mWebView.addJavascriptInterface(new JavaScriptObject(JSActivity.this), "myObj");
        //载入js
        mWebView.loadUrl("file:///android_asset/test.html");
        //点击调用js中方法
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mWebView.loadUrl("javascript:funFromjs()");
                Toast.makeText(JSActivity.this, "调用javascript:funFromjs()", Toast.LENGTH_SHORT).show();
            }
        });

最后是上面代码中用到的JavaScriptObject对象:


public class JavaScriptObject {
    private Context mContext;


    public JavaScriptObject(Context context){
        this.mContext = context;
    }

    @JavascriptInterface
    public void fun1FromAndroid(String name) {
        Toast.makeText(mContext, name, Toast.LENGTH_LONG).show();
    }
    @JavascriptInterface
    public void fun2(String name){
        Toast.makeText(mContext, "调用fun2:"+name, Toast.LENGTH_SHORT).show();
    }
}

Android调用JS有一个漏洞:
http://blog.csdn.net/leehong2005/article/details/11808557

(7)Android5.0 WebView中Http和Https混合问题:
在Android 5.0上webview默认不允许加载Http与Https混合内容:
解决办法:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
            mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }

参数类型说明:
(1) MIXED_CONTENT_ALWAYS_ALLOW:允许从任何来源加载内容,即使起源是不安全的;
(2)MIXED_CONTENT_NEVER_ALLOW:不允许Https加载Http的内容,即不允许从安全的起源去加载一个不安全的资源;
(3)MIXED_CONTENT_COMPLTIBILITY_MODE:当涉及到混合式内容时,WebView会尝试去兼容最新Web浏览器的风格;
在5.0以下Android默认是全允许的。
但是到了5.0以上,就是不允许,实际情况下我们很难确定所有的网页都是Https的,所以我们就需要这一步的操作。

分享:WebView加载https页面不能正常显示资源问题

(8)Cookie相关
同步cookie只需要获得CookieManager的对象将cookie设置进去就可以了。
前提:从服务器的返回头中取出cookie根据Http请求的客户端不同,获取cookie的方式也不同,请自行获取。

  • 客户端通过一下代码设置cookie,如果两次设置相同,会覆盖上一次的。
    /**
     *将cookie设置到webView
     * @param url 需要加载的url
     * @param cookie 要同步的cookie
     */
    public static void syncCookie(String url,String cookie){
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
            CookieSyncManager.createInstance(context);
        }
        CookieManager cookieManager = CookieManager.getInstance();
        //如果没有特殊需求,这里只需要将session id以“key=value”形式作为cookie即可
        cookieManager.setCookie(url,cookie);
    }

注意:
1.同步cookie要在WebView加载url之前,否则WebView无法获得相应的cookie,也就无法通过验证;
2.cookie应该被及时更新,否则很可能导致WebView拿的是就得session id和服务器进行通信。

  • CookieManager会将这个Cookie存入该应用程序data/data/package_name/app_WebView/Cookies.db
  • 打开网页,WebView从数据库中读取该cookie值,放到http请求的头部,传到服务器;
    /**
     * 获取指定url的cookie
     */
    public static String syncCookie(String url){
        CookieManager cookieManager = CookieManager.getInstance();
        return cookieManager.getCookie(url);
    }
  • 清除Cookie:
        //这两个在API level 21被抛弃
        CookieManager.getInstance().removeSessionCookie();
        CookieManager.getInstance().removeAllCookie();

        //推荐使用这两个,level 21新加的
        CookieManager.getInstance().removeSessionCookies();//移除所有过期的cookie
        CookieManager.getInstance().removeAllCookies();//移除所有的cookie
    private void removeCookie(Context context){
        CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
            @Override
            public void onReceiveValue(Boolean aBoolean) {
                //清除结果
            }
        });
    }

(9)避免WebView内存泄漏的一些方式

  • 可以将WebView的Activity新起一个进程,结束的时候直接System.exit(0),退出当前进程;
    启动新进程,主要代码:AndroidManifest.xml配置文件代码如下:
        <activity android:name=".Html5Activity"
            android:process=":gjj.process.web">
            <intent-filter>
                <action android:name="com.gjj.activity.htmlactivity"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

在新进程中启动Activity,里面传了一个Url:

        Intent intent = new Intent("com.gjj.activity.htmlactivity");
        Bundle bundle = new Bundle();
        bundle.putString("url",url);
        intent.putExtra("bundle",bundle);
        startActivity(intent);

然后在Html5Activity的onDestroy()最后加上System.exit(0),杀死当前进程。

  • 不能在xml中定义WebView,而是在需要的时候创建,并且Context使用getApplicationContext,如下代码:
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        mWebView = new WebView(getApplicationContext());
        mWebView.setLayoutParams(params);
        mLayout.addView(mWebView);
  • 在Activity销毁的时候,可以先让WebView加载null内容,然后移除WebView,再销毁Webview,最后置空。
    @Override
    protected void onDestroy() {
        if (mWebView != null){
            mWebView.loadDataWithBaseURL(null,"","text/html","utf-8",null);
            mWebView.clearHistory();
            ((ViewGroup) mWebView.getParent()).removeView(mWebView);
            mWebView.destroy();
            mWebView = null
        }
        super.onDestroy();
    }

参考文章:
史上最全WebView使用,附送Html5Activity一份
轻松搞定WebView cookie同步问题


亲,如果您感觉本文有用,请点个赞再走吧✌(>‿◠)!!

转载于:https://my.oschina.net/ZhenyuanLiu/blog/1841619

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值