Gradle构建Android项目

本文参考自:https://segmentfault.com/a/1190000002910311

统一app和module的版本
默认写法:

compileSdkVersion 21    // 编译SDK的版本
buildToolsVersion '21.1.2'  // build tools的版本

defaultConfig {
  applicationId "com.xw.beidou"   // 应用的包名
  minSdkVersion 15
  targetSdkVersion 23
  versionCode 1
  versionName "1.0"
}

现在可以这样写

compileSdkVersion rootProject.ext.androidCompileSdkVersion
buildToolsVersion rootProject.ext.androidBuildToolsVersion

defaultConfig {
    applicationId "com.xw.beidou" 
    minSdkVersion 15
    targetSdkVersion rootProject.ext.androidTargetSdkVersion
    versionCode 1
    versionName "1.0"
}

然后在project的setting.gradle上加上

ext {
  androidBuildToolsVersion = "21.1.2"
  androidCompileSdkVersion = 21
  androidTargetSdkVersion = 23
}

gradle本身支持直接签名,只需要在releas部分添加如下代码即可

signingConfigs {
       debug {

       }
       release {
           storeFile file("../yourapp.keystore")
           storePassword "your password"
           keyAlias "your alias"
           keyPassword "your password"
       }
   }

   buildTypes {
       debug {
           minifyEnabled false
           zipAlignEnabled false
           shrinkResources false
           signingConfig signingConfigs.debug
       }

       release {
           minifyEnabled true//混淆编译
           zipAlignEnabled true
           //移除无用的资源文件
           shrinkResources true
           signingConfig signingConfigs.release
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
       }
   }

一般填上上面的代码即可执行签名,但是这种方式不太安全,建议不要在build.gradle文件中写上签名文件的密码,因为build.gradle文件一般都会集成到代码的版本控制中,这样所有人都会有签名文件的密码。

所以应该把签名文件的密码隔离起来,写到一个配置文件中,此配置文件不包含在代码版本控制中,这样其他开发者就不会知道签名文件的密码。

gradle配置文件一般以.properties结束,我们先新建一个signing.properties文件,内容如下:

STORE_FILE=yourapp.keystore
STORE_PASSWORD=your password
KEY_ALIAS=your alias
KEY_PASSWORD=your password

*注意没有字符串双引号”“*

接下在guild.gradle文件中读取signing.properties配置文件,读取的代码如下:

File propFile = file('signing.properties');
if (propFile.exists()) {
   def Properties props = new Properties()
   props.load(new FileInputStream(propFile))
   if (props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&
           props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {
       android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
       android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
       android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
       android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
   } else {
       android.buildTypes.release.signingConfig = null
   }
} else {
   android.buildTypes.release.signingConfig = null
}

代码很简单,就是读取文件,然后拿到签名需要的四个变量值分别赋值即可。

多渠道打包

美团Android自动化之旅—生成渠道包
由于国内Android市场众多渠道,为了统计每个渠道的下载及其它数据统计,就需要我们针对每个渠道单独打包。 gradle的多渠道打包很简单,因为gradle已经帮我们做好了很多基础功能。
下面以友盟统计为例说明,一般友盟统计在AndroidManifest.xml里面会有这么一段声明:

<meta-data
   android:name="UMENG_CHANNEL"
   android:value="CHANNEL_ID" />

其中CHANNEL_ID就是友盟的渠道标示,多渠道的实现一般就是通过修改CHANNEL_ID值来实现的。

接下来将一步一步来实现多渠道版本打包。

1.在AndroidManifest.xml里配置PlaceHolder,用与在build.gradle文件中来替换成自己想要设置的值

<meta-data
    android:name="UMENG_CHANNEL"
    android:value="${UMENG_CHANNEL_VALUE}" />

2.在build.gradle设置productFlavors,修改PlaceHolder的值

productFlavors {
    playStore {
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "playStore"]
    }
    miui {
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "miui"]
    }
    wandoujia {
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
    }
}

或者批量修改

productFlavors {
        playStore {}
        miui {}
        wandoujia {}
}
 //批量处理
productFlavors.all { 
       flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
}

按照上面两步即可编译打多渠道包了,命令是 ./gradlew assembleRelease,可以打包所有的多渠道包。

3.如果希望可以对最终的文件名做修改,如需要针对不同的需求生成不同的文件。而修改文件名也很简单,参考以下代码即可实现

def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

