Baseline Profile

新环境

  • 当前所使用的Android Studio的版本为Android Studio Panda 4 | 2025.3.4 Patch 1
  • Gradle的版本为8.11.1
  • AGP的版本为8.9.2

新建模块

在项目中创建一个Baseline Profile Generator模块,在窗口的参数中,只说一下Target application,和Use Gradle Managed Device

其中,Target application是要生成的基准配置文件所对应的应用模块,Use Gradle Managed Device选中后,将模块设置为在自动管理的Android模拟器上运行基准配置文件生成器,使用真机的情况下,不需要勾选这个选项。完成后点击Finish

项目变化

完事之后,除了添加一个新模块之外,项目中还会发生如下的变化

  1. gradle目录下的libs.versions.toml配置文件
  2. 项目根目录下的build.gradle
  3. 项目根目录下的settings.gradle
  4. 项目根目录下的gradle.properties
  5. app模块的build.gradle

libs.versions.toml

会增加如下配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[versions]
uiautomator = "2.3.0"
benchmarkMacroJunit4 = "1.4.1"
baselineprofile = "1.4.1"
profileinstaller = "1.4.1"

[libraries]
androidx-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" }
androidx-benchmark-macro-junit4 = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "benchmarkMacroJunit4" }
androidx-profileinstaller = { group = "androidx.profileinstaller", name = "profileinstaller", version.ref = "profileinstaller" }

[plugins]
android-test = { id = "com.android.test", version.ref = "agp" }
baselineprofile = { id = "androidx.baselineprofile", version.ref = "baselineprofile" }

如果引入上面的配置,实际上相当于

1
2
3
4
5
6
7
8
9
10
// libraries
implementation 'androidx.test.uiautomator:uiautomator:2.3.0'
implementation 'androidx.benchmark:benchmark-macro-junit4:1.4.1'
implementation 'androidx.profileinstaller:profileinstaller:1.4.1'

// plugins
plugins {
id 'com.android.test' version '8.9.2' apply false
id 'androidx.baselineprofile' version '1.4.1' apply false
}

project:build.gradle

在项目根目录下的build.gradle文件中,会增加如下配置,声明了两个插件的版本,之后在app模块的build.gradle文件中再声明时无需注明版本号

1
2
3
4
plugins {
alias(libs.plugins.android.test) apply false
alias(libs.plugins.baselineprofile) apply false
}

settings.gradle

没什么好说的,增加了一个模块的引用

1
include ':baselineprofile'

gradle.properties

gradle.properties文件中,会增加如下配置,启用Gradle的配置缓存功能,以加快构建速度

1
org.gradle.configuration-cache=true

app:build.gradle

app模块的build.gradle文件中会增加如下配置,其中:

  1. baselineProfile project(':baselineprofile')依赖项,让Gradle知道应该从哪个模块获取已生成的基准配置文件
  2. profileinstaller依赖项,应用首次启动时,它会读取并安装打包在APK中的基准配置文件,告诉Android Runtime(ART)哪些代码路径需要提前编译(AOT)
1
2
3
4
5
6
7
8
9
10
plugins {
// 新增
alias(libs.plugins.baselineprofile)
}

dependencies {
// 新增
implementation libs.androidx.profileinstaller
baselineProfile project(':baselineprofile')
}

Baseline Profile模块配置

Baseline Profile Generator模块的build.gradle文件中,简单分析一下如下配置

alias(libs.plugins.android.test)声明了这是一个测试模块

1
2
3
4
5
plugins {
alias(libs.plugins.android.test)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.baselineprofile)
}

targetProjectPath指定了要生成基准配置文件的目标应用模块,animationsDisabled则是自动关闭设备动画,保证测试结果稳定

1
2
3
4
5
6
7
8
android {
targetProjectPath = ":app"

testOptions {
// 自动关闭设备动画,保证测试结果稳定。
animationsDisabled = true
}
}

baselineProfile配置项中,启用useConnectedDevices选项,让生成器在连接的设备上运行测试,以收集基准配置文件数据

1
2
3
baselineProfile {
useConnectedDevices = true
}

如下依赖项,其中:

  1. benchmark-macro-junit4是基准测试框架
  2. espresso-coreuiautomator是用于编写用户界面测试的库
  3. junit是用于编写单元测试的库
1
2
3
4
5
6
dependencies {
implementation libs.androidx.benchmark.macro.junit4
implementation libs.androidx.espresso.core
implementation libs.androidx.junit
implementation libs.androidx.uiautomator
}

其他配置

实际上,在有了上面的配置之后,项目就已经具备了生成基准配置文件的能力了,但是在生成之前,我们还需要对baselineprofile模块进行一些额外的配置

app模块的build.gradle文件中,增加如下配置,让启动热点代码尽可能位于DEX前部,减少启动时的随机I/O和页面加载时间,在较新的gradle版本中,这个配置项已经被默认启用

1
2
3
4
baselineProfile {
// 让启动热点代码尽可能位于 DEX 前部
dexLayoutOptimization = true
}

编写测试用例

BaselineProfileRule负责采集性能数据和Profile,并将其转换为基准配置文件格式,UIAutomator负责点击、滑动、长按、输入等用户界面交互操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@get:Rule
val rule = BaselineProfileRule()

@Test
fun generate() {
rule.collect(
packageName = TARGET_PACKAGE,
includeInStartupProfile = true
) {
// 模拟按下 Home 键
pressHome()
// 启动 Activity
startActivityAndWait()

/*
* device 实际上是 UiDevice
* 等价于UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
*/

// 等待页面加载
device.waitForIdle()
}
}

查找text为 分类 的view并点击

1
2
3
device.findObject(
By.text("分类")
)?.click()

通过资源id匹配view并点击

1
2
3
4
5
6
7
device.findObject(
By.res(TARGET_PACKAGE, "btn_login")
)?.click()

device.findObject(
By.res("${TARGET_PACKAGE}:id/btn_login")
)?.click()

RecyclerView滚动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 通过资源 id 匹配 recyclerView
val list = device.findObject(
By.res(
TARGET_PACKAGE,
"rv_list"
)
)
// 获取 recyclerView 的可见区域
val rect = list.visibleBounds
// 滑动 recyclerView 3 次
device.swipe(
rect.centerX(),
rect.bottom - 100,
rect.centerX(),
rect.top + 100,
3
)

还有很多,用到的时候再查文档吧

生成基准配置文件

在旧的AGP版本中,执行如下命令(其中:baselineprofile是模块名),会在连接的设备上运行测试用例,收集性能数据,并生成基准配置文件

1
./gradlew :baselineprofile:generateBaselineProfile

但是AGP 8.2+以后,这个Taskapp模块上了,所以执行如下命令

1
./gradlew :app:generateBaselineProfile

也有可能Task名字变了,执行如下命令查看一下指定的模块中有没有相应的Task

1
./gradlew :baselineprofile:tasks --all

打包

生成基准配置文件之后,如果配置文件路径没在main目录下,需要将生成的基准配置文件复制到app模块的src/main/baseline-prof.txt路径下,之后可以通过如下命令将其打包到APK

1
./gradlew :app:assembleRelease

参考:

  1. https://developer.android.com/topic/performance/baselineprofiles/overview
  2. https://codelabs.developers.google.com/android-baseline-profiles-improve