文档概述

关于Android开发,除了技术方面需要掌握,还有发布流程需要了解。本文档就包括以上两个方面,主要介绍:

  • 使用配置文件配置不同功能的apk
  • 使用gradle为Android构建签名包
  • Jenkins集成Android自动化打包
  • 使用gradle为Android生成不同配置的签名包

一、场景描述

在项目开发中,我们可能有多个功能有区别但是整体框架一致的工程。

情景:我们有一app,基础功能包括a,b,c,扩张功能包括d,e,f,其中客户1需要扩展功能d,f,客户2需要e,f。

二、配置文件简介

鉴于以上场景,开发app过程应该怎么做?如果客户1创建一份工程代码,客户2创建一份工程代码效率就太低了。因此我们需要另辟思路,采用配置文件的方式进行开发。

配置文件分类

关于配置文件目前有两种方式:

  1. apk文件写注释
  2. apk源码属性文件

配置方式的区别

方式1主要适用于轻量的注释,例如书写渠道名等一些简单的注释,不用修改源码。方式2就比较适合当前的场景,但是缺点在于配置文件在源码部分,所以修改配置文件就必须修改源码。

配置文件的使用

关于方式1的使用,可以: 美团批量打包

基本原理就是在apk文件生成之后,修改apk文件的部分字段,而不影响apk本身签名验证,在源码中根据apk安装的位置获取安装包文件再读取其中的字段。

方式2就是使用属性文件。实现方式就是使用java.util.Properties类进行文件加载。
预先在Android工程的main文件夹下创建assets文件夹,里面存放配置文件,客户1的配置文件命名为:a.propertiesb.properties,里面的内容如下:

fun_a=truefun_b=truefun_c=truefun_d=truefun_e=falsefun_f=true

读取配置属性代码:

