Android入门——WebView使用及Java和JavaScript交互小结

引言

目前很多android app都内置了可以显示web页面的界面,会发现这个界面一般都是由一个叫做WebView的组件渲染出来的,学习该组件可以为你的app开发提升扩展性。Java和Javascript交互项目实战源码

一、WebView 概述

正如字面意思一样,是用来展示Web页面的。通过WebView控件我们可以在App中直接使用PC端的Web页面,通过addJavascriptInterface方法还可以实现JavaScript方法和Java方法的互相调用,减少了不少的开发成本。简而言之,WebView就是内置小型浏览器。

二、WebView的常用的方法

1、构造方法

方法名参数说明
WebView(Context context)传递上下文用于访问应用程序资源
WebView(Context context, AttributeSet attrs)attrs:传递给父容器的属性集合
WebView(Context context, AttributeSet attrs, int defStyle)defStyle:样式style资源的id

2、其他常用方法

方法名参数说明用法说明
void addJavascriptInterface(Object obj, String interfaceName)obj:自定义的Java对象,interfaceName:js中调用时使用的实例变量名将对象绑定到的Javascript,这样的方法可以从JavaScript访问。
boolean canGoBack()/canGoBackOrForward()/canGoForward()设置是否允许返回上一页、前进等
boolean dispatchKeyEvent(KeyEvent event)event对象设置事件的传递
String getOriginalUrl()获取原始的Url
int getProgress()获取当前网页的进度
WebSettings getSettings()获取WebView一系列属性集合,用于配置WebView
void loadData(String data, String mimeType, String encoding)data:字符串拼接形式的html代码用于把字符串形式的html代码渲染成为网页的形式
void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)
void loadUrl(String url)把url对应的文件或者url网址渲染成为网页
void setWebChromeClient(WebChromeClient client)设置打开i时不用系统浏览器,而使用本地WebView打开

3、WebSettings常用的方法

