Android Gradle:如何在应用安装后执行自定义任务
解决方案:Android Debug构建后安装启动前复制文件到应用私有目录
针对你遇到的Gradle任务顺序错乱、运行配置脚本不执行的问题,这里有几个经过验证的可行方案,帮你实现「构建→安装→复制文件→启动应用」的流程:
方案1:调整Gradle任务关联逻辑,精准绑定installDebug
你之前的问题出在任务匹配范围和依赖方向上——用startsWith('install')会匹配所有install相关任务,导致自定义任务被提前触发。正确的做法是直接针对Debug专属的安装任务,同时处理adb访问私有目录的权限问题:
- 在app模块的
build.gradle(或build.gradle.kts)中添加自定义任务:
// Groovy版本示例 task copyFilesToAppDir(type: Exec) { // 仅在Debug构建时生效 onlyIf { gradle.startParameter.taskNames.any { it.contains("Debug") } } // 明确依赖installDebug任务,确保安装完成后再执行 dependsOn tasks.named("installDebug") // 用run-as绕过root权限,直接访问应用私有目录 commandLine( "adb", "shell", "run-as", "com.your.package.name", "cp", "/sdcard/your/source/files/*", "/data/data/com.your.package.name/files/" ) // 可选:如果需要从本地电脑推送文件到设备,先执行push doFirst { exec { commandLine("adb", "push", "${project.rootDir}/local/files/", "/sdcard/your/source/files/") } } } // 让Debug启动任务依赖自定义复制任务 tasks.whenTaskAdded { task -> if (task.name == "appStartDebug") { // 对应Android Studio的Debug启动任务 task.dependsOn(copyFilesToAppDir) } }
现在点击Debug按钮时,流程会严格按照buildDebug→installDebug→copyFilesToAppDir→appStartDebug执行,完全符合你的预期。
方案2:修复Android Studio运行配置的Before Launch脚本
之前脚本不执行大概率是配置细节出错,按以下步骤调整:
- 打开Run/Debug Configurations,选中你的Debug配置
- 在Before Launch区域点击
+→选择Run External Tool→点击+新建工具:- Name: 自定义名称(比如
Copy Files to App) - Program: 填
/bin/bash(Windows用cmd.exe) - Arguments:
-c "adb shell run-as com.your.package.name cp /sdcard/your/source/files/* /data/data/com.your.package.name/files/" - Working directory: 留空或设为项目根目录
- Name: 自定义名称(比如
- 勾选
Execute in terminal(方便查看输出排查问题),保存配置 - 调整工具顺序:把这个脚本移到
Gradle-aware Make和Install之后
这样配置后,每次启动Debug都会先完成构建安装,再执行复制脚本,最后启动应用。
方案3:应用代码中Debug模式自动复制(兜底方案)
如果Gradle和运行配置的方案仍有问题,可以在应用启动时自动执行复制,这种方式不受构建工具限制:
- 在你的Application类中添加代码:
class MyApp : Application() { override fun onCreate() { super.onCreate() if (BuildConfig.DEBUG) { copyFilesToPrivateDir() } } private fun copyFilesToPrivateDir() { try { // 用Runtime执行adb命令,依赖设备已连接adb且应用是Debug签名 val process = Runtime.getRuntime().exec( arrayOf( "adb", "shell", "run-as", packageName, "cp", "/sdcard/your/source/files/*", filesDir.absolutePath ) ) process.waitFor() val exitCode = process.exitValue() if (exitCode == 0) { Log.d("CopyTask", "文件复制成功") } else { Log.e("CopyTask", "文件复制失败,退出码:$exitCode") } } catch (e: Exception) { Log.e("CopyTask", "复制出错", e) } } }
注意:这种方式需要应用有READ_EXTERNAL_STORAGE权限,Debug模式下可以通过权限申请弹窗获取。
内容的提问来源于stack exchange,提问作者Tobias Reich




