博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android multidex 将指定类打入class.dex
阅读量:6474 次
发布时间:2019-06-23

本文共 5886 字,大约阅读时间需要 19 分钟。

hot3.png

在app项目下新建multidex.keep文件,将指定类保存到此文件下

build.gradle中添加:(这个脚本将在编译项目的时候把multidex.keep 和 由Gradle生成的maindexlist.txt 结合在一起。)

android.applicationVariants.all { variant ->    task "fix${variant.name.capitalize()}MainDexClassList" << {        logger.info "Fixing main dex keep file for $variant.name"        File keepFile = new File("$buildDir/intermediates/multi-dex/$variant.buildType.name/maindexlist.txt")        keepFile.withWriterAppend { w ->            // Get a reader for the input file            w.append('\n')            new File("${projectDir}/multidex.keep").withReader { r ->                // And write data from the input into the output                w << r << '\n'            }            logger.info "Updated main dex keep file for ${keepFile.getAbsolutePath()}\n$keepFile.text"        }    }}tasks.whenTaskAdded { task ->    android.applicationVariants.all { variant ->        if (task.name == "create${variant.name.capitalize()}MainDexClassList") {            task.finalizedBy "fix${variant.name.capitalize()}MainDexClassList"        }    }}

 

附:

下面的方法是将App启动时查找加载除class.dex外的class文件:

  • 在你认为app启动结束的地方运行下面util类中的getLoadedExternalDexClasses 

  • 把上面这个方法返回的列表添加到你的 multidex.keep 文件然后重新编译。

public class MultiDexUtils {    private static final String EXTRACTED_NAME_EXT = ".classes";    private static final String EXTRACTED_SUFFIX = ".zip";    private static final String SECONDARY_FOLDER_NAME = "code_cache" + File.separator +            "secondary-dexes";    private static final String PREFS_FILE = "multidex.version";    private static final String KEY_DEX_NUMBER = "dex.number";    private SharedPreferences getMultiDexPreferences(Context context) {        return context.getSharedPreferences(PREFS_FILE,                Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB                        ? Context.MODE_PRIVATE                        : Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);    }    /**     * get all the dex path     *     * @param context the application context     * @return all the dex path     * @throws PackageManager.NameNotFoundException     * @throws IOException     */    public List
getSourcePaths(Context context) throws PackageManager.NameNotFoundException, IOException { final ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); final File sourceApk = new File(applicationInfo.sourceDir); final File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME); final List
sourcePaths = new ArrayList<>(); sourcePaths.add(applicationInfo.sourceDir); //add the default apk path //the prefix of extracted file, ie: test.classes final String extractedFilePrefix = sourceApk.getName() + EXTRACTED_NAME_EXT; //the total dex numbers final int totalDexNumber = getMultiDexPreferences(context).getInt(KEY_DEX_NUMBER, 1); for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++) { //for each dex file, ie: test.classes2.zip, test.classes3.zip... final String fileName = extractedFilePrefix + secondaryNumber + EXTRACTED_SUFFIX; final File extractedFile = new File(dexDir, fileName); if (extractedFile.isFile()) { sourcePaths.add(extractedFile.getAbsolutePath()); //we ignore the verify zip part } else { throw new IOException("Missing extracted secondary dex file '" + extractedFile.getPath() + "'"); } } return sourcePaths; } /** * get all the external classes name in "classes2.dex", "classes3.dex" .... * * @param context the application context * @return all the classes name in the external dex * @throws PackageManager.NameNotFoundException * @throws IOException */ public List
getExternalDexClasses(Context context) throws PackageManager.NameNotFoundException, IOException { final List
paths = getSourcePaths(context); if(paths.size() <= 1) { // no external dex return null; } // the first element is the main dex, remove it. paths.remove(0); final List
classNames = new ArrayList<>(); for (String path : paths) { try { DexFile dexfile = null; if (path.endsWith(EXTRACTED_SUFFIX)) { //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache" dexfile = DexFile.loadDex(path, path + ".tmp", 0); } else { dexfile = new DexFile(path); } final Enumeration
dexEntries = dexfile.entries(); while (dexEntries.hasMoreElements()) { classNames.add(dexEntries.nextElement()); } } catch (IOException e) { throw new IOException("Error at loading dex file '" + path + "'"); } } return classNames; } /** * Get all loaded external classes name in "classes2.dex", "classes3.dex" .... * @param context * @return get all loaded external classes */ public List
getLoadedExternalDexClasses(Context context) { try { final List
externalDexClasses = getExternalDexClasses(context); if (externalDexClasses != null && !externalDexClasses.isEmpty()) { final ArrayList
classList = new ArrayList<>(); final java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[]{String.class}); m.setAccessible(true); final ClassLoader cl = context.getClassLoader(); for (String clazz : externalDexClasses) { if (m.invoke(cl, clazz) != null) { classList.add(clazz.replaceAll("\\.", "/").replaceAll("$", ".class")); } } return classList; } } catch (Exception e) { e.printStackTrace(); } return null; }}

 

转载于:https://my.oschina.net/u/992018/blog/682948

你可能感兴趣的文章
Airbnb改进部署管道安全性,规范部署顺序
查看>>
腾讯最大规模裁撤中层干部,让贤年轻人
查看>>
当我们谈性能的时候,我们实际上在谈什么?
查看>>
i4o开源项目增强LINQ索引功能
查看>>
蔡超:入门 Go 语言必须跨越的五个思维误区
查看>>
使用Akka Actor和Java 8构建反应式应用
查看>>
curl常用命令详解
查看>>
saltstack 添加计划任务
查看>>
Puppet module命令参数介绍(六)
查看>>
《UNIX网络编程》中第一个timer_server的例子
查看>>
CISCO 路由器(4)
查看>>
网络服务搭建、配置与管理大全(Linux版)
查看>>
Silverlight 5 Beta新特性[4]文本缩进控制
查看>>
springMVC多数据源使用 跨库跨连接
查看>>
简单java在线测评程序
查看>>
Git服务端和客户端安装笔记
查看>>
Spring Security(14)——权限鉴定基础
查看>>
IntelliJ IDEA快捷键
查看>>
【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(下)
查看>>
MongoDB的基础使用
查看>>