月度归档:2017年02月

Android Studio让module library application并存的尝试

Published / by sickworm / Android Studio让module library application并存的尝试有4条评论

在做UAF的时候,我产生了一个需求:我希望我可以把demoUAF ClientUAF ASM分别打包成3个apk,又可以打包成1个apk。当分别打包的时候,UAF Client/UAF ASM是application;统一打包的时候,UAF Client/UAF ASM是library。我开始进行尝试。

方案1: 通过apply library 和 application plugin进行配置

初步想法

我希望在debug的时候,UAF Client/UAF ASM的build.gradle apply plugin: 'com.android.library',release的时候apply plugin: 'com.android.application'。我找到识别debug和release的方法:

var debug = gradle.getStartParameter().getTaskRequests().toString().contains("Debug")
if (debug) {
    apply plugin: 'com.android.library'
} else {
    apply plugin: 'com.android.application'
}

因为我需要在Generate Signed APK中可以选择UAF Client导出apk,所以需要默认是application。(gradle进行sync的时候会进行一次配置,此时debug变量恒为false)

因为library module无可以配置applicationId,所以还需要:

android {
    defaultConfig {
        if (!debug) {
            applicationId "com.*****"
        }
        // ......
    }
}

然后在demo中加入依赖:

debugCompile project(':asm')
debugCompile project(':client')

存在问题

如此配置导致的问题是gradle sync now失败。报错是“demo无法依赖一个application的module”。但不sync直接运行demo和Generate Signed APK都是可以的。一开始我以为是我debug判断条件有问题,使用println打印信息发现没有输出。

后来了解到gradle sync会遍历一遍gradle文件进行配置,再执行常规编译。在遍历过程中并没有**Debug这样的task进行判断,所以此时UAF Client/ASM是当作application来处理的。

初步想法改进

那为了可以sync成功,我只能把默认改为library了。

var debug = gradle.getStartParameter().getTaskRequests().toString().contains("Debug")
if (!debug) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

这样一来,我就无法使用Generate Signed APK导出UAF Client/UAF ASM了。但同时我发现了一个有趣的现象:在这个配置之下,我导出demo-release.apk的同时,UAF Client和UAF ASM的release.apk也一并导出了。我猜测是配置过程由于我判断条件的干扰导致的。我试着导出demo-debug.apk,UAF Client和UAF ASM还是导出release.apk,但大小和原来不一样了(原本debug版本是带日志的,会大一点)。生成物是正确的,但名字不对。

然后我把混合/独立的判断条件从debug/release改为flavor控制之后,出现了更多的问题。

结论

不可行。

方案2:新建一个module,引用原library/复用原library代码

方案2一听就是靠谱的。通过新建一个module,引用原library module,专门用于导出apk;或通过配置,复用library module的main文件夹:

android {
    sourceSets {
        main.setRoot("../asm/src/main")
    }
}

结论

可行。

思考

为什么我会没想到简单的方案2,而是在方案1中纠结良久,不可自拔呢?因为我不久之前在某个网站(貌似是简书)上看过一篇文章,它最后说明了如何调试多个apk,就是debug的时候把application的module改为library module,release的时候再独立打包。我只留了个印象,没有收藏这篇文章。而到了用到这个的时候我找不到原文章了,但我内心会一直认为该方案可行,且解决方法优雅。

我再想了想,其实合并多个apk对调试并没有什么优势,这样的编译时间反而更长,只让修改部分的apk重新安装还更快速。。

——————————

我再想了想,那篇文章好像讲的是多个独立模块调试时,可以拆开apk独立运行,不用一点修改就要重新打包整个工程,以提高速度。。不过有了 instant run 这个技巧也不是特别有用了。

版权所有,转载请注明出处:
http://sickworm.com/?p=313

Android Studio Gradle中buildTypes + flavor(flavor group, flavor dimensions)组合依赖编译,添加buildTypes

Published / by sickworm / Leave a Comment

最近在做UAF打包的事情,其中一个需求是根据debug/release和flavor来决定不同的依赖。比如debug情况下,我要打包带日志的,release情况下,我要打包带日志,不带日志,含其他module的,不含其他module的两两组合(也就是flavorDimensions)。现分享方法。

buildTypes + flavor(flavor group, flavor dimensions)组合依赖编译

参考build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "24.0.2"

    defaultConfig {
        applicationId "com.sickworm.test"
        minSdkVersion 10
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), '../proguard-rules-remove-logs.pro'
        }

        // keep log and stacktrace
        preview {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    flavorDimensions 'log', 'combine'

    productFlavors {

        withoutLogs {
            dimension 'log'
        }

        withLogs {
            dimension 'log'
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        standalone {
            dimension 'combine'
        }

        mixed {
            dimension 'combine'
        }
    }
}

// This works because when we combine the flavor+build type into variant and create their associated
// configuration objects, we only create them if they don't already exist. otherwise we reuse the ones that are created.
configurations {
    withoutLogsMixedReleaseCompile
    withLogsMixedReleaseCompile
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile project(':clientapplication')
    debugCompile project(':asm')
    debugCompile project(':client')
    withoutLogsMixedReleaseCompile project(':asm')
    withLogsMixedReleaseCompile project(':asm')
    withoutLogsMixedReleaseCompile project(':client')
    withLogsMixedReleaseCompile project(':client')
}

大家都用过简单的debugCompile, releaseCompile。如果是根据flavor来定义依赖,则是flavor1Compile,flavor2Compile(flavor1,flavor2为flavor名字)。但如果要使用buildTypes + flavor依赖,直接使用flavor1DebugCompile或debugFlavorCompile是不行的,会提示没有这个方法。

解决方法是使用configurations来预定义这个方法:Provide configurations for flavor+type combinations.。原因是,flavor+buildType的组合依赖在最开始检测的时候是不存在的,我们需要先用configurations定义出来,此时该组合是一个空的配置。等到编译期时,flavor+buildType已经被真正创建并重写了我们之前定义的空配置,所以此时编译用到的是正确的编译配置。我们预定义只是为了防报错。这个应该是设计缺陷吧。(gradle 2.2.3)

于是我兴高采烈的使用了mixedReleaseCompile,以达到mixed+Release的组合依赖。结果并没有依赖成功。

我想了半天,终于想到我用的是flavorDimensions(旧版gradle称为flavorGroups)特性,所以结果应该是定义withoutLogsMixedReleaseCompile和withLogsMixedReleaseCompile。(withoutLogsMixed这样才是真正的flavor名)。猜想正确,编译成功。

自定义buildTypes

后来我想,其实对于withLogs和withoutLogs这个flavorDimensions,我要的是一个正式发布前带日志但混淆过的版本,其实我可以定义一个preview版本,组成debug/preview/release三种发布版本。如何定义呢:

    buildTypes {
        preview {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

这样我就不需要用到flavorDimensions这个特性了。

注意:有些教程里会让你在signingConfig中创建一个同名的preview,其实如果没用到自动签名是不需要的

版权所有,转载请注明出处:
http://sickworm.com/?p=308