方法名用法说明
setSupportZoom(boolean support)设置WebView是否支持使用屏幕控件或手势进行缩放,默认是true,支持缩放。
setMediaPlaybackRequiresUserGesture(boolean require)设置WebView是否通过手势触发播放媒体,默认是true,需要手势触发。
setBuiltInZoomControls(boolean enabled)设置WebView是否使用其内置的变焦机制,该机制集合屏幕缩放控件使用,默认是false,不使用内置变焦机制。
setDisplayZoomControls(boolean enabled)设置WebView使用内置缩放机制时,是否展现在屏幕缩放控件上,默认true,展现在控件上。
setAllowFileAccess(boolean allow)设置在WebView内部是否允许访问文件,默认允许访问。
setAllowContentAccess(boolean allow)设置WebView是否使用其内置的变焦机制,该机制结合屏幕缩放控件使用,默认是false,不使用内置变焦机制。
setLoadWithOverviewMode(boolean overview)设置WebView是否使用预览模式加载界面。
setSaveFormData(boolean save)设置WebView是否保存表单数据,默认true,保存数据。
setTextZoom(int textZoom)设置WebView中加载页面字体变焦百分比,默认100,整型数。
setAcceptThirdPartyCookies(boolean accept)设置WebView访问第三方Cookies策略,参考CookieManager提供的方法:setShouldAcceptThirdPartyCookies
setUseWideViewPort(boolean use)设置WebView是否使用viewport,当该属性被设置为false时,加载页面的宽度总是适应WebView控件宽度;当被设置为true,当前页面包含viewport属性标签,在标签中指定宽度值生效,如果页面不包含viewport标签,无法提供一个宽度值,这个时候该方法将被使用,当setUseWideViewPort(true)和setLoadWithOverviewMode(true)可以支持自适应
setSupportMultipleWindows(boolean support)设置WebView是否支持多屏窗口,参考WebChromeClient#onCreateWindow,默认false,不支持。
setLayoutAlgorithm(LayoutAlgorithm l)设置WebView底层的布局算法,参考LayoutAlgorithm#NARROW_COLUMNS,将会重新生成WebView布局
setStandardFontFamily(String font)设置WebView标准字体库字体,默认字体“sans-serif”。
setFixedFontFamily(String font)设置WebView固定的字体库字体,默认“monospace”。
setSansSerifFontFamily(String font)设置WebView Sans SeriFontFamily字体库字体,默认“sans-serif”。
setSerifFontFamily(String font)设置WebView seri FontFamily字体库字体,默认“sans-serif”。
setCursiveFontFamily(String font)设置WebView字体库字体,默认“cursive”
setFantasyFontFamily(String font)设置WebView字体库字体,默认“fantasy”。
setMinimumFontSize(int size)设置WebView字体最小值,默认值8,取值1到72
setMinimumLogicalFontSize(int size)设置WebView逻辑上最小字体值,默认值8,取值1到72
setDefaultFontSize(int size)设置WebView默认值字体值,默认值16,取值1到72
setDefaultFixedFontSize(int size)设置WebView默认固定的字体值,默认值16,取值1到72
setLoadsImagesAutomatically(boolean flag)设置WebView是否加载图片资源,默认true,自动加载图片
setBlockNetworkImage(boolean flag)设置WebView是否以http
setBlockNetworkLoads(boolean flag)设置WebView是否从网络加载资源,Application需要设置访问网络权限,否则报异常
setJavaScriptEnabled(boolean flag)设置WebView是否允许执行JavaScript脚本,默认false,不允许
setAllowUniversalAccessFromFileURLs(boolean flag)设置WebView运行中的脚本可以是否访问任何原始起点内容,默认true
setAllowFileAccessFromFileURLs(boolean flag)设置WebView运行中的一个文件方案被允许访问其他文件方案中的内容,默认值true
setGeolocationDatabasePath(String databasePath)设置WebView保存地理位置信息数据路径,指定的路径Application具备写入权限
setAppCacheEnabled(boolean flag)设置Application缓存API是否开启,默认false,设置有效的缓存路径参考setAppCachePath(String path)方法
setAppCachePath(String appCachePath)设置当前Application缓存文件路径,Application Cache API能够开启需要指定Application具备写入权限的路径
setDatabaseEnabled(boolean flag)设置是否开启数据库存储API权限,默认false,未开启,可以参考setDatabasePath(String path)
setDomStorageEnabled(boolean flag)设置是否开启DOM存储API权限,默认false,未开启,设置为true,WebView能够使用DOM storage API
setGeolocationEnabled(boolean flag)设置是否开启定位功能,默认true,开启定位
setJavaScriptCanOpenWindowsAutomatically(boolean flag)设置脚本是否允许自动打开弹窗,默认false,不允许
setDefaultTextEncodingName(String encoding)设置WebView加载页面文本内容的编码,默认“UTF-8”。
setUserAgentString(String ua)设置WebView代理字符串,如果String为null或为空,将使用系统默认值
setNeedInitialFocus(boolean flag)设置WebView是否需要设置一个节点获取焦点当被回调的时候,默认true
setCacheMode(int mode)重写缓存被使用到的方法,该方法基于Navigation Type,加载普通的页面,将会检查缓存同时重新验证是否需要加载,如果不需要重新加载,将直接从缓存读取数据,允许客户端通过指定LOAD_DEFAULT
setMixedContentMode(int mode)设置当一个安全站点企图加载来自一个不安全站点资源时WebView的行为,android.os.Build.VERSION_CODES.KITKAT默认为MIXED_CONTENT_ALWAYS_ALLOW,android.os.Build.VERSION_CODES#LOLLIPOP默认为MIXED_CONTENT_NEVER_ALLOW,取值其中之一:MIXED_CONTENT_NEVER_ALLOW

三、WebView的应用

1、使用WebView的基本步骤

  • 首先,构造WebView,可以通过静态构造直接在xml布局里声明,还可以通过java代码动态创建。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    <WebView android:id="@+id/id_table_webview" android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

 mWebview = (WebView) findViewById(R.id.id_table_webview);//获取WebVIew
WebView webView = new WebView(context);
  • 其次,在Activity的生命周期方法(一般在onCreate)里,配置WebView(主要是先调用getSetting()获取属性集再设置、设置支持javascript、回退、是否使用系统自带浏览器打开等等)
public class MyWebViewCient extends WebViewClient {
    /**
     * WebView能够响应页面的超链接
     * @param view
     * @param url
     * @return
     */
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }
}
mWebview.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);///一系列的初始化设置
mWebview.getSettings().setAllowFileAccess(true);// 设置允许访问文件数据
mWebview.getSettings().setSupportZoom(true);//支持放大网页功能
mWebview.getSettings().setBuiltInZoomControls(true);//支持缩小网页功能
mWebview.getSettings().setJavaScriptEnabled(true);
mWebview.addJavascriptInterface(new JSObject(), "employee");//前面对象,后面js中的调用名(我们可以看成这个JSObject类的实例是employee,用于给javascript里调用
mWebview.setWebViewClient(new MyWebViewCient());//设置打开i时不用系统浏览器。使用本地WebView打开
  • 然后调用loadUrl、loadData、loadDataWithBaseURL加载并显示对应的网页内容
