Supports plugin installation with the same version

This commit is contained in:
liuzhiwei-ms 2017-07-13 17:53:20 +08:00
parent e06f331b8a
commit f2d71d5c68
3 changed files with 147 additions and 10 deletions

View File

@ -72,6 +72,12 @@ public class Constant {
*/
public static final String LOCAL_PLUGIN_APK_LIB_DIR = "p_n";
/**
* "纯APK"插件同版本升级时插件OdexNativeSO库的用于覆盖的存放目录
* Added by Zhiwei Liu
*/
public static final String LOCAL_PLUGIN_APK_COVER_DIR = "p_c";
/**
* 插件文件名name-low-high-current.jar
* 插件文件名规范barcode-1-10-2.jar

View File

@ -108,6 +108,10 @@ public class PluginInfo implements Parcelable, Cloneable {
// 若插件需要卸载则会有此值
private PluginInfo mPendingDelete;
// 若插件需要同版本覆盖安装更新则会有此值
private PluginInfo mPendingCover;
private boolean mIsPendingCover;
private PluginInfo(JSONObject jo) {
initPluginInfo(jo);
}
@ -155,6 +159,10 @@ public class PluginInfo implements Parcelable, Cloneable {
if (pi.mPendingDelete != null) {
this.mPendingDelete = new PluginInfo(pi.mPendingDelete);
}
this.mIsPendingCover = pi.mIsPendingCover;
if (pi.mPendingCover != null) {
this.mPendingCover = new PluginInfo(pi.mPendingCover);
}
}
private void initPluginInfo(JSONObject jo) {
@ -171,6 +179,15 @@ public class PluginInfo implements Parcelable, Cloneable {
if (djo != null) {
mPendingDelete = new PluginInfo(djo);
}
// 缓存"待覆盖安装"的插件信息
JSONObject cjo = jo.optJSONObject("coverinfo");
if (cjo != null) {
mPendingCover = new PluginInfo(cjo);
}
// 缓存"待覆盖安装"的插件覆盖字段
mIsPendingCover = jo.optBoolean("cover");
}
// 通过别名和包名来最终确认插件名
@ -347,6 +364,7 @@ public class PluginInfo implements Parcelable, Cloneable {
/**
* 获取APK存放的文件信息 <p>
* 若为"纯APK"插件则会位于app_p_a中若为"p-n"插件则会位于"app_plugins_v3" <p>
* 注意若支持同版本覆盖安装的话则会位于app_p_c中 <p>
*
* @return Apk所在的File对象
*/
@ -356,6 +374,8 @@ public class PluginInfo implements Parcelable, Cloneable {
File dir;
if (isPnPlugin()) {
dir = context.getDir(Constant.LOCAL_PLUGIN_SUB_DIR, 0);
} else if (getIsPendingCover()) {
dir = context.getDir(Constant.LOCAL_PLUGIN_APK_COVER_DIR, 0);
} else {
dir = context.getDir(Constant.LOCAL_PLUGIN_APK_SUB_DIR, 0);
}
@ -365,6 +385,7 @@ public class PluginInfo implements Parcelable, Cloneable {
/**
* 获取Dex优化后生成时所在的目录 <p>
* 若为"纯APK"插件则会位于app_p_od中若为"p-n"插件则会位于"app_plugins_v3_odex" <p>
* 若支持同版本覆盖安装的话则会位于app_p_c中 <p>
* 注意仅供框架内部使用
*
* @return 优化后Dex所在目录的File对象
@ -374,6 +395,8 @@ public class PluginInfo implements Parcelable, Cloneable {
Context context = RePluginInternal.getAppContext();
if (isPnPlugin()) {
return context.getDir(Constant.LOCAL_PLUGIN_ODEX_SUB_DIR, 0);
} else if (getIsPendingCover()) {
return context.getDir(Constant.LOCAL_PLUGIN_APK_COVER_DIR, 0);
} else {
return context.getDir(Constant.LOCAL_PLUGIN_APK_ODEX_SUB_DIR, 0);
}
@ -394,6 +417,7 @@ public class PluginInfo implements Parcelable, Cloneable {
/**
* 根据类型来获取SO释放的路径 <p>
* 若为"纯APK"插件则会位于app_p_n中若为"p-n"插件则会位于"app_plugins_v3_libs" <p>
* 若支持同版本覆盖安装的话则会位于app_p_c中 <p>
* 注意仅供框架内部使用
*
* @return SO释放路径所在的File对象
@ -404,6 +428,8 @@ public class PluginInfo implements Parcelable, Cloneable {
File dir;
if (isPnPlugin()) {
dir = context.getDir(Constant.LOCAL_PLUGIN_DATA_LIB_DIR, 0);
} else if (getIsPendingCover()) {
dir = context.getDir(Constant.LOCAL_PLUGIN_APK_COVER_DIR, 0);
} else {
dir = context.getDir(Constant.LOCAL_PLUGIN_APK_LIB_DIR, 0);
}
@ -491,6 +517,62 @@ public class PluginInfo implements Parcelable, Cloneable {
}
}
/**
* 是否已准备好了新待覆盖的版本
*
* @return 是否已准备好
*/
public boolean isNeedCover() {
return mPendingCover != null;
}
/**
* 获取将来要覆盖更新的插件的信息将会在下次启动时才能被使用
*
* @return 插件覆盖安装信息
*/
public PluginInfo getPendingCover() {
return mPendingCover;
}
/**
* 设置插件的覆盖更新信息此信息有可能等到下次才能被使用 <p>
* 注意若为纯APK方案所用则修改后需调用PluginInfoList.save来保存否则会无效
*
* @param info 插件覆盖安装信息
*/
public void setPendingCover(PluginInfo info) {
mPendingCover = info;
if (info != null) {
JSONHelper.putNoThrows(mJson, "coverinfo", info.getJSON());
} else {
mJson.remove("coverinfo");
}
}
/**
* 此PluginInfo是否包含同版本覆盖的字段只在调用RePlugin.install方法才能看到 <p>
* 注意仅框架内部使用
*
* @return 是否包含同版本覆盖字段
*/
public boolean getIsPendingCover() {
return mIsPendingCover;
}
/**
* 设置PluginInfo的同版本覆盖的字段 <p>
* 注意仅框架内部使用
*/
public void setIsPendingCover(boolean coverInfo) {
mIsPendingCover = coverInfo;
if (mIsPendingCover) {
JSONHelper.putNoThrows(mJson, "cover", mIsPendingCover);
} else {
mJson.remove("cover");
}
}
/**
* 获取最小支持宿主API的版本
*/

View File

@ -201,7 +201,19 @@ public class PluginManagerServer {
}
private boolean checkVersion(PluginInfo instPli, PluginInfo curPli) {
if (instPli.getVersion() <= curPli.getVersion()) {
// 支持插件同版本覆盖安装
// 若现在要安装的与之前的版本相同则覆盖掉之前的版本
if (instPli.getVersion() == curPli.getVersion()) {
if (LogDebug.LOG) {
LogDebug.d(TAG, "isSameVersion: same version. " +
"inst_ver=" + instPli.getVersion() + "; cur_ver=" + curPli.getVersion());
}
instPli.setIsPendingCover(true);
return true;
}
// 若现在要安装的比之前的版本还要旧则忽略更新
if (instPli.getVersion() < curPli.getVersion()) {
if (LogDebug.LOG) {
LogDebug.e(TAG, "checkVersion: Older than current, install fail. pn=" + curPli.getName() +
"; inst_ver=" + instPli.getVersion() + "; cur_ver=" + curPli.getVersion());
@ -210,9 +222,9 @@ public class PluginManagerServer {
}
// 已有待更新版本
// 若现在要安装的待更新版本还要旧或相同则也可以忽略
// 若现在要安装的待更新版本还要旧则也可以忽略
PluginInfo curUpdatePli = curPli.getPendingUpdate();
if (curUpdatePli != null && instPli.getVersion() <= curUpdatePli.getVersion()) {
if (curUpdatePli != null && instPli.getVersion() < curUpdatePli.getVersion()) {
if (LogDebug.LOG) {
LogDebug.e(TAG, "checkVersion: Older than updating plugin. Ignore. pn=" + curPli.getName() + "; " +
"cur_ver=" + curPli.getVersion() + "; old_ver=" + curUpdatePli.getVersion() + "; new_ver=" + instPli.getVersion());
@ -273,8 +285,14 @@ public class PluginManagerServer {
if (LogDebug.LOG) {
LogDebug.w(TAG, "updateOrLater: Plugin is running. Later. pn=" + curPli.getName());
}
instPli.setIsThisPendingUpdateInfo(true);
curPli.setPendingUpdate(instPli);
if (instPli.getVersion() > curPli.getVersion()) {
// 高版本升级
instPli.setIsThisPendingUpdateInfo(true);
curPli.setPendingUpdate(instPli);
} else if (instPli.getVersion() == curPli.getVersion()){
// 同版本覆盖
curPli.setPendingCover(instPli);
}
} else {
if (LogDebug.LOG) {
LogDebug.i(TAG, "updateOrLater: Not running. Update now! pn=" + curPli.getName());
@ -348,7 +366,9 @@ public class PluginManagerServer {
// 需要更新插件那就直接来
updateNow(curInfo, curInfo.getPendingUpdate());
return true;
} else if (curInfo.isNeedCover()) {
updateNow(curInfo, curInfo.getPendingCover());
return true;
} else {
// 既不需要删除也不需要更新
if (LogDebug.LOG) {
@ -359,8 +379,13 @@ public class PluginManagerServer {
}
private void updateNow(PluginInfo curInfo, PluginInfo newInfo) {
// 删除旧版本插件不管是不是p-n的且清掉Dex和Native目录
delete(curInfo);
final boolean covered = newInfo.getIsPendingCover();
if (covered) {
move(curInfo, newInfo);
} else {
// 删除旧版本插件不管是不是p-n的且清掉Dex和Native目录
delete(curInfo);
}
newInfo.setType(PluginInfo.TYPE_EXTRACTED);
if (LogDebug.LOG) {
@ -368,8 +393,32 @@ public class PluginManagerServer {
"; cur_ver=" + curInfo.getVersion() + "; update_ver=" + newInfo.getVersion());
}
curInfo.update(newInfo);
curInfo.setPendingUpdate(null);
if (covered) {
curInfo.setPendingCover(null);
} else {
curInfo.update(newInfo);
curInfo.setPendingUpdate(null);
}
}
private void move(@NonNull PluginInfo curPi, @NonNull PluginInfo newPi) {
try {
FileUtils.copyFile(newPi.getApkFile(), curPi.getApkFile());
FileUtils.copyFile(newPi.getDexFile(), curPi.getDexFile());
FileUtils.copyFile(newPi.getNativeLibsDir(), curPi.getNativeLibsDir());
} catch (IOException e) {
if (LogRelease.LOGR) {
e.printStackTrace();
}
} finally {
try {
FileUtils.forceDelete(newPi.getApkFile().getParentFile());
} catch (IOException e) {
if (LogRelease.LOGR) {
e.printStackTrace();
}
}
}
}
private void delete(@NonNull PluginInfo pi) {