Skip to content

Commit 9beaab6

Browse files
committed
完善x5ku
1 parent 2f565c1 commit 9beaab6

22 files changed

+505
-77
lines changed

Question.md

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#### 问题汇总目录介绍
2+
- 01.关于js注入时机修改
3+
- 02.WebView进化史介绍
4+
- 03.提前初始化WebView必要性
5+
- 04.如何保证js安全性
6+
- 07.如何代码开启硬件加速
7+
- 08.WebView设置Cookie
8+
- 09.webView加载网页不显示图片
9+
- 11.提前显示加载进度条
10+
- 12.绕过证书校验漏洞
11+
- 13.allowFileAccess漏洞
12+
- 14.WebView嵌套ScrollView问题
13+
- 15.WebView中图片点击放大
14+
15+
16+
### 参考博客
17+
- https://juejin.im/post/58a037df86b599006b3fade4
18+
19+
20+
### 01.关于js注入时机修改
21+
- 反馈的问题:js注入时间有bug,OnPageFinished中注入,虽然最后都会全局注入成功,但是完成时间有可能太晚,当页面在初始化调用接口函数时会等待时间过长,可能不成功
22+
- 修改代码如下所示
23+
```
24+
/**
25+
* 当页面加载完成会调用该方法
26+
* @param view view
27+
* @param url url链接
28+
*/
29+
@Override
30+
public void onPageFinished(WebView view, String url) {
31+
if (!X5WebUtils.isConnected(webView.getContext()) && webListener!=null) {
32+
//隐藏进度条方法
33+
webListener.hindProgressBar();
34+
}
35+
super.onPageFinished(view, url);
36+
//设置网页在加载的时候暂时不加载图片
37+
//webView.getSettings().setBlockNetworkImage(false);
38+
//页面finish后再发起图片加载
39+
if(!webView.getSettings().getLoadsImagesAutomatically()) {
40+
webView.getSettings().setLoadsImagesAutomatically(true);
41+
}
42+
//这个时候添加js注入方法
43+
/*BridgeUtil.webViewLoadLocalJs(view, BridgeWebView.TO_LOAD_JS);
44+
if (webView.getStartupMessage() != null) {
45+
for (Message m : webView.getStartupMessage()) {
46+
//分发message 必须在主线程才分发成功
47+
webView.dispatchMessage(m);
48+
}
49+
webView.setStartupMessage(null);
50+
}*/
51+
//html加载完成之后,添加监听图片的点击js函数
52+
//addImageClickListener();
53+
//addImageClickListener(webView);
54+
}
55+
56+
57+
//修改后代码
58+
* 这个方法是监听加载进度变化的,当加载到百分之八十五的时候,页面一般就出来呢
59+
* 作用:获得网页的加载进度并显示
60+
* @param view view
61+
* @param newProgress 进度值
62+
*/
63+
@Override
64+
public void onProgressChanged(WebView view, int newProgress) {
65+
super.onProgressChanged(view, newProgress);
66+
if (webListener!=null){
67+
webListener.startProgress(newProgress);
68+
int max = 85;
69+
if (newProgress> max && !isShowContent){
70+
webListener.hindProgressBar();
71+
isShowContent = true;
72+
73+
//在这个时候添加js注入方法,具体可以看readme文档
74+
BridgeUtil.webViewLoadLocalJs(view, BridgeWebView.TO_LOAD_JS);
75+
if (webView.getStartupMessage() != null) {
76+
for (Message m : webView.getStartupMessage()) {
77+
webView.dispatchMessage(m);
78+
}
79+
webView.setStartupMessage(null);
80+
}
81+
}
82+
}
83+
}
84+
```
85+
86+
87+
### 02.WebView进化史介绍
88+
- 进化史如下所示
89+
- 从Android4.4系统开始,Chromium内核取代了Webkit内核。
90+
- 从Android5.0系统开始,WebView移植成了一个独立的apk,可以不依赖系统而独立存在和更新。
91+
- 从Android7.0 系统开始,如果用户手机里安装了 Chrome , 系统优先选择 Chrome 为应用提供 WebView 渲染。
92+
- 从Android8.0系统开始,默认开启WebView多进程模式,即WebView运行在独立的沙盒进程中。
93+
94+
95+
96+
### 03.提前初始化WebView必要性
97+
- https://www.jianshu.com/p/fc7909e24178
98+
- 代码里怎么设置Cookie,如下所示
99+
```
100+
/**
101+
* 同步cookie
102+
*
103+
* @param url 地址
104+
* @param cookieList 需要添加的Cookie值,以键值对的方式:key=value
105+
*/
106+
private void syncCookie (Context context , String url, ArrayList<String> cookieList) {
107+
//初始化
108+
CookieSyncManager.createInstance(context);
109+
//获取对象
110+
CookieManager cookieManager = CookieManager.getInstance();
111+
cookieManager.setAcceptCookie(true);
112+
//移除
113+
cookieManager.removeSessionCookie();
114+
//添加
115+
if (cookieList != null && cookieList.size() > 0) {
116+
for (String cookie : cookieList) {
117+
cookieManager.setCookie(url, cookie);
118+
}
119+
}
120+
String cookies = cookieManager.getCookie(url);
121+
X5LogUtils.d("cookies-------"+cookies);
122+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
123+
cookieManager.flush();
124+
} else {
125+
CookieSyncManager.getInstance().sync();
126+
}
127+
}
128+
```
129+
- 在android里面在调用webView.loadUrl(url)之前一句调用此方法就可以给WebView设置Cookie
130+
- 注:这里一定要注意一点,在调用设置Cookie之后不能再设置,否则设置Cookie无效。该处需要校验,为何???
131+
```
132+
webView.getSettings().setBuiltInZoomControls(true);
133+
webView.getSettings().setJavaScriptEnabled(true);
134+
```
135+
136+
137+
### 04.如何保证js安全性
138+
- Android和js如何通信
139+
- 为了与Web页面实现动态交互,Android应用程序允许WebView通过WebView.addJavascriptInterface接口向Web页面注入Java对象,页面Javascript脚本可直接引用该对象并调用该对象的方法。
140+
- 这类应用程序一般都会有类似如下的代码:
141+
```
142+
webView.addJavascriptInterface(javaObj, "jsObj");
143+
```
144+
- 此段代码将javaObj对象暴露给js脚本,可以通过jsObj对象对其进行引用,调用javaObj的方法。结合Java的反射机制可以通过js脚本执行任意Java代码,相关代码如下:
145+
- 当受影响的应用程序执行到上述脚本的时候,就会执行someCmd指定的命令。
146+
```
147+
<script>
148+
  function execute(cmdArgs) {
149+
  return jsobj.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
150+
  }
151+
152+
  execute(someCmd);
153+
</script>
154+
```
155+
- addJavascriptInterface任何命令执行漏洞
156+
- 在webview中使用js与html进行交互是一个不错的方式,但是,在Android4.2(16,包含4.2)及以下版本中,如果使用addJavascriptInterface,则会存在被注入js接口的漏洞;在4.2之后,由于Google增加了@JavascriptInterface,该漏洞得以解决。
157+
- @JavascriptInterface注解做了什么操作
158+
- 之前,任何Public的函数都可以在JS代码中访问,而Java对象继承关系会导致很多Public的函数都可以在JS中访问,其中一个重要的函数就是getClass()。然后JS可以通过反射来访问其他一些内容。通过引入 @JavascriptInterface注解,则在JS中只能访问 @JavascriptInterface注解的函数。这样就可以增强安全性。
159+
160+
161+
### 07.如何代码开启硬件加速
162+
- 开启软硬件加速这个性能提升还是很明显的,但是会耗费更大的内存 。直接调用代码api即可完成,webView.setOpenLayerType(true);
163+
164+
165+
### 08.WebView设置Cookie
166+
- https://www.jianshu.com/p/53897db4d734
167+
168+
169+
### 09.webView加载网页不显示图片
170+
- webView从Lollipop(5.0)开始webView默认不允许混合模式, https当中不能加载http资源, 而开发的时候可能使用的是https的链接, 但是链接中的图片可能是http的, 所以需要设置开启。
171+
```
172+
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
173+
mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
174+
}
175+
mWebView.getSettings().setBlockNetworkImage(false);
176+
```
177+
178+
179+
### 11.提前显示加载进度条
180+
- 提前显示进度条不是提升性能 , 但是对用户体验来说也是很重要的一点 , WebView.loadUrl("url") 不会立马就回调 onPageStarted 或者 onProgressChanged 因为在这一时间段,WebView 有可能在初始化内核,也有可能在与服务器建立连接,这个时间段容易出现白屏,白屏用户体验是很糟糕的 ,所以建议
181+
```
182+
//正确
183+
pb.setVisibility(View.VISIBLE);
184+
mWebView.loadUrl("https://github.com/yangchong211/LifeHelper");
185+
186+
//不太好
187+
@Override
188+
public void onPageStarted(WebView webView, String s, Bitmap bitmap) {
189+
super.onPageStarted(webView, s, bitmap);
190+
//设定加载开始的操作
191+
pb.setVisibility(View.VISIBLE);
192+
}
193+
```
194+
195+
196+
### 12.绕过证书校验漏洞
197+
- webviewClient中有onReceivedError方法,当出现证书校验错误时,我们可以在该方法中使用handler.proceed()来忽略证书校验继续加载网页,或者使用默认的handler.cancel()来终端加载。
198+
- 因为我们使用了handler.proceed(),由此产生了该“绕过证书校验漏洞”。如果确定所有页面都能满足证书校验,则不必要使用handler.proceed()
199+
```
200+
@SuppressLint("NewApi")
201+
@Override
202+
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
203+
//handler.proceed();// 接受证书
204+
super.onReceivedSslError(view, handler, error);
205+
}
206+
```
207+
208+
209+
210+
### 13.allowFileAccess漏洞
211+
- 如果webview.getSettings().setAllowFileAccess(boolean)设置为true,则会面临该问题;该漏洞是通过WebView对Javascript的延时执行和html文件替换产生的。
212+
- 解决方案是禁止WebView页面打开本地文件,即:webview.getSettings().setAllowFileAccess(false);
213+
- 或者更直接的禁止使用JavaScript:webview.getSettings().setJavaScriptEnabled(false);
214+
215+
216+
217+
### 14.WebView嵌套ScrollView问题
218+
- 问题描述
219+
- 当 WebView 嵌套在 ScrollView 里面的时候,如果 WebView 先加载了一个高度很高的网页,然后加载了一个高度很低的网页,就会造成 WebView 的高度无法自适应,底部出现大量空白的情况出现。
220+
- 为何出现这种情况
221+
222+
223+
224+
### 15.WebView中图片点击放大
225+
226+
227+
228+

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- 4.0.5 使用scheme协议打开链接风险
2020
- 4.0.6 如何处理加载错误
2121
- 4.0.7 webView防止内存泄漏
22+
- 4.1.9 掘金问题反馈记录
2223
- 05.webView优化
2324
- 5.0.1 视频全屏播放按返回页面被放大
2425
- 5.0.2 加快加载webView中的图片资源
@@ -29,6 +30,7 @@
2930
- 5.0.7 DNS采用和客户端API相同的域名
3031
- 5.0.8 如何设置白名单操作
3132
- 5.0.9 后台无法释放js导致发热耗电
33+
- 5.1.0 可以提前显示加载进度条
3234
- 06.关于参考
3335
- 07.其他说明介绍
3436

