IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]WebView使用详解(一)——Native与JS相互调用(附JadX反编译)

    harvic880925发表于 2016-05-20 21:56:20
    love 0

    前言:念念不忘,必有回响,永远坚持你所坚持的!


    一直在用WebView,还没有系统的总结过它的用法,下面就系统的总结下,分享给大家

    一、基本用法

    1、加载在线URL

    void loadUrl(String url)
    这个函数主要加载url所对应的网页地址,或者用于调用网页中的指定的JS方法(调用js方法的用法,后面会讲),但有一点必须注意的是:loadUrl()必须在主线程中执行!!!否则就会报错!!!。
    注意:加载在线网页地址是会用到联网permission权限的,所以需要在AndroidManifest.xml中写入下面代码申请权限:
    <uses-permission android:name="android.permission.INTERNET" />
    本示例效果为:

    从效果图中可以明显看出本示例的布局:
    main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent"
            >
        <Button
                android:id="@+id/btn"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="加载URL"/>
    
        <WebView
                android:id="@+id/webview"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
    </LinearLayout>
    对应的处理代码如下
    public class MyActivity extends Activity {
    
        private WebView mWebView;
        private Button mBtn;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            mWebView = (WebView)findViewById(R.id.webview);
            mBtn = (Button)findViewById(R.id.btn);
    
            mBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mWebView.loadUrl("http://www.baidu.com");
                }
            });
        }
    }
    代码很简单,就是在点击按钮的时候加载网址,但需要注意的是:网址必须完整即以http://或者ftp://等协议开头,不能省略!不然将加载不出来,这是因为webview是没有自动补全协议功能的,所以如果我们不加,它将识别不出来网址类型,也就加载不出来了。
    但如果我们运行上面的代码,效果却是利用浏览器来打开网址,却不是使用webview打开网址:

    如果我们想实现像示例一样在webview中打开网址需要怎么做呢?
    我们需要设置WebViewClient:
    修改后的代码为:

    public class MyActivity extends Activity {
    
        private WebView mWebView;
        private Button mBtn;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            mWebView = (WebView)findViewById(R.id.webview);
            mBtn = (Button)findViewById(R.id.btn);
    
            mWebView.setWebViewClient(new WebViewClient());
    
            mBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mWebView.loadUrl("http://www.baidu.com");
                }
            });
        }
    }
    在上面的基础上,我们添加了下面一段代码:
    mWebView.setWebViewClient(new WebViewClient());
    在这里我们利用mWebView.setWebViewClient()函数仅仅设置了一个WebViewClient实例,就可以实现在WebView中打开链接了,至于原因我们下篇会讲到,这里就先忽略了,大家只需要知道要在WebView中打开链接,就必须要设置WebViewClient;
    最终的效果图就与开篇时一样的了,这里就不再帖效果图了,下面我们来看看如何加载本地html网页
    源码在文章底部给出

    2、加载本地URL

    一般而言,我们会将本地html文件放在assets文件夹下,比如:


    web.html的内容为:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <h1>欢迎光临启舰的blog</h1>
    </head>
    <body>
    </body>
    </html>
    即大标题显示一段文字
    我们同样在上面的示例的基础上加以改造,在点击按钮的时候加载本地web.html文件
    public class MyActivity extends Activity {
    
        private WebView mWebView;
        private Button mBtn;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            mWebView = (WebView)findViewById(R.id.webview);
            mBtn = (Button)findViewById(R.id.btn);
    
            mBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mWebView.loadUrl("file:///android_asset/web.html");
                }
            });
        }
    }    
    从这里可以看到与加载在线URL有两点不同:
    1、URL类型不一样
    在加载本地URL时,是以“file:///”开头的,而assets目录所对应的路径名为anroid_asset,写成其它的将识别不了,这是assets目录的以file开头的url形式的固定访问形式。
    2、不需要设置WebViewClient
    这里很明显没有设置WebViewClient函数,但仍然是在webview中打开的本地文件。具体原因下篇文章讲到WebViewClient时我们会具体解释。
    本例效果图如下:

    所以对于加载URL的总结就是:
    1、如果是在线网址记得添加网络访问权限
    2、在线网址中,如果要使用webview打开,记得设置WebViewClient
    3、打开本地html文件时,是不需要设置WebViewClient,对应的asstes目录的url为:file:///android_asset/xxxxx

    源码在文章底部给出

    3、WebView基本设置

    如果我们需要设置WebView的属性,是通过WebView.getSettings()获取设置WebView的WebSettings对象,然后调用WebSettings中的方法来实现的。
    WebSettings的方法及说明如下:(这里先列出来所有的方法及解释,大家可以先忽略,看后面的举例中所使用的几个常用方法即可,用到哪个函数的时候再回来查查就可以了)

    /**
     * 是否支持缩放,配合方法setBuiltInZoomControls使用,默认true
     */
    setSupportZoom(boolean support)
    
    /**
     * 是否需要用户手势来播放Media,默认true
     */
    setMediaPlaybackRequiresUserGesture(boolean require)
    
    /**
     * 是否使用WebView内置的缩放组件,由浮动在窗口上的缩放控制和手势缩放控制组成,默认false
     */
    setBuiltInZoomControls(boolean enabled)
    
    /**
     * 是否显示窗口悬浮的缩放控制,默认true
     */
    setDisplayZoomControls(boolean enabled)
    
    /**
     * 是否允许访问WebView内部文件,默认true
     */
    setAllowFileAccess(boolean allow)
    
    /**
     * 是否允许获取WebView的内容URL ,可以让WebView访问ContentPrivider存储的内容。 默认true
     */
    setAllowContentAccess(boolean allow)
    
    /**
     * 是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false
     */
    setLoadWithOverviewMode(boolean overview)
    
    /**
     * 是否保存表单数据,默认false
     */
    setSaveFormData(boolean save)
    
    /**
     * 设置页面文字缩放百分比,默认100%
     */
    setTextZoom(int textZoom)
    
    /**
     * 是否支持ViewPort的meta tag属性,如果页面有ViewPort meta tag 指定的宽度,则使用meta tag指定的值,否则默认使用宽屏的视图窗口
     */
    setUseWideViewPort(boolean use)
    
    
    /**
     * 是否支持多窗口,如果设置为true ,WebChromeClient#onCreateWindow方法必须被主程序实现,默认false
     */
    setSupportMultipleWindows(boolean support)
    
    /**
     * 指定WebView的页面布局显示形式,调用该方法会引起页面重绘。默认LayoutAlgorithm#NARROW_COLUMNS
     */
    setLayoutAlgorithm(LayoutAlgorithm l)
    
    /**
     * 设置标准的字体族,默认”sans-serif”。font-family 规定元素的字体系列。
     * font-family 可以把多个字体名称作为一个“回退”系统来保存。如果浏览器不支持第一个字体,
     * 则会尝试下一个。也就是说,font-family 属性的值是用于某个元素的字体族名称或/及类族名称的一个
     * 优先表。浏览器会使用它可识别的第一个值。
     */
    setStandardFontFamily(String font)
    
    /**
     * 设置混合字体族。默认”monospace”
     */
    setFixedFontFamily(String font)
    
    /**
     * 设置SansSerif字体族。默认”sans-serif”
     */
    setSansSerifFontFamily(String font)
    
    /**
     * 设置SerifFont字体族,默认”sans-serif”
     */
    setSerifFontFamily(String font)
    
    /**
     * 设置CursiveFont字体族,默认”cursive”
     */
    setCursiveFontFamily(String font)
    
    /**
     * 设置FantasyFont字体族,默认”fantasy”
     */
    setFantasyFontFamily(String font)
    
    /**
     * 设置最小字体,默认8. 取值区间[1-72],超过范围,使用其上限值。
     */
    setMinimumFontSize(int size)
    
    /**
     * 设置最小逻辑字体,默认8. 取值区间[1-72],超过范围,使用其上限值。
     */
    setMinimumLogicalFontSize(int size)
    
    /**
     * 设置默认字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。
     */
    setDefaultFontSize(int size)
    
    /**
     * 设置默认填充字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。
     */
    setDefaultFixedFontSize(int size)
    
    /**
     * 设置是否加载图片资源,注意:方法控制所有的资源图片显示,包括嵌入的本地图片资源。
     * 使用方法setBlockNetworkImage则只限制网络资源图片的显示。值设置为true后,
     * webview会自动加载网络图片。默认true
     */
    setLoadsImagesAutomatically(boolean flag)
    
    /**
     * 是否加载网络图片资源。注意如果getLoadsImagesAutomatically返回false,则该方法没有效果。
     * 如果使用setBlockNetworkLoads设置为false,该方法设置为false,也不会显示网络图片。
     * 当值从true改为false时。WebView会自动加载网络图片。
     */
    setBlockNetworkImage(boolean flag)
    
    /**
     * 设置是否加载网络资源。注意如果值从true切换为false后,WebView不会自动加载,
     * 除非调用WebView#reload().如果没有android.Manifest.permission#INTERNET权限,
     * 值设为false,则会抛出java.lang.SecurityException异常。
     * 默认值:有android.Manifest.permission#INTERNET权限时为false,其他为true。
     */
    setBlockNetworkLoads(boolean flag)
    
    /**
     * 设置是否允许执行JS。
     */
    setJavaScriptEnabled(boolean flag)
    
    /**
     * 是否允许Js访问任何来源的内容。包括访问file scheme的URLs。考虑到安全性,
     * 限制Js访问范围默认禁用。注意:该方法只影响file scheme类型的资源,其他类型资源如图片类型的,
     * 不会受到影响。ICE_CREAM_SANDWICH_MR1版本以及以下默认为true,JELLY_BEAN版本
     * 以上默认为false
     */
    setAllowUniversalAccessFromFileURLs(boolean flag)
    
    
    /**
     * 是否允许Js访问其他file scheme的URLs。包括访问file scheme的资源。考虑到安全性,
     * 限制Js访问范围默认禁用。注意:该方法只影响file scheme类型的资源,其他类型资源如图片类型的,
     * 不会受到影响。如果getAllowUniversalAccessFromFileURLs为true,则该方法被忽略。
     * ICE_CREAM_SANDWICH_MR1版本以及以下默认为true,JELLY_BEAN版本以上默认为false
     */
    setAllowFileAccessFromFileURLs(boolean flag)
    
    /**
     * 设置存储定位数据库的位置,考虑到位置权限和持久化Cache缓存,Application需要拥有指定路径的
     * write权限
     */
    setGeolocationDatabasePath(String databasePath)
    
    /**
     * 是否允许Cache,默认false。考虑需要存储缓存,应该为缓存指定存储路径setAppCachePath
     */
    setAppCacheEnabled(boolean flag)
    
    /**
     * 设置Cache API缓存路径。为了保证可以访问Cache,Application需要拥有指定路径的write权限。
     * 该方法应该只调用一次,多次调用自动忽略。
     */
    setAppCachePath(String appCachePath)
    
    /**
     * 是否允许数据库存储。默认false。查看setDatabasePath API 如何正确设置数据库存储。
     * 该设置拥有全局特性,同一进程所有WebView实例共用同一配置。注意:保证在同一进程的任一WebView
     * 加载页面之前修改该属性,因为在这之后设置WebView可能会忽略该配置
     */
    setDatabaseEnabled(boolean flag)
    
    /**
     * 是否存储页面DOM结构,默认false。
     */
    setDomStorageEnabled(boolean flag)
    
    /**
     * 是否允许定位,默认true。注意:为了保证定位可以使用,要保证以下几点:
     * Application 需要有android.Manifest.permission#ACCESS_COARSE_LOCATION的权限
     * Application 需要实现WebChromeClient#onGeolocationPermissionsShowPrompt的回调,
     * 接收Js定位请求访问地理位置的通知
     */
    setGeolocationEnabled(boolean flag)
    
    /**
     * 是否允许JS自动打开窗口。默认false
     */
    setJavaScriptCanOpenWindowsAutomatically(boolean flag)
    
    /**
     * 设置页面的编码格式,默认UTF-8
     */
    setDefaultTextEncodingName(String encoding)
    
    /**
     * 设置WebView代理,默认使用默认值
     */
    setUserAgentString(String ua)
    
    /**
     * 通知WebView是否需要设置一个节点获取焦点当
     * WebView#requestFocus(int,android.graphics.Rect)被调用的时候,默认true
     */
    setNeedInitialFocus(boolean flag)
    
    /**
     * 基于WebView导航的类型使用缓存:正常页面加载会加载缓存并按需判断内容是否需要重新验证。
     * 如果是页面返回,页面内容不会重新加载,直接从缓存中恢复。setCacheMode允许客户端根据指定的模式来
     * 使用缓存。
     * LOAD_DEFAULT 默认加载方式
     * LOAD_CACHE_ELSE_NETWORK 按网络情况使用缓存
     * LOAD_NO_CACHE 不使用缓存
     * LOAD_CACHE_ONLY 只使用缓存
     */
    setCacheMode(int mode)
    
    /**
     * 设置加载不安全资源的WebView加载行为。KITKAT版本以及以下默认为MIXED_CONTENT_ALWAYS_ALLOW方
     * 式,LOLLIPOP默认MIXED_CONTENT_NEVER_ALLOW。强烈建议:使用MIXED_CONTENT_NEVER_ALLOW
     */
    setMixedContentMode(int mode)
    下面我们就举个例子来看下用法

    示例1:在WebView中启用JavaScript:

    public class MyActivity extends Activity {
    
        private WebView mWebView;
        private Button mBtn;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            mWebView = (WebView) findViewById(R.id.webview);
            mBtn = (Button) findViewById(R.id.btn);
    
            WebSettings webSettings = mWebView.getSettings();
            webSettings.setJavaScriptEnabled(true);
        }
    }

    示例2:设置缓存

    优先使用缓存
    webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
    不使用缓存:
    webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

    示例3:打开页面时, 自适应屏幕:

    WebSettings webSettings =   mWebView .getSettings();       
    webSettings.setUseWideViewPort(true);//设置此属性,可任意比例缩放
    webSettings.setLoadWithOverviewMode(true);
    效果图如下:(所使用的网址为:http://www.w3school.com.cn/)

    示例4:使页面支持缩放:

    WebSettings webSettings = mWebView.getSettings();
    //开启javascript支持
    webSettings.setJavaScriptEnabled(true); 
    // 设置可以支持缩放
    webSettings.setSupportZoom(true);
    // 设置出现缩放工具
    webSettings.setBuiltInZoomControls(true);

    示例5:.如果webView中需要用户手动输入用户名、密码或其他,则webview必须设置支持获取手势焦点

    webview.requestFocusFromTouch();
    其它的设置就靠大家自己去尝试啦,这里就不再一一缀述了,大家只需要记着,如果需要设置webview就从WebSettings里面去找就可以啦。
    源码在文章底部给出

    二、JS调用Java代码

    在看了如何设置webview以后,我们来看下如何让Webview与网页中的JS代码交互的问题。

    1、概述

    更多时候,网页中需要通过JS代码来调用本地的Android代码,比如H5页面需要判断当前用户是否登录等。
    利用JS代码调用JAVA代码,主要是用到WebView下面的一个函数:
    public void addJavascriptInterface(Object obj, String interfaceName)
    这个函数有两个参数:
    • Object obj:interfaceName所绑定的对象
    • String interfaceName:所绑定的对象所对应的名称
    它有意义就是向WebView注入一个interfaceName的对象,这个对象绑定的是obj对象,通过interfaceName就可以调用obj对象中的方法,这个表述可能大家不太理解,因为interfaceName是一个String,怎么被你说成对象了,理解不了没关系,下面有具体示例

    2、示例

    下面同样是上面的示例,我们对它加以更改,效果图如下:





















沪ICP备19023445号-2号
友情链接