2024年最全深度学习js与安卓的交互以及WebView的那些坑(1),腾讯的面试官是什么等级

最后

总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。

在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

2.在 Activity 销毁( WebView )的时候,先让 WebView 加载null内容,然后移除 WebView,再销毁 WebView,最后置空。

@Override
protected void onDestroy() {
if (mWebView != null) {
mWebView.loadDataWithBaseURL(null, “”, “text/html”, “utf-8”, null);
mWebView.clearHistory();

((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}

⇒ 三、WebView的使用漏洞 及其修复方式

WebView中,主要漏洞有三类:

1.任意代码执行漏洞
2.密码明文存储漏洞
3.域控制不严格漏洞

(一)任意代码执行漏洞

  • (1)addJavascriptInterface 接口引起远程代码执行漏洞

1. 漏洞产生原因:

js调用Android的其中一个方式是通过addJavascriptInterface接口进行对象映射:

webView.addJavascriptInterface(new JSObject(), “myObj”);
// 参数1:Android的本地对象
// 参数2:JS的对象
// 通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法
所以,漏洞产生原因是:当JS拿到android这个对象后,就可以调用这个Android对象中所有的方法,包括系统类(Java.lang.Runtime 类),
从而进行任意代码执行。(比如我们可以执行命令获取本地设备的SD卡中的文件等信息从而造成信息泄露

具体获取系统类的描述:(结合 Java 反射机制)

    1. Android中的对象有一公共的方法:getClass() ;
    1. 该方法可以获取到当前类 类型Class
    1. 该类有一关键的方法: Class.forName;
    1. 该方法可以加载一个类(可加载 java.lang.Runtime 类)
    1. 而该类是可以执行本地命令的

以下是攻击的Js核心代码:

function execute(cmdArgs) {
// 步骤1:遍历 window 对象
// 目的是为了找到包含 getClass ()的对象
// 因为Android映射的JS对象也在window中,所以肯定会遍历到
for (var obj in window) {
if (“getClass” in window[obj]) {
// 步骤2:利用反射调用forName()得到Runtime类对象
alert(obj);
return window[obj].getClass().forName(“java.lang.Runtime”)
// 步骤3:以后,就可以调用静态方法来执行一些命令,比如访问文件的命令
getMethod(“getRuntime”,null).invoke(null,null).exec(cmdArgs);
// 从执行命令后返回的输入流中得到字符串,有很严重暴露隐私的危险。
// 如执行完访问文件的命令之后,就可以得到文件名的信息了。
}
}
}

当一些 APP 通过扫描二维码打开一个外部网页时,攻击者就可以执行这段 js 代码进行漏洞攻击。在微信盛行、扫一扫行为普及的情况下,该漏洞的危险性非常大

2.解决方法

Android 4.2版本之后:Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击

Android 4.2版本之前:采用拦截prompt()进行漏洞修复。 具体步骤如下:

1.继承 WebView ,重写 addJavascriptInterface 方法,然后在内部自己维护一个对象映射关系的 Map ( 将需要添加的 JS 接口放入该Map中 )
2.每次当 WebView 加载页面前加载一段本地的 JS 代码,原理是:

  1. 让JS调用一Javascript方法:该方法是通过调用prompt()把JS中的信息(含特定标识,方法名称等)传递到Android端;
  2. 在Android的onJsPrompt()中 ,解析传递过来的信息,再通过反射机制调用Java对象的方法,这样实现安全的JS调用Android代码。
    关于Android返回给JS的值:可通过prompt()把Java中方法的处理结果返回到Js中

具体需要加载的JS代码如下:

javascript:(function JsAddJavascriptInterface_(){
// window.jsInterface 表示在window上声明了一个Js对象
// jsInterface = 注册的对象名
// 它注册了两个方法,onButtonClick(arg0)和onImageClick(arg0, arg1, arg2)
// 如果有返回值,就添加上return
if (typeof(window.jsInterface)!=‘undefined’) {
console.log(‘window.jsInterface_js_interface_name is exist!!’);}
else {
window.jsInterface = {
// 声明方法形式:方法名: function(参数)
onButtonClick:function(arg0) {
// prompt()返回约定的字符串
// 该字符串可自己定义
// 包含特定的标识符MyApp和 JSON 字符串(方法名,参数,对象名等)
return prompt(‘MyApp:’+JSON.stringify({obj:‘jsInterface’,func:‘onButtonClick’,args:[arg0]}));
},
onImageClick:function(arg0,arg1,arg2) {
return prompt(‘MyApp:’+JSON.stringify({obj:‘jsInterface’,func:‘onImageClick’,
args:[arg0,arg1,arg2]}));
},
};
}
}
)()
// 当JS调用 onButtonClick() 或 onImageClick() 时,就会回调到Android中的 onJsPrompt ()
// 我们解析出方法名,参数,对象名
// 再通过反射机制调用Java对象的方法


关于采用拦截prompt()进行漏洞修复需要注意的两点细节:

细节1:加载上述JS代码的时机

由于当 WebView 跳转到下一个页面时,之前加载的 JS 可能已经失效,所以,通常需要在以下方法中加载js:
onLoadResource();
doUpdateVisitedHistory();
onPageStarted();
onPageFinished();
onReceivedTitle();
onProgressChanged();

细节2:需要过滤掉 Object 类的方法

由于最终是通过反射得到Android指定对象的方法,所以同时也会得到基类的其他方法(最顶层的基类是 Object类)
为了不把 getClass()等方法注入到 JS 中,我们需要把 Object 的共有方法过滤掉,需要过滤的方法列表如下:
getClass()
hashCode()
notify()
notifyAl()
equals()
toString()
wait()

  • (2)searchBoxJavaBridge_接口引起远程代码执行漏洞

1. 产生原因

  1. 在Android 3.0以下,Android系统会默认通过searchBoxJavaBridge_的Js接口给 WebView 添加一个JS映射对象:
    searchBoxJavaBridge_对象
  2. 该接口可能被利用,实现远程任意代码。

2. 解决方法

删除searchBoxJavaBridge_接口
// 通过调用该方法删除接口removeJavascriptInterface();

  • (3)accessibility和 accessibilityTraversal接口引起远程代码执行漏洞

1. 产生原因

  1. 在Android 3.0以下,Android系统会默认通过searchBoxJavaBridge_的Js接口给 WebView 添加一个JS映射对象:
    searchBoxJavaBridge_对象
  2. 该接口可能被利用,实现远程任意代码。

2. 解决方法

删除searchBoxJavaBridge_接口
// 通过调用该方法删除接口removeJavascriptInterface();

(二)密码明文存储漏洞

  • (1)问题分析

//WebView默认开启密码保存功能 : mWebView.setSavePassword(true) 开启后,在用户输入密码时,会弹出提示框:询问用户是否保存密码; 如果选择”是”,密码会被明文保到 /data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险

  • (2)解决方案

//关闭密码保存提醒 WebSettings.setSavePassword(false)

(三)域控制不严格漏洞

先看Android里的WebViewActivity.java:

public class WebViewActivity extends Activity {
private WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webview);
webView = (WebView) findViewById(R.id.webView);

//webView.getSettings().setAllowFileAccess(false); (1)
//webView.getSettings().setAllowFileAccessFromFileURLs(true); (2)
//webView.getSettings().setAllowUniversalAccessFromFileURLs(true); (3)
Intent i = getIntent();
String url = i.getData().toString(); //url = file:///data/local/tmp/attack.html
webView.loadUrl(url);
}
}

/Mainifest.xml/
// 将该 WebViewActivity 在Mainifest.xml设置exported属性
// 表示:当前Activity是否可以被另一个Application的组件启动
android:exported=“true”

  • (1)问题分析

上述demo中:即 A 应用可以通过 B 应用导出的 Activity 让 B 应用加载一个恶意的 file 协议的 url,从而可以获取 B 应用的内部私有文件,从而带来数据泄露威胁

**具体:**当其他应用启动此 Activity 时, intent 中的 data 直接被当作 url 来加载(假定传进来的 url 为 file:///data/local/tmp/attack.html ),其他 APP 通过使用显式 ComponentName 或者其他类似方式就可以很轻松的启动该 WebViewActivity 并加载恶意url。

下面我们着重分析WebView中getSettings类的方法对 WebView 安全性的影响:

setAllowFileAccess()
setAllowFileAccessFromFileURLs()
setAllowUniversalAccessFromFileURLs()

  • (2) setAllowFileAccess()

// 设置是否允许 WebView 使用 File 协议,默认设置为true,即允许在 File 域下执行任意 JavaScript 代码 webView.getSettings().setAllowFileAccess(true);

但是同时也限制了 WebView 的功能,使其不能加载本地的 html 文件,( 移动版的 Chrome 默认禁止加载 file 协议的文件 ) ,如下图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解决方案:

  1. 对于不需要使用 file 协议的应用,禁用 file 协议;
    setAllowFileAccess(false);

  2. 对于需要使用 file 协议的应用,禁止 file 协议加载 JavaScript。
    setAllowFileAccess(true);
    // 禁止 file 协议加载 JavaScript
    if (url.startsWith(“file://”) {
    setJavaScriptEnabled(false);
    } else {
    setJavaScriptEnabled(true);
    }

  • (3)setAllowFileAccessFromFileURLs()

设置是否允许通过 file url 加载的 Js代码读取其他的本地文件 , 在Android 4.1前默认允许 , 在Android 4.1后默认禁止

webView.getSettings().setAllowFileAccessFromFileURLs(true);

当AllowFileAccessFromFileURLs()设置为 true 时,攻击者的JS代码为 ( 通过该代码可成功读取 /etc/hosts 的内容数据 ) :

解决方案:

设置setAllowFileAccessFromFileURLs(false);

当设置成为 false 时,上述JS的攻击代码执行会导致错误,表示浏览器禁止从 file url 中的 JavaScript 读取其它本地文件。

  • (4) setAllowUniversalAccessFromFileURLs()

设置是否允许通过 file url 加载的 Javascript 可以访问其他的源(包括http、https等源),在Android 4.1前默认允许(setAllowFileAccessFromFileURLs()不起作用),在Android 4.1后默认禁止

webView.getSettings().setAllowUniversalAccessFromFileURLs(true);

当AllowFileAccessFromFileURLs()被设置成true时,攻击者的JS代码是:

// 通过该代码可成功读取 http://www.so.com 的内容

解决方案:

设置setAllowUniversalAccessFromFileURLs(false);

  • (5) setJavaScriptEnabled()

设置是否允许 WebView 使用 JavaScript(默认是不允许),但很多应用(包括移动浏览器)为了让 WebView 执行 http 协议中的 JavaScript,都会主动设置为true,不区别对待是非常危险的,如下代码所示:

webView.getSettings().setJavaScriptEnabled(true);

即使把setAllowFileAccessFromFileURLs()和setAllowUniversalAccessFromFileURLs()都设置为 false,通过 file URL 加载的 javascript仍然有方法访问其他的本地文件:符号链接跨源攻击(前提是允许 file URL 执行 javascript,即webView.getSettings().setJavaScriptEnabled(true);)

原因分析:

这一攻击能奏效的原因是:通过 javascript 的延时执行和将当前文件替换成指向其它文件的软链接就可以读取到被符号链接所指的文件。

具体攻击步骤:(在该命令执行前 xx.html 是不存在的;执行完这条命令之后,就生成了这个文件,并且将 Cookie 文件链接到了 xx.html 上。) 1. 把恶意的 js 代码输出到攻击应用的目录下,随机命名为 xx.html,修改该目录的权限; 2. 修改后休眠 1s,让文件操作完成; 3. 完成后通过系统的 Chrome 应用去打开该 xx.html 文件 4. 等待 4s 让 Chrome 加载完成该 html,最后将该 html 删除,并且使用 ln -s 命令为 Chrome 的 Cookie 文件创建软连接, 于是就可通过链接来访问 Chrome 的 Cookie


注意事项:   Google 没有进行修复,只是让Chrome 最新版本默认禁用 file 协议,所以这一漏洞在最新版的 Chrome 中并不存在。   但是,在日常大量使用 WebView 的App和浏览器,都有可能受到此漏洞的影响。通过利用此漏洞,容易出现数据泄露的危险   如果是 file 协议,禁用 javascript 可以很大程度上减小跨源漏洞对 WebView 的威胁。   但并不能完全杜绝跨源文件泄露。例:应用实现了下载功能,对于无法加载的页面,会自动下载到 sd 卡中;由于 sd 卡中的文件所有应用都可以访问,于是可以通过构造一个 file URL 指向被攻击应用的私有文件,然后用此 URL 启动被攻击应用的 WebActivity,这样由于该 WebActivity 无法加载该文件,就会将该文件下载到 sd 卡下面,然后就可以从 sd 卡上读取这个文件了

  • (6) 最终解决方案

1)对于不需要使用 file 协议的应用,禁用 file 协议;

// 禁用 file 协议;
setAllowFileAccess(false);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);

2)对于需要使用 file 协议的应用,禁止 file 协议加载 JavaScript。

// 需要使用 file 协议
setAllowFileAccess(true);
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);

