ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MultiDex解析

2020-12-25 19:33:37  阅读:283  来源: 互联网

标签:files Log MultiDex IOException new 解析 data


1:dex如何分包:

在build.gradle里面设置:

defaultConfig {
        multiDexEnabled true
    }

自定义的application继承MultiDexApplication。

public class MyApplication extends MultiDexApplication {
       ..............   
}

 

2:MultiDexApplicatioin代码如何分包:

public class MultiDexApplication extends Application {
    public MultiDexApplication() {
    }

    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

1:MultiDex.install(this);

public static void install(Context context) {
        Log.i("MultiDex", "Installing application");
        if (IS_VM_MULTIDEX_CAPABLE) {
            Log.i("MultiDex", "VM has multidex support, MultiDex support library is disabled.");
        } else if (VERSION.SDK_INT < 4) {
            throw new RuntimeException("MultiDex installation failed. SDK " + VERSION.SDK_INT + " is unsupported. Min SDK version is " + 4 + ".");
        } else {
            try {
                ApplicationInfo applicationInfo = getApplicationInfo(context);
                if (applicationInfo == null) {
                    Log.i("MultiDex", "No ApplicationInfo available, i.e. running on a test Context: MultiDex support library is disabled.");
                    return;
                }
          // applicationInfo.sourceDir:获取应用存放数据目录  /data/app/package-2/base.apk
        // applicationInfo.dataDir: 存放数据的路径 应用数据目录 /data/data/com.example.admin.frameworkdemo doInstallation(context, new File(applicationInfo.sourceDir), new File(applicationInfo.dataDir), "secondary-dexes", "", true); } catch (Exception var2) { Log.e("MultiDex", "MultiDex installation failure", var2); throw new RuntimeException("MultiDex installation failed (" + var2.getMessage() + ")."); } Log.i("MultiDex", "install done"); } }
2:doInstallation:
private static void doInstallation(Context mainContext, File sourceApk, File dataDir, String secondaryFolderName, String prefsKeyPrefix, boolean reinstallOnPatchRecoverableException) throws IOException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException {
        synchronized(installedApk) {
        // 检查是否已经install过了,避免重复install if (!installedApk.contains(sourceApk)) { installedApk.add(sourceApk); if (VERSION.SDK_INT > 20) { Log.w("MultiDex", "MultiDex is not guaranteed to work in SDK version " + VERSION.SDK_INT + ": SDK version higher than " + 20 + " should be backed by " + "runtime with built-in multidex capabilty but it's not the " + "case here: java.vm.version=\"" + System.getProperty("java.vm.version") + "\""); } ClassLoader loader; try {
            // 获取到的是一个PathClassloader loader = mainContext.getClassLoader(); } catch (RuntimeException var25) { Log.w("MultiDex", "Failure while trying to obtain Context class loader. Must be running in test mode. Skip patching.", var25); return; } if (loader == null) { Log.e("MultiDex", "Context class loader is null. Must be running in test mode. Skip patching."); } else { try { clearOldDexDir(mainContext); } catch (Throwable var24) { Log.w("MultiDex", "Something went wrong when trying to clear old MultiDex extraction, continuing without cleaning.", var24); } // 构造存放classes.dex的目录/data/data/package/code_cache/secondary-dexes File dexDir = getDexDir(mainContext, dataDir, secondaryFolderName); MultiDexExtractor extractor = new MultiDexExtractor(sourceApk, dexDir); IOException closeException = null; // 将apk中的classes.dex提取并存放为data/data/package/code_cache/secondary-dexes/package--1.apk.classN.zip,以便后续加载到内存中。 try { List files = extractor.load(mainContext, prefsKeyPrefix, false); try {
                // 加载 installSecondaryDexes(loader, dexDir, files); } catch (IOException var26) { if (!reinstallOnPatchRecoverableException) { throw var26; } Log.w("MultiDex", "Failed to install extracted secondary dex files, retrying with forced extraction", var26); files = extractor.load(mainContext, prefsKeyPrefix, true); installSecondaryDexes(loader, dexDir, files); } } finally { try { extractor.close(); } catch (IOException var23) { closeException = var23; } } if (closeException != null) { throw closeException; } } } } }

3:getDexDir:

// 构造存放classes.dex的目录/data/data/package/code_cache/secondary-dexes


其中dataDir为: /data/data/package
secondaryFolderName为前面传进来的"secondary-dexes"
private static File getDexDir(Context context, File dataDir, String secondaryFolderName) throws IOException { File cache = new File(dataDir, "code_cache"); try { mkdirChecked(cache); } catch (IOException var5) { cache = new File(context.getFilesDir(), "code_cache"); mkdirChecked(cache); }
// /data/data/package/code_cache/secondary-dexes File dexDir = new File(cache, secondaryFolderName); mkdirChecked(dexDir); return dexDir; }
4:extractor.load: 
// 将apk中的classes.dex提取并存放为data/data/package/code_cache/secondary-dexes/package--1.apk.classN.zip,以便后续加载到内存中。
List<? extends File> load(Context context, String prefsKeyPrefix, boolean forceReload) throws IOException {
        Log.i("MultiDex", "MultiDexExtractor.load(" + this.sourceApk.getPath() + ", " + forceReload + ", " + prefsKeyPrefix + ")");
        if (!this.cacheLock.isValid()) {
            throw new IllegalStateException("MultiDexExtractor was closed");
        } else {
            List files;
            if (!forceReload && !isModified(context, this.sourceApk, this.sourceCrc, prefsKeyPrefix)) {
                try {
                    files = this.loadExistingExtractions(context, prefsKeyPrefix);
                } catch (IOException var6) {
                    Log.w("MultiDex", "Failed to reload existing extracted secondary dex files, falling back to fresh extraction", var6);
                    files = this.performExtractions();
                    putStoredApkInfo(context, prefsKeyPrefix, getTimeStamp(this.sourceApk), this.sourceCrc, files);
                }
            } else {
                if (forceReload) {
                    Log.i("MultiDex", "Forced extraction must be performed.");
                } else {
                    Log.i("MultiDex", "Detected that extraction must be performed.");
                }

                files = this.performExtractions();
                putStoredApkInfo(context, prefsKeyPrefix, getTimeStamp(this.sourceApk), this.sourceCrc, files);
            }

            Log.i("MultiDex", "load found " + files.size() + " secondary dex files");
            return files;
        }
    }

5:解析performExtractions

private List<MultiDexExtractor.ExtractedDex> performExtractions() throws IOException {
    // extractedFilePrefix = package-2.apk.classes
    String extractedFilePrefix = this.sourceApk.getName() + ".classes";
    this.clearDexDir();
    List<MultiDexExtractor.ExtractedDex> files = new ArrayList();
      // 获取apk的zip对象 ZipFile apk = new ZipFile(this.sourceApk); try { int secondaryNumber = 2; for(ZipEntry dexFile = apk.getEntry("classes" + secondaryNumber + ".dex"); dexFile != null; dexFile = apk.getEntry("classes" + secondaryNumber + ".dex")) {
         // fileName = package-2.apk.classes2.zip
         String fileName = extractedFilePrefix + secondaryNumber + ".zip";
         // dexDir:/data/data/package/code_cache/secondary-dexes MultiDexExtractor.ExtractedDex extractedFile = new MultiDexExtractor.ExtractedDex(this.dexDir, fileName);
// extractedFile:/data/data/package/code_cache/secondary-dexes/package-2.apk.classes2.zip files.add(extractedFile); Log.i("MultiDex", "Extraction is needed for file " + extractedFile); int numAttempts = 0; boolean isExtractionSuccessful = false; while(numAttempts < 3 && !isExtractionSuccessful) { ++numAttempts; extract(apk, dexFile, extractedFile, extractedFilePrefix); try { extractedFile.crc = getZipCrc(extractedFile); isExtractionSuccessful = true; } catch (IOException var18) { isExtractionSuccessful = false; Log.w("MultiDex", "Failed to read crc from " + extractedFile.getAbsolutePath(), var18); } Log.i("MultiDex", "Extraction " + (isExtractionSuccessful ? "succeeded" : "failed") + " '" + extractedFile.getAbsolutePath() + "': length " + extractedFile.length() + " - crc: " + extractedFile.crc); if (!isExtractionSuccessful) { extractedFile.delete(); if (extractedFile.exists()) { Log.w("MultiDex", "Failed to delete corrupted secondary dex '" + extractedFile.getPath() + "'"); } } } if (!isExtractionSuccessful) { throw new IOException("Could not create zip file " + extractedFile.getAbsolutePath() + " for secondary dex (" + secondaryNumber + ")"); } ++secondaryNumber; } } finally { try { apk.close(); } catch (IOException var17) { Log.w("MultiDex", "Failed to close resource", var17); } } return files; }

 

6:接上面的第2步骤里面的installSecondaryDexes

 private static void installSecondaryDexes(ClassLoader loader, File dexDir, List<? extends File> files) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException, SecurityException, ClassNotFoundException, InstantiationException {
        if (!files.isEmpty()) {
            if (VERSION.SDK_INT >= 19) {
                MultiDex.V19.install(loader, files, dexDir);
            } else if (VERSION.SDK_INT >= 14) {
                MultiDex.V14.install(loader, files);
            } else {
                MultiDex.V4.install(loader, files);
            }
        }

    }

install:将每一个.zip转化为DexPathList.Element,添加到DexPathListelements字段中

static void install(ClassLoader loader, List<? extends File> additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException {
            Field pathListField = MultiDex.findField(loader, "pathList");
            Object dexPathList = pathListField.get(loader);
            ArrayList<IOException> suppressedExceptions = new ArrayList();
            MultiDex.expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory, suppressedExceptions));
            if (suppressedExceptions.size() > 0) {
                Iterator var6 = suppressedExceptions.iterator();

                while(var6.hasNext()) {
                    IOException e = (IOException)var6.next();
                    Log.w("MultiDex", "Exception in makeDexElement", e);
                }

                Field suppressedExceptionsField = MultiDex.findField(dexPathList, "dexElementsSuppressedExceptions");
                IOException[] dexElementsSuppressedExceptions = (IOException[])((IOException[])suppressedExceptionsField.get(dexPathList));
                if (dexElementsSuppressedExceptions == null) {
                    dexElementsSuppressedExceptions = (IOException[])suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
                } else {
                    IOException[] combined = new IOException[suppressedExceptions.size() + dexElementsSuppressedExceptions.length];
                    suppressedExceptions.toArray(combined);
                    System.arraycopy(dexElementsSuppressedExceptions, 0, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length);
                    dexElementsSuppressedExceptions = combined;
                }

                suppressedExceptionsField.set(dexPathList, dexElementsSuppressedExceptions);
                IOException exception = new IOException("I/O exception during makeDexElement");
                exception.initCause((Throwable)suppressedExceptions.get(0));
                throw exception;
            }
        }

 

 

 

 

标签:files,Log,MultiDex,IOException,new,解析,data
来源: https://www.cnblogs.com/wnpp/p/14190479.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有