当前位置: 移动技术网 > 移动技术>移动开发>Android > Gradle 常用配置总结

Gradle 常用配置总结

2018年09月12日  | 移动技术网移动技术  | 我要评论

这里分享下我在日常开发中对 gradle 的常用配置规则

一、版本号配置

当项目逐渐演进的过程中,主工程依赖的 module 可能会越来越多,此时就需要统一配置各个 module 的编译参数了

在工程的根目录下新建一个 gradle 文件,命名为 config.gradle,在此文件中统一声明工程的编译属性和依赖库的版本号

ext {
    compilesdkversion = 28
    minsdkversion = 15
    targetsdkversion = 28
    versioncode = 1
    versionname = '1.0'

    dependencies = [
            appcompatv7     : 'com.android.support:appcompat-v7:28.0.0-rc02',
            constraintlayout: 'com.android.support.constraint:constraint-layout:1.1.3',
            junit           : 'junit:junit:4.12',
            testrunner      : 'com.android.support.test:runner:1.0.2',
            espressocore    : 'com.android.support.test.espresso:espresso-core:3.0.2'
    ]

}

默认情况下,app modulebuild.gradle 文件的默认配置如下所示

apply plugin: 'com.android.application'

android {
    compilesdkversion 28
    defaultconfig {
        applicationid "leavesc.hello.gradlesamples"
        minsdkversion 15
        targetsdkversion 28
        versioncode 1
        versionname "1.0"
        testinstrumentationrunner "android.support.test.runner.androidjunitrunner"
    }
    buildtypes {
        release {
            minifyenabled false
            proguardfiles getdefaultproguardfile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation filetree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0-rc02'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testimplementation 'junit:junit:4.12'
    androidtestimplementation 'com.android.support.test:runner:1.0.2'
    androidtestimplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

这里将其改为引用 config.gradle 文件的形式

首先,需要在根目录下的 build.gradle 文件中应用 config.gradle 文件,这样在 module 配置文件中才引用得到当中的属性值

此时就可以修改应用版本号以及依赖库的声明方式了

apply plugin: 'com.android.application'

def globalconfiguration = rootproject.ext
def presentationdependencies = globalconfiguration.dependencies

android {
    compilesdkversion globalconfiguration["compilesdkversion"]
    defaultconfig {
        applicationid "leavesc.hello.gradlesamples"
        minsdkversion globalconfiguration["minsdkversion"]
        targetsdkversion globalconfiguration["targetsdkversion"]
        versioncode globalconfiguration["versioncode"]
        versionname globalconfiguration["versionname"]
        testinstrumentationrunner "android.support.test.runner.androidjunitrunner"
    }

    buildtypes {
        release {
            minifyenabled false
            proguardfiles getdefaultproguardfile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation filetree(include: ['*.jar'], dir: 'libs')
    implementation presentationdependencies.appcompatv7
    implementation presentationdependencies.constraintlayout
    testimplementation presentationdependencies.junit
    androidtestimplementation presentationdependencies.testrunner
    androidtestimplementation presentationdependencies.espressocore
}

这样,即使以后工程中包含多个 module ,只要配置的属性都是来自于 config.gradle 文件,就可以做到统一修改编译属性与依赖库版本了

二、签名属性配置

通常,应用的签名类型会分为 releasedebug 两类,并分别使用不同的签名文件
为了安全考虑以及实现自动化打包,可以通过 gradle 来声明签名配置,包括签名文件路径、签名别名、签名密码等
local.properties 文件中声明签名文件路径以及签名密码

sdk.dir=c\:\\software\\sdk
key.keystorepath=..\\doc\\key.jks
key.keyalias=leavesc
key.keypassword=987654321
key.storepassword=123456789

根据配置可知,签名文件是放在工程的 doc 文件夹内

通过代码获取到签名的各个配置项

properties properties = new properties()
properties.load(project.rootproject.file('local.properties').newdatainputstream())
def keystorepath_ = properties.getproperty("key.keystorepath")
def storepassword_ = properties.getproperty("key.storepassword")
def keyalias_ = properties.getproperty("key.keyalias")
def keypassword_ = properties.getproperty("key.keypassword")
def storefile_ = file(keystorepath_)

配置不同的签名属性以及 build 类型

    signingconfigs {
        release {
            storefile storefile_
            storepassword storepassword_
            keyalias keyalias_
            keypassword keypassword_
            v1signingenabled true
            v2signingenabled true
        }
        debug {
            storefile storefile_
            storepassword storepassword_
            keyalias keyalias_
            keypassword keypassword_
            v1signingenabled true
            v2signingenabled true
        }
    }

    buildtypes {
        debug {
            minifyenabled false
            proguardfiles getdefaultproguardfile('proguard-android.txt'), 'proguard-rules.pro'
            signingconfig signingconfigs.debug
        }
        release {
            minifyenabled true
            proguardfiles getdefaultproguardfile('proguard-android.txt'), 'proguard-rules.pro'
            signingconfig signingconfigs.release
        }
    }

此处,我配置了两种不同的 buildtypedebugrelease,并对应不同的签名文件

以后只要选定不同的 build variant,即可打包具体签名的 apk 文件

local.properties 文件可以保存到服务器来实现远程打包,从而保证了隐私安全

三、多渠道打包

有时候,为了方便进行精准营销,会有生成不同渠道包的要求,此时就需要在同个应用上打上不同的渠道id(channelid),这可以通过 productflavors 来实现
先在 androidmanifest.xml 文件中配置占位符,appkey 即对应各个渠道的 id 值

        <meta-data
            android:name="app_key"
            android:value="${appkey}" />

gradle.properties 文件中声明需要的 channelid以及对应的 applicationid,在此文件中声明的属性可以直接在 build.gradle 中直接获取到

#默认配置
defaultapplicationid=leavesc.hello.gradlesamples
##各个渠道的配置
#应用宝
yingyongbaochannelid="yingyongbao"
yingyongbaoapplicationid=leavesc.hello.gradlesamples.yingyongbao
yingyongbaoappkey=appkey_yingyongbao
#豌豆荚
wandoujiachannelid="wandoujia"
wandoujiaapplicationid=leavesc.hello.gradlesamples.wandoujia
wandoujiaappkey=appkey_wandoujia
#小米
xiaomichannelid="xiaomi"
xiaomiapplicationid=leavesc.hello.gradlesamples.xiaomi
xiaomiappkey=appkey_xiaomi

productflavors 可以理解为是对同个产品的不同“风味要求”,可以根据配置项生成特定风味的产品(app)
例如,此处就为不同渠道设定了不同的 applicationid

buildconfigfield 属性则用于在 buildconfig.java 文件中生成特定类型的字段,此处就生成了一个类型为 string ,名为 channelid 的字段,用于方便在应用运行过程中判断当前应用的渠道类型

manifestplaceholders 就是用于替换 androidmanifest.xml 文件中的指定占位符了

    productflavors {
        yingyongbao {
            applicationid yingyongbaoapplicationid
            buildconfigfield "string", "channelid", yingyongbaochannelid
            manifestplaceholders = [appkey: yingyongbaoappkey]
        }
        wandoujia {
            applicationid wandoujiaapplicationid
            buildconfigfield "string", "channelid", wandoujiachannelid
            manifestplaceholders = [appkey: wandoujiaappkey]
        }
        xiaomi {
            applicationid xiaomiapplicationid
            buildconfigfield "string", "channelid", xiaomichannelid
            manifestplaceholders = [appkey: xiaomiappkey]
        }
    }

在主布局文件中展示当前应用的各项属性值

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);
        stringbuilder sb = new stringbuilder();
        sb.append("applicationid: ");
        sb.append(getapplicationinfo().packagename);
        sb.append("\n");
        sb.append("applicationname: ");
        sb.append(getstring(getapplicationinfo().labelres));
        sb.append("\n");
        sb.append("channelid: ");
        sb.append(buildconfig.channelid);
        sb.append("\n");
        try {
            applicationinfo appinfo = getpackagemanager().getapplicationinfo(getpackagename(), packagemanager.get_meta_data);
            string appkey = appinfo.metadata.getstring("app_key");
            sb.append("appkey: ");
            sb.append(appkey);
        } catch (packagemanager.namenotfoundexception e) {
            e.printstacktrace();
        }
        textview tv_appinfo = findviewbyid(r.id.tv_appinfo);
        tv_appinfo.settext(sb);
        imageview iv_log = findviewbyid(r.id.iv_log);
        iv_log.setimageresource(getapplicationinfo().icon);
    }

四、打包时指定 apk 名字

为了方便标识各个测试包的版本已经打包时间,可以通过 gradle 来指定生成的 apk 文件的命名规则

例如,以下配置就根据 buildtype、flavorname编译时间 来命名 apk 文件

    applicationvariants.all { variant ->
        def buildtype = variant.buildtype.name
        def flavorname = variant.flavorname
        def createtime = new date().format("yyyy-mm-dd_hh_mm_ss", timezone.gettimezone("gmt+08:00"))
        variant.outputs.all {
            outputfilename = flavorname + "_" + buildtype + "_v" + defaultconfig.versionname + "_" + createtime + ".apk"
        }
    }

五、生成属性字段与资源文件值

上边讲过,buildconfigfield 属性可用于在 buildconfig.java 文件中生成特定类型的字段,此处可以利用其来记录应用的编译时间

此外,也可以利用 resvalue 来生成一个 id 引用类型的 string 字符串

首先,声明两个方法,分别用于获取当前时间以及当前电脑的用户信息

static def buildtime() {
    return new date().format("yyyy-mm-dd hh:mm:ss")
}

static def hostname() {
    return system.getproperty("user.name") + "@" + inetaddress.localhost.hostname
}
    defaultconfig {
        applicationid defaultapplicationid
        minsdkversion globalconfiguration["minsdkversion"]
        targetsdkversion globalconfiguration["targetsdkversion"]
        versioncode globalconfiguration["versioncode"]
        versionname globalconfiguration["versionname"]
        testinstrumentationrunner "android.support.test.runner.androidjunitrunner"
        flavordimensions '1'
        resvalue "string", "build_host", hostname()
        buildconfigfield "string", "build_time", "\"" + buildtime() + "\""
    }

用代码来获取这两个属性值

@override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);
        stringbuilder sb = new stringbuilder();
        sb.append("applicationid: ");
        sb.append(getapplicationinfo().packagename);
        sb.append("\n");
        sb.append("applicationname: ");
        sb.append(getstring(getapplicationinfo().labelres));
        sb.append("\n");
        sb.append("channelid: ");
        sb.append(buildconfig.channelid);
        sb.append("\n");
        sb.append("buildtime: ");
        sb.append(buildconfig.build_time);
        sb.append("\n");
        sb.append("builduser: ");
        sb.append(getstring(r.string.build_host));
        sb.append("\n");
        try {
            applicationinfo appinfo = getpackagemanager().getapplicationinfo(getpackagename(), packagemanager.get_meta_data);
            string appkey = appinfo.metadata.getstring("app_key");
            sb.append("appkey: ");
            sb.append(appkey);
        } catch (packagemanager.namenotfoundexception e) {
            e.printstacktrace();
        }
        textview tv_appinfo = findviewbyid(r.id.tv_appinfo);
        tv_appinfo.settext(sb);
        imageview iv_log = findviewbyid(r.id.iv_log);
        iv_log.setimageresource(getapplicationinfo().icon);
    }

六、替换资源文件

在多渠道打包时,除了需要在应用中打上特定的标签外,也可能需要使之使用不同的资源文件,例如应用图标和应用名称

此时可以以各个 productflavor 的名称来命名相应的文件夹,并在其中放置相应的图标文件以及声明了应用名称的 string.xml 文件,这样在多渠道打包时,gradle 就会自动引用相应的资源文件

上述所有的示例代码可以在这里获取:gradlesamples

更多的读书笔记可以看这里:一份关于 java 、kotlin 、 android 的学习笔记

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网