AndroidWebView的Js对象注入,对象存储使用场景景是怎样的?

Android webview js注入和替换 - 简书
Android webview js注入和替换
公司最近做Android应用,顺便学下Android开发。有个需求是把ie上的网站在手机上浏览,并提供自动登录功能,用到了js注入和替换。private class myWebViewClient extends WebViewClient{
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//制定showDownPTA.html地址不去处理
if(url.endsWith("showDownPTA.html"))
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
Cursor cursor = iOpenHelper.getUrlOfReplace(url,Long.parseLong(appId));
//若包含此URL,则进行替换
if(cursor.getCount()&0&&cursor.moveToNext()){
int colIndex = cursor.getColumnIndex(ItrusOpenHelper.URL_FILE);
String fileName = cursor.getString(colIndex);//
String mimeType = "application/x-javascript";//资源类型
网页:text/html
WebResourceResponse webResource =
File file = new File(CommonDb.APP_DIF,fileName);
FileInputStream fis = new FileInputStream(file);
webResource = new WebResourceResponse(null, "UTF-8", fis);
} catch (Exception e) {
e.printStackTrace();
cursor.close();
return webR
cursor.close();
return super.shouldInterceptRequest(view, url);
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
pageEncode = shared.getString(url, null);
if(null == pageEncode){
getCharset(url);
showStop(true);
public void onPageFinished(WebView view, String url) {
Cursor cursor = iOpenHelper.getUrlOfInject(url,Long.parseLong(appId));
//进行代码注入
if(cursor.getCount()&0&&cursor.moveToNext()){
int colIndex = cursor.getColumnIndex(ItrusOpenHelper.URL_FILE);
String fileName = cursor.getString(colIndex);
StringBuffer jsb = new StringBuffer();
File file = new File(CommonDb.APP_DIF,fileName);
FileInputStream fis = new FileInputStream(file);
InputStreamReader read = new InputStreamReader(fis, "UTF-8");// 考虑到编码格式
BufferedReader bufferedReader = new BufferedReader(read);
String lineTxt =
while ((lineTxt = bufferedReader.readLine()) != null) {
jsb.append(lineTxt);
fis.close();
read.close();
view.loadUrl("javascript:"+jsb.toString());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
showStop(false);
cja.setPageEncode(pageEncode);//
view.addJavascriptInterface(new CertJsApi(DisplayMessageActivity.this, view, pageEncode), "certApi");
}private WebView genNewWebView(){
WebView chileWebView = new WebView(this);
WebSettings setting = chileWebView.getSettings();
//以下两行为实现 overview mode
setting.setLoadWithOverviewMode(true);
setting.setUseWideViewPort(true);
// 显示放大缩小按钮
setting.setSupportZoom(true);
setting.setBuiltInZoomControls(true);
setting.setJavaScriptEnabled(true);
setting.setJavaScriptCanOpenWindowsAutomatically(true);
setting.setSupportMultipleWindows(true);
// 设置点击网页中的链接不会打开android内置的浏览器,默认情况下点击链接会打开android内置的浏览器
chileWebView.setWebViewClient(new myWebViewClient());
chileWebView.setWebChromeClient(new myWebChromeClient());
chileWebView.setLayoutParams(new ViewGroup.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
chileWebView.clearCache(true);
cja = new CertJsApi(DisplayMessageActivity.this, chileWebView, pageEncode);
chileWebView.addJavascriptInterface(cja, "certApi");
return chileWebV}实现网页调用webview js接口的同步机制,主要是拦截prompt方法private class myWebChromeClient extends WebChromeClient{
public boolean onJsPrompt(WebView view, String url, final String message,
String defaultValue, final JsPromptResult result) {//实现webview调用Android的同步机制
//多加几个判断保证不会错误拦截
if(null != defaultValue && defaultValue.equals("signMessage")
&& null != message && message.contains("jsReqID") && message.contains("certID") && message.contains("dataToSign")){
debug("dataToSign:"+message);
final Gson gson = new Gson();
final Map jsonMap = gson.fromJson(message, java.util.Map.class);
final String dataToSign = (String) jsonMap.remove("dataToSign");
AlertDialog.Builder builder = new AlertDialog.Builder(DisplayMessageActivity.this)
.setTitle(R.string.tip).setMessage(Html.fromHtml("确定签名数据:&br /&&br /&" + dataToSign))
.setPositiveButton(R.string.confirm, new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
result.confirm(cja.signData(gson, jsonMap, dataToSign));
}).setNegativeButton(R.string.cancel, new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {//
result.cancel();
jsonMap.put("repCode", -1);//取消返回-1
result.confirm(gson.toJson(jsonMap));
builder.setCancelable(false);
builder.create();
builder.show();
return super.onJsPrompt(view, url, message, defaultValue, result);
* 进度变化
public void onProgressChanged(WebView view, int newProgress) {
// Activity和Webview根据加载程度决定进度条的进度大小
// 当加载到100%的时候 进度条自动消失//
SDisplayMessageActivity.this.setProgress(newProgress * 100);
ProgressBar chromeClientPb = DisplayMessageActivity.this.
if( newProgress == 100){
chromeClientPb.setVisibility(View.GONE);
mIbRefresh.setVisibility(View.VISIBLE);
mIbStop.setVisibility(View.GONE);
mIbTopRefresh.setVisibility(View.VISIBLE);
mIbTopStop.setVisibility(View.GONE);
}else if(newProgress & 0 && chromeClientPb.getVisibility() == View.GONE){
chromeClientPb.setVisibility(View.VISIBLE);
chromeClientPb.setProgress(newProgress);
mIbRefresh.setVisibility(View.GONE);
mIbStop.setVisibility(View.VISIBLE);
mIbTopRefresh.setVisibility(View.GONE);
mIbTopStop.setVisibility(View.VISIBLE);
chromeClientPb.setProgress(newProgress);
mIbRefresh.setVisibility(View.GONE);
mIbStop.setVisibility(View.VISIBLE);
mIbTopRefresh.setVisibility(View.GONE);
mIbTopStop.setVisibility(View.VISIBLE);
public boolean onCreateWindow(WebView view, boolean isDialog,
boolean isUserGesture, Message resultMsg) {
WebView chileWebView = genNewWebView();
webView.addView(chileWebView);
((WebView.WebViewTransport) resultMsg.obj).setWebView(chileWebView);
resultMsg.sendToTarget();
public void onCloseWindow(WebView window) {
//若webView中只包含一个view,此时关闭window返回上一个activity
if(webView.getChildCount() & 2)
DisplayMessageActivity.this.finish();
webView.removeView(window);
window.destroy();
我不是码农,我是代码的组织者。互联网最大的作用是资源共享,我只是让获取资源更方便。欢迎扫描关注我的公众号,我会分享技术,分享我感兴趣的诸如中医、阴阳五行等等,还有小伙伴的投搞。欢迎扫微信关注我~雨中无伞与您一同见证前端开发,这里提供最新前端开发知识
随笔- 475&
评论- 312&
&&&&&&&&&&&
在android4.2以前,注入步骤如下:
webview.getSetting().setJavaScriptEnable(true);&&
class&JsObject&{&&
&&&&public&String&toString()&{&return&"injectedObject";&}&&
&webView.addJavascriptInterface(new&JsObject(),&"injectedObject");&&
Android4.2及以后,注入步骤如下:
webview.getSetting().setJavaScriptEnable(true);&&
class&JsObject&{&&
&&&&@JavascriptInterface&&
&&&&public&String&toString()&{&return&"injectedObject";&}&&
&webView.addJavascriptInterface(new&JsObject(),&"injectedObject");&&
发现区别没?4.2之前向webview注入的对象所暴露的接口toString没有注释语句@JavascriptInterface,而4.2及以后的则多了注释语句@JavascriptInterface
经过查官方文档所知,因为这个接口允许JavaScript 控制宿主应用程序,这是个很强大的特性,但同时,在4.2的版本前存在重大安全隐患,因为JavaScript 可以使用反射访问注入webview的java对象的public fields,在一个包含不信任内容的WebView中使用这个方法,会允许攻击者去篡改宿主应用程序,使用宿主应用程序的权限执行java代码。因此4.2以后,任何为JS暴露的接口,都需要加
@JavascriptInterface
注释,这样,这个Java对象的fields 将不允许被JS访问。
官方文档说明:
From the Android 4.2 documentation:
Caution: If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available your web page code (the method must also be public). If you do not provide the annotation, then the method will not accessible by your web page when running on Android 4.2 or higher.
注:如果将targetSdkVersion 设置为17或者更高,但却没有给暴露的js接口加@JavascriptInterface注释,则logcat会报如下输出:
E/Web Console: Uncaught TypeError: Object [object Object] has no method 'toString'
public void&addJavascriptInterface&(&object,&&name)
阅读(...) 评论()您还可以使用以下方式登录
当前位置:&>&&>&&>& > Android WebView - 全面总结(概述、捕获url、js交互、小技巧、内存泄漏、缓存机制)
Android WebView - 全面总结(概述、捕获url、js交互、小技巧、内存泄漏、缓存机制)
前言结合H5页面开发的App日渐多了起来,而WebView正是Html与Native的纽带,今天就借着一个新的项目需求顺便做一下WebView的知识总结,如有错漏,恳请大家指点指点。(项目需求:将适配好的网页打包成App,并能够调用系统摄像头进行二维码识别、拍照或是选择本地图片上传、获取用户位置等)WebView 小科普官方文档Class OverviewA View that displays web pages. This class is the basis upon which you can rollyour own web browser or simply display some online content within your Activity.It uses the WebKit rendering engine to display web pages and includes methodsto navigate forward and backward through a history, zoom in and out, perform text searches and more.理解:WebView是一个显示网页的一个View,基本应用于浏览器或是Activity中网页的简单显示。使用了WebKit渲染引擎实现一系列神奇的功能。Basic usageBy default, a WebView provides no browser-like widgets, does not enable JavaScript and web page errors are ignored.理解:默认情况,WebView并没有开启对JavaScript的支持,仅起展示作用,因此,我们需要进一步配置WebView才能满足各种各样的需求。WebView基本使用在 AndroidManifest.xml 中添加联网权限(如果webView需要联网的话,仅加载本地html、js文件则不需要添加联网权限) 一些 WebSettings 常用配置(其实还有许多没有列出来,大家可以利用IDE,点击进入方法,查看源码继续发掘) WebSettings
mWebSetting = mWebView.getSettings();
//获取WebSetting setJavaScriptEnabled(true);//让WebView支持JavaScript setDomStorageEnabled(true);//启用H5 DOM API (默认false) setDatabaseEnabled(true);//启用数据库api(默认false)可结合 setDatabasePath 设置路径 setCacheMode(WebSettings.LOAD_DEFAULT)//设置缓存模式 setAppCacheEnabled(true);//启用应用缓存(默认false)可结合 setAppCachePath 设置缓存路径 setAppCacheMaxSize()//已过时,高版本API上,系统会自行分配 setPluginsEnabled(true);
//设置插件支持 setRenderPriority(RenderPriority.HIGH);
//提高渲染的优先级 setUseWideViewPort(true);
//将图片调整到适合webview的大小 setLoadWithOverviewMode(true); // 缩放至屏幕的大小 setSupportZoom(true);
//支持缩放,默认为true setBuiltInZoomControls(true); //设置内置的缩放控件(若SupportZoom为false,该设置项无效) setDisplayZoomControls(false); //隐藏原生的缩放控件 setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //支持内容重新布局 supportMultipleWindows();
//支持多窗口 setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//关闭webview中缓存 setAllowFileAccess(true);
//设置可以访问文件 setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点 setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 setLoadsImagesAutomatically(true);
//自动加载图片 setDefaultTextEncodingName(&utf-8&);//设置编码格式 //实际应用中,一般配置即可满足基本需求 mWebSettings.setSupportZoom(true); mWebSettings.setJavaScriptEnabled(true); mWebSettings.setLoadWithOverviewMode(true); mWebSettings.setUseWideViewPort(true); mWebSettings.setDefaultTextEncodingName(&utf-8&); mWebSettings.setLoadsImagesAutomatically(true);加载网页、本地、assets中的html页面基本方式//网页private static final String URL_NET = &&; // 记得加 &http://&//assets 中的 html 资源private static final String URL_LOCAL =&file:///android_asset/xxx.html路径&; //SD 卡中的 html 资源private static final String URL_SD_CARD =&content://com.android.htmlfileprovider/mnt/sdcard/xxx.html&; mWebView.loadUrl(URL_NET);mWebView.loadUrl(URL_LOCAL);mWebView.loadUrl(URL_SD_CARD);WebViewClient 与 WebChromeClientWebViewClient 用于帮助WebView处理各种通知、请求事件WebViewClient 常用方法说明shouldOverrideUrlLoading加载时调用,可捕获urlonPageStart开始加载时调用(可以设置加载中提示)onPageFinish加载完成时调用(无法打开也是完成的一种,在这里取消加载提示显示)onReceiveError接收到错误信息时调用(通常在该方法中处理404之类的加载错误,但这里有点坑,API23中,在低于API23的设备上运行时,该方法失效,不调用我猜原因可能是: 新版的onReceiveError不再接收网页连接的错误,而是接收WebView自身运行出现的错误,另外有onReceivedHttpError方法来接收(然而在我的测试中,该方法还是未能接收到404错误)。可暂时用API23过时的方法&onReceivedError(WebView view, int errorCode, String description, String failingUrl)&替代新版本中的&onReceivedError(WebView view, WebResourceRequest request, WebResourceError error)&;)传送门:stackoverflow Q&AWebChromeClient 用于辅助 WebView处理Javascript的对话框,网站图标、Title、位置、加载进度等信息WebChromeClient 常用方法说明onProgressChanged加载进度onReceivedTitle、onReceivedIcon获取网页标题、图标onGeolocationPermissionsShowPrompt页面发起GEO定位请求时调用&WebChromeClient源码中对各种方法都有详细解析,需要用到的时候查一下即可两者用法都是简单的set方法mWebView.setWebViewClient(mWebViewClient);mWebView.setChromeClient(mWebChromeClient);WebView与Javascript交互前提条件:setJavaScriptEnabled(true) 调用js方法mWebView.loadUrl(&javascript: 方法名('&+参数+&')&); js调用android中方法4.2及之前版本该方法存在漏洞:引用&漏洞描述&:1,WebView添加了JavaScript对象,并且当前应用具有读写SDCard的权限,也就是:android.permission.WRITE_EXTERNAL_STORAGE2,JS中可以遍历window对象,找到存在&getClass&方法的对象的对象,然后再通过反射的机制,得到Runtime对象,然后调用静态方法来执行一些命令,比如访问文件的命令.3,再从执行命令后返回的输入流中得到字符串,就可以得到文件名的信息了。然后想干什么就干什么,好危险。/** * This method can be used to allow JavaScript to control the host * application. This is a powerful feature, but also presents a security * risk for apps targeting{@link android.os.Build.VERSION_CODES#JELLY_BEAN}
* or earlier. * / //理解:该方法可以让js控制app,很强势,但在API17(4.2)及之前的版本存在安全问题 addJavascriptInterface(Object object, String name); //使用方法 mWebView.addJavascriptInterface(MethodObject,&name&); //还需要写一个方法类 class MethodObject extends Object {
//无参函数,js中通过:var str = window.name.HtmlcallJava(); 获取到
@JavascriptInterface
public String HtmlcallJava() {
return &Html call Java&;
//有参函数,js中通过:window.jsObj.HtmlcallJava2(&IT-homer blog&);
@JavascriptInterface
public String HtmlcallJava2(final String param) {
return &Html call Java : & +
}}WebView小技巧/** * 捕获Url * 多页面在同一个WebView打开 * /@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.equal(&需要捕获的url&)){
// 捕获后的操作
// 前面提到的项目需求中,调用系统摄像头识别二维码、拍照、选择本地图片等功能
// 均可该方式简单实现(当然addJavascriptInterface方式也能达到相同效果)
view.loadUrl(url);//该方法可让多页面在同一个WebView中打开(不用新建Activity或是调用浏览器)
}//我们再回头看看该方法的官方API,会发现上面的方法多少还是有点坑(重定向问题,出现原理)
* Give the host application a chance to take over the control when a new
* url is about to be loaded in the current WebView. If WebViewClient is not
* provided, by default WebView will ask Activity Manager to choose the
* proper handler for the url. If WebViewClient is provided, return true
* means the host application handles the url, while return false means the
* current WebView handles the url.
//该方法为应用提供处理新url的机会,如果WebView没有设置WebViewClient,WebView会调用系统来找到合适应用来处理该url;而如果设置了WebViewClient,该方法返回true说明该url由应用自行处理,而false则交给WebView自动处理。
//那么,问题来了:上面方法中,我们returne的是true,而处理代码是让WebView直接loadUrl(不管什么情况都是直接loadUrl,并把该url加入历史记录),如果该url会重定向到其他url,如果调用了goBack,返回到该url,而该url又重定向到另外一个url,造成goBack失败。
//解决方式:将处理重定向的url交给webView本身,webView能自行判断url是否为重定向url,能够确保历史记录准确性,自身跳转则需要另想办法:
//1. 与前端人员协商能够去掉重定向url?
//2. 建立自身的历史栈,舍弃goBack()方法,移除重定向url与重定向后的url,根据需求自行进行loadUrl(需要思考一个合理的跳转逻辑)
//3. 建立自身的历史栈,与前端配合,提供js函数判断是否为重定向url,捕获url调用js函数,若为重定向url则作过滤处理,则不加入历史栈public boolean shouldOverrideUrlLoading(WebView view, String url){}/** * 返回上一浏览页面 * /public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return super.onKeyDown(keyCode, event);
}// WebClient 中 onReceivedError 的旧方法(API23 已过时) @Overridepublic void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
showErrorTips();// 显示错误页面/提示(大家可以将 WebView 错误页面替换掉、结合 mWebView.reload 实现点击重连)}WebView 进阶WebView 内存泄漏问题Android WebView Memory Leak WebView解析网页时会申请Native堆内存用于保存页面元素,当页面较复杂时会有很大的内存占用。如果页面包含图片,内存占用会更严重。并且打开新页面时,为了能快速回退,之前页面占用的内存也不会释放。有时浏览十几个网页,都会占用几百兆的内存。这样加载网页较多时,会导致系统不堪重负,最终强制关闭应用,也就是出现应用闪退或重启。由于占用的都是Native堆内存,所以实际占用的内存大小不会显示在常用的DDMS Heap工具中(这里看到的只是Java虚拟机分配的内存,一般即使Native堆内存已经占用了几百兆,这里显示的还只是几兆或十几兆)。只有使用adb shell中的一些命令比如dumpsys meminfo 包名,或者在程序中使用Debug.getNativeHeapSize()才能看到。据说由于WebView的一个BUG,即使它所在的Activity(或者Service)结束也就是onDestroy()之后,或者直接调用WebView.destroy()之后,它所占用这些内存也不会被释放。解决这个问题最直接的方法是:把使用了WebView的Activity(或者Service)放在单独的进程里。然后在检测到应用占用内存过大有可能被系统干掉或者它所在的Activity(或者Service)结束后,调用System.exit(0),主动Kill掉进程。由于系统的内存分配是以进程为准的,进程关闭后,系统会自动回收所有内存。WebView 缓存机制经过一番搜索得来的结果:1. WebView缓存分为:页面缓存和数据缓存。页面缓存指加载网页时,对页面或资源数据的缓存。一般使用RE管理器进入目录: &/data/data/(packageName)/cache/org.chromium.android_webview&可看到;数据缓存又分为 AppCache 与 DOM Storage 。AppCache可以有选择地缓存我们所想要缓存的东西;DOM Storage 则是HTML5的一个缓存机制,常用于存储简单的表单数据。2. webView的缓存模式: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,都使用缓存中的数据。3. 将缓存路径转移到外置sd卡查看 Context 类API 发现这样一个方法,重写该方法即可(注意赋予相关权限,但Android 4.4 上权限限制,会使该方法失效)/**
* Returns the absolute path to the application specific cache directory
* on the filesystem. These files will be ones that get deleted first when the
* device runs low on storage.
* There is no guarantee when these files will be deleted.
* Note: you should not rely on the system deleting these
* you should always have a reasonable maximum, such as 1 MB,
* for the amount of space you consume with cache files, and prune those
* files when exceeding that space.
* @return The path of the directory holding application cache files.
* @see #openFileOutput
* @see #getFileStreamPath
* @see #getDir
public abstract File getCacheDir();File extStorageAppCachePath =
public File getCacheDir() {
//读写权限判断
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
//获取外置存储路径,生成相应缓存路径
File externalStorageDir = Environment.getExternalStorageDirectory();
if (externalStorageDir != null) {
extStorageAppCachePath = new File(externalStorageDir.getAbsolutePath() +
File.separator + &Android& + File.separator + &data& + File.separator + getPackageName() + File.separator + &webViewCache&);
//路径不存在,创建
if (!extStorageAppCachePath.exists()) {
if (!extStorageAppCachePath.mkdirs()) {
//创建路径失败
extStorageAppCachePath =
return super.getCacheDir();
//成功创建,返回路径
if (extStorageAppCachePath != null) {
return extStorageAppCacheP
//路径已存在,直接返回
if (extStorageAppCachePath != null) {
return extStorageAppCacheP
return super.getCacheDir();
}结束语本文主要是对自己学习WebView的过程、应用WebView遇到的一些问题,结合强大的网络资源总结而来,如果错漏,恳请指教,希望能给大家提供小小的帮助,在分享技术过程中,提升、成长!(有很长一段时间没有发布过博客,贵在坚持,贵在坚持!)就爱阅读网友整理上传,为您提供最全的知识大全,期待您的分享,转载请注明出处。
欢迎转载:
推荐:    }

我要回帖

更多关于 spring 注入list对象 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信