// 禁止 file 协议加载 JavaScript
if (url.startsWith(“file://”) {
setJavaScriptEnabled(false);
} else {
setJavaScriptEnabled(true);
}

⇒ 四、安卓通过WebView和js交互

Android与js通过WebView互相调用方法,二者沟通的桥梁是WebView,实际上是:

  • Android去调用JS的代码
  • JS去调用Android的代码

对于 Android调用JS代码 的方法有2种: 1. 通过WebView的loadUrl() 2. 通过WebView的evaluateJavascript()

对于 JS调用Android代码 的方法有3种: 1. 通过WebView的addJavascriptInterface()进行对象映射 2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url 3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息

⇒ 五、WebView 的缓存机制 & 资源预加载方案

⇒ 六、WebView的那些坑(我自己整理收集的)

(1) 为什么Webview打开一个页面,播放一段音乐,退出Activity时音乐还在后台播放?

◆◆ 解决方案 1:

//销毁Webview
@Override
protected void onDestroy() {
if (mWebview != null) {
mWebview.loadDataWithBaseURL(null, “”, “text/html”, “utf-8”, null);
mWebview.clearHistory();
((ViewGroup) mWebview.getParent()).removeView(mWebview);
mWebview.destroy();
mWebview = null;
}
super.onDestroy();
}

还有别问我为什么要移除,等你Error: WebView.destroy() called while still attached!之后你就知道了。

◆◆ 解决方案 2:

@Override
protected void onPause() {
h5_webview.onPause();
h5_webview.pauseTimers();
super.onPause();
}
@Override
protected void onResume() {
h5_webview.onResume();
h5_webview.resumeTimers();
super.onResume();
}

Webview的onPause()方法官网是这么解释的:

Does a best-effort attempt to pause any processing that can be paused safely, such as animations
and geolocation. Note that this call does not pause JavaScript. To pause JavaScript globally, use
pauseTimers(). To resume WebView, call onResume().
【翻译:】通知内核尝试停止所有处理,如动画和地理位置,但是不能停止Js,如果想全局停止Js,
可以调用pauseTimers()全局停止Js,调用onResume()恢复。

(2) 怎么用网页的标题来设置自己的标题栏?

◆◆ 解决方案:

WebChromeClient mWebChromeClient = new WebChromeClient() {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
txtTitle.setText(title);
}
};
mWedView.setWebChromeClient(mWebChromeClient());

