在上一篇文章中介绍了可以有效解决WebView多进程崩溃的办法,但隔了两个版本后这个问题竟然死灰复燃,这究竟是怎么回事呢?
《凉州词》
葡萄美酒夜光杯,欲饮琵琶马上催。
醉卧沙场君莫笑,古来征战几人回?
-王翰
问题原因
使用上一篇文章中提供的解决方案上线后取得了不错的效果,但最近这个问题又出现了,使用debug包查看webview数据目录发现系统默认添加了进程名后缀,这是由于用户更新了手机系统导致,使用华为mate20X测试调用WebView.setDataDirectorySuffix
自定义后缀已不生效,会默认强制指定后缀为进程名,另外还发现部分华为手机直接将webview目录名app_webview改为了app_hws_webview。
oppo手机OPPO PDNM00
华为mate30pro
荣耀10手机荣耀 HRY AL00A
解决方案
综上所述,我们需要针对不同手机系统遍历可能的文件路径,最新解决代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70private static void handleWebviewDir(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
return;
}
try {
Set<String> pathSet = new HashSet<>();
String suffix = "";
String dataPath = context.getDataDir().getAbsolutePath();
String webViewDir = "/app_webview";
String huaweiWebViewDir = "/app_hws_webview";
String lockFile = "/webview_data.lock";
String processName = getProcessName(context);
if (!TextUtils.equals(context.getPackageName(), processName)) {//判断不等于默认进程名称
suffix = TextUtils.isEmpty(processName) ? context.getPackageName() : processName;
WebView.setDataDirectorySuffix(suffix);
suffix = "_" + suffix;
pathSet.add(dataPath + webViewDir + suffix + lockFile);
if (RomUtils.INSTANCE.checkIsHuaweiRom()) {
pathSet.add(dataPath + huaweiWebViewDir + suffix + lockFile);
}
}else{
//主进程
suffix = "_" + processName;
pathSet.add(dataPath + webViewDir + lockFile);//默认未添加进程名后缀
pathSet.add(dataPath + webViewDir + suffix + lockFile);//系统自动添加了进程名后缀
if (RomUtils.INSTANCE.checkIsHuaweiRom()) {//部分华为手机更改了webview目录名
pathSet.add(dataPath + huaweiWebViewDir + lockFile);
pathSet.add(dataPath + huaweiWebViewDir + suffix + lockFile);
}
}
for (String path : pathSet) {
File file = new File(path);
if (file.exists()) {
tryLockOrRecreateFile(file);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@TargetApi(Build.VERSION_CODES.P)
private static void tryLockOrRecreateFile(File file) {
try {
FileLock tryLock = new RandomAccessFile(file, "rw").getChannel().tryLock();
if (tryLock != null) {
tryLock.close();
} else {
createFile(file, file.delete());
}
} catch (Exception e) {
e.printStackTrace();
boolean deleted = false;
if (file.exists()) {
deleted = file.delete();
}
createFile(file, deleted);
}
}
private static void createFile(File file, boolean deleted){
try {
if (deleted && !file.exists()) {
file.createNewFile();
}
} catch (Exception e) {
e.printStackTrace();
}
}