Webview与Javascript

本文详细介绍了Android WebView的使用,包括WebView概述、相关工具类、基本使用和与JavaScript的交互。强调了混合开发的优势和可能存在的安全漏洞,如密码明文存储、File域控制不严格和远程代码执行等,并给出了相应的防范措施。此外,还讨论了其他问题,如http/https混合问题、内存泄漏和后台耗电等。
摘要由CSDN通过智能技术生成

文章中的所有用例可以在JSDemo中找到

0x01 WebView 概述

WebView 是 Android 的一个控件,用于在应用程序中展示 Web 网页

Google 的官方解释为

A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.

Android 的 WebView 使用 webkit 引擎,Android 4.4(API 19)之后直接使用 Chromium,因此可以支持 HTML5、CSS3 以及 JavaScript

基于 WebView 出现了混合开发,开发的应用也称为 Hybrid APP,原生开发一些迭代稳定的页面及功能,快速迭代的内容则基于 WebView 框架/容器通过 HTML5 展示,好处在于,HTML5 代码可以轻易实现跨平台,且迭代方便,但是受网络限制以及可能会存在一些体验问题(前端页面代码渲染,受限于JS的解析效率及设备硬件性能)

总结来说,WebView 的作用包括:

  1. 展示和渲染网页;
  2. 混合开发,与页面的 JavaScript 交互。
0x02 WebView 相关工具类
2.1 WebSettings

对 WebView 的相关配置进行管理,以下为常用接口

// 获取 WebView 配置对象
WebSettings webSettings = webView.getSettings();
// 允许保存网页密码
webSettings.setSavePassword(true);
// 允许网页与JS交互【可能导致严重漏洞】
webSettings.setJavaScriptEnabled(true);
// 允许通过JS打开新窗口
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// 允许插件
webSettings.setPluginsEnabled(true);
// 允许网页开启定位功能
webSettings.setGeolocationEnabled(true);
// 允许本地File域访问
webSettings.setAllowFileAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setAllowUniversalAccessFromFileURLs(true);
// 调节屏幕自适应
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);
// 调节允许缩放,但不显示按钮
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setDisplayZoomControls(false);			// 缩放按钮,部分系统在缩放按钮消失前退出Activity可能引发应用崩溃,故通常设置为false,或在Activity被销毁时手动隐藏这个View
webSettings.setTextZoom(20);				// 文本缩放倍数,默认100
// 缓存设置,缓存模式有四种
// 缓存内容会保存在沙箱目录下,databases会保存请求的url记录,cache则会保存url内容
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
// 使用DOM或数据库或文件构建离线缓存
webSettings.setDomStorageEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setAppCacheEnabled(true);
2.2 WebViewClient

处理各种通知、请求事件

webView.setWebViewClient(new WebViewClient() {
   
  @Override
  // 拦截url请求,进行处理或重定向,返回true表示已经处理完url,返回false则将url交还给webview加载
  public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
   
    return super.shouldOverrideUrlLoading(view, request);
  }
  
  // 证书认证错误时的回调
  @Override
  public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
   
    super.onReceivedSslError(view, handler, error);
  }    
});

// onPageStarted()/onPageFinished():页面开始加载及加载完成
// shouldInterceptRequest():页面请求资源
// onLoadResource():页面加载资源
2.3 WebChromeClient

处理JS的对话框、网址图标、网址标题和加载进度等

webView.setWebChromeClient(new WebChromeClient() {
   
  @Override
  public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
   
    // 网页弹出提示框时回调
    result.cancel();
    // 返回true表示不弹出系统的提示框,返回false则弹出
    return true;
  }
  
  @Override
  public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
   
    // 网页弹出确认框时回调,confirm确认,cancel取消
    result.confirm();
    return true;
  }
  
  @Override
  public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
   
    // 网页弹出输入框时回调,可以调用confirm返回内容或cancel取消
    result.confirm("got it!");
    return true;
  }    
});

