Gradle案例:apk构建、安装、启动一体化

背景

我们知道在调试时,只需要点击一下运行按钮就会自动为我们执行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就比较麻烦了,有两种解决办法:

  1. 直接写死
    这个最简单直观,由于我们的启动activity一般不会轻易去改,所以如果是通过修改module的build.gradle方式添加task,直接写死是可以接受的。但是如果是通过gradle插件的方式添加task很明显就不合适了。
  2. 通过解析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)
        //        at.dependsOn runTask  // 我们不需要改变原task的行为,所以这里注掉
    }
}

OK,以后就可以运行:gradlew app:assemebleXXXReleaseAndrRun来打包并直接安装启动啦!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值