@@ -121,6 +123,31 @@
121123
android:layout_height="match_parent"
122124
android:scrollbarSize="3dp" />
123125
```
126+
- **如何使用自己的WebViewClient和WebChromeClient**
127+
```
128+
//主要是在X5WebViewClient和X5WebChromeClient已经做了很多常见的逻辑处理,如果不满足你使用,可以如下这样写
129+
MyX5WebViewClient webViewClient = new MyX5WebViewClient(webView, this);
130+
webView.setWebViewClient(webViewClient);
131+
MyX5WebChromeClient webChromeClient = new MyX5WebChromeClient(this);
132+
webView.setWebChromeClient(webChromeClient);
133+
134+
private class MyX5WebViewClient extends X5WebViewClient {
135+
public MyX5WebViewClient(BridgeWebView webView, Context context) {
136+
super(webView, context);
137+
}
138+
139+
//重写你需要的方法即可
140+
}
141+
142+
private class MyX5WebChromeClient extends X5WebChromeClient{
143+
public MyX5WebChromeClient(Activity activity) {
144+
super(activity);
145+
}
146+
147+
//重写你需要的方法即可
148+
}
149+
```
150+
124151
125152
#### 2.3 常用api
126153
- **关于web的接口回调,包括常见状态页面切换,进度条变化等监听处理**
@@ -168,6 +195,10 @@
168195
}
169196
});
170197
```
198+
- **其他api说明**
199+
```
200+
201+
```
171202
172203
#### 2.4 使用建议
173204
- **优化一下相关的操作**
@@ -391,6 +422,12 @@
391422
```
392423
393424
425+
#### 4.1.9 掘金问题反馈记录
426+
- 使用JsBridge遇到的坑
427+
- 由于JsBridge采用 json字符串,客户端传给前端数据中/进行了转义,导致前端收到数据后解析不出来。二,当前端给Native端发消息时,如果发送的消息频率过快,导致队列清空 shouldurl不回调,最终callback不回调,客户端也就收不到消息了。
428+
429+
430+
394431
### 05.webView优化
395432
#### 5.0.1 视频全屏播放按返回页面被放大(部分手机出现)
396433
- 至于原因暂时没有找到,解决方案如下所示
@@ -623,6 +660,9 @@
623660
```
624661
625662
663+
#### 5.1.0 可以提前显示加载进度条
664+
- 提前显示进度条不是提升性能 , 但是对用户体验来说也是很重要的一点 , WebView.loadUrl("url") 不会立马就回调 onPageStarted 或者 onProgressChanged 因为在这一时间段 , WebView 有可能在初始化内核 , 也有可能在与服务器建立连接 , 这个时间段容易出现白屏
665+
626666
627667
### 06.关于参考
628668
- 感谢开源库