★★ 注意事项:

● 1.可能当前页面没有标题,获取到的是null,那么你可以在跳转到该Activity的时候自己带一个标题,或者有一个默认标题。
● 2.在一些机型上面,Webview.goBack()后,这个方法不一定会调用,所以标题还是之前页面的标题。那么
你就需要用一个ArrayList来保持加载过的url,一个HashMap保存url及对应的title.然后就是用WebView.canGoBack()来做判断处理了。

(3) 为什么打包之后JS调用失败(或者WebView与JavaScript相互调用时,如果是debug没有配置混淆时,调用时没问题的,但是当设置混淆后发现无法正常调用了)?

◆◆ 解决方案:在proguard-rules.pro中添加混淆。

-keepattributes Annotation
-keepattributes JavascriptInterface
-keep public class org.mq.study.webview.DemoJavaScriptInterface{
public ;
}
#假如是内部类,混淆如下:
-keepattributes JavascriptInterface
-keep public class org.mq.study.webview.webview.DemoJavaScriptInterface$InnerClass{
public ;
}

其中org.mq.study.webview.DemoJavaScriptInterface 是不需要混淆的类名

(4) 5.0 以后的WebView加载的链接为Https开头,但是链接里面的内容,比如图片为Http链接,这时候,图片就会加载不出来,怎么解决?

