Skip to content

Commit c8c0a30

Browse files
committed
添加对插件依赖插件的支持
1 parent b39601e commit c8c0a30

11 files changed

+132
-48
lines changed

PluginCore/src/com/plugin/content/PluginDescriptor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ public class PluginDescriptor implements Serializable {
8484

8585
private String installedPath;
8686

87+
private String[] dependencies;
88+
8789
private transient Application pluginApplication;
8890

8991
private transient DexClassLoader pluginClassLoader;
@@ -206,6 +208,14 @@ public void setInstalledPath(String installedPath) {
206208
this.installedPath = installedPath;
207209
}
208210

211+
public String[] getDependencies() {
212+
return dependencies;
213+
}
214+
215+
public void setDependencies(String[] dependencies) {
216+
this.dependencies = dependencies;
217+
}
218+
209219
public void setDescription(String description) {
210220
this.description = description;
211221
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.plugin.core;
2+
3+
import com.plugin.content.PluginProviderInfo;
4+
import com.plugin.util.LogUtil;
5+
6+
import dalvik.system.DexClassLoader;
7+
8+
/**
9+
* 为了支持Receiver和ContentProvider,增加此类。
10+
*
11+
* @author Administrator
12+
*
13+
*/
14+
public class HostClassLoader extends DexClassLoader {
15+
16+
public HostClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
17+
super(dexPath, optimizedDirectory, libraryPath, parent);
18+
}
19+
20+
@Override
21+
public String findLibrary(String name) {
22+
LogUtil.d("findLibrary", name);
23+
return super.findLibrary(name);
24+
}
25+
26+
@Override
27+
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
28+
29+
//Just for Receiver and service
30+
if (className.startsWith(PluginIntentResolver.prefix)) {
31+
String realName = className.replace(PluginIntentResolver.prefix, "");
32+
LogUtil.d("className ", className, "target", realName);
33+
Class clazz = PluginLoader.loadPluginClassByName(realName);
34+
if (clazz != null) {
35+
return clazz;
36+
}
37+
} else if (className.startsWith(PluginProviderInfo.prefix)) {
38+
//Just for contentprovider
39+
String realName = className.replace(PluginProviderInfo.prefix, "");
40+
LogUtil.d("className ", className, "target", realName);
41+
Class clazz = PluginLoader.loadPluginClassByName(realName);
42+
if (clazz != null) {
43+
return clazz;
44+
}
45+
}
46+
return super.loadClass(className, resolve);
47+
}
48+
49+
}

PluginCore/src/com/plugin/core/PluginAppTrace.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,14 @@
22

33
import android.app.Service;
44
import android.content.Context;
5-
import android.content.ContextWrapper;
65
import android.os.Handler;
76
import android.os.IBinder;
87
import android.os.Message;
98

10-
import com.plugin.content.PluginDescriptor;
119
import com.plugin.util.ClassLoaderUtil;
1210
import com.plugin.util.LogUtil;
1311
import com.plugin.util.RefInvoker;
1412

15-
import java.util.Iterator;
1613
import java.util.Map;
1714

1815
/**
@@ -88,7 +85,7 @@ private static Result beforeCreateService(Message msg) {
8885
String serviceName = PluginIntentResolver.hackServiceName(msg.obj);
8986

9087
if (serviceName != null) {
91-
ClassLoaderUtil.hackClassLoaderIfNeeded();
88+
ClassLoaderUtil.hackHostClassLoaderIfNeeded();
9289
}
9390
Result result = new Result();
9491
result.serviceName = serviceName;
Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
package com.plugin.core;
22

3-
import java.util.concurrent.BlockingQueue;
4-
import java.util.concurrent.LinkedBlockingQueue;
5-
6-
import com.plugin.content.PluginProviderInfo;
3+
import com.plugin.content.PluginDescriptor;
74
import com.plugin.util.LogUtil;
85

96
import dalvik.system.DexClassLoader;
107

118
/**
12-
* 为了支持Receiver和ContentProvider,增加此类。
9+
* 为了支持插件间依赖,增加此类。
1310
*
1411
* @author Administrator
1512
*
1613
*/
1714
public class PluginClassLoader extends DexClassLoader {
1815

19-
public PluginClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
16+
private String[] dependencies;
17+
18+
public PluginClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent, String[] dependencies) {
2019
super(dexPath, optimizedDirectory, libraryPath, parent);
20+
this.dependencies = dependencies;
2121
}
2222

2323
@Override
@@ -27,26 +27,38 @@ public String findLibrary(String name) {
2727
}
2828

