为了账号安全,请及时绑定邮箱和手机立即绑定

Android多渠道打包之速成大法

标签:
Android

前言


目的  多渠道主要目的是为了统计各个应用市场用户数据分析(比如活跃数,崩溃率等),收集用户信息,这时需要唯一标识来区分这些渠道,本文主要针对多渠道(几百个渠道甚至更多的情况)如何快速打包?

  • Jenkins集成Gradle实现打包自动化

  • 通过Jenkins参数化构建实现自定义环境和渠道打包,签名

  • 测试包自动上传fir并通过钉钉发送通知

  • 正式包按版本归档到OSS,发布时拷贝包到发布目录

  • 自动刷新CDN

环境说明

  • 系统 : Centos6.5 x64

  • jdk-7u79-linux-x64

  • android-sdk_r24.4.1-linux

  • gradle-2.2.1

  • Python-2.7.10(操作DingTalk和OSS API)

  • Jenkins2.0/Tomcat-7.0.65

配置环境

1.安装JDK


1

2

3

wget 'http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz?AuthParam=1460974294_526e0f8471004294cb163c9c730ba4f9' -O jdk1.7.0_79.tar.gz

tar xf jdk-7u79-linux-x64.tar.gz -C /usr/local/jdk1.7.0_79

 


2.安装Python2.7.10


1

2

3

4

5

6

7

8

wget https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz

tar xf Python-2.7.10.tgz

cd Python-2.7.10

./configure

make -j4

make install

sed -i 's#python/python2.6#g' /usr/bin/yum

 


3.安装Android的SDK


1

2

3

wget http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz

tar xf android-sdk_r24.4.1-linux.tgz -C /usr/local/android-sdk-linux

 


4.安装tomcat和jenkins


1

2

3

yum -y install tomcat

wget http://mirrors.jenkins-ci.org/war-rc/2.0/jenkins.war -O /usr/share/tomcat/webapps/jenkins.war

 


5.配置环境变量,启动服务


1

2

3

4

5

6

7

8

vim /etc/profile

export ANDROID_HOME=/usr/local/android-sdk-linux

export JAVA_HOME=/usr/local/jdk1.7.0_80

export PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

source /etc/profile

service tomcat start

Jenkins访问地址:http://192.168.2.2:8080/jenkins/

 


6.安装Android SDK依赖包


1

2

3

由于Android SDK工具基于32位在64位系统上需要安装32位必须安装的i386依赖库

yum install -y glibc.i686 glibc-devel.i686 libstdc++.i686 zlib-devel.i686 ncurses-devel.i686 libX11-devel.i686 libXrender.i686 libXrandr.i686

 


####安装更新对应版本的SDK


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

由于国内直接解析访问dl.google.com,dl-ssl.google.com域名较慢,可以通过更改hosts方式解决:

dig dl.google.com dl-ssl.google.com

将获得IP写入/etc/hosts,例如:

203.208.43.110 dl.google.com

74.125.23.91 dl-ssl.google.com

查看SDK相关列表

android  list sdk --all

Packages available for installation or update: 150

   1- Android SDK Tools, revision 25.1.1

   2- Android SDK Tools, revision 25.1.3 rc1

   3- Android SDK Platform-tools, revision 23.1

   4- Android SDK Platform-tools, revision 24 rc2

   5- Android SDK Build-tools, revision 24 rc3

   6- Android SDK Build-tools, revision 23.0.3

   7- Android SDK Build-tools, revision 23.0.2

   8- Android SDK Build-tools, revision 23.0.1

   9- Android SDK Build-tools, revision 23 (Obsolete)

  10- Android SDK Build-tools, revision 22.0.1

  11- Android SDK Build-tools, revision 22 (Obsolete)

  12- Android SDK Build-tools, revision 21.1.2

  13- Android SDK Build-tools, revision 21.1.1 (Obsolete)

  14- Android SDK Build-tools, revision 21.1 (Obsolete)

  15- Android SDK Build-tools, revision 21.0.2 (Obsolete)

  16- Android SDK Build-tools, revision 21.0.1 (Obsolete)

  17- Android SDK Build-tools, revision 21 (Obsolete)

  18- Android SDK Build-tools, revision 20

  19- Android SDK Build-tools, revision 19.1

  20- Android SDK Build-tools, revision 19.0.3 (Obsolete)

  21- Android SDK Build-tools, revision 19.0.2 (Obsolete)

  22- Android SDK Build-tools, revision 19.0.1 (Obsolete)

  23- Android SDK Build-tools, revision 19 (Obsolete)

  24- Android SDK Build-tools, revision 18.1.1 (Obsolete)

  ...

