用 Eclipse 来给Android 打包是很考验耐心的事
领导布置了任务给好多渠道,好多应用打包
网上有不少方案,参考了一些。
反复调试之后,记录下操作步骤和脚本。
一、 首先要安装 Ant
对于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
然后就好用了!
二、增加 Ant 调用所需要的配置文件
在终端,进入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
三、献上脚本
3.1 主逻辑脚本
完整脚本下载地址: 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
3.2 生成 so 文件脚本 build_native.sh
# 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
3.3 Ant配置文件 custom_rules.xml
这个文件需要放置到工程目录下。
<?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拉。