用 Eclipse 来给Android 打包是很考验耐心的事
领导布置了任务给好多渠道,好多应用打包
网上有不少方案,参考了一些。
反复调试之后,记录下操作步骤和脚本。
对于Android外行的我来说, Ant 也是外行,所以一开始就有一种特别强烈的排斥感 ,想着是否有方法不调用 Ant 。首先试想着正常打出一个包,然后用脚本把包解开,然后修改 AndroidManifest.xml 文件,修改包名,渠道名等,然后再加签。后来反复想了下有好几处难走通,还是用 Ant 来做重复打包的工作吧。
安装完 Ant 之后,发现好简单啊。。。
我在 Mac os 上安装的
下载地址 : http://ant.apache.org/bindownload.cgi
下载完后解压,将包考到 /usr/local 下。
打开 Terminal
Sudo -s chmod +w /etc/bashrc vi /etc/bashrc
在文件最后输入环境变量(为免麻烦,把 Android Home 和 NDK_HOME 什么的也都设置进来,注意改成自己的路径)。
export ANDROID_HOME=/Users/xxxxx/Documents/tools/androidsdk/adt-bundle-mac-x86_64-20130219/sdk export PATH=${PATH}:${ANDROID_HOME}/platform-tools export PATH=${PATH}:${ANDROID_HOME}/tools export NDK_HOME=/Users/xxxxxx/Documents/tools/androidsdk/android-ndk-r8e export PATH=${PATH}:${NDK_HOME} export NDK_ROOT=$NDK_HOME export ANT_HOME=/usr/local/apache-ant-1.9.3 export PATH=${PATH}:${ANT_HOME}/bin
然后就好用了!
在终端,进入android工程目录,输入
android update project -p xxxxx
其中 xxxxx 是工程路径
执行完毕后,会生成几个文件。暂不管。另外要手动添加一个文件 custom_rules.xml 文件。这个文件在 build.xml 里面会被调用。 Ant 的入口是 build.xml ,然后再进入 custom_rules.xml ,这个文件就是我们打包可以做文章的地方。(其实也可以在 sh 上实现渠道的修改)
在 ant.properties 文件里面输入签名要用到的用户名和密码
key.store=key path key.store.password=password key.alias=alias name key.alias.password=password
完整脚本下载地址: http://download.csdn.net/detail/qhexin/7499643
我写了三个脚本,一个是用来 debug 的,一个是用来 release 单个,一个是用来批量打多个渠道的包。按日常使用情况选择不同的脚本来执行。这里我只放批量打包那个。
#!/usr/bin/sh # @Author:agui # 本文件的主要作用是快速打 包 # 然后安装到设备上 再启动 echo 'We will start' echo "This sh file is run for Release all channel !!" #获取.sh文件的路径 #shFilePath="noPathYet" cd `dirname $0` shFilePath=$(pwd) echo $shFilePath #cd - # 创建输出目录.打包后的文件会在这里生成 output_release_filepath="$shFilePath/outputChannelsApk" rm -rf $output_release_filepath mkdir $output_release_filepath # 编译 .so 文件 echo " " echo " " echo "----开始编译 .so 文件----" echo " " echo " " echo $shFilePath cd $shFilePath sh build_native.sh -j4 # 打包 echo " " echo " " echo "----开始部署 打包 所有渠道----" echo " " echo " " ant deployall # 安装 echo " " echo " " adb devices cd $output_release_filepath hasRunAApplication="false" # 遍历文件,全安装起来 for file in $output_release_filepath/* do if [ -f "$file" ] then echo "Find file="$file singalFileHouZhui=${file##*.} echo $singalFileHouZhui if [ "$singalFileHouZhui" == "apk" ] then #安装 echo "Going to install" echo "Now Call: adb install -r $file" adb install -r $file if [ "$hasRunAApplication" == "false" ] then echo "try open app" #启动 adb shell am start -n 你的包名/你的activity名 hasRunAApplication="true" fi fi fi done
# options buildexternalsfromsource= usage(){ cat << EOF usage: $0 [options] Build C/C++ code for $APPNAME using Android NDK OPTIONS: -s Build externals from source -h this help EOF } while getopts "sh" OPTION; do case "$OPTION" in s) buildexternalsfromsource=1 ;; h) usage exit 0 ;; esac done # paths if [ -z "${NDK_ROOT+aaa}" ];then echo "please define NDK_ROOT" exit 1 fi DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # ... use paths relative to current directory COCOS2DX_ROOT="$DIR/../../.." APP_ROOT="$DIR/.." APP_ANDROID_ROOT="$DIR" echo "NDK_ROOT = $NDK_ROOT" echo "COCOS2DX_ROOT = $COCOS2DX_ROOT" echo "APP_ROOT = $APP_ROOT" echo "APP_ANDROID_ROOT = $APP_ANDROID_ROOT" # make sure assets is exist if [ -d "$APP_ANDROID_ROOT"/assets ]; then rm -rf "$APP_ANDROID_ROOT"/assets fi mkdir "$APP_ANDROID_ROOT"/assets # copy resources for file in "$APP_ROOT"/Resources/* do if [ -d "$file" ]; then cp -rf "$file" "$APP_ANDROID_ROOT"/assets fi if [ -f "$file" ]; then cp "$file" "$APP_ANDROID_ROOT"/assets fi done # 删除资源文件中音效中的mp3格式和m4a格式,只留下ogg MusicCleanDir="$APP_ANDROID_ROOT/assets/music/majiangTable/action $APP_ANDROID_ROOT/assets/music/majiangTable/BigFan $APP_ANDROID_ROOT/assets/music/majiangTable/boy $APP_ANDROID_ROOT/assets/music/majiangTable/chipenggangtinghu $APP_ANDROID_ROOT/assets/music/majiangTable/girl $APP_ANDROID_ROOT/assets/music/FlappyBird/effect" for mDir in $MusicCleanDir do echo "clean non-ogg file in $mDir" rm -f "$mDir"/*.mp3 rm -f "$mDir"/*.m4a rm -f "$mDir"/*.wav done # run ndk-build if [[ "$buildexternalsfromsource" ]]; then echo "Building external dependencies from source" "$NDK_ROOT"/ndk-build -C "$APP_ANDROID_ROOT" $* \ "NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/source" else echo "Using prebuilt externals" "$NDK_ROOT"/ndk-build -C "$APP_ANDROID_ROOT" $* \ "NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt" fi
这个文件需要放置到工程目录下。
<?xml version="1.0" encoding="UTF-8"?> <project name="custom_rules" > <taskdef resource="net/sf/antcontrib/antcontrib.properties" > <classpath> <pathelement location="lib/ant-contrib-1.0b3.jar" /> </classpath> </taskdef> <target name="agdebug" > <antcall target="onlydebug"> <param name="channel" value="${main_channel}"/> </antcall> </target> <target name="deploy" > <antcall target="modify_manifest_only_offical"> <param name="channel" value="${main_channel}"/> </antcall> </target> <target name="deployall" > <foreach delimiter="," list="${all_channels}" param="channel" target="modify_channels" > </foreach> </target> <!-- 多渠道打包 --> <target name="modify_channels" > <echo level="warning" message="${channel}" /> <propertyregex property="channelname" input="${channel}" regexp="(.*):" select="\1"/> <propertyregex property="packagename" input="${channel}" regexp=":(.*)" select="\1"/> <echo level="warning" message="${channelname}" /> <echo level="warning" message="${packagename}" /> <echo level="warning" message="Ready to package" /> <!-- 设置渠道名 --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="android:name="UMENG_CHANNEL" android:value="(.*)"" /> <substitution expression="android:name="UMENG_CHANNEL" android:value="${channelname}"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 设置包名 --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="package="(.*)"" /> <substitution expression="package="${packagename}"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 修改 debug=false --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="android:debuggable="(.*)"" /> <substitution expression="android:debuggable="false"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 打包 --> <property name="out.final.file" location="outputChannelsApk/${apk_prename}_${channelname}.apk" /> <antcall target="clean" /> <antcall target="release" /> </target> <!-- 主渠道打包 --> <target name="modify_manifest_only_offical" > <echo level="warning" message="${channel}" /> <propertyregex property="channelname" input="${channel}" regexp="(.*):" select="\1"/> <propertyregex property="packagename" input="${channel}" regexp=":(.*)" select="\1"/> <!-- 设置渠道名 --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="android:name="UMENG_CHANNEL" android:value="(.*)"" /> <substitution expression="android:name="UMENG_CHANNEL" android:value="${channelname}"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 设置包名 --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="package="(.*)"" /> <substitution expression="package="${packagename}"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 修改 debug=false --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="android:debuggable="(.*)"" /> <substitution expression="android:debuggable="false"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 打包 --> <property name="out.final.file" location="outputOfficalApk/${apk_prename}_${channelname}.apk" /> <antcall target="clean" /> <antcall target="release" /> </target> <!-- debug 包 --> <target name="onlydebug" > <echo level="warning" message="${channel}" /> <propertyregex property="channelname" input="${channel}" regexp="(.*):" select="\1"/> <propertyregex property="packagename" input="${channel}" regexp=":(.*)" select="\1"/> <!-- 设置渠道名 --> <replaceregexp encoding="utf-8" flags="g" byline="true"> <regexp pattern="android:name="UMENG_CHANNEL" android:value="(.*)"" /> <substitution expression="android:name="UMENG_CHANNEL" android:value="${channelname}"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 设置包名 --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="package="(.*)"" /> <substitution expression="package="${packagename}"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 修改 debug=false --> <replaceregexp encoding="utf-8" flags="g" byline="false"> <regexp pattern="android:debuggable="(.*)"" /> <substitution expression="android:debuggable="false"" /> <fileset dir="" includes="AndroidManifest.xml" /> </replaceregexp> <!-- 打包 --> <property name="out.final.file" location="outputDebugApk/${apk_prename}_${channelname}.apk" /> <antcall target="clean" /> <antcall target="debug" /> </target> </project>
修改 local.properties 文件。具体按照你的项目来配置吧!
# This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must *NOT* be checked into Version Control Systems, # as it contains information specific to your local configuration. # location of the SDK. This is only used by Ant # For customization when using a Version Control System, please read the # header note. sdk.dir=/Users/gongzuo-qipai/Documents/tools/androidsdk/adt-bundle-mac-x86_64-20130219/sdk #main channel ,the format is "channel name : package name" main_channel=qudaoname:package.package.xxxx #all channel , the format is "channe name : package name" and other channel ,split with "," all_channels=qudaoname:package,quandaoname2:package,qudaoname3:package apk_dir=outputApk apk_prename=APKNAME
如果不需要第一个脚本,那么手动编译C代码,然后再输入 ant deployall 即可。(不用脚本的话,输出路径要保证有文件夹哦)
用第一个脚本的话,啥都不用改,妥妥的OK拉。