Android热更新方案之阿里AndFix-原理以及源码解析

mLoaders = new ConcurrentHashMap();
}

new了个AndFixmanager,看一下

public AndFixManager(Context context) {
mContext = context;
mSupport = Compat.*isSupport*();
if (mSupport) {
mSecurityChecker = new SecurityChecker(mContext);
mOptDir = new File(mContext.getFilesDir(), *DIR*);
if (!mOptDir.exists() && !mOptDir.mkdirs()) {// make directory fail
mSupport = false;
Log.*e*(*TAG*, "opt dir create error.");
} else if (!mOptDir.isDirectory()) {// not directory
mOptDir.delete();
mSupport = false;
}
}
}

在这个类里面主要是检测设备是否是支持的AndFix的设备,YunOS不支持。

在SecurityChecker里面获取数字证书和检测应用是否debugable

另外是初始化patch路径

PachManager.init()里面获取AndFix的版本信息,如果信息一致

public void init(String appVersion) {
if (!mPatchDir.exists() && !mPatchDir.mkdirs()) {// make directory fail
Log.*e*(*TAG*, "patch dir create error.");
return;
} else if (!mPatchDir.isDirectory()) {// not directory
mPatchDir.delete();
return;
}
SharedPreferences sp = mContext.getSharedPreferences(*SP_NAME*,
Context.*MODE_PRIVATE*);
String ver = sp.getString(*SP_VERSION*, null);
if (ver == null || !ver.equalsIgnoreCase(appVersion)) {
cleanPatch();
sp.edit().putString(*SP_VERSION*, appVersion).commit();
} else {
initPatchs();
}
}

则initPatchs

private void initPatchs() {
File[] files = mPatchDir.listFiles();
for (File file : files) {
addPatch(file);
}
}

把路径下的patch加到mPatch列表里面。

patchManager.loadPatch();
public void loadPatch() {
mLoaders.put("*", mContext.getClassLoader());// wildcard
Set patchNames;
List classes;
for (Patch patch : mPatchs) {
patchNames = patch.getPatchNames();
for (String patchName : patchNames) {
classes = patch.getClasses(patchName);
mAndFixManager.fix(patch.getFile(), mContext.getClassLoader(),
classes);
}
}
}

最终调用fix方法

mAndFixManager.fix(patch.getFile(), mContext.getClassLoader(),
classes);

fix方法首先签名验证,一般是文件的MD5,通过之后获取dex文件,

然后实现自己的加载器(只需要继承ClassLoader,并覆盖findClass方法)。

ClassLoader patchClassLoader = new ClassLoader(classLoader) {
@Override
protected Class findClass(String className)
throws ClassNotFoundException {
Class clazz = dexFile.loadClass(className, this);
if (clazz == null
&& className.startsWith("com.alipay.euler.andfix")) {
return Class.*forName*(className);// annotation’s class
// not found
}
if (clazz == null) {
throw new ClassNotFoundException(className);
}
return clazz;
}
};
Enumeration entrys = dexFile.entries();
Class clazz = null;
while (entrys.hasMoreElements()) {
String entry = entrys.nextElement();
if (classes != null && !classes.contains(entry)) {
continue;// skip, not need fix
}
clazz = dexFile.loadClass(entry, patchClassLoader);
if (clazz != null) {
fixClass(clazz, classLoader);
}
}
} catch (IOException e) {
Log.e(*TAG*, "pacth", e);
}

在类加载器里面,如果知道需要修改的方法(annotation标记的),则调用fixClass去修复bug.

private void fixClass(Class clazz, ClassLoader classLoader) {
Method[] methods = clazz.getDeclaredMethods();
MethodReplace methodReplace;
String clz;
String meth;
for (Method method : methods) {
methodReplace = method.getAnnotation(MethodReplace.class);
if (methodReplace == null)
continue;
clz = methodReplace.clazz();
meth = methodReplace.method();
if (!*isEmpty*(clz) && !*isEmpty*(meth)) {
replaceMethod(classLoader, clz, meth, method);
}
}
}

在fixClass里面调用replaceMethod方法用patch里面的方法替换掉要修改的方法。

private void replaceMethod(ClassLoader classLoader, String clz,
String meth, Method method) {
try {
String key = clz + "@" + classLoader.toString();
Class clazz = *mFixedClass*.get(key);
if (clazz == null) {// class not load
Class clzz = classLoader.loadClass(clz);
// initialize target class
clazz = AndFix.*initTargetClass*(clzz);
}
if (clazz != null) {// initialize class OK
*mFixedClass*.put(key, clazz);
Method src = clazz.getDeclaredMethod(meth,
method.getParameterTypes());
AndFix.*addReplaceMethod*(src, method);
}
} catch (Exception e) {
Log.e(*TAG*, "replaceMethod", e);
}
}

最终调用native层的方法

AndFix.*addReplaceMethod*(src, method);
public static void addReplaceMethod(Method src, Method dest) {
try {

你可能感兴趣的:(android,前端,数据库)