Contents
多渠道主要目的是为了统计各个应用市场用户数据分析(比如活跃数,崩溃率等),收集用户信息,这时需要唯一标识来区分这些渠道,本文主要针对多渠道(几百个渠道甚至更多的情况)如何快速打包?
1.安装JDK
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 tarxfjdk-7u79-linux-x64.tar.gz -C /usr/local/jdk1.7.0_79
2.安装Python2.7.10
wgethttps://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz tarxfPython-2.7.10.tgz cdPython-2.7.10 ./configure make -j4 makeinstall sed -i 's#python/python2.6#g' /usr/bin/yum
3.安装Android的SDK
wgethttp://dl.google.com/android/android-sdk_r24.4.1-linux.tgz tarxfandroid-sdk_r24.4.1-linux.tgz -C /usr/local/android-sdk-linux
4.安装tomcat和jenkins
yum -y installtomcat wgethttp://mirrors.jenkins-ci.org/war-rc/2.0/jenkins.war -O /usr/share/tomcat/webapps/jenkins.war
5.配置环境变量,启动服务
vim /etc/profile exportANDROID_HOME=/usr/local/android-sdk-linux exportJAVA_HOME=/usr/local/jdk1.7.0_80 exportPATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools source /etc/profile servicetomcatstart Jenkins访问地址:http://192.168.2.2:8080/jenkins/
6.安装Android SDK依赖包
由于AndroidSDK工具基于32位在64位系统上需要安装32位必须安装的i386依赖库 yuminstall -y glibc.i686glibc-devel.i686libstdc++.i686zlib-devel.i686ncurses-devel.i686libX11-devel.i686libXrender.i686libXrandr.i686
####安装更新对应版本的SDK
由于国内直接解析访问dl.google.com,dl-ssl.google.com域名较慢,可以通过更改hosts方式解决: digdl.google.comdl-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 Packagesavailablefor installationor update: 150 1- AndroidSDKTools, revision 25.1.1 2- AndroidSDKTools, revision 25.1.3 rc1 3- AndroidSDKPlatform-tools, revision 23.1 4- AndroidSDKPlatform-tools, revision 24 rc2 5- AndroidSDKBuild-tools, revision 24 rc3 6- AndroidSDKBuild-tools, revision 23.0.3 7- AndroidSDKBuild-tools, revision 23.0.2 8- AndroidSDKBuild-tools, revision 23.0.1 9- AndroidSDKBuild-tools, revision 23 (Obsolete) 10- AndroidSDKBuild-tools, revision 22.0.1 11- AndroidSDKBuild-tools, revision 22 (Obsolete) 12- AndroidSDKBuild-tools, revision 21.1.2 13- AndroidSDKBuild-tools, revision 21.1.1 (Obsolete) 14- AndroidSDKBuild-tools, revision 21.1 (Obsolete) 15- AndroidSDKBuild-tools, revision 21.0.2 (Obsolete) 16- AndroidSDKBuild-tools, revision 21.0.1 (Obsolete) 17- AndroidSDKBuild-tools, revision 21 (Obsolete) 18- AndroidSDKBuild-tools, revision 20 19- AndroidSDKBuild-tools, revision 19.1 20- AndroidSDKBuild-tools, revision 19.0.3 (Obsolete) 21- AndroidSDKBuild-tools, revision 19.0.2 (Obsolete) 22- AndroidSDKBuild-tools, revision 19.0.1 (Obsolete) 23- AndroidSDKBuild-tools, revision 19 (Obsolete) 24- AndroidSDKBuild-tools, revision 18.1.1 (Obsolete) ... 选择要安装项目的序号 android updatesdk -u -a -t 5,6,7,31,34,136,137
gitclone git@git.maka.mobi:android/Android_demo.git cdAndroid_demo 查看当前项目包含的tasks(此时若无gradle会自动下载安装) ./gradlew tasks 清空build目录 ./gradlewclean 编译打包所有环境包 ./gradlewassemble 编译打包Debug包 ./gradlewassembleDebug 编译打包Release包 ./gradlewassembleRelease
apk包解压后目录结构: ├── AndroidManifest.xml ├── assets ├── classes.dex ├── lib ├── META-INF │ ├── CERT.RSA │ ├── CERT.SF │ ├── channel_huawei │ └── MANIFEST.MF ├── org ├── res └── resources.arsc
Gradle(apk通过gradle签名)例子app/build.gradle: applyplugin: '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的限制 multiDexEnabledtrue } dexOptions { jumboMode = true incrementaltrue javaMaxHeapSize "4g" preDexLibraries = false incrementaltrue } signingConfigs { debug { storeFilefile("../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 { checkReleaseBuildsfalse // Or, if you prefer, you can continue to check for errors in release builds, // but continue the build even when errors are found: abortOnErrorfalse } buildTypes { debug { // 显示Log buildConfigField "boolean", "LOG_DEBUG", "true" versionNameSuffix "-debug" minifyEnabledfalse zipAlignEnabledtrue shrinkResourcesfalse signingConfigsigningConfigs.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" minifyEnabledtrue zipAlignEnabledtrue // 移除无用的resource文件 shrinkResourcestrue proguardFile 'proguard-project.txt' debuggablefalse shrinkResourcesfalse signingConfigsigningConfigs.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 -> defoutputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { deffileName = 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' compilefileTree(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' compileproject(':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' }
匹配META-INF/channel_wandoujia文件名读取wandoujia渠道 public static String readChanel() { ApplicationInfoappInfo = ContextManager.getContext().getApplicationInfo(); String sourceDir = appInfo.sourceDir; String ret = ""; ZipFilezipfile = null; Log.i(TAG, "---begin-ret=" + ret); try { zipfile = new ZipFile(sourceDir); Enumeration<?> entries = zipfile.entries(); while (entries.hasMoreElements()) { ZipEntryentry = ((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(); } } }
基于上述方式实现多渠道打包流程如下:
插件: DynamicChoiceParameter **创建打包测试项目:Android-Test**
通过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')
构建脚本 #!/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} gitpull -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
获取channel列表 defver_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
构建脚本,通过OSSAPI拷贝要发布的归档渠道包到发布目录,发送钉钉通知 python /usr/share/tomcat/AndroidDeploy/androiddeploy.py
├── 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按照实际业务进行修改
任何自动化的前提必须先规范化,针对Android多渠道打包渠道命名,apk包命名需要先统一,apk包不要多环境混用(生产环境和测试环境要分离,测试包可自定义切换);到了这里,会发现我TM乱七八糟搞了这一陀哪里酸爽了?
Gradle入门 http://www.androidchina.net/2155.htmlAndroid签名 http://www.tuicool.com/articles/2eMZJfu