android{
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                File outputDirectory = new File(outputFile.parent);
                def fileName
                if (variant.buildType.name == "release") {
                    fileName =  "app_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                } else {
                    fileName = "app_v${defaultConfig.versionName}_${packageTime()}_debug.apk"
                }
                output.outputFile = new File(outputDirectory, fileName)
            }
        }
    }

}

此方法有一定局限性,就是渠道包多了之后编译花费的时间会很长,这里推荐美团打包的第三种方法。

buildConfigField自定义配置

大家可能会遇到下面这种情况,就是Beta版本服务器和Release版本服务器通常不在一台服务器上,而测试希望可以同时发布两个服务器的版本用于测试,这个时候我们就需要修改代码,然后一个一个老老实实的发包。gradle提供buildConfigField配合多渠道打不同服务器版本的方法。 其实用法很简单,首先在相应的节点加上定义,比如:

buildTypes {
    debug {
        buildConfigField "boolean", "LOG_DEBUG", "true"//是否输出LOG信息
        buildConfigField "String", "BASE_URL", '"http://xinwei.yixc.com/"'
        buildConfigField "String", "IMAGE_PREFIX_URL", '"http://rm-webapp-test.img-cn-hangzhou.aliyuncs.com/"'
       }
}

然后在代码中通过BuildConfig.LOG_DEBUG或者BuildConfig.API_HOST调用即可。

dex突破65535的限制

随着项目的一天天变大,慢慢的都会遇到单个dex最多65535个方法数的瓶颈,如果是ANT构建的项目就会比较麻烦,但是Gradle已经帮我们处理好了,而添加的方法也很简单,总共就分三步 :
1.首先是在defaultConfig节点使能多DEX功能

android {
    defaultConfig {
        // dex突破65535的限制
        multiDexEnabled true
    }
}

2.然后就是引入multidex库文件

dependencies {
   compile 'com.android.support:multidex:1.0.0'
}

3.最后就是你的AppApplication继承一下MultiDexApplication即可。

完整的gradle脚本

一份项目中使用的完整的gradle文件配置

// 声明是Android程序
apply plugin: 'com.android.application'

// 定义一个打包时间
def releaseTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

android {
    // 编译SDK的版本
    compileSdkVersion 21
    // build tools的版本
    buildToolsVersion '21.1.2'

    defaultConfig {
        // 应用的包名
        applicationId "com.**.*"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"

        // dex突破65535的限制
        multiDexEnabled true
        // 默认是umeng的渠道
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "umeng"]
    }

    // 移除lint检查的error
    lintOptions {
        abortOnError false
    }

    //签名配置
    signingConfigs {
        debug {
            // No debug config
        }

        release {
            storeFile file("../yourapp.keystore")
            storePassword "your password"
            keyAlias "your alias"
            keyPassword "your password"
        }
    }

    buildTypes {
        debug {
            // buildConfigField 自定义配置默认值
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "String", "API_HOST", "\"http://api.test.com\""//API Hos
            versionNameSuffix "-debug"
            minifyEnabled false
            //是否zip对齐
            zipAlignEnabled false
            shrinkResources false
            signingConfig signingConfigs.debug
        }

        release {
            // buildConfigField 自定义配置默认值
            buildConfigField "boolean", "LOG_DEBUG", "false"
            buildConfigField "String", "API_HOST", "\"http://api.release.com\""//API Host
             是否进行混淆
            minifyEnabled true
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //混淆规则文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release

            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    def outputFile = output.outputFile
                    if (outputFile != null && outputFile.name.endsWith('.apk')) {
                        // 输出apk名称为boohee_v1.0_2015-06-15_wandoujia.apk
                        def fileName = "boohee_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
                        output.outputFile = new File(outputFile.parent, fileName)
                    }
                }
            }
        }
    }

    // 友盟多渠道打包
    productFlavors {
        wandoujia {}
        _360 {}
        baidu {}
        xiaomi {}
        tencent {}
        taobao {}
        ...
    }

    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }
}

dependencies {
    // 编译libs目录下的所有jar包
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:21.0.3'
    compile 'com.jakewharton:butterknife:6.0.0'
    ...
}

查询签名

在Android Studio下,我们可以在命令行中通过输入命令来查询我们的应用签名信息:

keytool -list -v -keystore “E:\myfriendsshare.jks”

其中”E:myfriendsshare.jks”为我们刚才保存的签名相关文件的位置,在这里你直接替换成自己的文件位置即可。之后它会让你输入密码(注意,密码不会显示出来,输入之后点击回车就好)
查询结果如下:
这里写图片描述
其中SHA1的值即为应用的签名

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值