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

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


相关文章:
1、《WebView使用详解(一)——Native与JS相互调用(附JadX反编译)》
2、《WebView使用详解(二)——WebViewClient与常用事件监听》
3、《WebView使用详解(三)——WebChromeClient与LoadData补充》


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

一、基本用法

1、加载在线URL

[java] view plain copy
print ?
  1. void loadUrl(String url)  
void loadUrl(String url)
这个函数主要加载url所对应的网页地址,或者用于调用网页中的指定的JS方法(调用js方法的用法,后面会讲),但有一点必须注意的是:loadUrl()必须在主线程中执行!!!否则就会报错!!!。
注意:加载在线网页地址是会用到联网permission权限的,所以需要在AndroidManifest.xml中写入下面代码申请权限:
[html] view plain copy
print ?
  1. <uses-permission android:name=“android.permission.INTERNET” />  
本示例效果为:
WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第1张图片
从效果图中可以明显看出本示例的布局:
main.xml

[html] view plain copy
print ?
  1. xml version=“1.0” encoding=“utf-8”?>  
  2. <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
  3.               android:orientation=“vertical”  
  4.               android:layout_width=“fill_parent”  
  5.               android:layout_height=“fill_parent”  
  6.         >  
  7.     <Button  
  8.             android:id=“@+id/btn”  
  9.             android:layout_width=“match_parent”  
  10.             android:layout_height=“wrap_content”  
  11.             android:text=“加载URL”/>  
  12.   
  13.     <WebView  
  14.             android:id=“@+id/webview”  
  15.             android:layout_width=“match_parent”  
  16.             android:layout_height=“match_parent”/>  
  17. LinearLayout>  


    
对应的处理代码如下
[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.     @Override  
  6.     public void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.   
  10.         mWebView = (WebView)findViewById(R.id.webview);  
  11.         mBtn = (Button)findViewById(R.id.btn);  
  12.   
  13.         mBtn.setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View v) {  
  16.                 mWebView.loadUrl(”http://www.baidu.com”);  
  17.             }  
  18.         });  
  19.     }  
  20. }  
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使用详解(一)——Native与JS相互调用(附JadX反编译)_第2张图片
如果我们想实现像示例一样在webview中打开网址需要怎么做呢?
我们需要设置WebViewClient:
修改后的代码为:

[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.     @Override  
  6.     public void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.   
  10.         mWebView = (WebView)findViewById(R.id.webview);  
  11.         mBtn = (Button)findViewById(R.id.btn);  
  12.   
  13.         mWebView.setWebViewClient(new WebViewClient());  
  14.   
  15.         mBtn.setOnClickListener(new View.OnClickListener() {  
  16.             @Override  
  17.             public void onClick(View v) {  
  18.                 mWebView.loadUrl(”http://www.baidu.com”);  
  19.             }  
  20.         });  
  21.     }  
  22. }  
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");
            }
        });
    }
}
在上面的基础上,我们添加了下面一段代码:
[java] view plain copy
print ?
  1. mWebView.setWebViewClient(new WebViewClient());  
mWebView.setWebViewClient(new WebViewClient());
在这里我们利用mWebView.setWebViewClient()函数仅仅设置了一个WebViewClient实例,就可以实现在WebView中打开链接了,至于原因我们下篇会讲到,这里就先忽略了,大家只需要知道要在WebView中打开链接,就必须要设置WebViewClient;
最终的效果图就与开篇时一样的了,这里就不再帖效果图了,下面我们来看看如何加载本地html网页
源码在文章底部给出

2、加载本地URL

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


web.html的内容为:

[html] view plain copy
print ?
  1. >  
  2. <html lang=“en”>  
  3. <head>  
  4.     <meta charset=“UTF-8”>  
  5.     <title>Titletitle>  
  6.     <h1>欢迎光临启舰的blogh1>  
  7. head>  
  8. <body>  
  9. body>  
  10. html>  



    
    Title
    

欢迎光临启舰的blog

即大标题显示一段文字
我们同样在上面的示例的基础上加以改造,在点击按钮的时候加载本地web.html文件
[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.     @Override  
  6.     public void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.   
  10.         mWebView = (WebView)findViewById(R.id.webview);  
  11.         mBtn = (Button)findViewById(R.id.btn);  
  12.   
  13.         mBtn.setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View v) {  
  16.                 mWebView.loadUrl(”file:///android_asset/web.html”);  
  17.             }  
  18.         });  
  19.     }  
  20. }      
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时我们会具体解释。
本例效果图如下:
WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第3张图片

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

源码在文章底部给出

3、WebView基本设置

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