★★ 原因分析:原因是Android 5.0上Webview默认不允许加载Http与Https混合内容:

◆◆ 解决方案:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//两者都可以
webSetting.setMixedContentMode(webSetting.getMixedContentMode());
//mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

★★ 参数说明:

● MIXED_CONTENT_ALWAYS_ALLOW 允许从任何来源加载内容,即使起源是不安全的;
● MIXED_CONTENT_NEVER_ALLOW 不允许Https加载Http的内容,即不允许从安全的起源去加载一个不安全的
资源;
● MIXED_CONTENT_COMPLTIBILITY_MODE 当涉及到混合式内容时,WebView会尝试去兼容最新Web浏览器的
风格;

另外:在认证证书不被Android所接受的情况下,我们可以通过设置重写WebViewClient的onReceivedSslError方法在其中设置接受所有网站的证书来解决,具体代码如下:

webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view,
SslErrorHandler handler, SslError error) {
//super.onReceivedSslError(view, handler, error);注意一定要去除这行代码,否则设置无效。
// handler.cancel();// Android默认的处理方式
handler.proceed();// 接受所有网站的证书
// handleMessage(Message msg);// 进行其他处理
}
});

(5) WebView调用手机系统相册来上传图片,开发过程中发现在很多机器上无法正常唤起系统相册来选择图片。怎么解决?