2929
@Override
30-
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
31-
32-
//Just for Receiver and service
33-
if (className.startsWith(PluginIntentResolver.prefix)) {
34-
String realName = className.replace(PluginIntentResolver.prefix, "");
35-
LogUtil.d("className ", className, "target", realName);
36-
Class clazz = PluginLoader.loadPluginClassByName(realName);
37-
if (clazz != null) {
38-
return clazz;
39-
}
40-
} else if (className.startsWith(PluginProviderInfo.prefix)) {
41-
//Just for contentprovider
42-
String realName = className.replace(PluginProviderInfo.prefix, "");
43-
LogUtil.d("className ", className, "target", realName);
44-
Class clazz = PluginLoader.loadPluginClassByName(realName);
45-
if (clazz != null) {
46-
return clazz;
30+
protected Class<?> findClass(String className) throws ClassNotFoundException {
31+
Class<?> clazz = null;
32+
ClassNotFoundException suppressed = null;
33+
try {
34+
clazz = super.findClass(className);
35+
} catch (ClassNotFoundException e) {
36+
suppressed = e;
37+
}
38+
39+
if (clazz == null && !className.startsWith("android.view")) {//这里判断android.view 是为了解决webview的问题
40+
if (dependencies != null) {
41+
for (String dependencePluginId: dependencies) {
42+
PluginDescriptor pd = PluginLoader.initPluginByPluginId(dependencePluginId);
43+
if (pd != null) {
44+
try {
45+
clazz = pd.getPluginClassLoader().loadClass(className);
46+
} catch (ClassNotFoundException e) {
47+
}
48+
if (clazz != null) {
49+
break;
50+
}
51+
} else {
52+
LogUtil.e("PluginClassLoader", "未找到插件", dependencePluginId, className);
53+
}
54+
}
4755
}
4856
}
49-
return super.loadClass(className, resolve);
50-
}
5157

58+
if (clazz == null && suppressed != null) {
59+
throw suppressed;
60+
}
61+
62+
return clazz;
63+
}
5264
}