[java] view plain copy
print ?
  1. /** 
  2.  * 是否支持缩放,配合方法setBuiltInZoomControls使用,默认true 
  3.  */  
  4. setSupportZoom(boolean support)  
  5.   
  6. /** 
  7.  * 是否需要用户手势来播放Media,默认true 
  8.  */  
  9. setMediaPlaybackRequiresUserGesture(boolean require)  
  10.   
  11. /** 
  12.  * 是否使用WebView内置的缩放组件,由浮动在窗口上的缩放控制和手势缩放控制组成,默认false 
  13.  */  
  14. setBuiltInZoomControls(boolean enabled)  
  15.   
  16. /** 
  17.  * 是否显示窗口悬浮的缩放控制,默认true 
  18.  */  
  19. setDisplayZoomControls(boolean enabled)  
  20.   
  21. /** 
  22.  * 是否允许访问WebView内部文件,默认true 
  23.  */  
  24. setAllowFileAccess(boolean allow)  
  25.   
  26. /** 
  27.  * 是否允许获取WebView的内容URL ,可以让WebView访问ContentPrivider存储的内容。 默认true 
  28.  */  
  29. setAllowContentAccess(boolean allow)  
  30.   
  31. /** 
  32.  * 是否启动概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false 
  33.  */  
  34. setLoadWithOverviewMode(boolean overview)  
  35.   
  36. /** 
  37.  * 是否保存表单数据,默认false 
  38.  */  
  39. setSaveFormData(boolean save)  
  40.   
  41. /** 
  42.  * 设置页面文字缩放百分比,默认100% 
  43.  */  
  44. setTextZoom(int textZoom)  
  45.   
  46. /** 
  47.  * 是否支持ViewPort的meta tag属性,如果页面有ViewPort meta tag 指定的宽度,则使用meta tag指定的值,否则默认使用宽屏的视图窗口 
  48.  */  
  49. setUseWideViewPort(boolean use)  
  50.   
  51.   
  52. /** 
  53.  * 是否支持多窗口,如果设置为true ,WebChromeClient#onCreateWindow方法必须被主程序实现,默认false 
  54.  */  
  55. setSupportMultipleWindows(boolean support)  
  56.   
  57. /** 
  58.  * 指定WebView的页面布局显示形式,调用该方法会引起页面重绘。默认LayoutAlgorithm#NARROW_COLUMNS 
  59.  */  
  60. setLayoutAlgorithm(LayoutAlgorithm l)  
  61.   
  62. /** 
  63.  * 设置标准的字体族,默认”sans-serif”。font-family 规定元素的字体系列。 
  64.  * font-family 可以把多个字体名称作为一个“回退”系统来保存。如果浏览器不支持第一个字体, 
  65.  * 则会尝试下一个。也就是说,font-family 属性的值是用于某个元素的字体族名称或/及类族名称的一个 
  66.  * 优先表。浏览器会使用它可识别的第一个值。 
  67.  */  
  68. setStandardFontFamily(String font)  
  69.   
  70. /** 
  71.  * 设置混合字体族。默认”monospace” 
  72.  */  
  73. setFixedFontFamily(String font)  
  74.   
  75. /** 
  76.  * 设置SansSerif字体族。默认”sans-serif” 
  77.  */  
  78. setSansSerifFontFamily(String font)  
  79.   
  80. /** 
  81.  * 设置SerifFont字体族,默认”sans-serif” 
  82.  */  
  83. setSerifFontFamily(String font)  
  84.   
  85. /** 
  86.  * 设置CursiveFont字体族,默认”cursive” 
  87.  */  
  88. setCursiveFontFamily(String font)  
  89.   
  90. /** 
  91.  * 设置FantasyFont字体族,默认”fantasy” 
  92.  */  
  93. setFantasyFontFamily(String font)  
  94.   
  95. /** 
  96.  * 设置最小字体,默认8. 取值区间[1-72],超过范围,使用其上限值。 
  97.  */  
  98. setMinimumFontSize(int size)  
  99.   
  100. /** 
  101.  * 设置最小逻辑字体,默认8. 取值区间[1-72],超过范围,使用其上限值。 
  102.  */  
  103. setMinimumLogicalFontSize(int size)  
  104.   
  105. /** 
  106.  * 设置默认字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。 
  107.  */  
  108. setDefaultFontSize(int size)  
  109.   
  110. /** 
  111.  * 设置默认填充字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。 
  112.  */  
  113. setDefaultFixedFontSize(int size)  
  114.   
  115. /** 
  116.  * 设置是否加载图片资源,注意:方法控制所有的资源图片显示,包括嵌入的本地图片资源。 
  117.  * 使用方法setBlockNetworkImage则只限制网络资源图片的显示。值设置为true后, 
  118.  * webview会自动加载网络图片。默认true 
  119.  */  
  120. setLoadsImagesAutomatically(boolean flag)  
  121.   
  122. /** 
  123.  * 是否加载网络图片资源。注意如果getLoadsImagesAutomatically返回false,则该方法没有效果。 
  124.  * 如果使用setBlockNetworkLoads设置为false,该方法设置为false,也不会显示网络图片。 
  125.  * 当值从true改为false时。WebView会自动加载网络图片。 
  126.  */  
  127. setBlockNetworkImage(boolean flag)  
  128.   
  129. /** 
  130.  * 设置是否加载网络资源。注意如果值从true切换为false后,WebView不会自动加载, 
  131.  * 除非调用WebView#reload().如果没有android.Manifest.permission#INTERNET权限, 
  132.  * 值设为false,则会抛出java.lang.SecurityException异常。 
  133.  * 默认值:有android.Manifest.permission#INTERNET权限时为false,其他为true。 
  134.  */  
  135. setBlockNetworkLoads(boolean flag)  
  136.   
  137. /** 
  138.  * 设置是否允许执行JS。 
  139.  */  
  140. setJavaScriptEnabled(boolean flag)  
  141.   
  142. /** 
  143.  * 是否允许Js访问任何来源的内容。包括访问file scheme的URLs。考虑到安全性, 
  144.  * 限制Js访问范围默认禁用。注意:该方法只影响file scheme类型的资源,其他类型资源如图片类型的, 
  145.  * 不会受到影响。ICE_CREAM_SANDWICH_MR1版本以及以下默认为true,JELLY_BEAN版本 
  146.  * 以上默认为false 
  147.  */  
  148. setAllowUniversalAccessFromFileURLs(boolean flag)  
  149.   
  150.   
  151. /** 
  152.  * 是否允许Js访问其他file scheme的URLs。包括访问file scheme的资源。考虑到安全性, 
  153.  * 限制Js访问范围默认禁用。注意:该方法只影响file scheme类型的资源,其他类型资源如图片类型的, 
  154.  * 不会受到影响。如果getAllowUniversalAccessFromFileURLs为true,则该方法被忽略。 
  155.  * ICE_CREAM_SANDWICH_MR1版本以及以下默认为true,JELLY_BEAN版本以上默认为false 
  156.  */  
  157. setAllowFileAccessFromFileURLs(boolean flag)  
  158.   
  159. /** 
  160.  * 设置存储定位数据库的位置,考虑到位置权限和持久化Cache缓存,Application需要拥有指定路径的 
  161.  * write权限 
  162.  */  
  163. setGeolocationDatabasePath(String databasePath)  
  164.   
  165. /** 
  166.  * 是否允许Cache,默认false。考虑需要存储缓存,应该为缓存指定存储路径setAppCachePath 
  167.  */  
  168. setAppCacheEnabled(boolean flag)  
  169.   
  170. /** 
  171.  * 设置Cache API缓存路径。为了保证可以访问Cache,Application需要拥有指定路径的write权限。 
  172.  * 该方法应该只调用一次,多次调用自动忽略。 
  173.  */  
  174. setAppCachePath(String appCachePath)  
  175.   
  176. /** 
  177.  * 是否允许数据库存储。默认false。查看setDatabasePath API 如何正确设置数据库存储。 
  178.  * 该设置拥有全局特性,同一进程所有WebView实例共用同一配置。注意:保证在同一进程的任一WebView 
  179.  * 加载页面之前修改该属性,因为在这之后设置WebView可能会忽略该配置 
  180.  */  
  181. setDatabaseEnabled(boolean flag)  
  182.   
  183. /** 
  184.  * 是否存储页面DOM结构,默认false。 
  185.  */  
  186. setDomStorageEnabled(boolean flag)  
  187.   
  188. /** 
  189.  * 是否允许定位,默认true。注意:为了保证定位可以使用,要保证以下几点: 
  190.  * Application 需要有android.Manifest.permission#ACCESS_COARSE_LOCATION的权限 
  191.  * Application 需要实现WebChromeClient#onGeolocationPermissionsShowPrompt的回调, 
  192.  * 接收Js定位请求访问地理位置的通知 
  193.  */  
  194. setGeolocationEnabled(boolean flag)  
  195.   
  196. /** 
  197.  * 是否允许JS自动打开窗口。默认false 
  198.  */  
  199. setJavaScriptCanOpenWindowsAutomatically(boolean flag)  
  200.   
  201. /** 
  202.  * 设置页面的编码格式,默认UTF-8 
  203.  */  
  204. setDefaultTextEncodingName(String encoding)  
  205.   
  206. /** 
  207.  * 设置WebView代理,默认使用默认值 
  208.  */  
  209. setUserAgentString(String ua)  
  210.   
  211. /** 
  212.  * 通知WebView是否需要设置一个节点获取焦点当 
  213.  * WebView#requestFocus(int,android.graphics.Rect)被调用的时候,默认true 
  214.  */  
  215. setNeedInitialFocus(boolean flag)  
  216.   
  217. /** 
  218.  * 基于WebView导航的类型使用缓存:正常页面加载会加载缓存并按需判断内容是否需要重新验证。 
  219.  * 如果是页面返回,页面内容不会重新加载,直接从缓存中恢复。setCacheMode允许客户端根据指定的模式来 
  220.  * 使用缓存。 
  221.  * LOAD_DEFAULT 默认加载方式 
  222.  * LOAD_CACHE_ELSE_NETWORK 按网络情况使用缓存 
  223.  * LOAD_NO_CACHE 不使用缓存 
  224.  * LOAD_CACHE_ONLY 只使用缓存 
  225.  */  
  226. setCacheMode(int mode)  
  227.   
  228. /** 
  229.  * 设置加载不安全资源的WebView加载行为。KITKAT版本以及以下默认为MIXED_CONTENT_ALWAYS_ALLOW方 
  230.  * 式,LOLLIPOP默认MIXED_CONTENT_NEVER_ALLOW。强烈建议:使用MIXED_CONTENT_NEVER_ALLOW 
  231.  */  
  232. setMixedContentMode(int mode)  
