天天看点

android 手动分包,将指定class打包到主dex中

插件化开发时,想要使app启动很快,需要将主dex中只是包含首页以及基础模块的功能,其他的功能放到从dex文件中,这样就可以加快app的启动速度。那如何将核心首页以及基础模块的class文件打包到主dex文件中呢?下面来实现这个过程。

1.首先要是项目支持multidex,要是项目支持multidex,需要完成下面两个步骤

a.需要在module级别的build.gradle文件中配置

android {

    defaultConfig {

        // 设置支持multidex
        multiDexEnabled true

    }   
}

dependencies {
    //引入对multidex支持的库	
    compile 'com.android.support:multidex:1.0.1'

}
           

b.完成这些配置后,需要在自定义的application中的attachBaseContext方法中添加如下代码:

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

完成了这两个步骤后,项目才支持多dex。

2,要明确主dex文件中要包含哪些class文件,明确后,在module的build.gradle所在的目录下,新建一个maindexlist.txt文件,并将这些class文件所在的路径都写入到这个文件中。

3.在build.gradle文件中,在加入如下配置信息

android {

    defaultConfig {

        // 设置支持multidex
        multiDexEnabled true

    }  
    //新增的配置信息
    dexOptions{
	preDexLibraries = false
	additionalParameters = [    //配置multidex参数
	                                '--multi-dex',//多dex分包
	                                '--set-max-idx-number=30000',//每个包内方法数上限
	                                '--main-dex-list='+projectDir+'/maindexlist.txt', //打包到主classes.dex的文件列表
	                                '--minimal-main-dex'
	                            ]
	}
}

dependencies {
    //引入对multidex支持的库	
    compile 'com.android.support:multidex:1.0.1'

}
           

处理完后,打包apk,这样就会将maindexlist文件中指定的class文件打包到主dex文件中。这个就是将指定的class文件打包到主dex中的操作步骤,下面结合一个实际案例,来演示。

新建一个项目,在项目中新建一个名为plugin1的module,plugin1的结构如下图:

android 手动分包,将指定class打包到主dex中

上图中build.gradle的配置信息如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    buildToolsVersion "28.0.3"

    defaultConfig {
        applicationId "com.android.skill"
        minSdkVersion 14
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        // 设置支持multidex
        multiDexEnabled true

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    dexOptions{
        preDexLibraries = false
        additionalParameters = [    //配置multidex参数
                                    '--multi-dex',//多dex分包
                                    '--set-max-idx-number=30000',//每个包内方法数上限
                                    '--main-dex-list='+projectDir+'/maindexlist.txt', //打包到主classes.dex的文件列表
                                    '--minimal-main-dex'
                                ]
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:28.0.0'
    compile 'com.android.support.constraint:constraint-layout:1.1.3'
    testCompile 'junit:junit:4.12'
    androidTestCompile('com.android.support.test.espresso:espresso-core:+', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

    compile 'com.android.support:multidex:1.0.1'
    //依赖mypluglibrary库
    compile project(path:':mypluglibrary')
}
           

自定义的application中的代码如下:

import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;
import android.util.Log;

public class PluginOneApplication extends Application {
    private static final String TAG = "MY_LOG";

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

    @Override
    public void onCreate() {
        super.onCreate();
    }
}
           

maindexlist.txt文件中的信息如下(com/android/skill,这个是项目的包名):

com/android/skill/bean/Person.class
com/android/skill/MainActivity.class
com/android/skill/PluginOneApplication.class
com/android/skill/PluginReceiverOne.class
com/android/skill/PluginReceiverTwo.class
           

这些文件,可以在项目的文件夹目录下去查看(注意,不要通过AS的目录结构查看,因为通过AS的目录结构查看,会漏掉XXX$1.class这样的class文件),下面是本案例的这些class文件的位置

android 手动分包,将指定class打包到主dex中

将上图红框中这些class文件写入到maindexlist.txt文件中。

通过上面的步骤,就完成了将指定的class文件打包的主dex的功能。为了方便演示,指定和未定class到主dex的区别,新添加一个mypluglibrary库,将这个库的引入到plugin1这个module中,如果指定了只是将plugin1中的class文件打包到主dex中,则在生成的apk文件中,解压后是不会再主dex文件中看到mypluglibrary库的文件的。如果未指定将plugin1中的文件打包到主dex,则会在主dex中是可以看到mypluglibrary库中的 文件的。下面看看mypluglibrary库的结构图

android 手动分包,将指定class打包到主dex中

在plugin1这个module中依赖mypluglibrary这个库

dependencies {
      ...

    //依赖mypluglibrary库
    compile project(path:':mypluglibrary')

}
           

完成上述步骤后,执行plugin1这个module,找到生成的apk文件,将apk文件,拖动到AS中,可以看到如下

android 手动分包,将指定class打包到主dex中

从上图中,可以发现,确实使用多dex,图中有classes.dex和classes2.dex,其中,下面的大的红框中的就是在maindexlist.txt文件中指定的要将将这些文件打包打主dex的文件。

如果在plugin1的build.gradle文件中,去掉

additionalParameters = [    //配置multidex参数
                                    '--multi-dex',//多dex分包
                                    '--set-max-idx-number=30000',//每个包内方法数上限
                                    '--main-dex-list='+projectDir+'/maindexlist.txt', //打包到主classes.dex的文件列表
                                    '--minimal-main-dex'
                                ]
           

这个配置,在执行plugin1这个module,在将重新生成的apk包拖到AS中,可以看到:

android 手动分包,将指定class打包到主dex中

上图中,只有一个classes.dex,没有classes2.dex,并且,这个主classes.dex文件中是包含了依赖的库mypluglibrary的文件的,下面红框中的就是主dex文件包含的依赖库的文件。可以看出,未指定将哪些class文件放入到主dex,则在打包时,会根据单个dex的方法数是否会超过65535个方法来将主项目的类先添加后,如果方法数还未超过65535,则继续将依赖的库中的文件打包到主dex中。

如果在进行分包时报

java.io.FileNotFoundException: xxx\xxx\build\intermediates\transforms\dex\debug\folders\1000\1f\main\classes.dex\classes.dex (系统找不到指定的路径。)
           

则表示,项目还未支持multidex,需要进行multidex相关的配置,并在自定义的application中,调用MultiDex.install(this);方法。