Skip to content

Commit 522071a

Browse files
committed
fix(core.manager): 判断zip插件包是否已解压时不再依赖tag文件
单独提取zip中的config.json后先生成PluginConfig。 PluginConfig添加的isUnpacked方法根据各目标文件是否均已存在来判断是否已解压。 如果文件缺失,则会重新解压文件。 fix #691
1 parent 445f4d9 commit 522071a

File tree

12 files changed

+248
-93
lines changed

12 files changed

+248
-93
lines changed

projects/sdk/core/manager-db-test/src/androidTest/java/com/tencent/shadow/core/manager/installplugin/DbCompatibilityTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.apache.commons.io.FileUtils;
3131
import org.apache.commons.io.IOUtils;
3232
import org.json.JSONException;
33+
import org.json.JSONObject;
3334
import org.junit.Assert;
3435
import org.junit.Assume;
3536
import org.junit.Before;
@@ -141,7 +142,7 @@ private void initDbWithConfigJson(int... configJsonResId)
141142
InstalledDao installedDao = new InstalledDao(dbHelper);
142143

143144
for (String configJson : configs) {
144-
installedDao.insert(PluginConfig.parseFromJson(configJson, context.getCacheDir()), null, null);
145+
installedDao.insert(PluginConfig.parseFromJson(new JSONObject(configJson), context.getCacheDir()), null, null);
145146
}
146147

147148
dbHelper.close();

projects/sdk/core/manager/src/main/java/com/tencent/shadow/core/manager/BasePluginManager.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.tencent.shadow.core.manager.installplugin.UnpackManager;
4040

4141
import org.json.JSONException;
42+
import org.json.JSONObject;
4243