/**
 * 是否支持缩放,配合方法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:

[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.   
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.   
  11.         mWebView = (WebView) findViewById(R.id.webview);  
  12.         mBtn = (Button) findViewById(R.id.btn);  
  13.   
  14.         WebSettings webSettings = mWebView.getSettings();  
  15.         webSettings.setJavaScriptEnabled(true);  
  16.     }  
  17. }  
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:设置缓存

优先使用缓存
[java] view plain copy
print ?
  1. webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);  
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
不使用缓存:
[java] view plain copy
print ?
  1. webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);  
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

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

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

WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第4张图片

注意:对于我们自己写的网页代码,不必利用这处函数来做页面缩放适配,因为对于有些手机存在适配问题,只需要在HTML中做宽度100%自适应屏幕就行了

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

[java] view plain copy
print ?
  1. WebSettings webSettings = mWebView.getSettings();  
  2. //开启javascript支持  
  3. webSettings.setJavaScriptEnabled(true);   
  4. // 设置可以支持缩放  
  5. webSettings.setSupportZoom(true);  
  6. // 设置出现缩放工具  
  7. webSettings.setBuiltInZoomControls(true);  
WebSettings webSettings = mWebView.getSettings();
//开启javascript支持
webSettings.setJavaScriptEnabled(true); 
// 设置可以支持缩放
webSettings.setSupportZoom(true);
// 设置出现缩放工具
webSettings.setBuiltInZoomControls(true);

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

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

二、JS调用Java代码

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

1、概述

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

2、示例

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

WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第5张图片

在原来html上面添加了一个按钮,当点击按钮时调用Android的Toast函数弹出一个toast消息。
先看Android代码:

[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.   
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.   
  11.         mWebView = (WebView) findViewById(R.id.webview);  
  12.   
  13.         WebSettings webSettings = mWebView.getSettings();  
  14.         webSettings.setJavaScriptEnabled(true);  
  15.         mWebView.addJavascriptInterface(this“android”);  
  16.         mWebView.loadUrl(”file:///android_asset/web.html”);  
  17.     }  
  18.   
  19.     public void toastMessage(String message) {  
  20.         Toast.makeText(getApplicationContext(), ”通过Natvie传递的Toast:”+message, Toast.LENGTH_LONG).show();  
  21.     }  
  22. }      
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);

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(this, "android");
        mWebView.loadUrl("file:///android_asset/web.html");
    }

    public void toastMessage(String message) {
        Toast.makeText(getApplicationContext(), "通过Natvie传递的Toast:"+message, Toast.LENGTH_LONG).show();
    }
}    
这里最主要是的下面这句:
[java] view plain copy
print ?
  1. mWebView.addJavascriptInterface(this“android”);  
mWebView.addJavascriptInterface(this, "android");
这句的意思是把MyActivity对象注入到WebView中,在WebView中的对象别名叫android;另外,我们还在MyActivity中额外写了一个函数toastMessage(String message),用于弹出MSG
下面我们看看html代码:
[html] view plain copy
print ?
  1. >  
  2. <html lang=“en”>  
  3. <head>  
  4.     <meta charset=“UTF-8”>  
  5.     <title>Titletitle>  
  6.     <h1>欢迎光临启舰的blogh1>  
  7.     <input type=“button” value=“js调native” onclick=“ok()”>  
  8. head>  
  9. <body>  
  10. <script type=“text/javascript”>  
  11. function ok() {  
  12.  android.toastMessage(“哈哈,i m webview msg”);  
  13. }  
  14. script>  
  15. body>  
  16. html>  



    
    Title
    

欢迎光临启舰的blog

在这个html中,我添加了一个button按钮,当点击时调用ok函数:
[html] view plain copy
print ?
  1. function ok() {  
  2.  android.toastMessage(“哈哈,i m webview msg”);  
  3. }  
function ok() {
 android.toastMessage("哈哈,i m webview msg");
}
它的意义就是调用android对象里的toastMessage方法,这个android就是我们利用mWebView.addJavascriptInterface(this, “android”)注入到WebView的android,它所对应的对象就将MyActivity;所以在JS中,我们就可以通过android这个别名来调用MyActivity对象中的任何public方法。
源码在文章底部给出

3、addJavascriptInterface自定义作用对象

在上面的示例中mWebView.addJavascriptInterface(this, “android”);我们直接通过this,把当前整个类作为对象传给WebView了,但这会有很大风险,因为我们这个类中可能会有各种函数,而这些函数是只有本地Native代码才会用到,WebView是根本用不到的。所以如果通过全部注入给WebView的话,那么一些存心不良的同学就可以任意调用我们这个类中的方法,给我们APP带来危害。
所以,一般而言,我们很少直接会传this,把整个类注入给WebView,而是单独写一个类专门用于JS交互,比如:
[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.   
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.   
  11.         mWebView = (WebView) findViewById(R.id.webview);  
  12.         mBtn = (Button) findViewById(R.id.btn);  
  13.   
  14.         WebSettings webSettings = mWebView.getSettings();  
  15.         webSettings.setJavaScriptEnabled(true);  
  16.         mWebView.addJavascriptInterface(new JSBridge(), “android”);  
  17.         mWebView.loadUrl(”file:///android_asset/web.html”);  
  18.     }  
  19.   
  20.     public class JSBridge{  
  21.         public void toastMessage(String message) {  
  22.             Toast.makeText(getApplicationContext(), ”通过Natvie传递的Toast:”+message, Toast.LENGTH_LONG).show();  
  23.         }  
  24.     }  
  25. }      
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);
        mWebView.addJavascriptInterface(new JSBridge(), "android");
        mWebView.loadUrl("file:///android_asset/web.html");
    }

    public class JSBridge{
        public void toastMessage(String message) {
            Toast.makeText(getApplicationContext(), "通过Natvie传递的Toast:"+message, Toast.LENGTH_LONG).show();
        }
    }
}    
在这段代码中,在通过addJavascriptInterface注入时:
[java] view plain copy
print ?
  1. mWebView.addJavascriptInterface(new JSBridge(), “android”);  
mWebView.addJavascriptInterface(new JSBridge(), "android");
指定android对象绑定的是JSBridge对象!所以在WebView中,通过JS只能访问JSBridge中所定义的对象,如果访问其它类的函数,比如MyActivity中的函数,就会报下面的错误(即方法找不到)

大家可以自己尝试下;
然后对应的html代码:

[html] view plain copy
print ?
  1. >  
  2. <html lang=“en”>  
  3. <head>  
  4.     <meta charset=“UTF-8”>  
  5.     <title>Titletitle>  
  6.     <h1>欢迎光临启舰的blogh1>  
  7.     <input type=“button” value=“js调native” onclick=“ok()”>  
  8. head>  
  9. <body>  
  10. <script type=“text/javascript”>  
  11. function ok() {  
  12.   android.toastMessage(“哈哈,i m webview msg”);  
  13.  }  
  14. script>  
  15. body>  
  16. html>  



    
    Title
    

欢迎光临启舰的blog

由于在注入时的对象别名和所调用的函数名都没有变,所以HTML中的JS代码是无需更改的。效果图与上节一样,就不再帖出了。
源码在文章底部给出

4、addJavascriptInterface注入漏洞

上面我们说了在addJavascriptInterface注入时,为了防止WebView调用我们不想被它调用的函数,所以我们需要单独为WebView交互定义一个类,让它只执行这个类里面的函数
但……这真的能挡住黑客的攻击吗?
当然是NO……,不然我就不会写这一段了……
[java] view plain copy
print ?
  1. mWebView.addJavascriptInterface(new JSBridge(), “android”);  
mWebView.addJavascriptInterface(new JSBridge(), "android");
在注入时,我们已经把对象传给了JS,在JS中当然可以通过反射得到APP中的各种类的实例!现在反编译Android代码可不是什么难事(本文结尾附jadx反编译方法),很容易拿到你有哪些类,有哪些函数,通过这些就可以想执行哪个执行哪个了,有没有细思极恐……
具体的细节我就不讲了,不在本篇范围,给大家找了篇文章,有兴趣的同学可以参考下: 《Android WebView的Js对象注入漏洞解决方案》

5、JavascriptInterface注解

为了解决addJavascriptInterface()函数的安全问题,在android:targetSdkVersion数值为17(Android4.2)及以上的APP中,JS只能访问带有 @JavascriptInterface注解的Java函数,所以如果你的android:targetSdkVersion是17+,与JS交互的Native函数中,必须添加JavascriptInterface注解,不然无效,比如:
[java] view plain copy
print ?
  1. public class JSBridge {  
  2.     @JavascriptInterface  
  3.     public void toastMessage(String message) {  
  4.         Toast.makeText(getApplicationContext(), ”通过Natvie传递的Toast:” + message, Toast.LENGTH_LONG).show();  
  5.     }  
  6. }  
public class JSBridge {
    @JavascriptInterface
    public void toastMessage(String message) {
        Toast.makeText(getApplicationContext(), "通过Natvie传递的Toast:" + message, Toast.LENGTH_LONG).show();
    }
}
这也就是很多同学在高target上,addJavascriptInterface()函数无效的主要原因。
注意:虽然在target 17以后,已经修复了这个安全问题,但目前大多数APP都还是target 17以前的,所以大家可以尝试着找一些APP来演示下这个漏洞哦……

三、JAVA调用JS代码

1、JAVA调用JS代码

前面给大家演示了如何通过JS调用Java代码,这里就反过来看看,如何在Native中调用JS的代码
本例的效果图如下:
WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第6张图片

在点击“加载URL”按钮时,调用webview中的JavaScript求和函数,将结果显示在标题中。
先看html代码:

[html] view plain copy
print ?
  1. >  
  2. <html lang=“en”>  
  3. <head>  
  4.     <meta charset=“UTF-8”>  
  5.     <title>Titletitle>  
  6.     <h1 id=“h”>欢迎光临启舰的blogh1>  
  7.     <input type=“button” value=“js调native” onclick=“ok()”>  
  8. head>  
  9. <body>  
  10. <script type=“text/javascript”>  
  11. function sum(i,m)  
  12. {  
  13.  document.getElementById(“h”).innerHTML= (i+m);  
  14. }  
  15. script>  
  16. body>  
  17. html>  



    
    Title
    

欢迎光临启舰的blog

在这里,我们写了一个求和函数sum(i,m)
结果中就是把h1标签的内容改为求和后的结果值。
再来看看JAVA的调用代码:
[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.   
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.   
  11.         mWebView = (WebView) findViewById(R.id.webview);  
  12.         mBtn = (Button) findViewById(R.id.btn);  
  13.   
  14.         WebSettings webSettings = mWebView.getSettings();  
  15.         webSettings.setJavaScriptEnabled(true);  
  16.         mWebView.loadUrl(”file:///android_asset/web.html”);  
  17.   
  18.         mBtn.setOnClickListener(new View.OnClickListener() {  
  19.             @Override  
  20.             public void onClick(View v) {  
  21.                 mWebView.loadUrl(”javascript:sum(3,8)”);  
  22.             }  
  23.         });  
  24.      }  
  25. }          
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);
        mWebView.loadUrl("file:///android_asset/web.html");

        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWebView.loadUrl("javascript:sum(3,8)");
            }
        });
     }
}        
在点击按钮时调用JS函数:
[java] view plain copy
print ?
  1. mWebView.loadUrl(“javascript:sum(3,8)”);  
mWebView.loadUrl("javascript:sum(3,8)");
这里也就是在JAVA中调用JS函数的方法:
[java] view plain copy
print ?
  1. String url = “javascript:methodName(params……);”  
  2. webView.loadUrl(url);  
String url = "javascript:methodName(params……);"
webView.loadUrl(url);
javascript:伪协议让我们可以通过一个链接来调用JavaScript函数
中间methodName是JavaScript中实现的函数
jsonParams是传入的参数列表
使用起来难度不大,就不再多讲了
源码在文章底部给出

2、JAVA中如何得到JS中的返回值(Android4.4以前)

现在我们再考虑一下,如果我们要在JAVA中需要得到JS的结果返回值要怎么办?比如在上面的例子中,我们需要在JAVA中得到在计算后的结果值
Android在4.4之前并没有提供直接调用js函数并获取值的方法,也就是说,我们只能调用JS中的函数,并不能得到该函数的返回值,想得到返回值我们就得想其它办法,所以在此之前,常用的思路是 java调用js方法,js方法执行完毕,再次调用java代码将值返回。

1.Java调用js代码

[java] view plain copy
print ?
  1. webView.addJavascriptInterface(this“android”);  
  2. mWebView.loadUrl(”javascript:sum(3,8)”);  
webView.addJavascriptInterface(this, "android");
mWebView.loadUrl("javascript:sum(3,8)");
注意,这里通过addJavascriptInterface将MyActiviy所对应的对象注入到WebView中了。
2.js函数处理,并将结果通过调用java方法返回
[java] view plain copy
print ?
  1. function sum(i,m){  
  2.  var result = i+m;  
  3.  document.getElementById(”h”).innerHTML= result;  
  4.  android.onSumResult(result)  
  5. }  
function sum(i,m){
 var result = i+m;
 document.getElementById("h").innerHTML= result;
 android.onSumResult(result)
}
3..Java在回调方法中获取js函数返回值
[java] view plain copy
print ?
  1. public void onSumResult(int result) {  
  2.   Log.i(LOGTAG, ”onSumResult result=” + result);  
  3. }  
public void onSumResult(int result) {
  Log.i(LOGTAG, "onSumResult result=" + result);
}
先看下效果图:
WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第7张图片

下面我们就完整地看一下代码:
JS代码:

[html] view plain copy
print ?
  1. >  
  2. <html lang=“en”>  
  3. <head>  
  4.     <meta charset=“UTF-8”>  
  5.     <title>Titletitle>  
  6.     <h1 id=“h”>欢迎光临启舰的blogh1>  
  7.     <input type=“button” value=“js调native” onclick=“ok()”>  
  8. head>  
  9. <body>  
  10. <script type=“text/javascript”>  
  11. function sum(i,m){  
  12.  var result = i+m;  
  13.  document.getElementById(“h”).innerHTMLresult;  
  14.  android.onSumResult(result);  
  15. }  
  16. script>  
  17. body>  
  18. html>  



    
    Title
    

欢迎光临启舰的blog

在function sum(i,m)中,先通过result得到结果,最后通过android.onSumResult(result);将结果传给Native
然后再来看看JAVA代码:
[java] view plain copy
print ?
  1. public class MyActivity extends Activity {  
  2.   
  3.     private WebView mWebView;  
  4.     private Button mBtn;  
  5.   
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.   
  11.         mWebView = (WebView) findViewById(R.id.webview);  
  12.         mBtn = (Button) findViewById(R.id.btn);  
  13.   
  14.         WebSettings webSettings = mWebView.getSettings();  
  15.         webSettings.setJavaScriptEnabled(true);  
  16.         mWebView.addJavascriptInterface(this“android”);  
  17.         mWebView.loadUrl(”file:///android_asset/web.html”);  
  18.   
  19.         mBtn.setOnClickListener(new View.OnClickListener() {  
  20.             @Override  
  21.             public void onClick(View v) {  
  22.                 mWebView.loadUrl(”javascript:sum(3,8)”);  
  23.             }  
  24.         });  
  25.     }  
  26.   
  27.     public void onSumResult(int result) {  
  28.         Toast.makeText(this,“received result:”+result,Toast.LENGTH_SHORT).show();  
  29.     }  
  30. }  
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);
        mWebView.addJavascriptInterface(this, "android");
        mWebView.loadUrl("file:///android_asset/web.html");

        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWebView.loadUrl("javascript:sum(3,8)");
            }
        });
    }

    public void onSumResult(int result) {
        Toast.makeText(this,"received result:"+result,Toast.LENGTH_SHORT).show();
    }
}
这里主要做了两件事:
第一,通过addJavascriptInterface注入MyActivity对象,以便JS访问其中的函数
[java] view plain copy
print ?
  1. mWebView.addJavascriptInterface(this“android”);  
mWebView.addJavascriptInterface(this, "android");
第二:供JS调用,以返回结果的函数onSumResult():
[java] view plain copy
print ?
  1. public void onSumResult(int result) {  
  2.     Toast.makeText(this,“received result:”+result,Toast.LENGTH_SHORT).show();  
  3. }  
public void onSumResult(int result) {
    Toast.makeText(this,"received result:"+result,Toast.LENGTH_SHORT).show();
}

3、JAVA中如何得到JS中的返回值(Android4.4之后)

Android 4.4之后使用evaluateJavascript即可。这里展示一个简单的交互示例
先写一个具有返回值的js方法
[html] view plain copy
print ?
  1. function getGreetings() {  
  2.  return 1;   
  3. }  
function getGreetings() {
 return 1; 
}
java代码时用evaluateJavascript方法调用:
[java] view plain copy
print ?
  1. private void testEvaluateJavascript(WebView webView) {  
  2.    webView.evaluateJavascript(”getGreetings()”new ValueCallback() {  
  3.        @Override  
  4.        public void onReceiveValue(String value) {  
  5.            Log.i(LOGTAG, ”onReceiveValue value=” + value);  
  6.        }  
  7.    });  
  8. }  
private void testEvaluateJavascript(WebView webView) {
   webView.evaluateJavascript("getGreetings()", new ValueCallback() {
       @Override
       public void onReceiveValue(String value) {
           Log.i(LOGTAG, "onReceiveValue value=" + value);
       }
   });
}
从上面的用法中很明显看到,通过evaluateJavascript调用JS中的方法,可以向其中添加结果回调,来接收JS的return值。
注意:
  • 上面限定了结果返回结果为String,对于简单的类型会尝试转换成字符串返回,对于复杂的数据类型,建议以字符串形式的json返回。
  • evaluateJavascript方法必须在UI线程(主线程)调用,因此onReceiveValue也执行在主线程。
好了,这篇文章中有关WebView的知识就先到这,下篇继续讲。下面给大家讲讲有关jadx-gui反编译的知识。

四、jadx-gui反编译

在遇到jadx-gui反编译之前,都是使用apktools进行反编译的,apktools有些是反编译不出来的,而且……难用……
想知道jadx-gui有多强?它都可以反编译淘宝、微信代码,是不是够强了。下面我们就来看看它是如何反编译的;

1、下载、配置

jadx-gui是开源的,项目地址:《 https://github.com/skylot/jadx》
mac电脑:
打开终端,切到某个路径下,输入以下命令:
[java] view plain copy
print ?
  1. git clone https://github.com/skylot/jadx.git  
  2. cd jadx  
  3. ./gradlew dist  
git clone https://github.com/skylot/jadx.git
cd jadx
./gradlew dist
其实这里只是做了两个动作:
第一,使用git命令将 项目clone下来(这里需要配置git环境,如果没有,请先搜资料配置git环境,然后再来)
然后,执行jadx目录 下gradlew脚本,这个是shell脚本
windows电脑:
[java] view plain copy
print ?
  1. git clone https://github.com/skylot/jadx.git  
  2. cd jadx  
  3. gradlew.bat dist  
git clone https://github.com/skylot/jadx.git
cd jadx
gradlew.bat dist
在windows电脑中,步骤与mac是一样的,只是最后一步中,已经不再是./gradlew所对应的shell脚本了,而是windows平台上的bat脚本。
可见作者有多牛X,shell脚本和bat脚本都会写,真是屌的不能直视

整个编译过程是比较慢的,这里需要耐心等待下。因为目前会使用gradle 2.7来编译项目,如果没有在环境变量中环境gradle 2.7的环境变量,会自己下载gradle 2.7
编译成功后会打出BUILD SUCCESS字样,如下图所示:
WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第8张图片

在编译成功后,在jadx目录下,会生成一个build目录,其中包含jadx目录和一个jadx-xxx-dev.zip的打包文件。在build/jadx目录下,就是源码编译出的jadx工具及所用jar包。jadx-xxx-dev.zip解压后的内容与build/jadx内容一样,只是将其打包了一下而已,方便移值,可见作者有多用心。build目录结构如下图所示:

WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第9张图片

2、开始反编译

等完毕后,可以开始了,我就介绍个最简单最常用的用法
(1)、把apk改成zip
(2)、解压zip获取class.dex文件
(3)、将class.dex文件放到jadx目录下

[plain] view plain copy
print ?
  1. cd build/jadx/  
  2. bin/jadx -d out classes.dex  # 反编译后放入out文件夹下(如果out不存在它会自动创建)  
  3. #or  
  4. bin/jadx-gui classes.dex  # 会反编译,并且使用gui打开  
cd build/jadx/
bin/jadx -d out classes.dex  # 反编译后放入out文件夹下(如果out不存在它会自动创建)




#or bin/jadx-gui classes.dex # 会反编译,并且使用gui打开目录结构图如下:
WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第10张图片

在使用jadx-gui反编译时,左下角会显示当前反编译的进度:
WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第11张图片

在反编译完成后,在左侧就可以看到目录结构和对应的代码,目录结构中显示的a,b,c,d这些字母是由于在生成apk时使用proguard混淆造成的,proguard混淆的类名是没办法反编译出对应的原类名的,这也是反编译代码中比较蛋疼的地方,下面给大家演示下结果:(还可以通过点击搜索按钮,搜索其中的代码)


有关jadx-gui工具的更多用法,只有靠大家自己去研究啦,到这里我们的源码就已经反编译出来了。

反编译工具和微信的Classes文件,会在源码中给出大家
这篇文章到这里就结束啦,下篇将会给大家讲解WebViewClient的知识。

如果本文有帮到你,记得加关注哦

源码下载地址:http://download.csdn.net/detail/harvic880925/9526801

请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/51464687 谢谢

如果你喜欢我的文章,那么你将会更喜欢我的微信公众号,将定期推送博主最新文章与收集干货分享给大家(一周一次)

WebView使用详解(一)——Native与JS相互调用(附JadX反编译)_第12张图片




你可能感兴趣的:(webview,Android)