1,概念
1)Android的包文件APK分为两个部分:代码和资源,所以打包方面也分为资源打包和代码打包。
2,打包流程
1)通过AAPT工具进行资源文件(包括AndroidManifest.xml、布局文件、各种xml资源等)的打包,生成R.java文件。
2)通过AIDL工具处理AIDL文件,生成相应的Java文件。
3)通过Javac工具编译项目源码,生成Class文件。
4)通过DX工具将所有的Class文件转换成DEX文件,该过程主要完成Java字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工作。
5)通过ApkBuilder工具将资源文件、DEX文件打包生成APK文件。
6)利用KeyStore对生成的APK文件进行签名。
7)如果是正式版的APK,还会利用ZipAlign工具进行对齐处理,对齐的过程就是将APK文件中所有的资源文件举例文件的起始距离都偏移4字节的整数倍,这样通过内存映射访问APK文件的速度会更快。
3,APK的安装流程
1)复制APK到/data/app目录下,解压并扫描安装包。
2)资源管理器解析APK里的资源文件。
3)解析AndroidManifest文件,并在/data/data/目录下创建对应的应用数据目录。
4)然后对dex文件进行优化,并保存在dalvik-cache目录下。
5)将AndroidManifest文件解析出的四大组件信息注册到PackageManagerService中。
6)安装完成后,发送广播。
4,app启动过程
点击应用图标后会去启动应用的LauncherActivity,如果LancerActivity所在的进程没有创建,还会创建新进程,整体的流程就是一个Activity的启动流程。
1)主要角色
①Instrumentation
监控应用与系统相关的交互行为。
②AMS
组件管理调度中心,什么都不干,但是什么都管。
③ActivityStarter
Activity启动的控制器,处理Intent与Flag对Activity启动的影响,具体说来有:
1 寻找符合启动条件的Activity,如果有多个,让用户选择;
2 校验启动参数的合法性;
3 返回int参数,代表Activity是否启动成功。
④ActivityStackSupervisior
这个类的作用你从它的名字就可以看出来,它用来管理任务栈。
这是高版本才有的类,它用来管理多个ActivityStack,早期的版本只有一个ActivityStack对应着手机屏幕,后来高版本支持多屏以后,就有了多个ActivityStack,于是就引入了ActivityStackSupervisior用来管理多个ActivityStack。
⑤ActivityStack
用来管理任务栈里的Activity。
⑥ActivityThread
最终干活的人,是ActivityThread的内部类,Activity、Service、BroadcastReceiver的启动、切换、调度等各种操作都在这个类里完成。
2)相关进程
①调用者进程
如果是在桌面启动应用就是Launcher应用进程。
②ActivityManagerService等所在的System Server进程
该进程主要运行着系统服务组件。
③Zygote进程
该进程主要用来fork新进程。
④新启动的应用进程
该进程就是用来承载应用运行的进程了,它也是应用的主线程(新创建的进程就是主线程),处理组件生命周期、界面绘制等相关事情。
3)整个流程
①点击桌面应用图标,Launcher进程将启动Activity(MainActivity)的请求以Binder的方式发送给了AMS。
②AMS接收到启动请求后,交付ActivityStarter处理Intent和Flag等信息,然后再交给ActivityStackSupervisior/ActivityStack
③处理Activity进栈相关流程。同时以Socket方式请求Zygote进程fork新进程。
Zygote接收到新进程创建请求后fork出新进程。
④在新进程里创建ActivityThread对象,新创建的进程就是应用的主线程,在主线程里开启Looper消息循环,开始处理创建Activity。
⑤ActivityThread利用ClassLoader去加载Activity、创建Activity实例,并回调Activity的onCreate()方法。这样便完成了Activity的启动。
5,类加载器
1)PathClassLoader
只能加载已经安装到Android系统的APK文件,即/data/app目录,Android默认的类加载器。
2)DexClassLoader
可以加载任意目录下的dex、jar、apk、zip文件。
6,64k方法
1)问题
随着功能的增加,方法数增多,就会出现所谓的64k方法数问题。
2)产生原因
Android APK文件本质上是一个压缩文件,它包含的classes.dex文件是Dalvik字节码文件,这个dex文件中存放的就是编译后的Java代码。Dalvik可执行文件规范限制了单个.dex文件最多引用的方法数是65536个。
在DEX文件中,method、field、class等的个数使用short类型来做索引,即两个字节(65535),method、field、class等均有此限制。
APK在安装过程中会调用dexopt将DEX文件优化成ODEX文件,dexopt使用LinearAlloc来存储应用信息,关于LinearAlloc缓冲区大小,不同的版本经历了4M/8M/16M的限制,超出缓冲区时就会抛出INSTALL_FAILED_DEXOPT错误。
3)解决方案–MultiDex的使用
google为了规避上述问题,推出了MultiDex解决方案解决方法数超限问题,可以配置方法数超过 64K 的应用。
4)解决原理
①Android5.0之前
Dalvik在5.0之前,为每一个APK只生成一个classes.dex,所以会有上述所说的方法数超限的问题,如果我们可以将一个dex文件分成多个,在应用启动时,加载第一个(主dex)dex文件,当启动以后,再依次加载其他dex文件。这样就可以规避上述问题了。MultiDex即是实现了这样的功能
②Android5.0之后
Android5.0及更高版本使用支持从apk中加载多个dex文件的ART运行时机制,在应用安装时,加载classed(…N).dex文件并编译成一个.oat文件以支持在Android设备上运行。
5)实现
配置build.gradle
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"//必须使用21或之后的版本
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
配置Application
如果用户没有重写Application,只需修改Manifest文件中的内容:
<application
...
android:name="android.support.multidex.MultiDexApplication">
...
</application>
如果用户继承变重写了Application,可以将继承的Application换成MultiDexApplication。
或者重写attachBaseContext() 方法,
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
特别注意,如果没有实现这部分代码,运行时会出现NoClassDefFoundError的错误,尤其是在依赖三方函数库时。
这个问题之前出现过很多次,当时是由于配置了build.gradle文件但是没有使用MultiDexApplication造成的。所以开发者一定要记得使用MultiDexApplication或者MultiDex.install(this),具体参考上面提到过的配置Application。
还有一种情况,上面提到过的,使用MultiDex机制,必然存在主dex文件和从dex文件,应用启动时所需要的类,都应放入主dex中,否则也会出现NoClassDefFoundError。这种情况可以手动添加一些类到主dex中:
multiDexKeepFile
手动加入要放到Main.dex中的类。
android/support/multidex/MultiDex.class
multiDexKeepProguard
以Proguard的方式手动加入要放到Main.dex中的类。
-keep class android.support.multidex.** {
*;
}
然后在build.gradle中进行配置:
android {
defaultConfig {
multiDexEnabled true
multiDexKeepProguard file('multiDexKeep.pro')
multiDexKeepFile file('multiDexKeep.txt')
}
}
dependencies {
compile'com.android.support:multidex:1.0.1'
}
6)Multidex优化
multidex会加长构建应用的时间,这个必要的过程可能会拖慢你的开发进度。 为加速构建过程,我们可以在Gradle中配置productFlavors。
开发时将minSdkVersion改为21使用ART运行时机制,这样能加快构建速度。release时改为合适的minSdkVersion,这样仅在release时费时较长。
build.gradle配置如下:
android {
productFlavors {
dev {
minSdkVersion 21
}
prod {
minSdkVersion 14
}
}
...
buildTypes {
release {
...
}
}
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
完成上述配置后,你可以使用结合了dev productFlavor和buildType属性的devDebug变体app。
这个变体app包含如下特性:
关闭了混淆(proguard)
支持multidex
minSdkVersion 设置为 Android API level 21.
值得注意的是:上述配置后的devDebug变种app仅能运行在Android 5.0设备上。