給插件提供Serivce(二周目)
昨天講到怎么模仿PluginActivity給插件提供一個(gè)PluginService,是一個(gè)大概思路臂容,今天寫的時(shí)候有些細(xì)節(jié)記錄在這里。
獲取Service的構(gòu)造器
首先张肾,要想獲得PluginService的構(gòu)造器管宵,就需要:
- 加載一個(gè)文件路徑+包名+PluginService的類文件(木偶Service)
- 要滿足1截珍,就要先把外部的dex/apk加載到指定的優(yōu)化路徑(optimizedDirectory)里面。
PluginActivity中具體是這樣操作的:
- new一個(gè)BaseDexClassLoader()箩朴,參數(shù)是:
super(apkPath, optimizedDirectory, libraryPath, parent);
這樣一來我們就有了一個(gè)指定了optimizedDirectory的classLoader。
用這個(gè)classLoader的loadClass(className)方法加載指定的類秋度。由于這個(gè)classLoader已經(jīng)綁定了optimizedDirectory炸庞,所以className是包名+類名就可以了。
用2中得到的serviceClass這個(gè)獲得構(gòu)造器荚斯。
Constructor<?> serviceConstructor = serviceClass
.getConstructor();
問題來了埠居,在PluginService需要這樣的步驟嗎查牌?
答案是我們需要獲得剛才new出來的那個(gè)classLoader,然后去直接用它去加載插件中繼承Serviceable的那個(gè)類滥壕。
怎么獲取剛才的classLoader呢纸颜?事實(shí)上,在剛才構(gòu)造classLoader的時(shí)候绎橘,PluginClassLoader用Map保存了classLoader的弱引用:
//PluginClassLoader.java
ClassLoader pluginLoader = new PluginClassLoader(apkPath,
apkOutputDir, libPath, parent);
if (pluginLoader != null) {
loader = pluginLoader;
pluginLoaders.put(apkPath, new WeakReference<ClassLoader>(
loader));
}
這樣的話目測(cè)就可以了胁孙,但總覺得還少點(diǎn)什么。
其他
另外称鳞,對(duì)于多Service的支持涮较,我們知道Activity是可以啟動(dòng)其他Activity的,也可以啟動(dòng)本身的Activity冈止,并且是standard啟動(dòng)模式狂票,可以覆蓋(有個(gè)疑問,目前插件中不是僅用到一個(gè)Activity實(shí)例嗎熙暴。闺属。);但是Service不能復(fù)用(為什么周霉?是不是因?yàn)樵俅蝞ew 同一個(gè)Service木偶的時(shí)候屋剑,ClassLoader發(fā)現(xiàn)parent已經(jīng)加載過這個(gè)類了,所以返回了同樣的實(shí)例诗眨?)唉匾。明天看看。
-DEC 1ST
Appendix:
現(xiàn)在的PluginService.java:
public class PluginService extends Service {
/**
* 插件文件路徑匠楚,文件路徑+包名+PluginService.java信息加起來才能構(gòu)造Plugin的Service實(shí)例
*/
private String mPluginPath;
/**
* 插件包名
*/
private String mPluginPackage;
/**
* 獲取PluginActivity初始化的classLoader
*/
private ClassLoader mClassLoader;
/**
* Serviceable實(shí)例
*/
protected Serviceable mPluginService;
private void useClassLoaderToLoadService(String mPluginPath, String packageNameAndServicePath) {
//mPluginPath是外部apk路徑巍膘,optimize之前的路徑;這里是用key取map中的值的操作
mClassLoader = PluginClassLoader.getClassLoader(mPluginPath);
try {
Class<?> serviceClass;
// if (CJConfig.DEF_STR.equals(mDexPath)) {
// serviceClass = super.getClassLoader().loadClass(mClass);
// } else {
// serviceClass = this.getClassLoader().loadClass(mClass);
// }
//packageNameAndServicePath是包名+木偶類名芋簿,用來定位插件中的木偶位置
serviceClass = mClassLoader.loadClass(packageNameAndServicePath);
Constructor<?> serviceConstructor = serviceClass
.getConstructor();
mPluginService = (Serviceable) serviceConstructor.newInstance();
} catch (Exception e) {
}
// mPluginService.setProxy(this, mDexPath);
}
private void initPath() {
//獲取插件路徑峡懈。mPluginPath這個(gè)路徑是要拿去loadPlugin的(構(gòu)造BaseDexClassLoader),所以与斤,mPluginPath是指下載的apk的路徑或是assets中內(nèi)置apk的路徑
mPluginPath = PluginManager.getInstance().getPlugin();
mPluginPackage = getPluginPackageName(mPluginPath);
}
private String getPluginPackageName(String pluginPath) {
try {
PackageInfo packageInfo = getPackageManager()
.getPackageArchiveInfo(pluginPath, 0);
if (packageInfo == null) {
return null;
}
return packageInfo.packageName;
} catch (Exception e) {
return null;
}
}
@Override
public void onCreate() {
initPath();
useClassLoaderToLoadService(mPluginPath, mPluginPackage + ".RemoteService");
if (mPluginService != null) {
mPluginService.onCreate();
}
super.onCreate();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mPluginService != null) {
mPluginService.onConfigurationChanged(newConfig);
}
super.onConfigurationChanged(newConfig);
}
@Override
public void onLowMemory() {
if (mPluginService != null) {
mPluginService.onLowMemory();
}
super.onLowMemory();
}
@Override
@SuppressLint("NewApi")
public void onTrimMemory(int level) {
if (mPluginService != null) {
mPluginService.onTrimMemory(level);
}
super.onTrimMemory(level);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public boolean onUnbind(Intent intent) {
if (mPluginService != null) {
mPluginService.onUnbind(intent);
}
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
if (mPluginService != null) {
mPluginService.onRebind(intent);
}
super.onRebind(intent);
}
}