背景
我们知道在调试时,只需要点击一下运行按钮就会自动为我们执行build ->install ->launch 三个动作,非常方便,然而到了release阶段,AS就没有为我们提供类似的快捷操作了。本文的初衷就是希望在release阶段实现与AS run App类似的一键操作,提高自测阶段的工作效率。
技术点
首先需要了解build ->install ->launch 这三个动作是如何实现的:
build :就是构建apk,相关的task为assemble<VariantName> ;install :借助adb,也就是我们熟知的adb install 命令;launch :借助adb,即adb shell am start 命令;
第一点我们只需要去hook对应的Task就好了,而且applicationVariant还提供了apk产物的具体文件路径,可以直接用到install 流程中。然后是启动,在安装成功后,启动apk需要知道apk的包名和启动activity,包名也可以从applicationVariant.applicationId 获取到,但是这个启动activity就比较麻烦了,有两种解决办法:
- 直接写死
这个最简单直观,由于我们的启动activity一般不会轻易去改,所以如果是通过修改module的build.gradle 方式添加task,直接写死是可以接受的。但是如果是通过gradle插件的方式添加task很明显就不合适了。 - 通过解析manifest获取
直接贴代码了:
String getLauncherActivityName(){
def file = android.sourceSets.main.manifest.srcFile
def root = new XmlParser().parse(file)
List<Node> activities = root.children().find {it.name()=='application'}.children().findAll{it.name()=='activity'}
def nameAttr = {Node node->node.attributes().keySet().find{it.localPart=='name'}}
Node main = activities.find {
def ifs = it.children()
if (ifs.isEmpty()) return false
return ifs.any {Node intentFilter->
def items = intentFilter.children()
def hasMainAction = items.any {
def attr = nameAttr(it)
return it.name()=='action'&&attr!=null&&it.attributes().get(attr)=='android.intent.action.MAIN'
}
def hasLauncherCategory = items.any {
def attr = nameAttr(it)
return it.name()=='category'&&attr!=null&&it.attributes().get(attr)=='android.intent.category.LAUNCHER'
}
return hasMainAction&&hasLauncherCategory
}
}
if (main==null) return null
return main.attributes().get(nameAttr(main))
}
特别需要注意这里返回的activity名称可能是相对包名,建议转成完整包名,上述代码是没有转换的
实现代码
至此实现相关功能的核心点都已罗列,这里给出最终实现代码:
afterEvaluate {
android.applicationVariants.each{ variant->
def at = tasks.findByName("assemble${variant.name.capitalize()}")
def outs = variant.outputs.matching {
it.outputFile != null && it.outputFile.name.endsWith('.apk')
}
if (outs.isEmpty()) return
println "variant.applicationId = ${variant.applicationId}"
def out = outs.first().outputFile
def runTask = task("${at.name}AndRun"){
group 'highway'
doFirst {
def startTime = System.currentTimeMillis()
def code = "adb install ${out.absolutePath}".execute().onExit().get().exitValue()
println "install result = $code, cost = ${(System.currentTimeMillis() - startTime)} ms."
if (code == 0) {
code = "adb shell am start ${variant.applicationId}/your.launch.Activity".execute().waitFor()
println "launch result = $code"
}
}
}
runTask.dependsOn at.taskDependencies.getDependencies(at)
}
}
OK,以后就可以运行:gradlew app:assemebleXXXReleaseAndrRun 来打包并直接安装启动啦!
|