PluginCore/src/com/plugin/core/PluginCreator.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,16 @@ private PluginCreator() {
2525
* 插件apk文件路径
2626
* @return
2727
*/
28-
public static DexClassLoader createPluginClassLoader(String absolutePluginApkPath, boolean isStandalone) {
29-
if (!isStandalone) {
30-
return new DexClassLoader(absolutePluginApkPath, new File(absolutePluginApkPath).getParent(),
28+
public static DexClassLoader createPluginClassLoader(String absolutePluginApkPath, boolean isStandalone,
29+
String[] dependences) {
30+
if (!isStandalone) {//非独立插件
31+
return new PluginClassLoader(absolutePluginApkPath, new File(absolutePluginApkPath).getParent(),
3132
new File(absolutePluginApkPath).getParent() + File.separator + "lib",
32-
PluginLoader.class.getClassLoader());
33-
} else {
34-
return new DexClassLoader(absolutePluginApkPath, new File(absolutePluginApkPath).getParent(),
33+
PluginLoader.class.getClassLoader(), dependences);//宿主classloader
34+
} else {//独立插件
35+
return new PluginClassLoader(absolutePluginApkPath, new File(absolutePluginApkPath).getParent(),
3536
new File(absolutePluginApkPath).getParent() + File.separator + "lib",
36-
PluginLoader.class.getClassLoader().getParent());
37+
PluginLoader.class.getClassLoader().getParent(), null);//系统classloader
3738
}
3839

3940
}

PluginCore/src/com/plugin/core/PluginInjector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ static void installContentProviders(Context context, Collection<PluginProviderIn
102102
LogUtil.d("安装插件ContentProvider", pluginProviderInfos.size());
103103
Object activityThread = PluginInjector.getActivityThread();
104104
if (activityThread != null) {
105-
ClassLoaderUtil.hackClassLoaderIfNeeded();
105+
ClassLoaderUtil.hackHostClassLoaderIfNeeded();
106106
List<ProviderInfo> providers = new ArrayList<ProviderInfo>();
107107
for (PluginProviderInfo pluginProviderInfo : pluginProviderInfos) {
108108
ProviderInfo p = new ProviderInfo();

PluginCore/src/com/plugin/core/PluginIntentResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class PluginIntentResolver {
2525
/* package */static void resolveService(Intent service) {
2626
String className = PluginLoader.matchPlugin(service);
2727
if (className != null) {
28-
ClassLoaderUtil.hackClassLoaderIfNeeded();
28+
ClassLoaderUtil.hackHostClassLoaderIfNeeded();
2929
String stubActivityName = PluginStubBinding.bindStubService(className);
3030
if (stubActivityName != null) {
3131
service.setClassName(PluginLoader.getApplicatoin(), stubActivityName);
@@ -38,7 +38,7 @@ public class PluginIntentResolver {
3838
// 不需要在这里记录目标className,className将在Intent中传递
3939
String className = PluginLoader.matchPlugin(intent);
4040
if (className != null) {
41-
ClassLoaderUtil.hackClassLoaderIfNeeded();
41+
ClassLoaderUtil.hackHostClassLoaderIfNeeded();
4242
intent.setComponent(new ComponentName(PluginLoader.getApplicatoin().getPackageName(),
4343
PluginStubReceiver.class.getName()));
4444
//hackReceiverForClassLoader检测到这个标记后会进行替换

PluginCore/src/com/plugin/core/PluginLoader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public static synchronized int installPlugin(String srcPluginFile) {
241241
} else {
242242
//通过创建classloader来触发dexopt,但不加载
243243
LogUtil.d("正在进行DEXOPT...", pluginDescriptor.getInstalledPath());
244-
PluginCreator.createPluginClassLoader(pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone());
244+
PluginCreator.createPluginClassLoader(pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone(), null);
245245
LogUtil.d("DEXOPT完毕");
246246

247247
changeListener.onPluginInstalled(pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
@@ -404,7 +404,7 @@ static void ensurePluginInited(PluginDescriptor pluginDescriptor) {
404404
pluginDescriptor.isStandalone());
405405

406406
pluginClassLoader = PluginCreator.createPluginClassLoader(pluginDescriptor.getInstalledPath(),
407-
pluginDescriptor.isStandalone());
407+
pluginDescriptor.isStandalone(), pluginDescriptor.getDependencies());
408408
Context pluginContext = PluginCreator
409409
.createPluginContext(pluginDescriptor, sApplication, pluginRes, pluginClassLoader);
410410

PluginCore/src/com/plugin/core/localservice/LocalServiceManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.plugin.core.localservice;
22

3+
import com.plugin.util.LogUtil;
4+
35
import java.util.HashMap;
46

57
/**
@@ -22,10 +24,12 @@ public Object createService(int serviceId) {
2224
};
2325
fetcher.mServiceId ++;
2426
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
27+
LogUtil.d("registerService", serviceName);
2528
}
2629

2730
public static Object getService(String name) {
2831
LocalServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
32+
LogUtil.d("getService", fetcher == null?"No fetcher":"fetcher found");
2933
return fetcher == null ? null : fetcher.getService();
3034
}
3135

PluginCore/src/com/plugin/util/ClassLoaderUtil.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@
33
import android.app.Application;
44

55
import com.plugin.core.PluginLoader;
6-
import com.plugin.core.PluginClassLoader;
6+
import com.plugin.core.HostClassLoader;
77

88

99
public class ClassLoaderUtil {
1010

1111
/**
1212
* 如果插件中不包含service、receiver和contentprovider,是不需要替换classloader的
1313
*/
14-
public static void hackClassLoaderIfNeeded() {
14+
public static void hackHostClassLoaderIfNeeded() {
1515
Object mLoadedApk = RefInvoker.getFieldObject(PluginLoader.getApplicatoin(), Application.class.getName(),
1616
"mLoadedApk");
1717
ClassLoader originalLoader = (ClassLoader) RefInvoker.getFieldObject(mLoadedApk, "android.app.LoadedApk",
1818
"mClassLoader");
19-
if (!(originalLoader instanceof PluginClassLoader)) {
20-
PluginClassLoader newLoader = new PluginClassLoader("", PluginLoader.getApplicatoin()
19+
if (!(originalLoader instanceof HostClassLoader)) {
20+
HostClassLoader newLoader = new HostClassLoader("", PluginLoader.getApplicatoin()
2121
.getCacheDir().getAbsolutePath(),
2222
PluginLoader.getApplicatoin().getCacheDir().getAbsolutePath(), originalLoader);
2323
RefInvoker.setFieldObject(mLoadedApk, "android.app.LoadedApk", "mClassLoader", newLoader);

PluginCore/src/com/plugin/util/ManifestParser.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@ public static PluginDescriptor parseManifest(String pluginPath) {
6262
desciptor.setVersion(versionName + "_" + versionCode);
6363

6464
desciptor.setStandalone(sharedUserId == null || !PluginLoader.getApplicatoin().getPackageName().equals(sharedUserId));
65-
65+
66+
String dependencies = parser.getAttributeValue("", "dependencies");
67+
if (dependencies != null) {
68+
String[] pluginIds = dependencies.split(",");
69+
desciptor.setDependencies(pluginIds);
70+
}
71+
6672
LogUtil.d(packageName, versionCode, versionName, sharedUserId);
6773
} else if (tag.equals("meta-data")) {
6874

@@ -110,7 +116,7 @@ public static PluginDescriptor parseManifest(String pluginPath) {
110116

111117
desciptor.setDescription(parser.getAttributeValue(namespaceAndroid, "label"));
112118

113-
LogUtil.d("applicationName" + applicationName + " Description " + desciptor.getDescription());
119+
LogUtil.d("applicationName", applicationName, " Description ", desciptor.getDescription());
114120

115121
} else if ("activity".equals(parser.getName())) {
116122

@@ -198,7 +204,12 @@ public static PluginDescriptor parseManifest(String pluginPath) {
198204
} while (eventType != XmlPullParser.END_DOCUMENT);
199205

200206
desciptor.setEnabled(true);
201-
207+
208+
//有可能没有配置application节点,这里需要检查一下application
209+
if (desciptor.getApplicationName() == null) {
210+
desciptor.setApplicationName(Application.class.getName());
211+
}
212+
202213
return desciptor;
203214
} catch (XmlPullParserException e) {
204215
e.printStackTrace();

0 commit comments

Comments
 (0)