mWebView.loadUrl("http://www.google.com"); //加载互联网的url地址
mWebView.loadUrl("file:///android_asset/xxx.html"); //加载并显示存放在assets 文件下的html
mWebView.loadUrl("file:///mnt/sdcard/web/xxx.html" );//加载sdcard下的html
//设置回退,覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法  
public boolean onKeyDown(int keyCode, KeyEvent event) {  
    if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebview.canGoBack()) {  
        mWebview.goBack(); //返回WebView的上一页面  
        return true;  
    }  
    return false;  
}  
  • 接着,若用WebView点链接跳转到其他页以后,为了让WebView支持回退功能,则需要覆盖Activity类的onKeyDown()方法;反之,不做任何处理,点击系统回退剪键,整个浏览器会调用finish()而结束自身,而不是回退到上一页面

5.最后,还需在AndroidManifest.xml文件中添加权限——uses-permission android:name=“android.permission.INTERNET”,否则会出现Web page not available错误。

package com.xiaoi.app.smartbot.view.activity;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.xiaoi.app.smartbot.R;

/**
 * auther: Crazy.Mo
 * Date: 2017/4/5
 * Time:15:08
 * Des:
 */

public class WebViewActivity extends BaseActivity {
    private WebView webView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);
        init();
    }

    private void init(){
        webView= (WebView) findViewById(R.id.id_webv);
        initWebView();
    }

    private void initWebView(){

        if(getIntent()!=null) {
            webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);///一系列的初始化设置
            webView.getSettings().setAllowFileAccess(true);// 设置允许访问文件数据
            webView.getSettings().setSupportZoom(true);//支持放大网页功能
            webView.getSettings().setBuiltInZoomControls(true);//支持缩小网页功能
            webView.getSettings().setJavaScriptEnabled(true);
            ///webView.addJavascriptInterface(new JSObject(), "employee");//前面对象,后面js中的调用名(我们可以看成这个JSObject类的实例是employee,用于给javascript里调用
            webView.loadUrl(getIntent().getStringExtra("url"));
            webView.setWebViewClient(new MyWebViewCient());//设置打开i时不用系统浏览器。使用本地WebView打开
        }
    }

    public static void openWebViewActivity(@NonNull Context context,@NonNull int requestCode,@NonNull String url){
        WebViewActivity activity=new WebViewActivity();
        Intent intent=new Intent(context,WebViewActivity.class);
        intent.putExtra("url", url);
        context.startActivity(intent);
        ///activity.startActivityForResult(intent,requestCode);
    }

    //设置回退,覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法
