从 10 到 1

-- Android 打包工具重构经验分享

2015-07-23 曾嵘

这是一个复杂的系统。

Boss 交给你一个任务:

对一个 5 年以上历史的,经过多个团队维护的线上系统进行重构。

你应该如何着手?

辞 职

主要问题

  • 组织结构混乱
  • 想到哪里就写到哪里
  • 不考虑兼容性
  • 不考虑重用
  • 各种硬编码

这让我想到了一句话 ——

你不是一个人在战斗,不是一个人!

我们都做了什么?

开闭原则

软件应该对扩展开放,对修改关闭

没有版本管理!!!

没有版本管理!!!

没有版本管理!!!

setup.sh 的功能

  • 修改 project.properties 以增加 android.library.reference
  • 修改 AndroidManifest.xml 以增加 Activity 支持、权限支持,更改包名、游戏名
  • 修改 game.properteis 以支持不同的设置(服务器地址等)
  • 修改 project-proguard.txt 以支持 class 混淆
  • 复制内容到 proj.android 用于打包

规则违反 ——

单一职责原则

不要存在多于一个导致类变更的原因

setup.sh 的一部分内容

#add mm params in game.properties and game_debug.properties
PARAMS_MM=`cat ${SCRIPT_DIR}/${GAME_NAME}/config.txt | grep "params" | cut -d "=" -f 2`
if [ -z "$PARAMS_MM" ]; then
    echo "Build Failure! notice!! please set the payment_third_params in config.txt in your game directory"
    exit 1
else
    echo "payment_mm_params=$PARAMS_MM"
    sed -i -e '/payment_third_provider/a\#set mmbilling params' ${PROJECT_ROOT}/assets/game.properties
    sed -i -e '/set mmbilling params/a payment_mm_params=mmtag' ${PROJECT_ROOT}/assets/game.properties
    sed -i -e "s/mmtag/$PARAMS_MM/g" ${PROJECT_ROOT}/assets/game.properties

    sed -i -e '/payment_third_provider/a\#set mmbilling params' ${PROJECT_ROOT}/assets/game_debug.properties
    sed -i -e '/set mmbilling params/a payment_mm_params=mmtag' ${PROJECT_ROOT}/assets/game_debug.properties
    sed -i -e "s/mmtag/$PARAMS_MM/g" ${PROJECT_ROOT}/assets/game_debug.properties
fi

echo "add mmbilling2.4.0 successfully"

这么长的一段代码,只是为了在 game.properteis 的 payment_third_provider 变量之后增加一个 payment_mm_params 变量。

png_compress.sh

#!/bin/bash

#rely on pbgquant2.3, so just run in Linux

for file in $(find ../Resources/images/package/)
do
  if [ "${file##*.}" = "png" ]; then
    file_path=${file##*/}
    if [ "$file_path" = "broadcast_and_chat.png" ] || [ "$file_path" = "mainlayer.png" ] || [ "$file_path" = "share.png" ]; then
      echo start png high quality
      echo $file
      pngquant --force --verbose --ordered --output ${file} --speed=1 --quality=50-90 $file
    else
      echo start png low quality
      pngquant --iebug --force --verbose --ordered --output ${file} --speed=1 256 $file
    fi
  fi
done

无法在项目级别重用

proj.win32/writereourcepacked.bat

setlocal enabledelayedexpansion
cd ../
cd Classes/
del ResourcePacked.h
cd .>ResourcePacked.h
for /f "delims=" %%i in (ResourceUnpack.h) do (
set ifo=%%i
set ifo=!ifo:/=_!
set ifo=!ifo:__=//!
echo !ifo!>>ResourcePacked.h
)
call ../proj.win32/rename.bat

模糊的路径关系,不清晰的调用结构

project.properties

# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.

# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):


# Project target.
target=android-15


android.library.reference.1=..\\..\\cocos2d-x\\cocos2dx\\platform\\android\\java
android.library.reference.7=../../game_client_framework/social/proj.android/java
android.library.reference.3=../../game_client_framework/clientbase/proj.android/java
android.library.reference.2=../../game_client_framework/network/proj.android/java
android.library.reference.5=../../game_client_framework/payment/proj.android/java
android.library.reference.6=../../game_client_framework/livevideo/liblivevideo
android.library.reference.4=../../game_protocol_base/config_libpayment/upmp/libUpmpPayment

引用是有顺序的

从不考虑跨平台

AndroidManifest.xml

<!-- beluga -->
<meta-data
    android:name="BELUGA_TRACK_ID"
    android:value="d595c45d575747111111111111111111" />
<!-- TalkingData -->
<meta-data
    android:name="TDGA_APP_ID"
    android:value="3E24015A301B7D111111111111111111" />
<meta-data
    android:name="TDGA_CHANNEL_ID"
    android:value="mmarket" />
<!-- end --> 
<meta-data
    android:name="com.crashlytics.ApiKey"
    android:value="03f2d6966af6e311111111111111111111111111" />
<!-- ShareSDK [ -->

setup.py 对 AndroidManifest.xml 的修改

<receiver
        android:name="com.dolphin.eshore.message.MessageTriggerReceiver"
        android:process=":msg" >
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <activity
        android:name="com.starfield.game.android.message.DialogActivity"
        android:configChanges="keyboard|keyboardHidden|orientation"
        android:screenOrientation="portrait" >
    </activity>
</application>

使用 sed 通过特征文本对信息进行替换,容易出错

game.properties 中的属性

  • payment_init_provider 字符串,可多个(取消)
  • payment_sms_provider 字符串,可多个(取消)
  • payment_third_provider 字符串,可多个(取消)
  • payment_login_provider 整数,只能1个
  • payment_exit_provider 整数,只能1个

改为

  • provider_login=0
  • provider_exit=0
  • providers_payment=6|7|16|200
  • providers_kit=400|500|600

程序体量

文件名 行数 文件数
setup.sh 300+ 20+
auto_release_build* 500~700 10+
build_version.sh 400 4
脚本集合 <100 10+
合计 20K+ 60+

Be Elegant

graceful

什么是重点?

什么是重点?

什么是重点?

通用 —— 将通用的操作抽象出来(例如复制)

安全 —— 将脚本对打包的影响降到最低

保护 —— SDK 接入者不需要关心具体实现,也无法关心具体实现

易用性 —— 批量功能

通用性 —— 单机/Jenkins

独特性 —— 单机的特殊功能

选择开发语言

不用bash的原因

  • 不能跨平台
  • 语法古怪
  • 多版本不兼容,例如数组
  • 环境依赖

使用python的原因

  • 完整的语言
  • 丰富的库
  • 完善的多平台支持
  • 包管理机制
  • gui支持

选择配置文件格式

  • py 格式
  • xml 格式
  • json 格式
  • ini 格式
  • yaml 格式

ini 格式的优点

  • 人类友好
  • 足够简单,设计良好
  • 支持简单的层级关系
  • 逐行解析

增强的 ini 格式

增加 [@list section] 来支持列表

看看

Good Night