├── README.md ├── build.gradle ├── gradle.properties ├── image ├── image_1.png ├── image_10.png ├── image_11.png ├── image_12.png ├── image_13.png ├── image_14.png ├── image_15.png ├── image_16.png ├── image_17.png ├── image_18.png ├── image_19.png ├── image_2.png ├── image_20.png ├── image_21.png ├── image_22.png ├── image_23.png ├── image_24.png ├── image_25.png ├── image_26.png ├── image_27.png ├── image_28.png ├── image_29.png ├── image_3.png ├── image_4.png ├── image_5.png ├── image_6.png ├── image_7.png ├── image_8.png └── image_9.png ├── plugins.zip └── upload.py /README.md: -------------------------------------------------------------------------------- 1 |

利用Jenkins玩转Android自动打包发包

2 | ### 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 3 | 4 | ### 请尊重原创,转载请注明出处:http://blog.csdn.net/mabeijianxi/article/details/52680283 5 | ### 先看一眼效果图: 6 | 7 |

功能描述:

可以选择不同的环境与不同的渠道,可以输入显示在App上的版本号,打包完成后可自动上传并且生成安装二维码
8 |

总体步骤可为:

9 |
    10 |
  1. 下载新版Jenkins挂载到Tomcat
  2. 11 |
  3. 编写Python脚本拉取蒲公英上Apk二维码(可选)
  4. 12 |
  5. 配置项目build.gradle里面的脚本
  6. 13 |
  7. 安装Jenkins里面需要用到的一些插件并且配置Jenkins参数
  8. 14 |
15 | 脚本配置地址:https://github.com/mabeijianxi/android-automation 16 |

正式开撸

17 |

一、下载新版Jenkins挂载到Tomcat:

18 | 到Jenkins下载适合的版本后点击安装,之后在Tomcat的webapps目录下新建一个Jenkins目录,再把刚安装好的Jenkins目录打开找到war目录,拷贝目录下全部数据到webapps下新建的Jenkins目录中。还有种启动方式是通过命令启动jenkins.war就行了,```java -jar jenkins_located_path/jenkins.war```。我们可以先为工作空间配置个环境变量。

19 | 我使用的是第一种方式,再启动Tomcat后访问http://localhost:8080/jenkins就会进入引导进入页面,如果有选择安装插件界面进去后点击安装就行,一会儿就能进入主界面。

20 |

二、安装Jenkins里面需要用到的一些插件:

21 | 这里也没什么技术含量,系统管理->插件管理->管理插件->可选插件: 22 | 勾选如下插件: 23 |
    24 |
  1. Branch API Plugin
  2. 25 |
  3. build timeout plugin
  4. 26 |
  5. build-name-setter
  6. 27 |
  7. Credentials Binding Plugin
  8. 28 |
  9. description setter plugin
  10. 29 |
  11. Dynamic Parameter Plug-in
  12. 30 |
  13. Environment Injector Plugin
  14. 31 |
  15. fir-plugin(可选)
  16. 32 |
  17. Git plugin(可选)
  18. 33 |
  19. GIT server Plugin(可选)
  20. 34 |
  21. Gradle Plugin
  22. 35 |
  23. Pipeline: Basic Steps
  24. 36 |
  25. Pipeline: Build Step
  26. 37 |
  27. Pipeline: Input Step
  28. 38 |
  29. Pipeline: Nodes and Processes
  30. 39 |
  31. Pipeline: Stage Step
  32. 40 |
  33. Post-Build Script Plug-in
  34. 41 |
  35. SSH Slaves plugin
  36. 42 |
  37. Subversion Release Manager plugin(可选)
  38. 43 |
  39. Timestamper
  40. 44 |
  41. Workspace Cleanup Plugin
  42. 45 |
  43. Subversion Plug-in(可选)
  44. 46 |
47 | 由于有些插件之间有依赖关系所以没全部列出来,如过有我问题可以对比我的截图。
48 | 49 |