选择要安装项目的序号

android  update sdk -u -a -t 5,6,7,31,34,136,137

 


手动编译测试Android项目


1

2

3

4

5

6

7

8

9

10

11

12

13

git clone git@git.maka.mobi:android/Android_demo.git

cd Android_demo

查看当前项目包含的tasks(此时若无gradle会自动下载安装)

./gradlew  tasks

清空build目录

./gradlew clean

编译打包所有环境包

./gradlew assemble

编译打包Debug包

./gradlew assembleDebug

编译打包Release包

./gradlew assembleRelease

 


多渠道打包项目改造

  1. 包的签名在build.gradle中配置,打包后自动签名

  2. 由于META-INF目录下是存放签名信息的,用来保证apk包的完整性和安全,在生成apk时对文件做校验计算并把结果存放在META-INF目录中,安装apk包时应用管理器会按照同样的算法对包里的文件做校验,如果和META-INF中的内容不一致,则无法安装,通过修改apk包在重新打包基本不可能,以此来保证apk包的安全,因此在打完第一个包时,可以在META-INF目录中添加一个channel_wandoujia空文件,代码匹配这个文件获取渠道名wandoujia,来快速实现多渠道打包的目的

  3. 代码库根目录channel文件存放渠道名


1

2

3

4

5

6

7

8

9

10

11

12

13

14

apk包解压后目录结构:

├── AndroidManifest.xml

├── assets

├── classes.dex

├── lib

├── META-INF

│   ├── CERT.RSA

│   ├── CERT.SF

│   ├── channel_huawei

│   └── MANIFEST.MF

├── org

├── res

└── resources.arsc

 



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

Gradle(apk通过gradle签名)例子app/build.gradle:

apply plugin: 'com.android.application'

android {

    compileSdkVersion 22

    buildToolsVersion '23.0.2'

    defaultConfig {

        applicationId "com.maka.app"

        minSdkVersion 16

        targetSdkVersion 22

        versionCode 16

        versionName '2.0.0'

 

        //dex突破65535的限制

        multiDexEnabled true

    }

    dexOptions {

        jumboMode = true

        incremental true

        javaMaxHeapSize "4g"

        preDexLibraries = false

        incremental true

    }

    signingConfigs {

        debug {

            storeFile file("../key.jks")

            storePassword "helloworld"

            keyAlias "helloworld"

            keyPassword "helloworld"

        }

 

 

    }

    packagingOptions {

        exclude 'META-INF/LICENCE.txt'

        exclude 'META-INF/LICENSE.txt'

        exclude 'META-INF/NOTICE.txt'

    }

    lintOptions {

        checkReleaseBuilds false

        // Or, if you prefer, you can continue to check for errors in release builds,

        // but continue the build even when errors are found:

        abortOnError false

    }

    buildTypes {

        debug {

            // 显示Log

            buildConfigField "boolean", "LOG_DEBUG", "true"

            versionNameSuffix "-debug"

            minifyEnabled false

            zipAlignEnabled true

            shrinkResources false

            signingConfig signingConfigs.debug

            manifestPlaceholders = [

                    UMENG_APP_KEY   : "556ac653162s58e06c0000218",

                    UMENG_APP_SECRET: "2a231041d6aa10ec2b2s933003135a7"

            ]

            //Server config

            buildConfigField "boolean", "SELECT_SERVER", "true"

            buildConfigField "String", "TEST_IP", "\"http://test.api.simlinux.com/\""

            buildConfigField "String", "TEST_PROJECT_URL", "\"http://test.viewer.simlinux.com/k/\""

            buildConfigField "String", "TEST_PICTURE_URL", "\"http://test.img1.simlinux.com/\""

            buildConfigField "String", "TEST_RES_URL", "\"http://test.res.simlinux.com/\""

            buildConfigField "String", "FORMAL_IP", "\"http://api.simlinux.com/\""

            buildConfigField "String", "FORMAL_PROJECT_URL", "\"http://viewer.simlinux.com/k/\""

            buildConfigField "String", "FORMAL_PICTURE_URL", "\"http://img1.simlinux.com/\""

            buildConfigField "String", "FORMAL_RES_URL", "\"http://res.simlinux.com/\""

 

        }

        release {

            // 不显示Log

            buildConfigField "boolean", "LOG_DEBUG", "false"

            minifyEnabled true

            zipAlignEnabled true

            // 移除无用的resource文件

            shrinkResources true

            proguardFile 'proguard-project.txt'

            debuggable false

            shrinkResources false

            signingConfig signingConfigs.debug

            manifestPlaceholders = [

                    UMENG_APP_KEY   : "556ac6s3162358e06c0000218",

                    UMENG_APP_SECRET: "2a231041d6aa10ec2b2s933003135a7"

            ]

            //Server config

            buildConfigField "boolean", "SELECT_SERVER", "false"

            buildConfigField "String", "TEST_IP", "\"\""

            buildConfigField "String", "TEST_PROJECT_URL", "\"\""

            buildConfigField "String", "TEST_PICTURE_URL", "\"\""

            buildConfigField "String", "TEST_RES_URL", "\"\""

            buildConfigField "String", "FORMAL_IP", "\"http://api.simlinux.com/\""

            buildConfigField "String", "FORMAL_PROJECT_URL", "\"http://viewer.simlinux.com/k/\""

            buildConfigField "String", "FORMAL_PICTURE_URL", "\"http://img1.simlinux.com/\""

            buildConfigField "String", "FORMAL_RES_URL", "\"http://res.simlinux.com/\""

 

        }

 

    }

    applicationVariants.all { variant ->

        variant.outputs.each { output ->

            def outputFile = output.outputFile

            if (outputFile != null && outputFile.name.endsWith('.apk')) {

                def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionName}.apk")

                output.outputFile = new File(outputFile.parent, fileName)

            }

        }

    }

    productFlavors {

    }

 

}

 