4344
import java.io.File;
4445
import java.io.IOException;
@@ -104,7 +105,21 @@ public final PluginConfig installPluginFromDir(File dir) {
104105
* @return PluginConfig
105106
*/
106107
public final PluginConfig installPluginFromZip(File zip, String hash) throws IOException, JSONException {
107-
return mUnpackManager.unpackPlugin(hash, zip);
108+
String zipHash;
109+
if (hash != null) {
110+
zipHash = hash;
111+
} else {
112+
zipHash = mUnpackManager.zipHash(zip);
113+
}
114+
File pluginUnpackDir = mUnpackManager.getPluginUnpackDir(zipHash, zip);
115+
JSONObject configJson = mUnpackManager.getConfigJson(zip);
116+
PluginConfig pluginConfig = PluginConfig.parseFromJson(configJson, pluginUnpackDir);
117+
118+
if (!pluginConfig.isUnpacked()) {
119+
mUnpackManager.unpackPlugin(zip, pluginUnpackDir);
120+
}
121+
122+
return pluginConfig;
108123
}
109124

110125
/**

projects/sdk/core/manager/src/main/java/com/tencent/shadow/core/manager/installplugin/PluginConfig.java

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ public class PluginConfig {
6161
*/
6262
public File storageDir;
6363

64+
public boolean isUnpacked() {
65+
boolean pluginLoaderUnpacked = true;
66+
if (pluginLoader != null) {
67+
pluginLoaderUnpacked = pluginLoader.file.exists();
68+
}
69+
70+
boolean runtimeUnpacked = true;
71+
if (runTime != null) {
72+
runtimeUnpacked = runTime.file.exists();
73+
}
74+
75+
boolean pluginsUnpacked = true;
76+
for (PluginFileInfo pluginFileInfo : plugins.values()) {
77+
pluginsUnpacked = pluginsUnpacked && pluginFileInfo.file.exists();
78+
}
79+
return pluginLoaderUnpacked && runtimeUnpacked && pluginsUnpacked;
80+
}
81+
6482
public static class FileInfo {
6583
public final File file;
6684
public final String hash;
@@ -88,33 +106,31 @@ public static class PluginFileInfo extends FileInfo {
88106
}
89107
}
90108

91-
92-
public static PluginConfig parseFromJson(String json, File storageDir) throws JSONException {
93-
JSONObject jsonObject = new JSONObject(json);
109+
public static PluginConfig parseFromJson(JSONObject configJson, File storageDir) throws JSONException {
94110
PluginConfig pluginConfig = new PluginConfig();
95-
pluginConfig.version = jsonObject.getInt("version");
96-
JSONArray compact_version_json = jsonObject.optJSONArray("compact_version");
111+
pluginConfig.version = configJson.getInt("version");
112+
JSONArray compact_version_json = configJson.optJSONArray("compact_version");
97113
if (compact_version_json != null && compact_version_json.length() > 0) {
98114
pluginConfig.compact_version = new int[compact_version_json.length()];
99115
for (int i = 0; i < compact_version_json.length(); i++) {
100116
pluginConfig.compact_version[i] = compact_version_json.getInt(i);
101117
}
102118
}
103119
//todo #27 json的版本检查和不兼容检查
104-
pluginConfig.UUID = jsonObject.getString("UUID");
105-
pluginConfig.UUID_NickName = jsonObject.getString("UUID_NickName");
120+
pluginConfig.UUID = configJson.getString("UUID");
121+
pluginConfig.UUID_NickName = configJson.getString("UUID_NickName");
106122

107-
JSONObject loaderJson = jsonObject.optJSONObject("pluginLoader");
123+
JSONObject loaderJson = configJson.optJSONObject("pluginLoader");
108124
if (loaderJson != null) {
109125
pluginConfig.pluginLoader = getFileInfo(loaderJson, storageDir);
110126
}
111127

112-
JSONObject runtimeJson = jsonObject.optJSONObject("runtime");
128+
JSONObject runtimeJson = configJson.optJSONObject("runtime");
113129
if (runtimeJson != null) {
114130
pluginConfig.runTime = getFileInfo(runtimeJson, storageDir);
115131
}
116132

117-
JSONArray pluginArray = jsonObject.optJSONArray("plugins");
133+
JSONArray pluginArray = configJson.optJSONArray("plugins");
118134
if (pluginArray != null && pluginArray.length() > 0) {
119135
for (int i = 0; i < pluginArray.length(); i++) {
120136
JSONObject plugin = pluginArray.getJSONObject(i);

projects/sdk/core/manager/src/main/java/com/tencent/shadow/core/manager/installplugin/UnpackManager.java

Lines changed: 35 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,28 @@
1818

1919
package com.tencent.shadow.core.manager.installplugin;
2020

21+
import static com.tencent.shadow.core.utils.Md5.md5File;
22+
2123
import com.tencent.shadow.core.common.Logger;
2224
import com.tencent.shadow.core.common.LoggerFactory;
2325

2426
import org.json.JSONException;
27+
import org.json.JSONObject;
2528

2629
import java.io.BufferedReader;
2730
import java.io.File;
28-
import java.io.FileInputStream;
2931
import java.io.IOException;
32+
import java.io.InputStream;
3033
import java.io.InputStreamReader;
3134
import java.util.Enumeration;
3235
import java.util.zip.ZipEntry;
3336
import java.util.zip.ZipFile;
3437

35-
import static com.tencent.shadow.core.utils.Md5.md5File;
36-
3738

3839
public class UnpackManager {
3940

4041
private static final Logger mLogger = LoggerFactory.getLogger(UnpackManager.class);
4142

42-
private static final String UNPACK_DONE_PRE_FIX = "unpacked.";
4343
private static final String CONFIG_FILENAME = "config.json";//todo #28 json的格式需要沉淀文档。
4444
private static final String DEFAULT_STORE_DIR_NAME = "ShadowPluginManager";
4545

@@ -69,56 +69,48 @@ public File getAppDir() {
6969
* @param target Target
7070
* @return 插件解包的目标目录
7171
*/
72-
File getPluginUnpackDir(String appHash, File target) {
72+
public File getPluginUnpackDir(String appHash, File target) {
7373
return new File(getVersionDir(appHash), target.getName());
7474
}
7575

76-
/**
77-
* 判断一个插件是否已经解包了
78-
*
79-
* @param target Target
80-
* @return <code>true</code>表示已经解包了,即无需下载。
81-
*/
82-
boolean isPluginUnpacked(String versionHash, File target) {
83-
File pluginUnpackDir = getPluginUnpackDir(versionHash, target);
84-
return isDirUnpacked(pluginUnpackDir);
76+
public String zipHash(File zip) {
77+
return md5File(zip);
8578
}
8679

87-
/**
88-
* 判断一个插件解包目录是否解包了
89-
*
90-
* @param pluginUnpackDir 插件解包目录
91-
* @return <code>true</code>表示已经解包了,即无需下载。
92-
*/
93-
boolean isDirUnpacked(File pluginUnpackDir) {
94-
File tag = getUnpackedTag(pluginUnpackDir);
95-
return tag.exists();
96-
}
80+
public JSONObject getConfigJson(File zip) {
81+
ZipFile zipFile = null;
82+
try {
83+
zipFile = new SafeZipFile(zip);
84+
ZipEntry entry = zipFile.getEntry(CONFIG_FILENAME);
85+
InputStream inputStream = zipFile.getInputStream(entry);
86+
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
87+
StringBuilder sb = new StringBuilder();
88+
for (String line; (line = br.readLine()) != null; ) {
89+
sb.append(line);
90+
}
9791

92+
return new JSONObject(sb.toString());
93+
} catch (JSONException | IOException e) {
94+
throw new RuntimeException(e);
95+
} finally {
96+
try {
97+
if (zipFile != null) {
98+
zipFile.close();
99+
}
100+
} catch (IOException e) {
101+
mLogger.warn("zip关闭时出错忽略", e);
102+
}
103+
}
104+
}
98105

99106
/**
100107
* 解包一个下载好的插件
101-
* @param zipHash 插件包的hash
102-
* @param target 插件包
108+
*
109+
* @param target 插件包
110+
* @param pluginUnpackDir 解压目录
103111
*/
104-
public PluginConfig unpackPlugin(String zipHash, File target) throws IOException, JSONException {
105-
if (zipHash == null) {
106-
zipHash = md5File(target);
107-
}
108-
File pluginUnpackDir = getPluginUnpackDir(zipHash, target);
109-
112+
public void unpackPlugin(File target, File pluginUnpackDir) throws IOException {
110113
pluginUnpackDir.mkdirs();
111-
File tag = getUnpackedTag(pluginUnpackDir);
112-
113-
if (isDirUnpacked(pluginUnpackDir)) {
114-
try {
115-
return getDownloadedPluginInfoFromPluginUnpackedDir(pluginUnpackDir, zipHash);
116-
} catch (Exception e) {
117-
if (!tag.delete()) {
118-
throw new IOException("解析版本信息失败,且无法删除标记:" + tag.getAbsolutePath());
119-
}
120-
}
121-
}
122114
MinFileUtils.cleanDirectory(pluginUnpackDir);
123115

124116
ZipFile zipFile = null;
@@ -131,13 +123,6 @@ public PluginConfig unpackPlugin(String zipHash, File target) throws IOException
131123
MinFileUtils.writeOutZipEntry(zipFile, entry, pluginUnpackDir, entry.getName());
132124
}
133125
}
134-
135-
PluginConfig pluginConfig = getDownloadedPluginInfoFromPluginUnpackedDir(pluginUnpackDir, zipHash);
136-
137-
// 外边创建完成标记
138-
tag.createNewFile();
139-
140-
return pluginConfig;
141126
} finally {
142127
try {
143128
if (zipFile != null) {
@@ -149,26 +134,4 @@ public PluginConfig unpackPlugin(String zipHash, File target) throws IOException
149134
}
150135
}
151136

152-
File getUnpackedTag(File pluginUnpackDir) {
153-
return new File(pluginUnpackDir.getParentFile(), UNPACK_DONE_PRE_FIX + pluginUnpackDir.getName());
154-
}
155-
156-
PluginConfig getDownloadedPluginInfoFromPluginUnpackedDir(File pluginUnpackDir, String appHash)
157-
throws IOException, JSONException {
158-
File config = new File(pluginUnpackDir, CONFIG_FILENAME);
159-
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(config)));
160-
StringBuilder stringBuilder = new StringBuilder("");
161-
String lineStr;
162-
try {
163-
while ((lineStr = br.readLine()) != null) {
164-
stringBuilder.append(lineStr).append("\n");
165-
}
166-
} finally {
167-
//noinspection ThrowFromFinallyBlock
168-
br.close();
169-
}
170-
String versionJson = stringBuilder.toString();
171-
return PluginConfig.parseFromJson(versionJson, pluginUnpackDir);
172-
}
173-
174137
}

projects/test/dynamic/host/test-dynamic-host/src/androidTest/java/com/tencent/shadow/test/PluginTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,15 @@ private void launchJumpActivity(String partKey, Intent pluginIntent) {
9292
intent.putExtra(Constant.KEY_PLUGIN_PART_KEY, partKey);
9393
intent.putExtra(Constant.KEY_ACTIVITY_CLASSNAME, pluginIntent.getComponent().getClassName());
9494
intent.putExtra(Constant.KEY_EXTRAS, pluginIntent.getExtras());
95+
intent.putExtra(Constant.KEY_FROM_ID, getFromId());
9596
ActivityScenario.launch(intent);
9697
}
9798

9899
protected Class<? extends Activity> getJumpActivityClass() {
99100
return JumpToPluginActivity.class;
100101
}
102+
103+
protected int getFromId() {
104+
return Constant.FROM_ID_START_ACTIVITY;
105+
}
101106
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Tencent is pleased to support the open source community by making Tencent Shadow available.
3+
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
4+
*
5+
* Licensed under the BSD 3-Clause License (the "License"); you may not use
6+
* this file except in compliance with the License. You may obtain a copy of
7+
* the License at
8+
*
9+
* https://opensource.org/licenses/BSD-3-Clause
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package com.tencent.shadow.test.cases.plugin_main;
20+
21+
import androidx.test.ext.junit.runners.AndroidJUnit4;
22+
import androidx.test.filters.LargeTest;
23+
24+
import com.tencent.shadow.test.lib.constant.Constant;
25+
26+
import org.junit.runner.RunWith;
27+
28+
29+
@RunWith(AndroidJUnit4.class)
30+
@LargeTest
31+
public class ReinstallPluginTest extends BasicTest {
32+
33+
@Override
34+
protected int getFromId() {
35+
return Constant.FROM_ID_REINSTALL_PLUGIN;
36+
}
37+
}

projects/test/dynamic/host/test-dynamic-host/src/androidTest/java/com/tencent/shadow/test/cases/plugin_service/PluginServiceAppTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,9 @@ protected String getPartKey() {
3838
protected Class<? extends Activity> getJumpActivityClass() {
3939
return BindPluginServiceActivity.class;
4040
}
41+
42+
@Override
43+
protected int getFromId() {
44+
return Constant.FROM_ID_BIND_SERVICE;
45+
}
4146
}

projects/test/dynamic/host/test-dynamic-host/src/main/java/com/tencent/shadow/test/dynamic/host/BindPluginServiceActivity.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package com.tencent.shadow.test.dynamic.host;
2020

2121
import android.app.Activity;
22+
import android.content.Intent;
2223
import android.os.Bundle;
2324
import android.view.View;
2425

@@ -40,15 +41,18 @@ public void jump(View view) {
4041
HostApplication.getApp().loadPluginManager(PluginHelper.getInstance().pluginManagerFile);
4142

4243
Bundle bundle = new Bundle();
44+
Intent intent = getIntent();
4345
bundle.putString(Constant.KEY_PLUGIN_ZIP_PATH, PluginHelper.getInstance().pluginZipFile.getAbsolutePath());
44-
bundle.putString(Constant.KEY_PLUGIN_PART_KEY, getIntent().getStringExtra(Constant.KEY_PLUGIN_PART_KEY));
45-
bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME, getIntent().getStringExtra(Constant.KEY_ACTIVITY_CLASSNAME));
46-
bundle.putBundle(Constant.KEY_EXTRAS, getIntent().getBundleExtra(Constant.KEY_EXTRAS));
46+
bundle.putString(Constant.KEY_PLUGIN_PART_KEY, intent.getStringExtra(Constant.KEY_PLUGIN_PART_KEY));
47+
bundle.putString(Constant.KEY_ACTIVITY_CLASSNAME, intent.getStringExtra(Constant.KEY_ACTIVITY_CLASSNAME));
48+
bundle.putBundle(Constant.KEY_EXTRAS, intent.getBundleExtra(Constant.KEY_EXTRAS));
49+
50+
int fromId = intent.getIntExtra(Constant.KEY_FROM_ID, Constant.FROM_ID_NOOP);
4751

4852
final SimpleIdlingResource idlingResource = HostApplication.getApp().mIdlingResource;
4953
idlingResource.setIdleState(false);
5054
HostApplication.getApp().getPluginManager()
51-
.enter(this, Constant.FROM_ID_BIND_SERVICE, bundle, new EnterCallback() {
55+
.enter(this, fromId, bundle, new EnterCallback() {
5256
@Override
5357
public void onShowLoadingView(View view) {
5458

0 commit comments

Comments
 (0)