// onProgressChanged():获得网页的加载进度
// onReceivedTitle():获取网页标题
// onCreateWindow()/onCloseWindow():打开或关闭窗口
0x03 WebView 基本使用
  1. 需要在清单文件中声明网络访问权限
<uses-permission android:name="android.permission.INTERNET"/>
  1. WebView 布局
<WebView
  android:id="@+id/webview"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />
  1. 获取 WebView 控件
WebView webView = (WebView) findViewById(R.id.webview);

也可以在代码中动态创建,注意使用ApplicationContext,可以避免WebView内存泄漏

WebView webView = new WebView(getApplicationContext());
webView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
rootView.addView(webView);

有文章提到,使用ApplicationContext创建WebView可以避免WebView持有当前Activity的引用,因此也避免了内存泄漏的问题,但是同时会导致第三方应用打开网页链接异常、弹出Dialog异常、使用Flash异常;

也可以直接使用当前Activity作为Context创建WebView,并将此Activity运行在独立进程中,参考6.2

  1. 生命周期基本上同 Activity
@Override
protected void onResume() {
   
  super.onResume();
  // 恢复webview的状态(不建议)
  webView.resumeTimers();
  // 激活WebView为活跃状态,能正常执行网页的加载与响应
  webView.onResume();
}

@Override
protected void onPause() {
   
  super.onPause();
  // 失去焦点或进入后台时,暂停WebView的所有的解析和执行
  webView.onPause();
  // 暂停全局的WebView,降低CPU功耗(不建议)
  webView.pauseTimers();
}
  1. 销毁WebView时先加载null,接着清除相关数据,然后移除WebView,最后销毁并置空
@Override
protected void onDestroy() {
   
  // webView绑定了activity,为避免内存泄漏,调用destory时需先从父容器中移除再销毁
  if (webView != null) {
   
    webView.loadDataWithBaseURL(null, "", "", "", null);
    webView.clearCache(true);
    webView.clearHistory();
    webView.stopLoading();
    webView.setWebChromeClient(null);
    webView.setWebViewClient(null);
    ((ViewGroup) webView.getParent()).removeView(webView);
    webView.destroy();
    webView = null;
  }
  super.onDestroy();
}
  1. 加载网页或数据通常有以下四个API

loadUrl(String url)加载页面,可以为网页或本地页面,如

// 加载网页
webView.loadUrl("https://www.baidu.com");
// 加载应用资源文件内的文件
webView.loadUrl("file:///android_asset/javascript.html");
// 加载本地的文件
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/javascript.html");

loadUrl(String url, Map<String, String> additionalHttpHeaders)与上一个接口类似,第二个参数允许携带HTTP头部

loadData(String data, String mimeType, String encoding)加载一段代码,通常为网页的部分内容,参数分别为内容、类型和编码方式,如

webView.loadData("<html>\n" +
                "<head>\n" +
                "    <title>网页demo</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "<h2>\n" +
                "    使用WebView加载网页代码\n" +
                "</h2>\n" +
                "</body>\n" +
                "</html>", "text/html", "utf-8");

loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)与上一个接口相似,兼容性更好,适用场景更多,如

String img = "展示CSDN的图示,通过相对地址访问<img src='/cdn/content-toolbar/csdn-logo.png?v=20200416.1' />";
webView.loadDataWithBaseURL("https://csdnimg.cn", img, "text/html", "utf-8",null);

.

使用loadData()加载中文数据出现乱码的问题,一个方案是使用loadDataWithBaseURL()方法,另一个方案是mimeType参数传入“text/html;charset=UTF-8”;另外loadData()方法数据中的未定义字符#%\?需要使用%23%25%27%3f代替,但是非法字符的转换会影响运行速度

  1. 其他一些常用方法
// 页面的前进与后退
boolean canGoBack = webView.canGoBack
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值