Android外掛化(一):使用改進的MultiDex動態載入assets中的apk
轉自:http://blog.csdn.net/nupt123456789/article/details/50411581
簡介
為了解決65535方法數超標的問題,Google推薦使用MultiDex來載入classes2.dex,classes3.dex等等,其基本思想就是在執行時動態修改ClassLoader,以達到動態載入類的目的。為了更好的理解MultiDex的工作原理,可以先看一下ClassLoader的工作原理[1].然後參見PathClassLoader的原始碼,當然,它繼承自BaseDexClassLoader,主要原始碼都在BaseDexClassLoader中。MultiDex載入離線apk的過程如下:
我們可以在Application的onCreate方法或者Activity的attachBaseContext方法中開發載入。
動態載入assets中的apk
根據MultiDex的原始碼,我們可以修改其install方法,然後從assets資源中解壓出所需要載入的apk檔案,然後呼叫installSecondaryDexes方法,將其載入到當前Application的ClassLoader當中,這樣,在執行的時候,就可以通過當前的ClassLoader查詢到離線apk中的類了。
[AssetsMultiDexLoader.class]
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> net.mobctrl.hostapk; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.io.File; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.io.FilenameFilter; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.io.IOException; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.Array; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.Field; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.InvocationTargetException; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.lang.reflect.Method; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.ArrayList; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.Arrays; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.HashSet; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.List; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.ListIterator; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.Set; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.zip.ZipFile; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.content.Context; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.content.pm.ApplicationInfo; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.content.pm.PackageManager; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.content.pm.PackageManager.NameNotFoundException; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.os.Build; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.util.Log; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> dalvik.system.DexFile; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Author</span> Zheng Haibo *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Mail</span> mochuan.zhb@alibaba-inc.com *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Company</span> Alibaba Group *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @PersonalWebsite</span> http://www.mobctrl.net *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @version</span> $Id: AssetsDex.java, v 0.1 2015年12月10日 下午5:36:23 mochuan.zhb Exp $ *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Description</span> ClassLoader */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AssetsMultiDexLoader</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String TAG = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"AssetsApkLoader"</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> installed = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> MAX_SUPPORTED_SDK_VERSION = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> MIN_SDK_VERSION = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Set<String> installedApk = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HashSet<String>(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-title" style="box-sizing: border-box;">AssetsMultiDexLoader</span>() { } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 安裝Assets中的apk檔案 * *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> context */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">install</span>(Context context) { Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"install..."</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (installed) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { clearOldDexDir(context); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Throwable t) { Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Something went wrong when trying to clear old MultiDex extraction, "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"continuing without cleaning."</span>, t); } AssetsManager.copyAllAssetsApk(context); Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"install"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (Build.VERSION.SDK_INT < MIN_SDK_VERSION) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Multi dex installation failed. SDK "</span> + Build.VERSION.SDK_INT + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" is unsupported. Min SDK version is "</span> + MIN_SDK_VERSION + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"."</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { ApplicationInfo applicationInfo = getApplicationInfo(context); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (applicationInfo == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Looks like running on a test Context, so just return without</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// patching.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (installedApk) { String apkPath = applicationInfo.sourceDir; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (installedApk.contains(apkPath)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } installedApk.add(apkPath); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (Build.VERSION.SDK_INT > MAX_SUPPORTED_SDK_VERSION) { Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"MultiDex is not guaranteed to work in SDK version "</span> + Build.VERSION.SDK_INT + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">": SDK version higher than "</span> + MAX_SUPPORTED_SDK_VERSION + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" should be backed by "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"runtime with built-in multidex capabilty but it's not the "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"case here: java.vm.version=\""</span> + System.getProperty(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"java.vm.version"</span>) + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\""</span>); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional * DEX file entries. */</span> ClassLoader loader; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { loader = context.getClassLoader(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (RuntimeException e) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * Ignore those exceptions so that we don't break tests * relying on Context like a android.test.mock.MockContext * or a android.content.ContextWrapper with a null base * Context. */</span> Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Failure while trying to obtain Context class loader. "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Must be running in test mode. Skip patching."</span>, e); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (loader == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Note, the context class loader is null when running</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Robolectric tests.</span> Log.e(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Context class loader is null. Must be running in test mode. "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Skip patching."</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 獲取dex檔案列表</span> File dexDir = context.getDir(AssetsManager.APK_DIR, Context.MODE_PRIVATE); File[] szFiles = dexDir.listFiles(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> FilenameFilter() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">accept</span>(File dir, String filename) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> filename.endsWith(AssetsManager.FILE_FILTER); } }); List<File> files = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<File>(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (File f : szFiles) { Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"load file:"</span> + f.getName()); files.add(f); } Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"loader before:"</span> + context.getClassLoader()); installSecondaryDexes(loader, dexDir, files); Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"loader end:"</span> + context.getClassLoader()); } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) { Log.e(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Multidex installation failure"</span>, e); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Multi dex installation failed ("</span> + e.getMessage() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">")."</span>); } installed = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"install done"</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> ApplicationInfo <span class="hljs-title" style="box-sizing: border-box;">getApplicationInfo</span>(Context context) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> NameNotFoundException { PackageManager pm; String packageName; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { pm = context.getPackageManager(); packageName = context.getPackageName(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (RuntimeException e) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * Ignore those exceptions so that we don't break tests relying on * Context like a android.test.mock.MockContext or a * android.content.ContextWrapper with a null base Context. */</span> Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Failure while trying to obtain ApplicationInfo from Context. "</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Must be running in test mode. Skip patching."</span>, e); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (pm == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> || packageName == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// This is most likely a mock context, so just return without</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// patching.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; } ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> applicationInfo; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">installSecondaryDexes</span>(ClassLoader loader, File dexDir, List<File> files) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!files.isEmpty()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (Build.VERSION.SDK_INT >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">19</span>) { V19.install(loader, files, dexDir); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (Build.VERSION.SDK_INT >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>) { V14.install(loader, files, dexDir); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { V4.install(loader, files); } } } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Locates a given field anywhere in the class inheritance hierarchy. * *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> instance * an object to search the field into. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> name * field name *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> a field object *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @throws</span> NoSuchFieldException * if the field cannot be located */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Field <span class="hljs-title" style="box-sizing: border-box;">findField</span>(Object instance, String name) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> NoSuchFieldException { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (Class<?> clazz = instance.getClass(); clazz != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; clazz = clazz .getSuperclass()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { Field field = clazz.getDeclaredField(name); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!field.isAccessible()) { field.setAccessible(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> field; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (NoSuchFieldException e) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ignore and search next</span> } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> NoSuchFieldException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Field "</span> + name + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" not found in "</span> + instance.getClass()); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Locates a given method anywhere in the class inheritance hierarchy. * *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> instance * an object to search the method into. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> name * method name *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> parameterTypes * method parameter types *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> a method object *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @throws</span> NoSuchMethodException * if the method cannot be located */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Method <span class="hljs-title" style="box-sizing: border-box;">findMethod</span>(Object instance, String name, Class<?>... parameterTypes) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> NoSuchMethodException { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (Class<?> clazz = instance.getClass(); clazz != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; clazz = clazz .getSuperclass()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { Method method = clazz.getDeclaredMethod(name, parameterTypes); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!method.isAccessible()) { method.setAccessible(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> method; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (NoSuchMethodException e) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ignore and search next</span> } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> NoSuchMethodException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Method "</span> + name + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" with parameters "</span> + Arrays.asList(parameterTypes) + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" not found in "</span> + instance.getClass()); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Replace the value of a field containing a non null array, by a new array * containing the elements of the original array plus the elements of * extraElements. * *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> instance * the instance whose field is to be modified. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> fieldName * the field to modify. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> extraElements * elements to append at the end of the array. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">expandFieldArray</span>(Object instance, String fieldName, Object[] extraElements) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field jlrField = findField(instance, fieldName); Object[] original = (Object[]) jlrField.get(instance); Object[] combined = (Object[]) Array.newInstance(original.getClass() .getComponentType(), original.length + extraElements.length); System.arraycopy(original, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, combined, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, original.length); System.arraycopy(extraElements, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, combined, original.length, extraElements.length); jlrField.set(instance, combined); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">clearOldDexDir</span>(Context context) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { File dexDir = context.getDir(AssetsManager.APK_DIR, Context.MODE_PRIVATE); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dexDir.isDirectory()) { Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Clearing old secondary dex dir ("</span> + dexDir.getPath() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">")."</span>); File[] files = dexDir.listFiles(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (files == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Failed to list secondary dex dir content ("</span> + dexDir.getPath() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">")."</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (File oldFile : files) { Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Trying to delete old file "</span> + oldFile.getPath() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" of size "</span> + oldFile.length()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!oldFile.delete()) { Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Failed to delete old file "</span> + oldFile.getPath()); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Deleted old file "</span> + oldFile.getPath()); } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!dexDir.delete()) { Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Failed to delete secondary dex dir "</span> + dexDir.getPath()); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { Log.i(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Deleted old secondary dex dir "</span> + dexDir.getPath()); } } } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Installer for platform versions 19. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">V19</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">install</span>(ClassLoader loader, List<File> additionalClassPathEntries, File optimizedDirectory) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */</span> Field pathListField = findField(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pathList"</span>); Object dexPathList = pathListField.get(loader); ArrayList<IOException> suppressedExceptions = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<IOException>(); expandFieldArray( dexPathList, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"dexElements"</span>, makeDexElements(dexPathList, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<File>( additionalClassPathEntries), optimizedDirectory, suppressedExceptions)); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (suppressedExceptions.size() > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (IOException e : suppressedExceptions) { Log.w(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Exception in makeDexElement"</span>, e); } Field suppressedExceptionsField = findField(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"dexElementsSuppressedExceptions"</span>); IOException[] dexElementsSuppressedExceptions = (IOException[]) suppressedExceptionsField .get(loader); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (dexElementsSuppressedExceptions == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { dexElementsSuppressedExceptions = suppressedExceptions .toArray(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IOException[suppressedExceptions .size()]); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { IOException[] combined = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IOException[suppressedExceptions .size() + dexElementsSuppressedExceptions.length]; suppressedExceptions.toArray(combined); System.arraycopy(dexElementsSuppressedExceptions, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length); dexElementsSuppressedExceptions = combined; } suppressedExceptionsField.set(loader, dexElementsSuppressedExceptions); } } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * A wrapper around * {@code private static final dalvik.system.DexPathList#makeDexElements} * . */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Object[] <span class="hljs-title" style="box-sizing: border-box;">makeDexElements</span>(Object dexPathList, ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = findMethod(dexPathList, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"makeDexElements"</span>, ArrayList.class, File.class, ArrayList.class); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory, suppressedExceptions); } } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Installer for platform versions 14, 15, 16, 17 and 18. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">V14</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">install</span>(ClassLoader loader, List<File> additionalClassPathEntries, File optimizedDirectory) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * The patched class loader is expected to be a descendant of * dalvik.system.BaseDexClassLoader. We modify its * dalvik.system.DexPathList pathList field to append additional DEX * file entries. */</span> Field pathListField = findField(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"pathList"</span>); Object dexPathList = pathListField.get(loader); expandFieldArray( dexPathList, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"dexElements"</span>, makeDexElements(dexPathList, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList<File>( additionalClassPathEntries), optimizedDirectory)); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * A wrapper around * {@code private static final dalvik.system.DexPathList#makeDexElements} * . */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Object[] <span class="hljs-title" style="box-sizing: border-box;">makeDexElements</span>(Object dexPathList, ArrayList<File> files, File optimizedDirectory) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = findMethod(dexPathList, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"makeDexElements"</span>, ArrayList.class, File.class); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (Object[]) makeDexElements.invoke(dexPathList, files, optimizedDirectory); } } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Installer for platform versions 4 to 13. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">V4</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">install</span>(ClassLoader loader, List<File> additionalClassPathEntries) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> IllegalArgumentException, IllegalAccessException, NoSuchFieldException, IOException { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* * The patched class loader is expected to be a descendant of * dalvik.system.DexClassLoader. We modify its fields mPaths, * mFiles, mZips and mDexs to append additional DEX file entries. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> extraSize = additionalClassPathEntries.size(); Field pathField = findField(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"path"</span>); StringBuilder path = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> StringBuilder( (String) pathField.get(loader)); String[] extraPaths = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> String[extraSize]; File[] extraFiles = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File[extraSize]; ZipFile[] extraZips = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ZipFile[extraSize]; DexFile[] extraDexs = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> DexFile[extraSize]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (ListIterator<File> iterator = additionalClassPathEntries .listIterator(); iterator.hasNext();) { File additionalEntry = iterator.next(); String entryPath = additionalEntry.getAbsolutePath(); path.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">':'</span>).append(entryPath); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> index = iterator.previousIndex(); extraPaths[index] = entryPath; extraFiles[index] = additionalEntry; extraZips[index] = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ZipFile(additionalEntry); extraDexs[index] = DexFile.loadDex(entryPath, entryPath + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".dex"</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } pathField.set(loader, path.toString()); expandFieldArray(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"mPaths"</span>, extraPaths); expandFieldArray(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"mFiles"</span>, extraFiles); expandFieldArray(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"mZips"</span>, extraZips); expandFieldArray(loader, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"mDexs"</span>, extraDexs); } } } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li><li style="box-sizing: border-box; padding: 0px 5px;">124</li><li style="box-sizing: border-box; padding: 0px 5px;">125</li><li style="box-sizing: border-box; padding: 0px 5px;">126</li><li style="box-sizing: border-box; padding: 0px 5px;">127</li><li style="box-sizing: border-box; padding: 0px 5px;">128</li><li style="box-sizing: border-box; padding: 0px 5px;">129</li><li style="box-sizing: border-box; padding: 0px 5px;">130</li><li style="box-sizing: border-box; padding: 0px 5px;">131</li><li style="box-sizing: border-box; padding: 0px 5px;">132</li><li style="box-sizing: border-box; padding: 0px 5px;">133</li><li style="box-sizing: border-box; padding: 0px 5px;">134</li><li style="box-sizing: border-box; padding: 0px 5px;">135</li><li style="box-sizing: border-box; padding: 0px 5px;">136</li><li style="box-sizing: border-box; padding: 0px 5px;">137</li><li style="box-sizing: border-box; padding: 0px 5px;">138</li><li style="box-sizing: border-box; padding: 0px 5px;">139</li><li style="box-sizing: border-box; padding: 0px 5px;">140</li><li style="box-sizing: border-box; padding: 0px 5px;">141</li><li style="box-sizing: border-box; padding: 0px 5px;">142</li><li style="box-sizing: border-box; padding: 0px 5px;">143</li><li style="box-sizing: border-box; padding: 0px 5px;">144</li><li style="box-sizing: border-box; padding: 0px 5px;">145</li><li style="box-sizing: border-box; padding: 0px 5px;">146</li><li style="box-sizing: border-box; padding: 0px 5px;">147</li><li style="box-sizing: border-box; padding: 0px 5px;">148</li><li style="box-sizing: border-box; padding: 0px 5px;">149</li><li style="box-sizing: border-box; padding: 0px 5px;">150</li><li style="box-sizing: border-box; padding: 0px 5px;">151</li><li style="box-sizing: border-box; padding: 0px 5px;">152</li><li style="box-sizing: border-box; padding: 0px 5px;">153</li><li style="box-sizing: border-box; padding: 0px 5px;">154</li><li style="box-sizing: border-box; padding: 0px 5px;">155</li><li style="box-sizing: border-box; padding: 0px 5px;">156</li><li style="box-sizing: border-box; padding: 0px 5px;">157</li><li style="box-sizing: border-box; padding: 0px 5px;">158</li><li style="box-sizing: border-box; padding: 0px 5px;">159</li><li style="box-sizing: border-box; padding: 0px 5px;">160</li><li style="box-sizing: border-box; padding: 0px 5px;">161</li><li style="box-sizing: border-box; padding: 0px 5px;">162</li><li style="box-sizing: border-box; padding: 0px 5px;">163</li><li style="box-sizing: border-box; padding: 0px 5px;">164</li><li style="box-sizing: border-box; padding: 0px 5px;">165</li><li style="box-sizing: border-box; padding: 0px 5px;">166</li><li style="box-sizing: border-box; padding: 0px 5px;">167</li><li style="box-sizing: border-box; padding: 0px 5px;">168</li><li style="box-sizing: border-box; padding: 0px 5px;">169</li><li style="box-sizing: border-box; padding: 0px 5px;">170</li><li style="box-sizing: border-box; padding: 0px 5px;">171</li><li style="box-sizing: border-box; padding: 0px 5px;">172</li><li style="box-sizing: border-box; padding: 0px 5px;">173</li><li style="box-sizing: border-box; padding: 0px 5px;">174</li><li style="box-sizing: border-box; padding: 0px 5px;">175</li><li style="box-sizing: border-box; padding: 0px 5px;">176</li><li style="box-sizing: border-box; padding: 0px 5px;">177</li><li style="box-sizing: border-box; padding: 0px 5px;">178</li><li style="box-sizing: border-box; padding: 0px 5px;">179</li><li style="box-sizing: border-box; padding: 0px 5px;">180</li><li style="box-sizing: border-box; padding: 0px 5px;">181</li><li style="box-sizing: border-box; padding: 0px 5px;">182</li><li style="box-sizing: border-box; padding: 0px 5px;">183</li><li style="box-sizing: border-box; padding: 0px 5px;">184</li><li style="box-sizing: border-box; padding: 0px 5px;">185</li><li style="box-sizing: border-box; padding: 0px 5px;">186</li><li style="box-sizing: border-box; padding: 0px 5px;">187</li><li style="box-sizing: border-box; padding: 0px 5px;">188</li><li style="box-sizing: border-box; padding: 0px 5px;">189</li><li style="box-sizing: border-box; padding: 0px 5px;">190</li><li style="box-sizing: border-box; padding: 0px 5px;">191</li><li style="box-sizing: border-box; padding: 0px 5px;">192</li><li style="box-sizing: border-box; padding: 0px 5px;">193</li><li style="box-sizing: border-box; padding: 0px 5px;">194</li><li style="box-sizing: border-box; padding: 0px 5px;">195</li><li style="box-sizing: border-box; padding: 0px 5px;">196</li><li style="box-sizing: border-box; padding: 0px 5px;">197</li><li style="box-sizing: border-box; padding: 0px 5px;">198</li><li style="box-sizing: border-box; padding: 0px 5px;">199</li><li style="box-sizing: border-box; padding: 0px 5px;">200</li><li style="box-sizing: border-box; padding: 0px 5px;">201</li><li style="box-sizing: border-box; padding: 0px 5px;">202</li><li style="box-sizing: border-box; padding: 0px 5px;">203</li><li style="box-sizing: border-box; padding: 0px 5px;">204</li><li style="box-sizing: border-box; padding: 0px 5px;">205</li><li style="box-sizing: border-box; padding: 0px 5px;">206</li><li style="box-sizing: border-box; padding: 0px 5px;">207</li><li style="box-sizing: border-box; padding: 0px 5px;">208</li><li style="box-sizing: border-box; padding: 0px 5px;">209</li><li style="box-sizing: border-box; padding: 0px 5px;">210</li><li style="box-sizing: border-box; padding: 0px 5px;">211</li><li style="box-sizing: border-box; padding: 0px 5px;">212</li><li style="box-sizing: border-box; padding: 0px 5px;">213</li><li style="box-sizing: border-box; padding: 0px 5px;">214</li><li style="box-sizing: border-box; padding: 0px 5px;">215</li><li style="box-sizing: border-box; padding: 0px 5px;">216</li><li style="box-sizing: border-box; padding: 0px 5px;">217</li><li style="box-sizing: border-box; padding: 0px 5px;">218</li><li style="box-sizing: border-box; padding: 0px 5px;">219</li><li style="box-sizing: border-box; padding: 0px 5px;">220</li><li style="box-sizing: border-box; padding: 0px 5px;">221</li><li style="box-sizing: border-box; padding: 0px 5px;">222</li><li style="box-sizing: border-box; padding: 0px 5px;">223</li><li style="box-sizing: border-box; padding: 0px 5px;">224</li><li style="box-sizing: border-box; padding: 0px 5px;">225</li><li style="box-sizing: border-box; padding: 0px 5px;">226</li><li style="box-sizing: border-box; padding: 0px 5px;">227</li><li style="box-sizing: border-box; padding: 0px 5px;">228</li><li style="box-sizing: border-box; padding: 0px 5px;">229</li><li style="box-sizing: border-box; padding: 0px 5px;">230</li><li style="box-sizing: border-box; padding: 0px 5px;">231</li><li style="box-sizing: border-box; padding: 0px 5px;">232</li><li style="box-sizing: border-box; padding: 0px 5px;">233</li><li style="box-sizing: border-box; padding: 0px 5px;">234</li><li style="box-sizing: border-box; padding: 0px 5px;">235</li><li style="box-sizing: border-box; padding: 0px 5px;">236</li><li style="box-sizing: border-box; padding: 0px 5px;">237</li><li style="box-sizing: border-box; padding: 0px 5px;">238</li><li style="box-sizing: border-box; padding: 0px 5px;">239</li><li style="box-sizing: border-box; padding: 0px 5px;">240</li><li style="box-sizing: border-box; padding: 0px 5px;">241</li><li style="box-sizing: border-box; padding: 0px 5px;">242</li><li style="box-sizing: border-box; padding: 0px 5px;">243</li><li style="box-sizing: border-box; padding: 0px 5px;">244</li><li style="box-sizing: border-box; padding: 0px 5px;">245</li><li style="box-sizing: border-box; padding: 0px 5px;">246</li><li style="box-sizing: border-box; padding: 0px 5px;">247</li><li style="box-sizing: border-box; padding: 0px 5px;">248</li><li style="box-sizing: border-box; padding: 0px 5px;">249</li><li style="box-sizing: border-box; padding: 0px 5px;">250</li><li style="box-sizing: border-box; padding: 0px 5px;">251</li><li style="box-sizing: border-box; padding: 0px 5px;">252</li><li style="box-sizing: border-box; padding: 0px 5px;">253</li><li style="box-sizing: border-box; padding: 0px 5px;">254</li><li style="box-sizing: border-box; padding: 0px 5px;">255</li><li style="box-sizing: border-box; padding: 0px 5px;">256</li><li style="box-sizing: border-box; padding: 0px 5px;">257</li><li style="box-sizing: border-box; padding: 0px 5px;">258</li><li style="box-sizing: border-box; padding: 0px 5px;">259</li><li style="box-sizing: border-box; padding: 0px 5px;">260</li><li style="box-sizing: border-box; padding: 0px 5px;">261</li><li style="box-sizing: border-box; padding: 0px 5px;">262</li><li style="box-sizing: border-box; padding: 0px 5px;">263</li><li style="box-sizing: border-box; padding: 0px 5px;">264</li><li style="box-sizing: border-box; padding: 0px 5px;">265</li><li style="box-sizing: border-box; padding: 0px 5px;">266</li><li style="box-sizing: border-box; padding: 0px 5px;">267</li><li style="box-sizing: border-box; padding: 0px 5px;">268</li><li style="box-sizing: border-box; padding: 0px 5px;">269</li><li style="box-sizing: border-box; padding: 0px 5px;">270</li><li style="box-sizing: border-box; padding: 0px 5px;">271</li><li style="box-sizing: border-box; padding: 0px 5px;">272</li><li style="box-sizing: border-box; padding: 0px 5px;">273</li><li style="box-sizing: border-box; padding: 0px 5px;">274</li><li style="box-sizing: border-box; padding: 0px 5px;">275</li><li style="box-sizing: border-box; padding: 0px 5px;">276</li><li style="box-sizing: border-box; padding: 0px 5px;">277</li><li style="box-sizing: border-box; padding: 0px 5px;">278</li><li style="box-sizing: border-box; padding: 0px 5px;">279</li><li style="box-sizing: border-box; padding: 0px 5px;">280</li><li style="box-sizing: border-box; padding: 0px 5px;">281</li><li style="box-sizing: border-box; padding: 0px 5px;">282</li><li style="box-sizing: border-box; padding: 0px 5px;">283</li><li style="box-sizing: border-box; padding: 0px 5px;">284</li><li style="box-sizing: border-box; padding: 0px 5px;">285</li><li style="box-sizing: border-box; padding: 0px 5px;">286</li><li style="box-sizing: border-box; padding: 0px 5px;">287</li><li style="box-sizing: border-box; padding: 0px 5px;">288</li><li style="box-sizing: border-box; padding: 0px 5px;">289</li><li style="box-sizing: border-box; padding: 0px 5px;">290</li><li style="box-sizing: border-box; padding: 0px 5px;">291</li><li style="box-sizing: border-box; padding: 0px 5px;">292</li><li style="box-sizing: border-box; padding: 0px 5px;">293</li><li style="box-sizing: border-box; padding: 0px 5px;">294</li><li style="box-sizing: border-box; padding: 0px 5px;">295</li><li style="box-sizing: border-box; padding: 0px 5px;">296</li><li style="box-sizing: border-box; padding: 0px 5px;">297</li><li style="box-sizing: border-box; padding: 0px 5px;">298</li><li style="box-sizing: border-box; padding: 0px 5px;">299</li><li style="box-sizing: border-box; padding: 0px 5px;">300</li><li style="box-sizing: border-box; padding: 0px 5px;">301</li><li style="box-sizing: border-box; padding: 0px 5px;">302</li><li style="box-sizing: border-box; padding: 0px 5px;">303</li><li style="box-sizing: border-box; padding: 0px 5px;">304</li><li style="box-sizing: border-box; padding: 0px 5px;">305</li><li style="box-sizing: border-box; padding: 0px 5px;">306</li><li style="box-sizing: border-box; padding: 0px 5px;">307</li><li style="box-sizing: border-box; padding: 0px 5px;">308</li><li style="box-sizing: border-box; padding: 0px 5px;">309</li><li style="box-sizing: border-box; padding: 0px 5px;">310</li><li style="box-sizing: border-box; padding: 0px 5px;">311</li><li style="box-sizing: border-box; padding: 0px 5px;">312</li><li style="box-sizing: border-box; padding: 0px 5px;">313</li><li style="box-sizing: border-box; padding: 0px 5px;">314</li><li style="box-sizing: border-box; padding: 0px 5px;">315</li><li style="box-sizing: border-box; padding: 0px 5px;">316</li><li style="box-sizing: border-box; padding: 0px 5px;">317</li><li style="box-sizing: border-box; padding: 0px 5px;">318</li><li style="box-sizing: border-box; padding: 0px 5px;">319</li><li style="box-sizing: border-box; padding: 0px 5px;">320</li><li style="box-sizing: border-box; padding: 0px 5px;">321</li><li style="box-sizing: border-box; padding: 0px 5px;">322</li><li style="box-sizing: border-box; padding: 0px 5px;">323</li><li style="box-sizing: border-box; padding: 0px 5px;">324</li><li style="box-sizing: border-box; padding: 0px 5px;">325</li><li style="box-sizing: border-box; padding: 0px 5px;">326</li><li style="box-sizing: border-box; padding: 0px 5px;">327</li><li style="box-sizing: border-box; padding: 0px 5px;">328</li><li style="box-sizing: border-box; padding: 0px 5px;">329</li><li style="box-sizing: border-box; padding: 0px 5px;">330</li><li style="box-sizing: border-box; padding: 0px 5px;">331</li><li style="box-sizing: border-box; padding: 0px 5px;">332</li><li style="box-sizing: border-box; padding: 0px 5px;">333</li><li style="box-sizing: border-box; padding: 0px 5px;">334</li><li style="box-sizing: border-box; padding: 0px 5px;">335</li><li style="box-sizing: border-box; padding: 0px 5px;">336</li><li style="box-sizing: border-box; padding: 0px 5px;">337</li><li style="box-sizing: border-box; padding: 0px 5px;">338</li><li style="box-sizing: border-box; padding: 0px 5px;">339</li><li style="box-sizing: border-box; padding: 0px 5px;">340</li><li style="box-sizing: border-box; padding: 0px 5px;">341</li><li style="box-sizing: border-box; padding: 0px 5px;">342</li><li style="box-sizing: border-box; padding: 0px 5px;">343</li><li style="box-sizing: border-box; padding: 0px 5px;">344</li><li style="box-sizing: border-box; padding: 0px 5px;">345</li><li style="box-sizing: border-box; padding: 0px 5px;">346</li><li style="box-sizing: border-box; padding: 0px 5px;">347</li><li style="box-sizing: border-box; padding: 0px 5px;">348</li><li style="box-sizing: border-box; padding: 0px 5px;">349</li><li style="box-sizing: border-box; padding: 0px 5px;">350</li><li style="box-sizing: border-box; padding: 0px 5px;">351</li><li style="box-sizing: border-box; padding: 0px 5px;">352</li><li style="box-sizing: border-box; padding: 0px 5px;">353</li><li style="box-sizing: border-box; padding: 0px 5px;">354</li><li style="box-sizing: border-box; padding: 0px 5px;">355</li><li style="box-sizing: border-box; padding: 0px 5px;">356</li><li style="box-sizing: border-box; padding: 0px 5px;">357</li><li style="box-sizing: border-box; padding: 0px 5px;">358</li><li style="box-sizing: border-box; padding: 0px 5px;">359</li><li style="box-sizing: border-box; padding: 0px 5px;">360</li><li style="box-sizing: border-box; padding: 0px 5px;">361</li><li style="box-sizing: border-box; padding: 0px 5px;">362</li><li style="box-sizing: border-box; padding: 0px 5px;">363</li><li style="box-sizing: border-box; padding: 0px 5px;">364</li><li style="box-sizing: border-box; padding: 0px 5px;">365</li><li style="box-sizing: border-box; padding: 0px 5px;">366</li><li style="box-sizing: border-box; padding: 0px 5px;">367</li><li style="box-sizing: border-box; padding: 0px 5px;">368</li><li style="box-sizing: border-box; padding: 0px 5px;">369</li><li style="box-sizing: border-box; padding: 0px 5px;">370</li><li style="box-sizing: border-box; padding: 0px 5px;">371</li><li style="box-sizing: border-box; padding: 0px 5px;">372</li><li style="box-sizing: border-box; padding: 0px 5px;">373</li><li style="box-sizing: border-box; padding: 0px 5px;">374</li><li style="box-sizing: border-box; padding: 0px 5px;">375</li><li style="box-sizing: border-box; padding: 0px 5px;">376</li><li style="box-sizing: border-box; padding: 0px 5px;">377</li><li style="box-sizing: border-box; padding: 0px 5px;">378</li><li style="box-sizing: border-box; padding: 0px 5px;">379</li><li style="box-sizing: border-box; padding: 0px 5px;">380</li><li style="box-sizing: border-box; padding: 0px 5px;">381</li><li style="box-sizing: border-box; padding: 0px 5px;">382</li><li style="box-sizing: border-box; padding: 0px 5px;">383</li><li style="box-sizing: border-box; padding: 0px 5px;">384</li><li style="box-sizing: border-box; padding: 0px 5px;">385</li><li style="box-sizing: border-box; padding: 0px 5px;">386</li><li style="box-sizing: border-box; padding: 0px 5px;">387</li><li style="box-sizing: border-box; padding: 0px 5px;">388</li><li style="box-sizing: border-box; padding: 0px 5px;">389</li><li style="box-sizing: border-box; padding: 0px 5px;">390</li><li style="box-sizing: border-box; padding: 0px 5px;">391</li><li style="box-sizing: border-box; padding: 0px 5px;">392</li><li style="box-sizing: border-box; padding: 0px 5px;">393</li><li style="box-sizing: border-box; padding: 0px 5px;">394</li><li style="box-sizing: border-box; padding: 0px 5px;">395</li><li style="box-sizing: border-box; padding: 0px 5px;">396</li><li style="box-sizing: border-box; padding: 0px 5px;">397</li><li style="box-sizing: border-box; padding: 0px 5px;">398</li><li style="box-sizing: border-box; padding: 0px 5px;">399</li><li style="box-sizing: border-box; padding: 0px 5px;">400</li><li style="box-sizing: border-box; padding: 0px 5px;">401</li><li style="box-sizing: border-box; padding: 0px 5px;">402</li><li style="box-sizing: border-box; padding: 0px 5px;">403</li><li style="box-sizing: border-box; padding: 0px 5px;">404</li><li style="box-sizing: border-box; padding: 0px 5px;">405</li><li style="box-sizing: border-box; padding: 0px 5px;">406</li><li style="box-sizing: border-box; padding: 0px 5px;">407</li><li style="box-sizing: border-box; padding: 0px 5px;">408</li><li style="box-sizing: border-box; padding: 0px 5px;">409</li><li style="box-sizing: border-box; padding: 0px 5px;">410</li><li style="box-sizing: border-box; padding: 0px 5px;">411</li><li style="box-sizing: border-box; padding: 0px 5px;">412</li><li style="box-sizing: border-box; padding: 0px 5px;">413</li><li style="box-sizing: border-box; padding: 0px 5px;">414</li><li style="box-sizing: border-box; padding: 0px 5px;">415</li><li style="box-sizing: border-box; padding: 0px 5px;">416</li><li style="box-sizing: border-box; padding: 0px 5px;">417</li><li style="box-sizing: border-box; padding: 0px 5px;">418</li><li style="box-sizing: border-box; padding: 0px 5px;">419</li><li style="box-sizing: border-box; padding: 0px 5px;">420</li><li style="box-sizing: border-box; padding: 0px 5px;">421</li><li style="box-sizing: border-box; padding: 0px 5px;">422</li><li style="box-sizing: border-box; padding: 0px 5px;">423</li><li style="box-sizing: border-box; padding: 0px 5px;">424</li><li style="box-sizing: border-box; padding: 0px 5px;">425</li><li style="box-sizing: border-box; padding: 0px 5px;">426</li><li style="box-sizing: border-box; padding: 0px 5px;">427</li><li style="box-sizing: border-box; padding: 0px 5px;">428</li><li style="box-sizing: border-box; padding: 0px 5px;">429</li><li style="box-sizing: border-box; padding: 0px 5px;">430</li><li style="box-sizing: border-box; padding: 0px 5px;">431</li><li style="box-sizing: border-box; padding: 0px 5px;">432</li><li style="box-sizing: border-box; padding: 0px 5px;">433</li><li style="box-sizing: border-box; padding: 0px 5px;">434</li><li style="box-sizing: border-box; padding: 0px 5px;">435</li><li style="box-sizing: border-box; padding: 0px 5px;">436</li><li style="box-sizing: border-box; padding: 0px 5px;">437</li><li style="box-sizing: border-box; padding: 0px 5px;">438</li><li style="box-sizing: border-box; padding: 0px 5px;">439</li><li style="box-sizing: border-box; padding: 0px 5px;">440</li><li style="box-sizing: border-box; padding: 0px 5px;">441</li><li style="box-sizing: border-box; padding: 0px 5px;">442</li><li style="box-sizing: border-box; padding: 0px 5px;">443</li><li style="box-sizing: border-box; padding: 0px 5px;">444</li><li style="box-sizing: border-box; padding: 0px 5px;">445</li><li style="box-sizing: border-box; padding: 0px 5px;">446</li><li style="box-sizing: border-box; padding: 0px 5px;">447</li><li style="box-sizing: border-box; padding: 0px 5px;">448</li><li style="box-sizing: border-box; padding: 0px 5px;">449</li><li style="box-sizing: border-box; padding: 0px 5px;">450</li><li style="box-sizing: border-box; padding: 0px 5px;">451</li><li style="box-sizing: border-box; padding: 0px 5px;">452</li><li style="box-sizing: border-box; padding: 0px 5px;">453</li><li style="box-sizing: border-box; padding: 0px 5px;">454</li><li style="box-sizing: border-box; padding: 0px 5px;">455</li><li style="box-sizing: border-box; padding: 0px 5px;">456</li><li style="box-sizing: border-box; padding: 0px 5px;">457</li><li style="box-sizing: border-box; padding: 0px 5px;">458</li><li style="box-sizing: border-box; padding: 0px 5px;">459</li><li style="box-sizing: border-box; padding: 0px 5px;">460</li><li style="box-sizing: border-box; padding: 0px 5px;">461</li><li style="box-sizing: border-box; padding: 0px 5px;">462</li><li style="box-sizing: border-box; padding: 0px 5px;">463</li><li style="box-sizing: border-box; padding: 0px 5px;">464</li><li style="box-sizing: border-box; padding: 0px 5px;">465</li><li style="box-sizing: border-box; padding: 0px 5px;">466</li><li style="box-sizing: border-box; padding: 0px 5px;">467</li><li style="box-sizing: border-box; padding: 0px 5px;">468</li><li style="box-sizing: border-box; padding: 0px 5px;">469</li><li style="box-sizing: border-box; padding: 0px 5px;">470</li><li style="box-sizing: border-box; padding: 0px 5px;">471</li><li style="box-sizing: border-box; padding: 0px 5px;">472</li><li style="box-sizing: border-box; padding: 0px 5px;">473</li><li style="box-sizing: border-box; padding: 0px 5px;">474</li><li style="box-sizing: border-box; padding: 0px 5px;">475</li><li style="box-sizing: border-box; padding: 0px 5px;">476</li><li style="box-sizing: border-box; padding: 0px 5px;">477</li><li style="box-sizing: border-box; padding: 0px 5px;">478</li><li style="box-sizing: border-box; padding: 0px 5px;">479</li><li style="box-sizing: border-box; padding: 0px 5px;">480</li></ul>
[AssetsManager.java]
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> net.mobctrl.hostapk; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.io.File; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.io.FileOutputStream; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.io.InputStream; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.io.OutputStream; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.content.Context; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.content.res.AssetManager; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.util.Log; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Author</span> Zheng Haibo *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Mail</span> mochuan.zhb@alibaba-inc.com *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Company</span> Alibaba Group *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @PersonalWebsite</span> http://www.mobctrl.net *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @version</span> $Id: AssetsManager.java, v 0.1 2015年12月11日 下午4:41:10 mochuan.zhb Exp $ *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @Description</span> */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AssetsManager</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String TAG = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"AssetsApkLoader"</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//從assets複製出去的apk的目標目錄</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String APK_DIR = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"third_apk"</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//檔案結尾過濾</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String FILE_FILTER = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".apk"</span>; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 將資原始檔中的apk檔案拷貝到私有目錄中 * *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> context */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">copyAllAssetsApk</span>(Context context) { AssetManager assetManager = context.getAssets(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> startTime = System.currentTimeMillis(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { File dex = context.getDir(APK_DIR, Context.MODE_PRIVATE); dex.mkdir(); String []fileNames = assetManager.list(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">""</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(String fileName:fileNames){ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(!fileName.endsWith(FILE_FILTER)){ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } InputStream in = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; OutputStream out = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; in = assetManager.open(fileName); File f = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(dex, fileName); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (f.exists() && f.length() == in.available()) { Log.i(TAG, fileName+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"no change"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } Log.i(TAG, fileName+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" chaneged"</span>); out = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> FileOutputStream(f); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[] buffer = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2048</span>]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> read; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> ((read = in.read(buffer)) != -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) { out.write(buffer, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, read); } in.close(); in = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; out.flush(); out.close(); out = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; Log.i(TAG, fileName+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" copy over"</span>); } Log.i(TAG,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"###copyAssets time = "</span>+(System.currentTimeMillis() - startTime)); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) { e.printStackTrace(); } } } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li></ul>
以上就是從assets中載入apk的核心程式碼。
DEMO執行
開啟BundleApk專案,編譯成apk。然後將BundleApk.apk檔案拷貝到HostApk專案的assets目錄,在HostApk的MainActivity方法的onCreate當中,呼叫AssetsMultiDexLoader.install(getApplicationContext());載入BundleApk.apk。然後我們就可以通過如下兩種方式呼叫BundleApk中的類:
- Class.forName
由於我們的HostApk沒有BundleApk類的引用,所以我們需要用反射的方式呼叫。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadClass</span>(){ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>{ Class<?> clazz = Class.forName(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"net.mobctrl.normal.apk.FileUtils"</span>); Constructor<?> constructor = clazz.getConstructor(); Object bundleUtils = constructor.newInstance(); Method printSumMethod = clazz.getMethod(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"print"</span>, Context.class,String.class); printSumMethod.setAccessible(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>); printSumMethod.invoke(bundleUtils, getApplicationContext(), <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Hello"</span>); }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span>(Exception e){ e.printStackTrace(); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
- loadClass
我們也可以直接獲取當前的ClassLoader物件,然後呼叫其loadClass方法
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@TargetApi</span>(Build.VERSION_CODES.ICE_CREAM_SANDWICH) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadApk</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { Class<?> clazz = getClassLoader() .loadClass(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"net.mobctrl.normal.apk.Utils"</span>); Constructor<?> constructor = clazz.getConstructor(); Object bundleUtils = constructor.newInstance(); Method printSumMethod = clazz.getMethod(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"printSum"</span>, Context.class, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>.class, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>.class, String.class); printSumMethod.setAccessible(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>); Integer sum = (Integer)printSumMethod.invoke(bundleUtils, getApplicationContext(), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"計算結果"</span>); System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"debug:sum = "</span> + sum); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (ClassNotFoundException e) { e.printStackTrace(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (SecurityException e) { e.printStackTrace(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (NoSuchMethodException e) { e.printStackTrace(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (IllegalArgumentException e) { e.printStackTrace(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InstantiationException e) { e.printStackTrace(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (IllegalAccessException e) { e.printStackTrace(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InvocationTargetException e) { e.printStackTrace(); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li></ul>
參考文章
[1].ClassLoader的工作原理
[2].PathClassLoader原始碼
[3].MultiDex原始碼
相關文章
- Android外掛化(二):使用DexClassLoader動態載入assets中的apkAndroidAPK
- Android外掛化(三):載入外掛apk中的Resource資源AndroidAPK
- 外掛化知識梳理(7) 類的動態載入入門
- Android 外掛化 動態升級Android
- 寫個js/css動態載入的JavaScript外掛JSCSSJavaScript
- 外掛化知識梳理(8) 類的動態載入原始碼分析原始碼
- 動態載入APK原理分享APK
- Android-動態載入外掛資源,皮膚包的實現原理Android
- APK動態載入框架(DL)解析APK框架
- Android外掛化原理(一)Activity外掛化Android
- 外掛化知識梳理(9) 資源的動態載入示例及原始碼分析原始碼
- Android外掛化的一種方案Android
- 使用 Webapck 優化 VS Code 外掛載入效能Web優化
- [Android] 元件化 & 模組化 & 外掛化演進Android元件化
- Multidex(二)之 Dex 預載入優化IDE優化
- MultiDex(三)之非同步載入優化IDE非同步優化
- Android外掛化技術之旅 1 開篇 - 實現啟動外掛與呼叫外掛中的Activity和ServiceAndroid
- Spring Boot 如何熱載入 jar 實現動態外掛?Spring BootJAR
- Spring Boot 如何熱載入jar實現動態外掛?Spring BootJAR
- 基於 webpack 的 SPA 單頁 Web 應用 動態載入外掛的機制Web
- Android assets的一個bugAndroid
- Android進階(十)資源和Service的外掛化Android
- framework外掛化技術-類載入Framework
- 熱修復與外掛化基礎——Java與Android的類載入器JavaAndroid
- 圖片載入外掛imagesLoaded的配置和使用
- Android外掛化的相容性(中):Android P的適配Android
- Activity的外掛化(一)
- JQuery外掛:圖片上傳本地預覽外掛,改進案例一則。jQuery
- android: 動態載入碎片佈局的技巧Android
- 動態載入的一些坑
- Android動態載入jar/dexAndroidJAR
- web的自動化測試外掛Selenium-IDE外掛的安裝使用WebIDE
- Flutter外掛開發之APK自動安裝FlutterAPK
- 動態庫so打包到android apkAndroidAPK
- Android進階(九)Activity外掛化和VirtualApk分析AndroidAPK
- android apk巢狀 從一個apk啟動另外一個apkAndroidAPK巢狀
- Android Studio中的外掛ButterKnife的配置及其使用方法Android
- Android外掛化、熱補丁中繞不開的Proguard的坑Android