★★ 原因分析:因为Google攻城狮们对setWebChromeClient的回调方法openFileChooser做了多次修改,5.0以下openFileChooser有几种重载方法,在5.0以上将回调方法该为了onShowFileChooser。

◆◆ 解决方案:为了兼容各个版本,我们需要对openFileChooser()进行重载,同时针对5.0及以上重写onShowFileChooser()方法:

上一段示例代码,给大家看看:

public class MainActivity extends AppCompatActivity {

private ValueCallback uploadMessage;
private ValueCallback<Uri[]> uploadMessageAboveL;
private final static int FILE_CHOOSER_RESULT_CODE = 10000;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

WebView webview = (WebView) findViewById(R.id.web_view);
assert webview != null;
WebSettings settings = webview.getSettings();
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setJavaScriptEnabled(true);
webview.setWebChromeClient(new WebChromeClient() {

// android 3.0以下:用的这个方法
public void openFileChooser(ValueCallback valueCallback) {
uploadMessage = valueCallback;
openImageChooserActivity();
}

// android 3.0以上,android4.0以下:用的这个方法
public void openFileChooser(ValueCallback valueCallback, String acceptType) {
uploadMessage = valueCallback;
openImageChooserActivity();
}

//android 4.0 - android 4.3 安卓4.4.4也用的这个方法
public void openFileChooser(ValueCallback valueCallback, String acceptType,
String capture) {
uploadMessage = valueCallback;
openImageChooserActivity();
}

//android4.4 无方法。。。

// Android 5.0及以上用的这个方法
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]>
filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
uploadMessageAboveL = filePathCallback;
openImageChooserActivity();
return true;
}
});
String targetUrl = “file:///android_asset/up.html”;
webview.loadUrl(targetUrl);
}

