[Android基础]WebView的简单使用

[TOC]


[ Demo下载 ]

资源

  1. Web Apps
  2. WebView
  3. Android4.4 webview实现分析
  4. Android WebView使用深入浅出
  5. 深入讲解WebView(上) - 互调,缓存,异常处理等
  6. 深入讲解WebView(下) - session,cookie等
  7. Android WebView Memory Leak WebView内存泄漏 ==! 这个我用leakcanary没检测出来
  8. PHP、Android、iOS 的恩恩怨怨

从Android 4.4(KitKat)开始,WebView组件是基于开源的Chromium项目.包含V8 js引擎并支持新的web标准,新webView也共享Chrome for Android的渲染引擎,另外,从5.0(Lollipop)开始,WebView被移到独立的apk中,因此它可以进行单独更新,可以从 "settings -- Apps -- Android System WebView" 中查看其版本;

用途

默认情况下,webView不启用js交互,并会忽略页面错误,适用于展示静态信息;
也可以启用js功能,实现与用户的交互

辅助类

  • WebChromeClient 当可能影响webView UI的操作发生时会调用到该类,比如进度变化或者js提示框...
  • WebViewClient 当可能影响内容渲染的操作发生时会调用到该类,比如错误等...另外,可以通过重写 shouldOverrideUrlLoading() 来中断url的加载;
  • WebSettings 功能设置,比如可否允许js代码;

基本操作

  • 访问网络的话需要添加网络权限

  • 启用js功能
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

操作localStorage

项目中接到的要求,要传给H5页面添加一些token值,方便其发送非url请求的时候调用
P.S. shouldOverrideUrlLoading() 只能拦截url超链接请求,对于H5页面自己发送其他非跳转请求的话这个方法是没法拦截的
shouldInterceptRequest() 是返回给app端一个response,如果方法返回的是null则走正常网络请求返回,否则就返回给定的response,
想到的方案是调用js代码给localstorage中设定一些值,方便h5调用,当然给出一个原生方法给h5调用也一样

mWebSettings = mWebView.getSettings();
mWebSettings.setJavaScriptEnabled(true);
mWebSettings.setDomStorageEnabled(true);//给权限

mWebView.setWebViewClient(new WebViewClient() {

        // 不在 onPageStart() 中去设置是因为设置完以后又loadUrl(url),之前设定的值就无效了
        // 当然,在 onPageFinished() 设置的话也得H5中在document.ready()之后才能去获取
        // 或者也可以考虑在 WebChromeClient 的 onProgressChanged() 方法中作设定

        @Override
        public void onPageFinished(WebView view, String url) {
                                          LogUtils.d("footTest", "onPageFinished " + url);
                                          view.loadUrl(
                                                  "javascript:" +
                                                          "localStorage.setItem('token', '" + UacDataInstance.getUserTokenWithoutBear() + "');");
        }
    }
);

设置返回键回退功能

mWv.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                // 需要添加 mWv.canGoBack(),不然当返回到初始页面时,可能无法继续通过返回键关闭页面
                if (keyCode == KeyEvent.KEYCODE_BACK && mWv.canGoBack()) {
                    mWv.goBack();
                    return true;
                }
                return false;
            }
        });

也可以通过设置所在Activity的onBackPressed()方法来支持webView回退:

@Override
public void onBackPressed() {
    if (mWv.canGoBack()) {
        mWv.goBack();
    } else {
        super.onBackPressed();
    }
}

设置标题

mWv.setWebChromeClient(new WebChromeClient(){
    @Override
    public void onReceivedTitle(WebView view, String title) {
        // title 是获取到的网页title,可以将之设置为webView所在页面的标题
        MainActivity.this.setTitle(title);
    }
)};

设置加载进度