三、配置build.gradle:

50 | 上面都是枯燥的准备工作,好玩的才刚刚开始,下面的参数传入很有意思,也是我踩了很多坑以后想到的。 51 | 进入Android Studio->打开主Module的build.gradle:
52 |
    53 |
  1. 配置签名信息,不然打的包就没意义了
  2. 54 |
  3. 以参数化构建你想动态写入的数据。我自己需要动态写入的参数有versionName、打包时间戳、是来自Jenkjins运行还是我们本地打包的标识符,这里很重要,如果是来自Jenkins打包那么我们的生成路径肯定是服务器上的路径,否则是我们本地电脑上的路径。把这三个参数与其在本地的默认值定义在gradle.properties中,然后在build.gradle变能引用。
  4. 55 |
  5. 动态修改生成的Apk路径与名称,因为如果是Jenkins打包发包那么名称必须是Jenkins传递过来的,不能写死,且唯一,不然没法上传
  6. 56 |
57 | 废话不多说,程序员就哪需要看这么多文字,直接干代码(一下是项目中部分代码):
58 | 59 | 60 | ``` 61 | gradle.build: 62 | 63 | def getDate() { 64 | def date = new Date() 65 | def formattedDate = date.format('yyyyMMddHHmm') 66 | return formattedDate 67 | } 68 | def verCode = 14 69 | android { 70 | compileSdkVersion 22 71 | buildToolsVersion "23.0.3" 72 | signingConfigs { 73 | signingConfig { 74 | keyAlias 'xxx' 75 | keyPassword 'xxx' 76 | storeFile file('xxx') 77 | storePassword 'xxx' 78 | } 79 | } 80 | 81 | defaultConfig { 82 | applicationId "com.henanjianye.soon.communityo2o" 83 | minSdkVersion 14 84 | targetSdkVersion 22 85 | multiDexEnabled true 86 | versionCode verCode 87 | versionName APP_VERSION 88 | resValue("string", 'app_version', APP_VERSION) 89 | buildConfigField "boolean", "LEO_DEBUG", "true" 90 | buildConfigField 'String', 'API_SERVER_URL', RELEASE_API_SERVER_URL 91 | buildConfigField 'String', 'API_SERVER_URL_MALL', RELEASE_API_SERVER_URL_MALL 92 | signingConfig signingConfigs.signingConfig 93 | } 94 | buildTypes { 95 | release { 96 | buildConfigField 'String', 'API_SERVER_URL', RELEASE_API_SERVER_URL 97 | buildConfigField 'String', 'API_SERVER_URL_MALL', RELEASE_API_SERVER_URL_MALL 98 | buildConfigField 'String', 'IM_SERVER_HOST', RELEASE_IM_SERVER_HOST 99 | buildConfigField 'int', 'IM_SERVER_PORT', RELEASE_IM_SERVER_PORT 100 | buildConfigField "boolean", "LEO_DEBUG", RELEASE_LEO_DEBUG 101 | minifyEnabled true 102 | zipAlignEnabled true 103 | shrinkResources true 104 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 105 | } 106 | debug { 107 | buildConfigField 'String', 'API_SERVER_URL', RELEASE_API_SERVER_URL 108 | buildConfigField 'String', 'API_SERVER_URL_MALL', RELEASE_API_SERVER_URL_MALL 109 | buildConfigField 'String', 'IM_SERVER_HOST', RELEASE_IM_SERVER_HOST 110 | buildConfigField 'int', 'IM_SERVER_PORT', RELEASE_IM_SERVER_PORT 111 | buildConfigField "boolean", "LEO_DEBUG", RELEASE_LEO_DEBUG 112 | } 113 | } 114 | dexOptions { 115 | javaMaxHeapSize "2g" 116 | } 117 | 118 | 119 | //渠道Flavors,我这里写了一些常用的 120 | productFlavors { 121 | commonsoon { 122 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "commonsoon"] 123 | } 124 | zhushou91 { 125 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "zhushou91"] 126 | } 127 | } 128 | allprojects { 129 | repositories { 130 | mavenCentral() 131 | maven { url "https://jitpack.io" } 132 | } 133 | } 134 | //修改生成的apk名字 135 | applicationVariants.all { variant -> 136 | variant.outputs.each { output -> 137 | def newName 138 | def timeNow 139 | def oldFile = output.outputFile 140 | def outDirectory = oldFile.parent 141 | 142 | if ("true".equals(IS_JENKINS)) { 143 | timeNow = JENKINS_TIME 144 | outDirectory = 'G:/Tomcat/webapps/jenkins/apk' 145 | newName = 'yj-android-v' + 146 | APP_VERSION + '-' + variant.productFlavors[0].name + timeNow + '-' + variant.buildType.name + '.apk' 147 | } else { 148 | timeNow = getDate() 149 | if (variant.buildType.name.equals('debug')) { 150 | newName = "yj-android-v${APP_VERSION}-debug.apk" 151 | } else { 152 | newName = 'yj-android-v' + 153 | APP_VERSION + '-' + variant.productFlavors[0].name + timeNow + '-' + variant.buildType.name + '.apk' 154 | } 155 | } 156 | 157 | output.outputFile = new File(outDirectory, newName) 158 | 159 | } 160 | } 161 | } 162 | 163 | 164 | gradle.properties: 165 | 166 | 167 | RELEASE_API_SERVER_URL="xxx" 168 | RELEASE_API_SERVER_URL_MALL="xxx" 169 | RELEASE_IM_SERVER_HOST="xxx" 170 | RELEASE_IM_SERVER_PORT=5222 171 | RELEASE_LEO_DEBUG=false 172 | 173 | INSIDE_TEST_API_SERVER_URL="xxx" 174 | INSIDE_TEST_API_SERVER_URL_MALL="xxx" 175 | INSIDE_TEST_IM_SERVER_HOST="xxx" 176 | INSIDE_TEST_IM_SERVER_PORT=5222 177 | INSIDE_TEST_LEO_DEBUG=true 178 | 179 | APP_VERSION=2.4.0 180 | IS_JENKINS=false 181 | JENKINS_TIME='' 182 | 183 | ``` 184 | 185 |

