Android热更新实现原理
ÔÎijö´¦£ºhttp://blog.csdn.net/lzyzsd/article/details/49843581
×î½üAndroidÉçÇøµÄ·ÕΧºÜ²»´íÂÁ¬Ðø·Å³öһϵÁеÄAndroid¶¯Ì¬¼ÓÔزå¼þºÍÈȸüп⣬ÕâƪÎÄÕ¾ÍÀ´½éÉÜÒ»ÏÂAndroidÖÐʵÏÖÈȸüеÄÔÀí¡£
ClassLoader
ÎÒÃÇÖªµÀJavaÔÚÔËÐÐʱ¼ÓÔضÔÓ¦µÄÀàÊÇͨ¹ýClassLoaderÀ´ÊµÏֵģ¬ClassLoader±¾ÉíÊÇÒ»¸ö³éÏóÀ´£¬AndroidÖÐʹÓÃPathClassLoaderÀà×÷ΪAndroidµÄĬÈϵÄÀà¼ÓÔØÆ÷£¬
PathClassLoaderÆäʵʵÏֵľÍÊǼòµ¥µÄ´ÓÎļþϵͳÖмÓÔØÀàÎļþ¡£PathClassLoade±¾Éí¼Ì³Ð×ÔBaseDexClassLoader£¬BaseDexClassLoaderÖØдÁËfindClass·½·¨£¬
¸Ã·½·¨ÊÇClassLoaderµÄºËÐÄ
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \\"" + name + "\\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
¿´Ô´Âë¿ÉÖª£¬BaseDexClassLoader½«findClass·½·¨Î¯ÍиøÁËpathList¶ÔÏóµÄfindClass·½·¨£¬pathList¶ÔÏóÊÇÔÚBaseDexClassLoaderµÄ¹¹Ô캯ÊýÖÐnew³öÀ´µÄ£¬
ËüµÄÀàÐÍÊÇDexPathList¡£¿´ÏÂDexPathList.findClassÔ´ÂëÊÇÈçºÎ×öµÄ£º
public Class findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
Ö±½Ó¾ÍÊDZéÀúdexElementsÁÐ±í£¬È»ºóͨ¹ýµ÷ÓÃelement.dexFile¶ÔÏóÉϵÄloadClassBinaryName·½·¨À´¼ÓÔØÀ࣬Èç¹û·µ»ØÖµ²»ÊÇnull£¬¾Í±íʾ¼ÓÔØÀà³É¹¦£¬»á½«Õâ¸öClass¶ÔÏ󷵻ء£
¶ødexElements¶ÔÏóÊÇÔÚDexPathListÀàµÄ¹¹Ô캯ÊýÖÐÍê³É³õʼ»¯µÄ¡£
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
makeDexElementsËù×öµÄÊÂÇé¾ÍÊDZéÀúÎÒÃÇ´«µÝÀ´µÄdexPath£¬È»ºóÒ»´Î¼ÓÔØÿ¸ödexÎļþ¡£
ʵÏÖ
ÉÏÃæ·ÖÎöÁËAndroidÖеÄÀàµÄ¼ÓÔصÄÁ÷³Ì£¬¿ÉÒÔ¿´³öÀ´DexPathList¶ÔÏóÖеÄdexElementsÁбíÊÇÀà¼ÓÔصÄÒ»¸öºËÐÄ£¬Ò»¸öÀàÈç¹ûÄܱ»³É¹¦¼ÓÔØ£¬ÄÇôËüµÄdexÒ»¶¨
»á³öÏÖÔÚdexElementsËù¶ÔÓ¦µÄdexÎļþÖУ¬²¢ÇÒdexElementsÖгöÏÖµÄ˳ÐòÒ²ºÜÖØÒª£¬ÔÚdexElementsÇ°Ãæ³öÏÖµÄdex»á±»ÓÅÏȼÓÔØ£¬Ò»µ©Class±»¼ÓÔسɹ¦£¬
¾Í»áÁ¢¼´·µ»Ø£¬Ò²¾ÍÊÇ˵£¬ÎÒÃǵÄÈç¹ûÏë×öhotpatch£¬Ò»¶¨Òª±£Ö¤ÎÒÃǵÄhotpacth dexÎļþ³öÏÖÔÚdexElementsÁбíµÄÇ°Ãæ¡£
ҪʵÏÖÈȸüУ¬¾ÍÐèÒªÎÒÃÇÔÚÔËÐÐʱȥ¸ü¸ÄPathClassLoader.pathList.dexElements£¬ÓÉÓÚÕâЩÊôÐÔ¶¼ÊÇprivateµÄ£¬Òò´ËÐèҪͨ¹ý·´ÉäÀ´Ð޸ġ£ÁíÍ⣬¹¹ÔìÎÒÃÇ×Ô¼ºµÄdexÎļþ
Ëù¶ÔÓ¦µÄdexElementsÊý×éµÄʱºò£¬ÎÒÃÇÒ²¿ÉÒÔ²ÉÈ¡Ò»¸ö±È½ÏÈ¡Çɵķ½Ê½£¬¾ÍÊÇͨ¹ý¹¹ÔìÒ»¸öDexClassLoader¶ÔÏóÀ´¼ÓÔØÎÒÃǵÄdexÎļþ£¬²¢ÇÒµ÷ÓÃÒ»´ÎdexClassLoader.loadClass(dummyClassName);
·½·¨£¬ÕâÑù£¬dexClassLoader.pathList.dexElementsÖУ¬¾Í»á°üº¬ÎÒÃǵÄdex£¬Í¨¹ý°ÑdexClassLoader.pathList.dexElements²åÈ뵽ϵͳĬÈϵÄclassLoader.pathList.dexElementsÁбíÇ°Ã棬¾Í¿ÉÒÔÈÃϵͳÓÅÏȼÓÔØÎÒÃǵÄdexÖеÄÀ࣬´Ó¶ø¿ÉÒÔʵÏÖÈȸüÐÂÁË¡£ÏÂÃæչʾһ²¿·Ö´úÂë
private static synchronized Boolean injectAboveEqualApiLevel14(
String dexPath, String defaultDexOptPath, String nativeLibPath, String dummyClassName) {
Log.i(TAG, "--> injectAboveEqualApiLevel14");
PathClassLoader pathClassLoader = (PathClassLoader) DexInjector.class.getClassLoader();
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, defaultDexOptPath, nativeLibPath, pathClassLoader);
try {
dexClassLoader.loadClass(dummyClassName);
Object dexElements = combineArray(
getDexElements(getPathList(pathClassLoader)),
getDexElements(getPathList(dexClassLoader)));
Object pathList = getPathList(pathClassLoader);
setField(pathList, pathList.getClass(), "dexElements", dexElements);
} catch (Throwable e) {
e.printStackTrace();
return false;
}
Log.i(TAG, "<-- injectAboveEqualApiLevel14 End.");
return true;
}
ÍêÕûµÄdemoÇë²Î¿¼ÎÒµÄGitHub
ÉÏÃæÖ»ÊÇ˵ÁËÒ»ÏÂhotpatchµÄÔÀí£¬¾ßÌåʵÏÖµÄʱºò£¬Èç¹ûÄãµÄappÓ¦ÓÃÁËmultidex£¬»¹»áÓöµ½ÆäËûµÄ¿Ó£¬Çë²Î¿¼: