jblzg的技术园

关注基于.Net的Web解决方案,高性能数据库设计,高性能Web服务解决方案,关注移动开发

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  22 随笔 :: 0 文章 :: 356 评论 :: 3 引用

公告

前言

我写Android 刚不久,发现一个Android应用是否有更多人用,不仅取决于应用本身,还取决于应用的推广,在中国,起码就有以下十个市场需要推广:360开放平台、爱米吧、谷歌电子市场、安智市场、应用汇、优亿市场、机锋、安卓市场、N多、安卓星空。

为了衡量每个市场的效果,我使用了友盟的分发渠道分析接口,只需要为不同的市场在 AndroidManifest.xml 里定义不同的 meta-data UMENG_CHANNEL 值,然后为各市场分发各自的apk即可。

这时问题就来了,如果我的应用有更新,如果没有一个自动化的方法,我需要用eclipse手动export、签名…… ,光敲签名时的storepass和keypass就够受的了,更不用说还得每次记得修改签名文件代表不同市场的后缀,比如MyApp_360.apk、MyApp_androidmarket.apk……,非常容易出错,也很浪费时间。

于是我花了1天的时间,用powershell脚本将上面的操作自动化了,感觉很棒,和大家分享一下,希望能够帮到各位。

在阅读这篇文章之前,我假设您已经知道如何给Android 应用签名,了解apache ant,已经集成了友盟分发渠道分析接口,了解PowerShell。

实现思路

  1. 用PowerShell实现一个方法:使用ant自动编译项目,在每次编译之前,修改 AndroidManifest.xml 中meta-data UMENG_CHANNEL 的值为指定市场的标识。
  2. 用字符串数组存储所有市场的标识,遍历该数组,遍历至每个元素时,都将该元素传入上面的方法,可实现针对不同的市场进行编译,编译完成后,再对编译好的应用签名即可。

系统环境

  • Windows 7 Untimate
  • JDK 7 Update1,假设路径为: E:\Program Files\Java\jdk1.7.0_01
  • apache-ant-1.8.2,假设路径为:E:\Program Files\apache-ant-1.8.2
  • Android SDK,假设路径为:E:\Program Files\Android\android-sdk

用ant自动编译项目

  • 假设Android项目路径为:D:\workspace\MyApp
  • 检查是否存在文件D:\workspace\MyApp\build.xml,这是使用ant编译项目时需要用到的配置文件
    • 若不存在,在command窗口中执行:
      • CD D:\workspace\MyApp
      • D:
      • "E:\Program Files\Android\android-sdk\tools\android" update project --path .
    • 若存在或通过上面的步骤生成了build.xml,修改文件中<project name="xxx" default="help"> xxx为自己项目的名称(项目名称如何改,参见文末的更新),如:<project name="MyApp" default="help">
  • 新建批处理文件D:\workspace\MyApp\build.bat,该文件使用ant对android项目自动编译,文件内容如下,请根据自己项目、系统的实际情况修改路径
1 SET JAVA_HOME=E:\Program Files\Java\jdk1.7.0_01
2 cd D:\workspace\MyApp
3 D:
4 "E:\Program Files\apache-ant-1.8.2\bin\ant" release

如果系统环境没问题,build.bat执行后,在目录 D:\workspace\MyApp\bin 中应该可以看到编译好的MyApp-release-unsigned.apk。

注意:如果项目中有引用的第三方jar包类库,要把这些类库放到项目根目录的 "libs" 目录下,否则,ant在编译的时候会出错。

流程详解

1、定义参数

1 param($ProjectName$ProjectRootDirectory$KeystorePath$StorePass$KeyPass$Alias)
2 
3 $channels = @("360""aimi8""anzhi""appchina""eoemarket""gfan""hiapk""nduoa""starandroid")
4 $defaultChannel = "androidmarket"
5 $jdkPath = "E:\Program Files\Java\jdk1.7.0_01"
6 $androidSDKPath = "E:\Program Files\Android\android-sdk"
7 $signedPath = "$ProjectRootDirectory\bin\signed"
8 $zipalignedPath = "$ProjectRootDirectory\bin\zipaligned"
  • $ProjectName:项目名称,如:MyApp
  • $ProjectRootDirectory:项目路径,如:D:\workspace\MyApp
  • $KeystorePath:keystore路径,如:D:\workspace\MyApp\keystore
  • $StorePass:store password,如:123456
  • $KeyPass: key password,如:123456
  • $Alias: keystore alias,如:MyApp
  • $channels:定义了除AndroidManifest.xml中定义的默认市场标识外,剩下的所有市场标识
  • $defaultChannel:即上面提到的默认市场标识,为什么要有默认市场标识的原因是,我们的AndroidManifest.xml文件不会常改,我们也不希望每次自动编译、签名完毕后,看到这个文件处于被修改的状态,所以我设计在最后才给默认的市场编译,这样的话,前面修改了n次的AndroidManifest.xml在最后回到未修改的状态
  • $signedPath:即签好名的apk文件存储路径
  • $zipalignedPath:即zipalign优化后文件存储路径,最后要发布的也是这个目录下的apk文件

2、修改 AndroidManifest.xml

1 $manifestPath = "$ProjectRootDirectory\AndroidManifest.xml"
2 $FILE = [System.IO.File]::ReadAllText($manifestPath)
3 $FILE = [REGEX]::replace($FILE, '<meta-data\r?\n?\s+android:name="UMENG_CHANNEL"\r?\n?\s+(.*?)>', '<meta-data
4             android:name="UMENG_CHANNEL"
5             android:value="' + $ChannelName + '" />', [Text.regularexpressions.regexoptions]::SingleLine)
6 [System.IO.File]::WriteAllText($manifestPath$FILE)

$ChannelName 代表每次遍历传入的市场标识,如:anzhi

3、调用 build.bat 编译 项目

1 & "$ProjectRootDirectory\build"

4、为编译好的应用签名

1 & "$jdkPath\bin\jarsigner" -keystore $KeystorePath -storepass $StorePass -keypass $KeyPass -signedjar "$signedPath\$ProjectName-$ChannelName.apk" -verbose "$ProjectRootDirectory\bin\$ProjectName-release-unsigned.apk" $Alias -digestalg SHA1 -sigalg MD5withRSA 

  • 注意最后2个参数:-digestalg SHA1 -sigalg MD5withRSA,如果你当前的环境是 JDK 7,一定要加上这两个参数,否则签名完毕的应用在安装时会有错误:Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES] [1]
  • 签好名的应用在 $signedPath 定义的路径中

5、zipalign优化签好名的apk

1 if (Test-Path -path "$zipalignedPath\$ProjectName-$ChannelName.apk") {
2     Remove-Item "$zipalignedPath\$ProjectName-$ChannelName.apk"
3 }
4     
5 & "$androidSDKPath\tools\zipalign" -v 4 "$signedPath\$ProjectName-$ChannelName.apk" "$zipalignedPath\$ProjectName-$ChannelName.apk"

6、批处理调用powershell脚本,实现自动化编译、签名

假设powershell脚本存储于:D:\workspace\build4DifferentChannels.ps1,新建批处理脚本:D:\workspace\build4DifferentChannels_MyApp.bat:

1 powershell D:\workspace\build4DifferentChannels.ps1 MyApp "D:\workspace\MyApp" "D:\workspace\MyApp\keystore" 123456 123456 myapp

用批处理调用powershell脚本build4DifferentChannels.ps1,并传入了之前定义的各个参数。以后需要发布应用时,就执行该批处理,自动为各个市场编译、签名应用即可,十分方便。

如果执行改脚本遇到错误:

    File D:\workspace\build4DifferentChannels.ps1 cannot be loaded because the execution of scripts is disabled on this system. 

就用管理员权限打开command窗口,执行下面的命令:

1 powershell
2 Set-ExecutionPolicy RemoteSigned 

7、完整脚本下载

build4DifferentChannels_20111209.zip

参考 

[1]:http://code.google.com/p/android/issues/detail?id=19567

[2]:http://www.androidengineer.com/2010/06/using-ant-to-automate-building-android.html

广告

给最近开发的两个应用打一下广告

更新 

  • 2011-11-28
    谢谢wanx的提醒:<project name="xxx" default="help">,这里的xxx不是随便写,而是和使用eclipse手动编译出来的apk文件名一致,如果eclipse编译的文件名是Abc.apk,那么build.xml这段就应该改为:<project name="Abc" default="help"> 
  • 2011-12-02
    再次谢谢wanx的提醒:如果项目中有引用的第三方jar包类库,要把这些类库放到项目根目录的 "libs" 目录下,否则,ant在编译的时候会出错。
  • 2011-12-07
    加入zipalign优化脚本
  • 2011-12-09
    在zipalign之前,先删除旧有apk文件
posted on 2011-11-23 19:44 jblzg 阅读(...) 评论(...) 编辑 收藏