//    @Override
//    public boolean onKeyDown(int keyCode, KeyEvent event) {
//        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
//            webView.goBack(); //返回WebView的上一页面
//            return true;
//        }
//        return false;
//    }

    private static class MyWebViewCient extends WebViewClient {
        /**
         * WebView能够响应页面的超链接
         * @param view
         * @param url
         * @return
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }
}

    @Override
    protected void onDestroy() {
        super.onDestroy();
        webView.loadUrl("about:blank");
        webView.stopLoading();
        webView= null;
    }

四、通过WebView实现Java和Javascript的互相交互步骤

Android端是不能直接去和Javascript交互的,反过来也一样。WebView实现Java和Javascript的互相交互实例

1、Java端通过WebView调用Javascript脚本方法

  • 获取WebView对象并设置setJavaScriptEnabled(true)及其他初始化

  • 通过WebView实例的loadUrl方法调用javascript脚本方法,通用语法格式mWebview.loadUrl(“javascript: 网页中对应的Javascript的方法名([参数])”);//通过webview调用js 方法,需要注意的是参数类型必须一致,如果不一致需要转为为统一的数据格式

2、Javascript端调用Java方法

  • 获取WebView对象并设置setJavaScriptEnabled(true)及其他初始化

  • 在Java端自定义提供给Javascript端调用的公共方法showContacts并封装为Java对象,建议以JSXxxxx来命名这个对象,比如JSOject

  • 通过WebView实例的addJavascriptInterface(new JSXxxxx(),“employee”),添加上javascritp端对应的实例名employee

  • 在Javascript端通过javascript:employee.showContacts()间接调用Java方法showContacts

    private final class JSObject {
        /**
         * html中通过自定义的js 对象调用
         * 高能预警:If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface
         即在一切需要在JS中调用的对象方法前加上@JavascriptInterface, 在api 17 即 Android 4.2.2 之后
         */
        @JavascriptInterface
        public void showContacts() {

            List<Contacts> contactses = mContactsService.getContactsImf();
            JSONArray jsonArray = new JSONArray();
            try {
                for (Contacts contact : contactses) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("id", contact.getId());
                    jsonObject.put("name", contact.getName());
                    jsonObject.put("phone", contact.getPhone());
                    jsonArray.put(jsonObject);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            final String json = jsonArray.toString();
            /**
             *  A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread
             *  简单来说就是html里调用java方法和java调用js方法必须在同一线程
             */
            mWebview.post(new Runnable() {
                @Override
                public void run() {
                    mWebview.loadUrl("javascript:show('" + json + "')");//通过webview调用js 方法
                }
            });
        }
    }
    // Javascript端调用
<body onload="javascript:employee.showContacts()">

五、WebView的缓存机制

WebView是手机中内置了一款高性能webkit 内核浏览器,在SDK 中封装的一个组件,在Android端中缓存可以分为:网页缓存应用缓存

1、网页缓存

网页缓存在data/应用package下生成database与cache两个文件夹,请求的Url记录是保存在webviewCache.db里,而url的内容是保存在webviewCache文件夹下

/data/data/package_name/cache/
/data/data/package_name/database/webview.db
/data/data/package_name/database/webviewCache.db

支持的缓存模式有:

  • LOAD_CACHE_ONLY—— 不使用网络,只读取本地缓存数据,
  • LOAD_DEFAULT——根据cache-control决定是否从网络上取数据,
  • LOAD_CACHE_NORMAL——API level 17中已经废弃, 从API level 11开始作用同- - LOAD_DEFAULT模式,
  • LOAD_NO_CACHE——不使用缓存,只从网络获取数据,
  • LOAD_CACHE_ELSE_NETWORK——只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
    如果一个页面的cache-control为no-cache,在模式LOAD_DEFAULT下,无论如何都会从网络上取数据,如果没有网络,就会出现错误页面;在LOAD_CACHE_ELSE_NETWORK模式下,无论是否有网络,只要本地有缓存,都使用缓存。本地没有缓存时才从网络上获取。如果一个页面的cache-control为max-age=60,在两种模式下都使用本地缓存数据。

2、应用缓存

根据setAppCachePath(String appCachePath)提供的路径,在H5使用缓存过程中生成的缓存文件。无模式选择,通过setAppCacheEnabled(boolean flag)设置是否打开。默认关闭,即,H5的缓存无法使用。如果要手动清理缓存,需要找到调用setAppCachePath(String appCachePath)设置缓存的路径,把它下面的文件全部删除就OK了。

六、使用WebView时注意事项

1、加载本地assets里的js,css,html资源时候,在编写html文件引用这些资源需要把对应在assets下的绝对路径引入

2、 使用loadData(data)方法加载并显示网页时候,data里含有以下四个特殊字符:’#’, ‘%’, ‘’ , ’ ’ ,如果有的话可以用 %23, %25, %27, %3f来替换,解决中文乱码可以传递编码——utf-8来解决否则可能造成错误。

 %:会报找不到页面错误,页面全是乱码。
 
 #:会让你的goBack失效,但canGoBack是可以使用的。于是就会产生返回按钮生效,但不能返回的情况。
   
\:在转换时,会报错,因为它会把\当作转义符来使用,如果用两级转义,也不生效

目前较好的转码方案

//目前较好的转码方案
 final String digits = "0123456789ABCDEF";     
  public String encode(String s){  
                 
                  StringBuilder buf = new StringBuilder(s.length() + 16);  
                  for (int i = 0; i < s.length(); i++) {  
                      char ch = s.charAt(i);  
                      if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')  
                              || (ch >= '0' && ch <= '9') || ".-*_".indexOf(ch) > -1) { //$NON-NLS-1$   
                          buf.append(ch);  
                      } else {  
                          byte[] bytes = new String(new char[] { ch }).getBytes();  
                          for (int j = 0; j < bytes.length; j++) {  
                              buf.append('%');  
                              buf.append(digits.charAt((bytes[j] & 0xf0) >> 4));  
                              buf.append(digits.charAt(bytes[j] & 0xf));  
                          }  
                      }  
                  }  
                  return buf.toString();  
      }
mWebView.loadData(this.encode(html), "text/html", "utf-8");

值得注意的是,当我替换掉特殊字符再使用loadData时,如果有大量的特殊字符和大量stytle(会使用很多%号)会给运行速度带来很大的影响,页面的数据越多,运行的速度就会越慢。

3、加载有特殊字符的网页时,可以考虑使用loadDataWithBaseURL方法

4、加载静态网页没有问题,加载远程(WIFI)动态页面时需要注意,图片加载可能会出现问题(因为一般情况下Web页面中给出的是图片相对路径,并没有给完整的HTPP路径,所以有时候得自行处理下,不然图片无法正常加载)

待续…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值