@Override
protected void onCreate(Bundle savedInstanceState) {
    //requestWindowFeature(Window.FEATURE_PROGRESS);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
    ......

    mProgressDlg = new ProgressDialog(this);
    mProgressDlg.setMessage("loading...");
    
    mWv.setWebChromeClient(new WebChromeClient() {
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            //更新进度条示数
            
            //这种方式我没看到效果...
            //MainActivity.this.setProgress(newProgress);
            
            //使用控件ProgressDialog来显示进度
            //但记得这种方式需要在error发生时也进行取消
            if (newProgress <= 90) {
                mProgressDlg.setProgress(newProgress);
            } else {
                mProgressDlg.dismiss();
            }
        }
    });

    mWv.setWebViewClient(new WebViewClient() {
        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            super.onReceivedError(view, request, error);
            // 加载某些网站的时候会报:ERR_CONNECTION_REFUSED,因此需要在这里取消进度条的显示
            Toast.makeText(MainActivity.this, "error", Toast.LENGTH_SHORT).show();
            if (mProgressDlg.isShowing()) {
                mProgressDlg.dismiss();
            }
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            if (!mProgressDlg.isShowing()) {
                mProgressDlg.show();
            }
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (mProgressDlg.isShowing()) {
                mProgressDlg.dismiss();
            }
        }
    });

控制url跳转

mWv.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // 这个方法我没有重写的话也还是使用webView来加载链接
        // 而且我这里测试返回的true/false貌似没什么影响
        
        if (Uri.parse(url).getHost().endsWith("jianshu.com")) {
            //若是指定服务器的链接则在当前webView中跳转
            view.loadUrl(url);
            return false;
        } else if (Uri.parse(url).getHost().length() == 0) {
            // 本地链接的话直接在webView中跳转
            return false;
        }

        // 其他情况则使用系统浏览器打开网址
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
        return true;
    }
});

加载页面

1. 加载本地asset文件

 mWv.loadUrl("file:///android_asset/index.html");

2. 加载本地网页2

//index.html文件放置于 src/main/assets 目录中
myWebView.loadUrl("file:///android_asset/index.html");

3. 加载网页

myWebView.loadUrl("http://www.jianshu.com/users/302253a7ed00/latest_articles");

4. 解析html字符串

String summary = "\n" +
        "\n" +
        "\n" +
        "    \n" +
        "    webViewDemoFromAsset\n" +
        "    \n" +
        "\n" +
        "\n" +
        "
\n" + " \n" + "
\n" + "\n" + "\n" + "\n" + "
\n" + "个人主页\n" + "\n" + ""; // 官网例子给的下面的写法,但是会出现中文乱码, // 原因:http://blog.csdn.net/top_code/article/details/9163597 // mWv.loadData(summary, "text/html", "utf-8"); mWv.loadData(summary, "text/html;charset=UTF-8", null);

使用android studio的话,项目结构中没有asset目录,需要手动创建 src/main/assets 目录即可;
扩展:

  1. 如果html文件存于sdcard:则加前缀:
    content://com.android.htmlfileprovider/sdcard/
    另外, content 前缀可能导致异常,直接使用 file:///sdcard/ 或者 file:/sdcard 也可以;
  2. 也可使用 locaData() ,先将文件读取出来,在传入字符串到方法中,可以用于展示页面,但不会引用css,js等文件;

js与andorid互调

  1. 通过 addJavaScriptInterface() 来设置接口,传入实例和类名,让js可以调用;

Note: The object that is bound to your JavaScript runs in another thread and not in the thread in which it was constructed.
允许网页调用android功能可以存在风险,比如加载其他网页,默认做法是使用浏览器去加载外部其他网页;

  1. 自定义的js对应andoird实现类
//通过webView按钮调用android toast功能
public class BasicJsAppInterface {
    private Context cxt;
    public BasicJsAppInterface(Context cxt) {
        this.cxt = cxt;
    }
    // 如果targetSDKVersion设置为17以上,这里需要添加该annotation标志
    @JavascriptInterface
    public void showToast() {
        Toast.makeText(this.cxt, "toast in android", Toast.LENGTH_SHORT).show();
    }
}
// 实现js调用android功能
WebView mWv = (WebView) findViewById(R.id.wv);
 WebSettings wvSettings = mWv.getSettings();
wvSettings.setJavaScriptEnabled(true);
wvSettings.setDefaultTextEncodingName("utf-8");
//传入实现js功能的android实例 以及 js调用时使用的名称
mWv.addJavascriptInterface(new BasicJsAppInterface(this), "AndroidApp");
//加载本地asset文件,以 `file:///` 开头
mWv.loadUrl("file:///android_asset/index.html");

1. js 调用 android 功能

// 在src/main/assets 目录(不存在则手动创建)中创建该html文件



    
    webViewDemoFromAsset
    



github主页 主页

注意:这里引入的独立js文件标签不能简写成

你可能感兴趣的:([Android基础]WebView的简单使用)