四、配置Jenkins参数

186 | 回到主界面->系统管理->Global Tool Configuration: 187 | 配置好JDK与Gradle。由于我本地已安装好JDK与Gradle所以只需为其指定路径即可。

188 | 然后回到主界面->新建->构建一个自由风格的项目->ok:
189 |
    190 |
  1. 勾选上参数化构建过程,先点击Choice可为其配置可选参数。我的项目需要配置的可选参数有API环境、打包渠道、是否来自Jenkins打包的标识。
    191 |
  2. 192 |
  3. 点击String Parameter,让使用者可以自定义显示在App上的版本号,方便测试。可以再添加一个可输入的标签,最后把这个标签加到构建页的构建名称中。
  4. 193 |
  5. 点击Dynamic Parameter,注入Groovy脚本,主要是生成时间戳。
  6. 194 |
  7. 如果是SVN用户可选择List SubVersion tags,然后写地址帐号密码等,这个选项可以让你选择打包SVN上不同版本的代码。如果是Git用户可参照http://birdinroom.blog.51cto.com/7740375/1404930 上面的配置来拉取不同的版本。
  8. 195 |
  9. 勾选源码管理中自己所用的管理工具Git或者Subversion,填写好相关信息,当然我们的地址是动态的,所以需要引用上一步所选择的版本,如图。(如果是Linux后面得加上/,不然拉取的其目录下的内容不包含TAG_SVN这个目录)
  10. 196 |
  11. 在构建环境中勾选上Set Build Name,主要是动态生成每次显示在构建页上的名称方便查看。
  12. 197 |
  13. 在构建栏里面选择Invoke Gradle Script->选择配置好的Gradle Version->在Tasks中输入Gradle命令(没了解过的建议先看下Gradle的基本命令),我们先执行一个clean,然后开始编译,这时候就可以用引用上面配置的一些参数了,这里可以用-P命令把参数传入,也可以更方便的把下面的Pass jod parameters as Gradle properties勾选上,其实内部也是用-Pkey=Value的命令->在Root Build script中动态指定你项目的目录,为什么是动态的呢?这是因为我们上面提供了可选版本的功能,所以拉取的每个版本所放目录是不一样的,想要编译相应的版本就得动态指定编译目录。
  14. 198 |
  15. 上面的操作如果成功那么其实这时候构建已经可以在build.gradle所配置的输出路径中找到相应的Apk了,但是这还不够酷,我想把生成的Apk放到托管平台,一般用fir.im与蒲公英。如果选择fir.im那么本步骤略过,我个人推荐蒲公英,因为其可用命令行上传比较方(装)便(B)。下面是蒲公英上传的步骤。
    199 | 1)简单的实现方式:参照官方文档https://www.pgyer.com/doc/view/jenkins 。这种方式可以可以简单的通过命令行上传,方便使用,且后续可以动态拿到Apk的下载连接,与最新版本的二维码。但是想要拿到每个版本的二维码确实不行的。其实上传成功后返回的json数据中Apk的下载地址与二维码地址是写死的一个短网址,后续说明解决办法。这里按照官方的步骤,如果是Linux 200 | 那么在增加构建步骤中选择Execute Shell,而Windows环境的需要先下载curl工具,然后选择Execute Windows batch command。get地址与使用方法都在里面http://www.2cto.com/os/201205/131164.html

    201 | 需要注意这里的上传文件的名称也是动态引用的方式,因为每次生成的名称是唯一的。如果是Shell那么引用方式是${NAME},而batch引用方式是%NAME%。
    202 | 2)比较装逼的方式:我不只想要每个版本的下载长链接,我还想要每个版本二维码的长链接。但是就算通过浏览器打开最新上传的Apk地址,里面的二维码也只有短链接,不管是Apk的短链接还是二维码的它们其实是写死的,永远指向最新版的地址,这就有个问题,当在Jenkins中打开非最新版本的Apk地址或者二维码图片地址那么都会指向最新的,这就比较蛋疼了。经过仔细观察发现蒲公英Apk长链接生成的规则其实是固定字符串+appKey。Apk在返回的json串中可以找到。于是可以利用python脚本来执行上传,然后正则配置到AppKey,然后再拼上静态字符串就拿到了本次存放Apk的长链接。当然如果只是为了Apk安装长链接用第一种方式即可。现在需要的是二维码的长链接,用Apk的长链接发起Http请求然后就可以拿到页面数据,通过正则匹配可以匹配到里面二维码的img标签地址,但是是短地址,蒲公英只有非最新Apk才会在这个页面的img标签中返回长地址。于是我打了一个包名与签名同上传Apk相同的Apk,里面没东西,大小只有几十K。在第一个Apk上传完成后马上上传这个小的Apk,这样再去拉取页面里面的img标签就可以得到二维码的长网址了。具体实现看下面python代码。
    203 |
    
    204 | #coding: utf-8
    205 | import os
    206 | import re
    207 | import requests
    208 | import sys
    209 | 
    210 | if len(sys.argv) == 2:
    211 |     mainpath = sys.argv[-1]
    212 | else:
    213 |     exit()
    214 | 
    215 | temppath = r'G:\mydownload\GETUI_ANDROID_SDK\GETUI_ANDROID_SDK\Demo\PushDemo\yijia\temp.apk'
    216 | 
    217 | cmd = 'curl -F "file=@{path}" -F "uKey=xxx" -F "_api_key=xxx" http://www.pgyer.com/apiv1/app/upload'
    218 | content = os.popen(cmd.format(path=mainpath)).read()
    219 | print(content)
    220 | 
    221 | match = re.search('"appKey":"(\w+)"', content)
    222 | 
    223 | if match:
    224 |     appkey = match.group(1)
    225 | 
    226 |     content = os.popen(cmd.format(path=temppath)).read()
    227 | 
    228 |     url = 'http://static.pgyer.com/' + appkey
    229 |     html = requests.get(url).text
    230 | 
    231 |     match = re.search('http://static.pgyer.com/app/qrcodeHistory/\w+', html)
    232 |     if match:
    233 |         print('appKey#{soonAppkey}#appKeysoon#{soon}#soon'.format(soonAppkey=appkey,soon=match.group()))
    234 |     else:
    235 |         print('no qrcode')
    236 | 
    237 | 命令中执行如图代码:
    238 |
  16. 239 |
  17. 经过上面的操作后大业马上就成了,接下来就是收集成果的时候了,在增加构建后操作步骤中选择Set build description,在Regular expression中填写正则,然后Description中可以引用,这里去匹配的是构建日志中的内容,Description的内容将显示到构建页面。我们这里如果需要插入下载链接或者二维码的话那么就需要用到Html标签,这时候需要去先设置下。步骤:系统管理->Configure Global Security-> Markup Formatter->Safe HTML。如果是选择上面的简单实现方式那么Regular expression的正则可以用:"appKey":"(.*)","userKey",如果用我的pyhton脚本上传,那么正则可以是:appKey#(.*)#appKeysoon#(.*)#soon,然后在Description中通过\1或者\2引用即可。
  18. 240 |