private void openImageChooserActivity() {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(“image/*”);
startActivityForResult(Intent.createChooser(i, “Image Chooser”),
FILE_CHOOSER_RESULT_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILE_CHOOSER_RESULT_CODE) {
if (null == uploadMessage && null == uploadMessageAboveL) return;
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
if (uploadMessageAboveL != null) {
onActivityResultAboveL(requestCode, resultCode, data);
} else if (uploadMessage != null) {
uploadMessage.onReceiveValue(result);
uploadMessage = null;
}
}
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {
if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)
return;
Uri[] results = null;
if (resultCode == Activity.RESULT_OK) {
if (intent != null) {
String dataString = intent.getDataString();
ClipData clipData = intent.getClipData();
if (clipData != null) {
results = new Uri[clipData.getItemCount()];
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
results[i] = item.getUri();
}
}
if (dataString != null)
results = new Uri[]{Uri.parse(dataString)};
}
}
uploadMessageAboveL.onReceiveValue(results);
uploadMessageAboveL = null;
}

}


重点坑:针对Android4.4,系统把openFileChooser方法去掉了,怎么解决?

详情请见 博客 http://blog.csdn.net/xiexie758/article/details/52446937 我这里就不多说了。

(6) WebView调用手机系统相册来上传图片,处理好第六点说的方法,我们打好release包测试的时候却又发现还是没法选择图片了。怎么解决?

★★ 原因分析:无奈去翻WebChromeClient的源码,发现openFileChooser()是系统API,我们的release包是开启了混淆的,所以在打包的时候混淆了openFileChooser(),这就导致无法回调openFileChooser()了。

◆◆ 解决方案也很简单,直接不混淆openFileChooser()就好了。

-keepclassmembers class * extends android.webkit.WebChromeClient{
public void openFileChooser(…);
}


(7)怎么在 WebView 中长按保存图片?

1. 给 WebView添加监听

mWebview.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
}
});

2. 获取点击的图片地址

先获取类型,根据相应的类型来处理对应的数据。

//首先判断点击的类型
WebView.HitTestResult result = ((WebView) v).getHitTestResult();
int type = result.getType();

//获取具体信息,图片这里就是图片地址
String imgurl = result.getExtra();

type有这几种类型:

  • WebView.HitTestResult.UNKNOWN_TYPE 未知类型
  • WebView.HitTestResult.PHONE_TYPE 电话类型
  • WebView.HitTestResult.EMAIL_TYPE 电子邮件类型
  • WebView.HitTestResult.GEO_TYPE 地图类型
  • WebView.HitTestResult.SRC_ANCHOR_TYPE 超链接类型
  • WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE 带有链接的图片类型
  • WebView.HitTestResult.IMAGE_TYPE 单纯的图片类型
  • WebView.HitTestResult.EDIT_TEXT_TYPE 选中的文字类型

3. 操作图片

你可以弹出保存图片,或者点击之后跳转到显示图片的页面。

最后整理一下代码:

mWebView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
WebView.HitTestResult result = ((WebView)v).getHitTestResult();
if (null == result)
return false;
int type = result.getType();
if (type == WebView.HitTestResult.UNKNOWN_TYPE)
return false;

// 这里可以拦截很多类型,我们只处理图片类型就可以了
switch (type) {
case WebView.HitTestResult.PHONE_TYPE: // 处理拨号
break;
case WebView.HitTestResult.EMAIL_TYPE: // 处理Email
break;
case WebView.HitTestResult.GEO_TYPE: // 地图类型
break;
case WebView.HitTestResult.SRC_ANCHOR_TYPE: // 超链接
break;
case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
break;
case WebView.HitTestResult.IMAGE_TYPE: // 处理长按图片的菜单项
// 获取图片的路径
String saveImgUrl = result.getExtra();

// 跳转到图片详情页,显示图片
Intent i = new Intent(MainActivity.this, ImageActivity.class);
i.putExtra(“imgUrl”, saveImgUrl);
startActivity(i);
break;
default:
break;
}
}
});

(8) WebView 开启硬件加速导致的问题?

WebView有很多问题,比如:不能打开pdf,播放视屏也只能打开硬件加速才能支持,在某些机型上会崩溃。 下面看一下硬件加速, 硬件加速 分为四个级别:

  • Application级别

<application android:hardwareAccelerated=“true”…>

  • Activity级别

<activity android:hardwareAccelerated=“true”…>

  • window级别(目前为止,Android还不支持在Window级别关闭硬件加速。)

getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

  • View级别

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);

WebView开启硬件加速导致屏幕花屏问题的解决:

★★ 原因分析: 4.0以上的系统我们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是,当WebView视图被整体遮住一块,然后突然恢复时(比如使用SlideMenu将WebView从侧边滑出来时),这个过渡期会出现白块同时界面闪烁。

◆◆ 解决方案: 在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启,代码如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Android 4.0+ 版本中的EditText字符重叠问题: 做的软件,在一些机器上,打字的时候,EditText中的内容会出现重叠,而大部分机器没有,所以感觉不是代码的问题,一直没有头绪。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

出现原因:JellyBean的硬件加速bug,在此我们关掉硬件加速即可。 解决方案:在EditText中加入一句:

android:layerType=”software”

图片无法显示: 做的程序里有的时候会需要加载大图,但是硬件加速中 OpenGL对于内存是有限制的。如果遇到了这个限制,LogCat只会报一个Warning: Bitmap too large to be uploaded into a texture (587x7696, max=2048x2048)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这时我们就需要把硬件加速关闭了。 但开始我是这样处理的,我关闭了整个应用的硬件加速:

随后我就发现,虽然图片可以显示了,但是ListView和WebView等控件显得特别的卡,这说明硬件加速对于程序的性能提升是很明显的。所以我就改为对于Activity的关闭。

<activity
android:name=“icyfox.webviewimagezoomertest.MainActivity”
android:label=“@string/app_name”
android:hardwareAccelerated=“false”

(9) ViewPager里非首屏WebView点击事件不响应是什么原因?

如果你的多个WebView是放在ViewPager里一个个加载出来的,那么就会遇到这样的问题。ViewPager首屏WebView的创建是在前台,点击时没有问题;而其他非首屏的WebView是在后台创建,滑动到它后点击页面会出现如下错误日志:

20955-20968/xx.xxx.xxx E/webcoreglue﹕ Should not happen: no rect-based-test nodes found

◆◆ 解决方案: 这个问题的办法是继承WebView类,在子类覆盖onTouchEvent方法,填入如下代码:

@Override
public boolean onTouchEvent(MotionEvent ev) {

最后

为了方便有学习需要的朋友,我把资料都整理成了视频教程(实际上比预期多花了不少精力)

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!
  • 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,没有人能随随便便成功。

加油,共勉。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

appen: no rect-based-test nodes found

◆◆ 解决方案: 这个问题的办法是继承WebView类,在子类覆盖onTouchEvent方法,填入如下代码:

@Override
public boolean onTouchEvent(MotionEvent ev) {

最后

为了方便有学习需要的朋友,我把资料都整理成了视频教程(实际上比预期多花了不少精力)

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!
  • 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,没有人能随随便便成功。

加油,共勉。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值