WebViewLib/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ group = "cn.yc"
4646
//发布到JCenter上的项目名字,必须填写
4747
def libName = "WebViewLib"
4848
// 版本号,下次更新是只需要更改版本号即可
49-
version = "1.1.2"
49+
version = "1.1.3"
5050

5151
//生成源文件
5252
task sourcesJar(type: Jar) {

WebViewLib/src/main/java/com/ycbjie/webviewlib/BridgeUtil.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,8 @@ public static String assetFile2Str(Context c, String urlStr){
144144
sb.append(line);
145145
}
146146
} while (line != null);
147-
148147
bufferedReader.close();
149148
in.close();
150-
151149
return sb.toString();
152150
} catch (Exception e) {
153151
e.printStackTrace();

WebViewLib/src/main/java/com/ycbjie/webviewlib/BridgeWebView.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package com.ycbjie.webviewlib;
1717

1818
import android.annotation.SuppressLint;
19+
import android.app.Activity;
1920
import android.content.Context;
2021
import android.os.Build;
2122
import android.os.Looper;
@@ -46,14 +47,24 @@ public class BridgeWebView extends WebView implements WebViewJavascriptBridge{
4647

4748
public static final String TO_LOAD_JS = "WebViewJavascriptBridge.js";
4849
private long uniqueId = 0;
49-
Map<String, CallBackFunction> responseCallbacks = new HashMap<>();
50-
Map<String, BridgeHandler> messageHandlers = new HashMap<>();
50+
private Map<String, CallBackFunction> responseCallbacks = new HashMap<>();
51+
private Map<String, BridgeHandler> messageHandlers = new HashMap<>();
5152
BridgeHandler defaultHandler = new DefaultHandler();
5253
private List<Message> startupMessage = new ArrayList<>();
54+
private X5WebViewClient x5WebViewClient;
55+
private X5WebChromeClient x5WebChromeClient;
56+
57+
/**
58+
* 获取消息list集合
59+
* @return 集合
60+
*/
5361
public List<Message> getStartupMessage() {
5462
return startupMessage;
5563
}
5664

65+
/**
66+
* 设置消息,注意目前在onProgressChanged方法中调用
67+
*/
5768
public void setStartupMessage(List<Message> startupMessage) {
5869
this.startupMessage = startupMessage;
5970
}
@@ -89,13 +100,20 @@ private void init() {
89100
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
90101
WebView.setWebContentsDebuggingEnabled(true);
91102
}
92-
this.setWebViewClient(generateBridgeWebViewClient());
103+
x5WebViewClient = new X5WebViewClient(this,getContext());
104+
this.setWebViewClient(x5WebViewClient);
105+
x5WebChromeClient = new X5WebChromeClient(this, (Activity) getContext());
106+
this.setWebChromeClient(x5WebChromeClient);
93107
}
94108

95109
protected X5WebViewClient generateBridgeWebViewClient() {
96-
return new X5WebViewClient(this,getContext());
110+
return x5WebViewClient;
97111
}
98112

113+
protected X5WebChromeClient generateBridgeWebChromeClient() {
114+
return x5WebChromeClient;
115+
}
116+
99117
/**
100118
* 获取到CallBackFunction data执行调用并且从数据集移除
101119
* @param url url链接

WebViewLib/src/main/java/com/ycbjie/webviewlib/ImageJavascriptInterface.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* blog : https://github.com/yangchong211
2727
* time : 2019/9/10
2828
* desc : WebView与android交互的接口设置实现类
29-
* revise:
29+
* revise: js通信接口
3030
* </pre>
3131
*/
3232
public class ImageJavascriptInterface {

0 commit comments

Comments
 (0)