'Run' 按钮,一点下,Android Studio 就会开动,代码奇迹般地变成 APK,被安装到手机上,显示 APP 的界面。背后发生了什么?
点击 Run 按钮依次执行了 3 部分内容
- 检查项目和读取基本配置
- Gradle Build
- APK Install & Launch Activity
让我们继续,看看这个结论是怎么来的,以及一路上还发现了什么。
Android Studio 留下的面包屑
Android Studio 给我们留下了什么——日志
-
点击Android Studio 右下角 'Event Log'
android_studio_tab_event_log.PNG
20:55 Executing tasks: [:app:assembleDebug]
20:55 Gradle build finished in 16s 500ms
- 点击Android Studio 左下角的 '4:Run' android_studio_tab_run.PNG
06/25 20:55:44: Launching app
$ adb push F:\workspace\AndroidBuildProcess\app\build\outputs\apk\debug\app-debug.apk /data/local/tmp/com.example.buildprocess.androidbuildprocess
$ adb shell pm install -t -r "/data/local/tmp/com.example.buildprocess.androidbuildprocess"
pkg: /data/local/tmp/com.example.buildprocess.androidbuildprocess
Success
$ adb shell am start -n "com.example.buildprocess.androidbuildprocess/com.example.buildprocess.androidbuildprocess.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
根据日志,可见:
- 执行了 Gradle task:assembleDebug
- 安装 apk, 启动 MainActivity
assembleDebug/assembleRelease
执行的是 assembleRelease 还是 assembleDebug 实际是由 build variants 设置的类型决定的。
build_variants.PNG如果 Build Variants 修改为 Release ,点击 RUN 按钮后执行的就是 assembleRelease.
下面我们把 Build Variants 修改为 Release,点击 'RUN' 按钮,点击底部的 android_studio_tab_build.PNG,可以看到执行的 tasks 如下:
completed successfully 51s 886ms
Starting Gradle Daemon 2s 23ms
Run build 42s 250ms
Load build 1s 89ms
Configure build 6s 598ms
Calculate task graph 129ms
Run tasks 33s 806ms
Finalize build cache configuration 1ms
:app:preBuild 15ms
:app:preReleaseBuild 783ms
:app:compileReleaseAidl 173ms
:app:compileReleaseRenderscript 112ms
:app:checkReleaseManifest 12ms
:app:generateReleaseBuildConfig 45ms
:app:prepareLintJar 5ms
:app:mainApkListPersistenceRelease 34ms
:app:generateReleaseResValues 8ms
:app:generateReleaseResources 1ms
:app:mergeReleaseResources 7s 961ms
:app:createReleaseCompatibleScreenManifests 73ms
:app:processReleaseManifest 392ms
:app:splitsDiscoveryTaskRelease 32ms
:app:processReleaseResources 2s 134ms
:app:generateReleaseSources 1ms
:app:javaPreCompileRelease 865ms
:app:compileReleaseJavaWithJavac 2s 264ms
:app:compileReleaseNdk
:app:compileReleaseSources
:app:lintVitalRelease 4s 93ms
:app:mergeReleaseShaders 18ms
:app:compileReleaseShaders 11ms
:app:generateReleaseAssets
:app:mergeReleaseAssets 56ms
:app:transformClassesWithDexBuilderForRelease 2s 292ms
:app:transformDexArchiveWithExternalLibsDexMergerForRelease 6s 124ms
:app:transformDexArchiveWithDexMergerForRelease 1s 461ms
:app:mergeReleaseJniLibFolders 94ms
:app:transformNativeLibsWithMergeJniLibsForRelease 1s 749ms
:app:processReleaseJavaRes
:app:transformResourcesWithMergeJavaResForRelease 1s 653ms
:app:validateSigningRelease 4ms
:app:packageRelease 1s 133ms
:app:assembleRelease 1ms
为了更加详细的分析 assembleRelease 执行的内容,执行以下命令:
linux/macOS
./gradlew assembleRelease --info > output.txt
windows
gradlew.bat assembleRelease --info > output.txt
可以从 output.txt 文件看到详细的处理过程。
来自官方的说明
Android Stuido 打包流程
以下是 Android 官网的打包流程图,先学习一下。
build-process_2x.png
- 编译器将应用工程下的源码、资源文件、 AIDL 文件,依赖的 Module 、 AAR 库、 JAR 包转换成 DEX 文件, 其他的转换成已编译资源。
- 将 DEX 文件和已编译资源合并成单个 APK 。
- 使用 debug 或者 release keystore 对 APK 进行签名。
- 在生成最终的 APK 之前,打包器会使用 zipalign 工具对 APK 进行优化,以便减少在设备上运行时使用的内存。
APK 构建流程
APK 构建概览
build.pngAPK 构建详细流程
Android Build Process.png根据上图来说明一下构建的流程
图中使用的工具在哪里?
<SDK>/build-tools/<buildToolsVersion>/ 目录下
-
aapt(Android Asset Packaging Tool) 打包资源文件,生成 R.java 和已编译资源(二进制文件)
- Merge
* Merge Resources * Merge Manifest * Merge Assets
- aapt 工具将 Merged Resources 、Merged Manifest 、Merged Assets 处理生成 R.java 和 已编译资源
-
aidl(Android Interface Definition Language ) 文件处理
aidl 工具根据 aidl 文件生成 Java Classes
-
Java源码编译
Javac 编译 R.java 、Java 代码 、Java Classes 生成 .class 文件
-
代码混淆( proguard )
使用 ProGuard 工具进行混淆
-
转化为 dex 文件
dx 工具会将 .class 文件转化为 Dalvik 专用的 dex 文件
-
APK Builder
使用 sdklib.jar 的 ApkBuilder 类将 dex 文件、已编译资源打包生成 APK 文件。
-
对 APK 进行签名
使用 apksigner.jar 对 APK 进行签名
-
Zipalign 进行优化
使用 zipalign 工具对 APK 进行内存对齐
Android Studio 如何执行三个步骤
Android Run Configuration Execution Flow
The previous section talked about the overall execution flow. In this section, we look at the specific parts implemented within the android plugin. Overall, there are 3 parts to this:
- User presses Run/Debug. At this point,
AndroidRunConfigurationBase.getState
is called, and it constructs and returns anAndroidRunState
- The Gradle build is performed.
- Once the build is complete, the actual deployment is performed by the
AndroidRunState.execute
method.
以上是 Android Studio 对 IDEA 扩展中代码中对 Run Configuration 流程的说明。
AS 对 IDEA 扩展的代码放在:JetBrains/android。打包进 AS 之后,代码位于:ANDROID_STUDIO/plugins/android/lib/android.jar
使用以下工具查看 android.jar :
- jd-gui
- Luyten :如果 jd-gui 显示 '// INTERNAL ERROR //' ,不能显示类的内容,使用此工具
检查项目和读取基本配置
源代码位置:android/android/src/com/android/tools/idea/run/AndroidRunConfigurationBase.java
public RunProfileState getState(@NotNull Executor executor,
@NotNull ExecutionEnvironment env)
throws ExecutionException
{
// 验证项目( Gradle Sync 情况,是否是 Android 项目等)
validateBeforeRun(executor);
...
// 弹窗选择要安装的设备
deviceFutures = deployTarget.getDevices(deployTargetState, facet, getDeviceCount(isDebugging), isDebugging, getUniqueID());
...
// InstantRun 配置
if ((supportsInstantRun()) && (instantRunEnabled) && (existingSessionInfo != null))
{
...
}
...
return new AndroidRunState(env, getName(), module, applicationIdProvider, getConsoleProvider(), deviceFutures, providerFactory, processHandler);
}
可见:主要完成了对项目的检查,Instant Run 相关配置,选择安装设备等过程。
Gradle Build
在 RunState 创建完成之后,IDEA 允许你在执行之前,执行一些任务,比如一个 Java 项目在运行之前,你得编译。我们的 Android 项目也是类似,在安装和部署之前,你得编译打包。这个过程称之为:Before Launch。
gradle_aware_make.PNGAndroid Studio 默认为我们提供 Gradle-aware Make 。
如下面代码,本质上去执行了 Gradle Tasks,在 Debug 环境下默认是assembleDebug , 如果用户更改了 Build Variants 也会相应变化。
源代码位置:android/android/src/com/android/tools/idea/gradle/run/MakeBeforeRunTaskProvider.java
private static BeforeRunBuilder createBuilder(@NotNull final ExecutionEnvironment env,
@NotNull final Module[] modules,
@NotNull final RunConfiguration configuration,
@Nullable final AndroidRunConfigContext runConfigContext,
@Nullable final String userGoal) {
...
// 组装 Gradle task:gradle[:"assemble" + compileType]
if (deviceFutures == null || irContext == null) {
return new DefaultGradleBuilder(gradleTasksProvider.getTasksFor(BuildMode.ASSEMBLE, testCompileType), BuildMode.ASSEMBLE);
}
...
return new InstantRunBuilder(getLaunchedDevice(targetDevices.get(0)), irContext, runConfigContext, gradleTasksProvider);
}
源代码位置:android/android/src/com/android/tools/idea/gradle/project/build/invoker/GradleBuildInvoker.java
public void executeTasks(@NotNull final Request request) {
...
// 真正执行 Gradle 命令
final GradleTasksExecutor executor = this.myTaskExecutorFactory.create(request, this.myBuildStopper);
final GradleTasksExecutor gradleTasksExecutor;
final Runnable executeTasksTask = () -> {
this.myDocumentManager.saveAllDocuments();
gradleTasksExecutor.queue();
return;
};
...
}
APK Install & Launch Activity
源代码位置:android/android/src/com/android/tools/idea/run/AndroidRunState.java
在构建完成之后,会回到 RunState 的执行阶段,这一阶段应该叫做部署 : InstantRun 相关逻辑,版本判断,设备判断,输出日志,调用 pm 命令安装 APK,唤起首屏等等。
网友评论