241 |

四、打包喝咖啡

242 | 到这里那么最感动的时刻来了,轻轻的点击下保存按钮,这时候你会来到构建界面,轻击 Build with Parameters,就会出现这个界面

配置好参数,按下时代性的构建。从这一刻起谁向你要包你可以点根烟淡淡的说道:妈的,撸着呢,一边自己打去。我反正是受够了要包岁月。 243 |

注意事项:

244 | 1、参数传递的时候Jenkins里面的参数名称需要与build.gradle里面的一致,不然没什么卵用。如:

245 | 2、在Linux下需要注意一些编译工具的权限问题,如aapt。
246 | 3、在服务器上的SDK最好与你本地的一致,不然指不定编译的时候会少东西。如果服务器的环境与你本地环境不同就不能直接copy过去了,最好的办法是下载一个服务器环境的SDKManager或者直接用Android Studio,然后对照你本地SDK里面的数据挨个下载,完了再copy到服务器。 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | //获取时间戳 3 | def getDate() { 4 | def date = new Date() 5 | def formattedDate = date.format('yyyyMMddHHmm') 6 | return formattedDate 7 | } 8 | 9 | def verCode = 14 10 | android { 11 | compileSdkVersion 22 12 | buildToolsVersion "23.0.3" 13 | 14 | signingConfigs { 15 | signingConfig { 16 | keyAlias 'xxx' 17 | keyPassword 'xxx' 18 | storeFile file('xxx') 19 | storePassword 'xxx' 20 | } 21 | } 22 | 23 | defaultConfig { 24 | applicationId "com.henanjianye.soon.communityo2o" 25 | minSdkVersion 14 26 | targetSdkVersion 22 27 | multiDexEnabled true 28 | versionCode verCode 29 | versionName APP_VERSION 30 | resValue("string", 'app_version', APP_VERSION) 31 | buildConfigField "boolean", "LEO_DEBUG", "true" 32 | buildConfigField 'String', 'API_SERVER_URL', RELEASE_API_SERVER_URL 33 | buildConfigField 'String', 'API_SERVER_URL_MALL', RELEASE_API_SERVER_URL_MALL 34 | generatedDensities = [] 35 | signingConfig signingConfigs.signingConfig 36 | } 37 | 38 | compileOptions { 39 | sourceCompatibility JavaVersion.VERSION_1_7 40 | targetCompatibility JavaVersion.VERSION_1_7 41 | } 42 | lintOptions { 43 | abortOnError false 44 | } 45 | aaptOptions { 46 | additionalParameters "--no-version-vectors" 47 | } 48 | buildTypes { 49 | release { 50 | buildConfigField 'String', 'API_SERVER_URL', RELEASE_API_SERVER_URL 51 | buildConfigField 'String', 'API_SERVER_URL_MALL', RELEASE_API_SERVER_URL_MALL 52 | buildConfigField 'String', 'IM_SERVER_HOST', RELEASE_IM_SERVER_HOST 53 | buildConfigField 'int', 'IM_SERVER_PORT', RELEASE_IM_SERVER_PORT 54 | buildConfigField "boolean", "LEO_DEBUG", RELEASE_LEO_DEBUG 55 | minifyEnabled true 56 | zipAlignEnabled true 57 | shrinkResources true 58 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 59 | } 60 | ysc { 61 | buildConfigField 'String', 'API_SERVER_URL', YSC_API_SERVER_URL 62 | buildConfigField 'String', 'API_SERVER_URL_MALL', YSC_API_SERVER_URL_MALL 63 | buildConfigField 'String', 'IM_SERVER_HOST', YSC_IM_SERVER_HOST 64 | buildConfigField 'int', 'IM_SERVER_PORT', YSC_IM_SERVER_PORT 65 | buildConfigField "boolean", "LEO_DEBUG", YSC_LEO_DEBUG 66 | minifyEnabled true 67 | zipAlignEnabled true 68 | shrinkResources true 69 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 70 | } 71 | develop { 72 | buildConfigField 'String', 'API_SERVER_URL', DEVELOP_API_SERVER_URL 73 | buildConfigField 'String', 'API_SERVER_URL_MALL', DEVELOP_API_SERVER_URL_MALL 74 | buildConfigField 'String', 'IM_SERVER_HOST', DEVELOP_IM_SERVER_HOST 75 | buildConfigField 'int', 'IM_SERVER_PORT', DEVELOP_IM_SERVER_PORT 76 | buildConfigField "boolean", "LEO_DEBUG", DEVELOP_LEO_DEBUG 77 | minifyEnabled true 78 | zipAlignEnabled true 79 | shrinkResources true 80 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 81 | } 82 | inside_test { 83 | buildConfigField 'String', 'API_SERVER_URL', INSIDE_TEST_API_SERVER_URL 84 | buildConfigField 'String', 'API_SERVER_URL_MALL', INSIDE_TEST_API_SERVER_URL_MALL 85 | buildConfigField 'String', 'IM_SERVER_HOST', INSIDE_TEST_IM_SERVER_HOST 86 | buildConfigField 'int', 'IM_SERVER_PORT', INSIDE_TEST_IM_SERVER_PORT 87 | buildConfigField "boolean", "LEO_DEBUG", INSIDE_TEST_LEO_DEBUG 88 | minifyEnabled true 89 | zipAlignEnabled true 90 | shrinkResources true 91 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 92 | } 93 | debug { 94 | buildConfigField 'String', 'API_SERVER_URL', RELEASE_API_SERVER_URL 95 | buildConfigField 'String', 'API_SERVER_URL_MALL', RELEASE_API_SERVER_URL_MALL 96 | buildConfigField 'String', 'IM_SERVER_HOST', RELEASE_IM_SERVER_HOST 97 | buildConfigField 'int', 'IM_SERVER_PORT', RELEASE_IM_SERVER_PORT 98 | buildConfigField "boolean", "LEO_DEBUG", RELEASE_LEO_DEBUG 99 | } 100 | } 101 | dexOptions { 102 | javaMaxHeapSize "2g" 103 | } 104 | 105 | packagingOptions { 106 | exclude 'META-INF/DEPENDENCIES.txt' 107 | exclude 'META-INF/LICENSE.txt' 108 | exclude 'META-INF/NOTICE.txt' 109 | exclude 'META-INF/NOTICE' 110 | exclude 'META-INF/LICENSE' 111 | exclude 'META-INF/DEPENDENCIES' 112 | exclude 'META-INF/notice.txt' 113 | exclude 'META-INF/license.txt' 114 | exclude 'META-INF/dependencies.txt' 115 | exclude 'META-INF/LGPL2.1' 116 | } 117 | 118 | //渠道Flavors,我这里写了一些常用的 119 | productFlavors { 120 | commonsoon { 121 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "commonsoon"] 122 | } 123 | zhushou91 { 124 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "zhushou91"] 125 | } 126 | market360 { 127 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "market360"] 128 | } 129 | xiaomi { 130 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"] 131 | } 132 | wandoujia { 133 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"] 134 | } 135 | marketandroid { 136 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "marketandroid"] 137 | } 138 | yingyonghui { 139 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyonghui"] 140 | } 141 | jifengmarket { 142 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "jifengmarket"] 143 | } 144 | mumayi { 145 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "mumayi"] 146 | } 147 | anzhimarket { 148 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "anzhimarket"] 149 | } 150 | yingyongbao { 151 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyongbao"] 152 | } 153 | huaweimarket { 154 | manifestPlaceholders = [UMENG_CHANNEL_VALUE: "huaweimarket"] 155 | } 156 | } 157 | allprojects { 158 | repositories { 159 | mavenCentral() 160 | maven { url "https://jitpack.io" } 161 | } 162 | } 163 | 164 | //修改生成的apk名字 165 | applicationVariants.all { variant -> 166 | variant.outputs.each { output -> 167 | def newName 168 | def timeNow 169 | def oldFile = output.outputFile 170 | def outDirectory = oldFile.parent 171 | 172 | if ("true".equals(IS_JENKINS)) { 173 | timeNow = JENKINS_TIME 174 | outDirectory = 'G:/Tomcat/webapps/jenkins/apk' 175 | newName = 'yj-android-v' + 176 | APP_VERSION + '-' + variant.productFlavors[0].name + timeNow + '-' + variant.buildType.name + '.apk' 177 | } else { 178 | timeNow = getDate() 179 | if (variant.buildType.name.equals('debug')) { 180 | newName = "yj-android-v${APP_VERSION}-debug.apk" 181 | } else { 182 | newName = 'yj-android-v' + 183 | APP_VERSION + '-' + variant.productFlavors[0].name + timeNow + '-' + variant.buildType.name + '.apk' 184 | } 185 | } 186 | 187 | output.outputFile = new File(outDirectory, newName) 188 | 189 | } 190 | } 191 | } 192 | 193 | dependencies { 194 | compile fileTree(include: ['*.jar'], dir: 'libs') 195 | 196 | } 197 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Wed Aug 10 19:25:54 CST 2016 16 | android.useDeprecatedNdk=true 17 | 18 | #release config 19 | RELEASE_API_SERVER_URL="xxx" 20 | RELEASE_API_SERVER_URL_MALL="xxx" 21 | RELEASE_IM_SERVER_HOST="xxx" 22 | RELEASE_IM_SERVER_PORT=5222 23 | RELEASE_LEO_DEBUG=false 24 | 25 | #ysc config 26 | YSC_API_SERVER_URL="xxx" 27 | YSC_API_SERVER_URL_MALL="xxx" 28 | YSC_IM_SERVER_HOST="182.92.10.56" 29 | YSC_IM_SERVER_PORT=5222 30 | YSC_LEO_DEBUG=true 31 | 32 | #develop config 33 | DEVELOP_API_SERVER_URL="xxx" 34 | DEVELOP_API_SERVER_URL_MALL="xxx" 35 | DEVELOP_IM_SERVER_HOST="xxx" 36 | DEVELOP_IM_SERVER_PORT=5422 37 | DEVELOP_LEO_DEBUG=true 38 | 39 | #inside_test config 40 | INSIDE_TEST_API_SERVER_URL="xxx" 41 | INSIDE_TEST_API_SERVER_URL_MALL="xxx" 42 | INSIDE_TEST_IM_SERVER_HOST="xxx" 43 | INSIDE_TEST_IM_SERVER_PORT=5222 44 | INSIDE_TEST_LEO_DEBUG=true 45 | 46 | APP_VERSION=2.4.0 47 | 48 | IS_JENKINS=false 49 | JENKINS_TIME='' -------------------------------------------------------------------------------- /image/image_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_1.png -------------------------------------------------------------------------------- /image/image_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_10.png -------------------------------------------------------------------------------- /image/image_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_11.png -------------------------------------------------------------------------------- /image/image_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_12.png -------------------------------------------------------------------------------- /image/image_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_13.png -------------------------------------------------------------------------------- /image/image_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_14.png -------------------------------------------------------------------------------- /image/image_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_15.png -------------------------------------------------------------------------------- /image/image_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_16.png -------------------------------------------------------------------------------- /image/image_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_17.png -------------------------------------------------------------------------------- /image/image_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_18.png -------------------------------------------------------------------------------- /image/image_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_19.png -------------------------------------------------------------------------------- /image/image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_2.png -------------------------------------------------------------------------------- /image/image_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_20.png -------------------------------------------------------------------------------- /image/image_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_21.png -------------------------------------------------------------------------------- /image/image_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_22.png -------------------------------------------------------------------------------- /image/image_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_23.png -------------------------------------------------------------------------------- /image/image_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_24.png -------------------------------------------------------------------------------- /image/image_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_25.png -------------------------------------------------------------------------------- /image/image_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_26.png -------------------------------------------------------------------------------- /image/image_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_27.png -------------------------------------------------------------------------------- /image/image_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_28.png -------------------------------------------------------------------------------- /image/image_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_29.png -------------------------------------------------------------------------------- /image/image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_3.png -------------------------------------------------------------------------------- /image/image_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_4.png -------------------------------------------------------------------------------- /image/image_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_5.png -------------------------------------------------------------------------------- /image/image_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_6.png -------------------------------------------------------------------------------- /image/image_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_7.png -------------------------------------------------------------------------------- /image/image_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_8.png -------------------------------------------------------------------------------- /image/image_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/image/image_9.png -------------------------------------------------------------------------------- /plugins.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mabeijianxi/android-automation/cefcfb7f9ece3d8ec71e44c338a6a65f78084996/plugins.zip -------------------------------------------------------------------------------- /upload.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | import os 3 | import re 4 | import requests 5 | import sys 6 | 7 | if len(sys.argv) == 2: 8 | mainpath = sys.argv[-1] 9 | else: 10 | exit() 11 | 12 | temppath = r'G:\mydownload\GETUI_ANDROID_SDK\GETUI_ANDROID_SDK\Demo\PushDemo\yijia\temp.apk' 13 | 14 | cmd = 'curl -F "file=@{path}" -F "uKey=xxx" -F "_api_key=xxx" http://www.pgyer.com/apiv1/app/upload' 15 | content = os.popen(cmd.format(path=mainpath)).read() 16 | print(content) 17 | 18 | match = re.search('"appKey":"(\w+)"', content) 19 | 20 | if match: 21 | appkey = match.group(1) 22 | 23 | content = os.popen(cmd.format(path=temppath)).read() 24 | 25 | url = 'http://static.pgyer.com/' + appkey 26 | html = requests.get(url).text 27 | 28 | match = re.search('http://static.pgyer.com/app/qrcodeHistory/\w+', html) 29 | if match: 30 | print('appKey#{soonAppkey}#appKeysoon#{soon}#soon'.format(soonAppkey=appkey,soon=match.group())) 31 | else: 32 | print('no qrcode') 33 | --------------------------------------------------------------------------------