使用 Xcode和 Android Studio管理 iOS和 Android项目版本
在移动应用开发和运营的过程中,版本管理是一个老生常谈的基础问
题,一些版本的基本概念也常常会困扰我们的研发和运营人员。同时,
手动管理软件版本,也常常会因为不小心导致后续的发布和更新问题。
这里,我准备了一些 iOS 和 Android 版本的基础知识,以及如何在应
用中获取版本信息和如何使用 Xcode 和 Android Studio 自动管理版
本号。
版本号解释
无论是 iOS 还是 Android 都定义了两个版本属性:
iOS
在 中定义
CFBundleShortVersionString
在 Xcode中解释为 Version,这个就是我们常说的版本号,一般用户
可见,通常由 <主版本号>.<次版本号>.<维护号>三部分组成,主要用
来识别不同时期不同功能的产品。
CFBundleVersion
在 Xcode中解释为 Build,一般用于应用市场和程序内部识别版本,作
为更新判断的依据,通常是一个递增的 INT类型。
这两个值可以在 Xcode 的项目信息里面进行管理,
当然,你也可以直接编辑 。
Android
在 中定义
android:versionName
对应 iOS 中的 CFBundleShortVersionString版本号,用作产品管理。
android:versionCode
对应 iOS 中的 CFBundleVersion编译号,作为内部识别。
在使用 Eclipse 开发时,可以通过直接编辑 文件
修改,在使用 Android Studio 时,这些信息由 Gradle 脚本管理,找
到并打开项目目录下 app目录内的 文件,版本信息
在 defaultConfig段,
程序内获取版本信息
一般在应用的关于页面,我们都会显示应用的版本,方便客服定位问题,
在应用检查更新时,也常常需要用到版本信息。其实,无论是在 iOS 上,
还是 Android 平台,获取笨笨信息都比较简便:
iOS
索引 Bundle 信息中的相关字段:
1
2
3
4
5
NSBundle *bundle = [NSBundle mainBundle];
NSString *name = [[bundle localizedInfoDictionary] objectForKey:@"CFBun
dleDisplayName"];
NSString *version = [bundle objectForInfoDictionaryKey:@"CFBundleShortV
ersionString"];
NSString *build = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"
];
NSString *fullVersion = [NSString stringWithFormat:@"version: %@ (%@)",
version, build];
上述的代码中,name为本地化的程序名称,version为版本号,build为
编译号,'fullVersion' 则将版本号和编译号组成一个完整的版本信息。
Android
获取 PackageInfo中的相关信息:
1
2
3
4
PackageInfo pi = ().getPackageInfo(
etPackageName(), 0);
String versionName = ; int versionCode =
e;
String fullVersion = ("version: %s (%d)", versionName, v
ersionCode);
同样,versionName为版本号,versionCode为编译号,不同的是,在
Android 中 versionCode使用 int类型存储。
Xcode 和 Android Studio 编译号自增
一般应用的版本号都会由产品经理或项目经理决定,根据产品所处
的阶段和功能决定修改版本号的哪一个段。但编译号更多时候是根据
每次发布递增,有时候还会遇到同一个版本号对应多个编译号的情况,
如,紧急修复了一个关键 Bug 并更新发布一个版本,但如果每次发布
都要手动去修改编译号回很繁琐,也很容易忘记和出错,而不管是
Xcode 还是 Android Studio 都没有提供自增编译号的功能,我们只有
手动添加编译脚本来达到自增的目的。
Xcode
添加编译过程,读取并修改 中的版本信息:
1、打开工程,选择编译目标,点击 Build Phases选项卡。
2、点击左上角的 + 添加,选择 New Run Script Phase 添加一个编译
脚本。
3、在脚本编辑其中输入下面的脚本:
1
2
3
4
#!/bin/bash
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$INF
OPLIST_FILE")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$INFOP
LIST_FILE"
上述脚本使用 PlistBuddy工具,读取 中的 CFBundleVersion
值,+1 后写回 中。
4、我们需要让该段代码在应用打包前执行,以便将修改应用到 App包
内,因此我们将该编译过程重命名为 Increase Version Code并移动
到 Copy Bundle Resources之前。
5、这样,当我们每次编译该 Target 时 ,就会执行改脚本
将 CFBundleVersion值增加 1,但没次调试运行时,该值都会加 1,这
并不是我们想要的,我们只需要在每次打包发布时增加 1就行,因此,
我们将 Run script only wehn installing前的勾打上,这样就只会在打包
应用时执行改脚本。
Android Studio
Android Studio 的 versionCode 自增原理和 Xcode 类似,不同的是
我们不能让编译脚本修改自身,而是通过一个额外的 Java
Properties来文件存储版本信息:
1、打开工程,选择 Module: app的编译脚本 。
2、找到 defaultConfig段,替换为下面的脚本:
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
def versionPropsFile = file('') if (versionPropsFil
()) { Properties versionProps = new Properties()
(new FileInputStream(versionPropsFile)) d
ef verCode = versionProps['VERSION_CODE'].toInteger()
versionProps['VERSION_CODE'] = (++verCode).toString()
((), null)
defaultConfig {
applicationId ""
minSdkVersion 19
targetSdkVersion 23
versionCode verCode
versionName ""
}
} else { throw new GradleException("Could not read
rties!")
}
这段脚本会打开 app 目录下的 配置文件,读
取 VERSION_CODE字段并增加 1后写回,同时将值赋
给 defaultConfig中的 versionCode。
3、此时,点击 Sync 会报错 Could not read !,这是
我们刚刚在脚本中抛出的,原因是找不到 文件,我
们需要新建一个。打开命令行定为到项目目录下:
1
2
$ cd app/
$ echo "VERSION_CODE=1" >
再次点击 Sync 就不会报错了。查看 文件,
1
2
3
$ cat
#Mon Nov 02 15:18:49 CST 2015
VERSION_CODE=3
发现 VERSION_CODE 已经增加到 3 了,说明该脚本被执行了两次,
但这并不符合我们的预期。
4、同 Xcode 中一样,我们期望仅仅在应用打包时将 versionCode增
加 1 。因此我们需要获取编译参数,仅当 release时才
将 versionCode增加 1 。修改后的脚本如下:
1
2
3
4
5
6
7
8
9
1
0
def versionPropsFile = file('') if (versionPropsFil
()) { Properties versionProps = new Properties()
(new FileInputStream(versionPropsFile)) def
verCode = versionProps['VERSION_CODE'].toInteger() def runTasks =
if (':app:assembleRelease' in runTa
sks) {
versionProps['VERSION_CODE'] = (++verCode).toString()
((), null)
}
defaultConfig {
1
1
1
2
1
3
1
4
1
5
applicationId ""
minSdkVersion 19
targetSdkVersion 23
versionCode verCode
versionName ""
}
} else { throw new GradleException("Could not read
rties!")
}
这里获取当前 task的名称,仅当 task包含 :app:assembleRelease时
才会将 versionCode加 1 ,否则直接使用读取到的值。
小结
版本管理是产品和项目管理中非常重要的一环,但在开发初期也常常容
易被忽略,等到遇到问题时候才感到头痛。其实,产品经理和开发人员
在产品的立项阶段就应该对产品版本有一个一致的理解,我个人通常在
项目框架建立之初就将这些规则脚本添加到项目文件中,以期降低后续
版本维护的成本。
使用Xcode和Android Studio管理iOS和Android项目版本