repositories {

    flatDir {

        dirs 'libs' //this way we can find the .aar file in libs

    }

}

dependencies {

    compile 'com.google.code.gson:gson:2.3.1'

    compile 'com.github.japgolly.android:svg-android:2.0.6'

    compile fileTree(dir: 'libs', include: ['*.jar'])

    compile 'com.android.support:appcompat-v7:22.2.0'

    compile 'com.github.rey5137:material:1.2.1'

    compile 'com.squareup.okhttp:okhttp-apache:2.4.0'

    compile(name: 'vds-sdk-release', ext: 'aar')

    compile 'com.android.support:multidex:1.0.0'

    compile project(':PushSDK')

    compile 'com.google.zxing:core:3.2.1'

    compile 'com.android.support:recyclerview-v7:24.0.0-alpha1'

    compile 'com.rengwuxian.materialedittext:library:2.1.4'

}

 



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

匹配META-INF/channel_wandoujia文件名读取wandoujia渠道

 

    public static String readChanel() {

        ApplicationInfo appInfo = ContextManager.getContext().getApplicationInfo();

        String sourceDir = appInfo.sourceDir;

        String ret = "";

        ZipFile zipfile = null;

        Log.i(TAG, "---begin-ret=" + ret);

        try {

            zipfile = new ZipFile(sourceDir);

            Enumeration<?> entries = zipfile.entries();

            while (entries.hasMoreElements()) {

                ZipEntry entry = ((ZipEntry) entries.nextElement());

                String entryName = entry.getName();

                if (entryName.startsWith("META-INF/channel")) {

                    ret = entryName;

                    break;

                }

            }

        } catch (IOException e) {

            e.printStackTrace();

        } finally {

            if (zipfile != null) {

                try {

                    zipfile.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

 


Android多渠道打包流程

基于上述方式实现多渠道打包流程如下:

  • 执行gradlew clean清除build目录

  • 执行gradlew assemble编译打包Debug/Release(已自动签名)

  • 上传Debug包到Fir

  • 通过DingTalk发送通知信息到QA讨论组(发送提测apk包版本,下载地址及扫描下载二维码)

  • 提测不通过,修复bug后再次执行前四步

  • 提测通过后,点击Jenkins打包归档多渠道按钮,将执行生成多渠道包并归档包到本地目录/data/2.0.1/xxx.apk

  • 可选择此步上传归档文件到OSS

  • 点击Jenkins发布按钮将最新版本相关渠道归档拷贝至OSS发布目录

  • 刷新CDN生效

  • 通过DingTalk发送通知信息到QA讨论组哪些渠道已经发布

配置步骤

配置Jenkins


1

2

3

插件: Dynamic Choice Parameter

**创建打包测试项目:Android-Test**

 



1

2

3

4

通过Groovy脚本获取分支

def ver_keys = [ 'bash', '-c', 'cd /usr/share/tomcat/.jenkins/workspace/Android-Test;git branch -a|grep remotes|cut -d "/" -f3|grep -v HEAD|sort' ]

    ver_keys.execute().text.tokenize('\n')

 



1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

构建脚本

#!/bin/bash

 

PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/jdk1.7.0_80/bin:/usr/local/android-sdk-linux/tools:/usr/local/android-sdk-linux/platform-tools:/usr/local/gradle-2.2.1/bin:/usr/share/tomcat/bin

 

cd ${WORKSPACE}

git checkout ${BranchToDeploy}

git pull -f

 

if [ "${EnvToDeploy}"  = "All Env" ];then

 

        ${WORKSPACE}/gradlew clean

        ${WORKSPACE}/gradlew assemble

 

else

        ${WORKSPACE}/gradlew clean

        ${WORKSPACE}/gradlew assemble${EnvToDeploy}

 

fi

#测试包上传fir,发钉钉通知

/usr/local/bin/python /usr/share/tomcat/AndroidDeploy/androidtest.py

 


创建多渠道包归档项目:Android-Archive


1

2

3

4

5

6

获取channel列表

def ver_keys = [ 'bash', '-c', 'echo "All Channels"; cat /usr/share/tomcat/.jenkins/workspace/MAKA-Android-Testing/channels' ]

ver_keys.execute().text.tokenize('\n')

构建脚本,更改渠道文件,上传OSS,发送钉钉通知

python /usr/share/tomcat/AndroidDeploy/androidarchive.py

 


创建发布多渠道包项目:Android-Deploy


1

2

3

构建脚本,通过OSS API拷贝要发布的归档渠道包到发布目录,发送钉钉通知

python /usr/share/tomcat/AndroidDeploy/androiddeploy.py

 


相关脚本


1

2

3

4

5

6

7

8

9

10

11

12

├── androidarchive.py       多渠道打包归档脚本

├── androiddeploy.py        渠道包发布脚本

├── androidtest.py          测试打包脚本

└── libs

    ├── chinanetcenter.py   刷新CDN脚本

    ├── dingtalk.py         钉钉发送消息,图片,分享脚本

    ├── fir.py              测试包上传fir脚本

    ├── __init__.py

    └── libsoss.py          oss相关操作脚本(上传,拷贝等)

 

具体代码可根据https://github.com/geekwolf/AppDeployment按照实际业务进行修改

 


IOS打包流程

  • xcodebuild clean 清理build目录

  • xcodebuild archive 选择不同的环境/BundleID/ProvisionProfile/CodeSigningIdentify 编译,签名生成xcarchive文件放到工程根路径下的 build 文件夹里

  • xcodebuild -exportArchive 打包生成ipa

  • 测试包自动上传Fir,生产包手动更新AppStore

  • 具体可参考脚本https://github.com/geekwolf/AppDeployment/blob/master/IOSDeploy.sh

总结

任何自动化的前提必须先规范化,针对Android多渠道打包渠道命名,apk包命名需要先统一,apk包不要多环境混用(生产环境和测试环境要分离,测试包可自定义切换);到了这里,会发现我TM乱七八糟搞了这一陀哪里酸爽了?另外一个思路是通过修改apk文件的注释,程序在启动时读取apk文件注释获取渠道名(但是Android系统直到API 19,也就是4.4以上的版本才支持data/app/.apk)
爽在哪里?
1. 打包不再需要开发本地执行(避免中断开发,多人协作时优势更为明显)
2. 多渠道打包时间在于第一个包编译生成和签名的时间,之后的无论多少渠道都只是修改包的META-INF/channel_wandoujia空文件名实现
3. 点下Jenkins按钮无需在等待打包过程,打包完成后发送消息到钉钉会话,这下爽了吗?

原文链接:http://www.apkbus.com/blog-705730-60645.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消