public String funX(Context context, String x){    Properties props = new Properties();    try {        props.load(context.getAssets().open("a.properties"));    //  props.load(context.getAssets().open("b.properties"));    } catch (IOException e) {        e.printStackTrace();    }    return props.getProperties("fun_" + x);}

在源码中根据对应函数的配置信息决定是否执行对应操作。

对于客户1和客户2的不同需求可以选择性的加载配置文件进行打包操作。

以上就是不同需求的具体操作。但是我们可以发现,这个操作效率太低,每次打包都要修改源码。下面介绍自动化过程。

三、 自动化之gradle打包

配置操作

为了之后可以执行自动化操作,签名必须也要能进行自动化执行。

首先放置签名文件到:项目的根目录。

modulebuild.gradle文件中添加以下内容:

apply plugin: 'com.android.application'def keystorePSW = ''def keystoreAlias = ''def keystoreAliasPSW = ''// default keystore file, PLZ config file path in local.propertiesProperties properties = new Properties()// local.properties file in the root directorproperties.load(project.rootProject.file('gradle.properties').newDataInputStream())keystorePSW = properties.getProperty("keystore.password")keystoreAlias = properties.getProperty("keystore.alias")keystoreAliasPSW = properties.getProperty("keystore.alias_password")android {    ...    signingConfigs {        release {            keyAlias keystoreAlias            keyPassword keystoreAliasPSW            storePassword keystorePSW            storeFile file('../xxx.jks')            // 签名文件的位置        }    }    buildTypes {        release {            minifyEnabled false            zipAlignEnabled true            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'            signingConfig signingConfigs.release        }    }}dependencies {    ...}

为了能够在Jenkins环境也能使用自动打包操作,在项目的根目录gradle.properties文件中添加如下内容:

keystore.password = xxx             // 密钥的密码keystore.alias = xxx                // 密钥的别称keystore.alias_password = xxx       // 别称的密码

随后在项目的根目录下使用gradle即可进行打包。

执行命令

打包命令:

gradlew clean               // 清除build文件夹// 二选一gradlew build               // 检查依赖并编译打包,会生成debug和release两个包gradlew assesmRelease       // 生成release包

执行以上命令之后,会在项目的app/build/output/apk/*.apk生成对应的apk。

注:Windows操作系统使用gradlew,Linux系统使用./gradlew

以上,使用gradle自动打包就以完成。下面就是集成Jenkins持续集成环境了。

四、Jenkins集成

创建项目

关于构建介绍可以参考:Jenkins+Gradle实现android开发持续集成、打包

配置信息没什么特别的。主要是输出文件路径:直接填写app/build/output/app/*.apk即可。

Android的持续化集成及多版本打包_第1张图片 输出文件路径

可能遇到的问题

  • 由于Jenkins自动构建,所以对语法要求比较严格。如果出现以下错误:

      FAILURE: Build failed with an exception.  * What went wrong:  Execution failed for task ':app:lint'.  > Lint found errors in the project; aborting build.       Fix the issues identified by lint, or add the following to your build script to proceed with errors:    ...    android {        lintOptions {            abortOnError false        }    }    ...    * Try:  Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

    这个是因为代码不符合规范,lint检查时报错,因此中断了整个编译过程。

    只要在当前app的app/build.gradle文件内增加如下代码:

      android{      ...      lintOptions{          abortOnError false      }      ...  }
  • 安装Jenkins配置局域网访问

    在mac安装Jenkins之后,局域网无法访问,原因在于使用brew安装jenkins会避免很多其他安装方式产生的用户权限问题,但是会将httpListenAddress默认设置为127.0.0.1,这样我们虽然可以在本地用localhost:8080访问,但是本机和局域网均无法用ip访问。解决办法为修改两个路径下的plist配置。

      ~/Library/LaunchAgents/homebrew.mxcl.jenkins.plist  /usr/local/opt/jenkins/homebrew.mxcl.jenkins.plist

    修改之后重启Jenkins即可访问。

      brew services start jenkins         // 开启服务  brew services stop jenkins          // 关闭服务  brew services restart jenkins       // 重启服务
  • 更多错误查看:

    使用Jenkins持续集成Android项目遇到的坑

通过以上操作,Android项目就可以使用Jenkins自动集成了。

但是我们第一部分的场景问题还是没有解决,如何自动化区分客户的版本呢?

五、自动化版本区分

Android官网介绍了 构建变体

通过配置不同的 productFlavors我们可以获取不同版本的apk。

因此第一部分的需求通过以下操作实现。

更新buidl.gradle文件

android {    ...    buildTypes {        ...    }    productFlavors {        fun_a {            buildConfigField "String", "CONF_NAME", "\"a.properties\""        }        fun_b {            buildConfigField "String", "CONF_NAME", "\"b.properties\""        }    }}
  • 注1:字段解释参考 GRADLE自定义你的BUILDCONFIG
  • 注2:使用String属性时候,值需要使用\"进行转义

修改读取配置文件代码

配置属性文件不变,读取的代码进行如下修改:

public String funX(Context contex, tString x){    Properties props = new Properties();    try {        props.load(context.getAssets().open(BuildConfig.CONF_NAME));    } catch (IOException e) {           e.printStackTrace();    }    return props.getProperties("fun_" + x);}

之后使用打包命令就会生成两个apk安装包,一个是客户1定制的功能,一个是客户2定制的功能。

输出路径不变,生成包名:

  • app-fun_a-releas.apk
  • app-fun_b-releas.apk

这样,Jenkins一次编译也就可以获取到正确的版本。

修改输出文件的包名

以上操作之后已经可以正确获取目标apk,但是并不直观。如果可以在输出文件名中添加输出版本号和打包时间就完美了。

在项目的build.gradle文件中,最后节点添加:

def releaseTime() {    return new Date().format("yyyyMMdd-HHmm", TimeZone.getTimeZone("GMT+08:00"))}android{    applicationVariants.all { variant ->        variant.outputs.each { output ->            def outputFile = output.outputFile            if (variant.buildType.name.equals('release')) {                def fileName = outputFile.name.replace("app-","").replace("release", "v${defaultConfig.versionName}-${releaseTime()}")                output.outputFile = new File(outputFile.parent, fileName)            }        }    }}

修改之后输出文件名:

fun_a-v2.0.5-20171115-1655.apkfun_b-v2.0.5-20171115-1655.apk

以上。

六、小结

通过使用gradle+Jenkins,可以让程序员从繁复的打包任务中解放出来,更多时间去做核心开发的相关业务。

gradle的功能强大到我没法想象,好好学习,好好钻研。

技术,可以解放你。

更多相关文章

  1. 一步一步学Android ROM开发(一)——修改现有ROM资源文件
  2. Android 多级菜单联动操作
  3. 浅谈如何在Eclipse下的Android工程配置Git的.gitignore文件
  4. (Android design)新闻资讯类android客户端开源拉
  5. Android遍历本地视频文件加过滤
  6. Android生成pdf文件之PdfDocument及踩过的坑
  7. Android(Java):jni写文件打印调试信息
  8. android客户端接入新浪、腾讯微博以及人人网
  9. Android配置----DDMS 连接真机(己ROOT),用file explore看不到data/

随机推荐

  1. PHP格式化日期,显示“刚刚,几分钟前,几小时
  2. 在多维数组中查找最小值并返回键
  3. PHP Word上的短网址
  4. 一个关于用php输出文件的问题(急)
  5. 您是否认为PHP中的错误形式是在类方法中
  6. 040-PHP使用闭包函数来进行父实例的变量
  7. 如何通过PHP将HTML页面作为字符串获取?
  8. Php DateTime :: setDate()不在第一个DateP
  9. 使用ajax在服务器端恢复json时出错
  10. 在Cake PHP中更新现有的sql数据