最近、IonicでCordova始めました。
いろいろと触ってみてますが、小綺麗なCSSフレームワークが用意されていると、細かい調整をしなくてもなんとなくそれっぽくなるので、結構好きです。
本記事では、バージョン命名をCordovaで運用するときに直感的ではない動きをするところがあったので、調べて分かったことを備忘録がてら紹介します。
読むの面倒くさい人向けのまとめ
- config.xmlのversionにsemver形式のバージョンを指定できる
- versionCodeやCFBundleVersionはバージョンから自動生成される
- versionCodeを自動生成に任せると、1のケタに不思議な数字が入るので気をつけろ
- 自分で指定するオプションもあるので自動生成が気に食わない場合はそちらを使おう
confix.xmlのversionは何を表す
少し話がそれましたが、モバイルアプリケーションでもバージョンを表すパラメータがあります。以下の記事が詳しいです。
Cordovaのconfig.xmlにも、このバージョンを記述するための場所があります。
<widget
id="com.example.my-app"
version="0.1.0"
xmlns="http://www.w3.org/ns/widgets"
xmlns:cdv="http://cordova.apache.org/ns/1.0">
このversionに指定したものが、AndroidのversionNameとiOSのCFBundleShortVersionStringになります。
では、versionCodeやCFBundleVersionはどのように指定するのでしょうか?
一応、指定しなくても動くようになっています。一度ビルドした後の、各設定を見てみると、このようになっています。
このへんのルールについては公式リファレンスに記述がある通り、
- AndroidのversionCodeはversionNameが
X.Y.Z
であることを前提にして、PATCH + MINOR * 100 + MAJOR * 10000
- iOSのCFBundleVersionはCFBundleShortVersionStringと同じ
になるようです。
ふーん。Androidに関して言えば、よくある生成ルールじゃん。
と思っていたのですが。
versionCodeの生成規則が変
最終的に採用されるであろう、BuildConfig.xmlで設定されているversionCodeを見てみましょう。
package com.example.my_app;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.example.my_app";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1008;
public static final String VERSION_NAME = "";
}
期待していた値と違いますね。0 + 1 * 100 + 0 * 10000
、つまり100
になることを期待していたのですが、右側に1ケタ多くなっています。
まだ慌てる時間ではありません。AndroidManifest.xmlには100
と書いてあるのですから、きっとPlayストアに上げれば100
として表示されるかもしれません。
1008
でした。どうやらこの値で決まりのようです。
何故ケタが変わったのでしょうか。何故8
が入ったのでしょうか。
アーキテクチャやバージョンによって変わる1の桁
一度AndroidManifest.xmlに書かれた内容を覆せるやつなんて限られています。そう、build.gradleです。Cordovaプロジェクトが用意しているAndroidアプリのテンプレートがそのまま取り込まれたものということで、なにかやっていないかチェックしてみましょう。
android {
// 略
defaultConfig {
versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode") + "0")
if (cdvMinSdkVersion != null) {
minSdkVersion cdvMinSdkVersion
}
}
// 略
if (Boolean.valueOf(cdvBuildMultipleApks)) {
productFlavors {
armv7 {
versionCode cdvVersionCode ?: defaultConfig.versionCode + 2
ndk {
abiFilters "armeabi-v7a", ""
}
}
x86 {
versionCode cdvVersionCode ?: defaultConfig.versionCode + 4
ndk {
abiFilters "x86", ""
}
}
all {
ndk {
abiFilters "all", ""
}
}
}
} else if (!cdvVersionCode) {
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
// Vary versionCode by the two most common API levels:
// 14 is ICS, which is the lowest API level for many apps.
// 20 is Lollipop, which is the lowest API level for the updatable system webview.
if (minSdkVersion >= 20) {
defaultConfig.versionCode += 9
} else if (minSdkVersion >= 14) {
defaultConfig.versionCode += 8
}
}
// 略
簡単に解説すると、
versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode") + "0")
↑でversionCodeを左に1ケタシフトして、そのあとのif文の中でflavorやバージョンに応じて、1ケタ目に新しい数字を放り込んでいるようです。
判定 | 1のケタ |
---|---|
MultipleAPKをARMv7向けにビルド | 2 |
MultipleAPKをx86向けにビルド | 4 |
MultipleAPKをall向けにビルド | そのまま(0) |
API20(Android 4.4W)以上向けにビルド | 9 |
API14(Android 4.0)以上向けにビルド | 8 |
統一感ないな!!! しかも、"20 is Lollipop"って普通にチョンボじゃないか・・・?
ともあれ、これで謎は解けました。
<preference name="android-minSdkVersion" value="16"/>
今回扱っているプロジェクトのminSdkVersionは16
なので、1のケタに8
が入り、元々のルールと合わせる形で1008
という値になったのでしょう。
どこかのドキュメントに書いといてくれないかなこれ!!!
自分で指定できる
さて、自動生成されるversionCodeはちょっとアレな感じでした。こうなってくると、自分で設定したくなってくる人も多いと思います。
ということで、自分で設定する方法を紹介して、締めにしたいと思います。
<widget
id="com.example.my-app"
version="0.1.0"
android-versionCode="12345"
ios-CFBundleVersion="25.20151124"
xmlns="http://www.w3.org/ns/widgets"
xmlns:cdv="http://cordova.apache.org/ns/1.0">
上記のような形で、android-versionCodeやios-CFBundleVersionを指定しておくと、ビルド時に考慮してもらえます。
こんな感じに。
package com.example.my_app;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.example.my_app";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 12345;
public static final String VERSION_NAME = "";
}
まとめ
versionCodeの自動生成そのものはネイティブ開発でもときどき見かけるベストプラクティスですし、いちいち自分で決めるのも面倒なので、いいことだと思います。
ただ、一度PlayストアにリリースしてしまったversionCodeは、加算はできても減算はできない厄介なシロモノになります。自動生成に任せるのはよいですが、生成ルールに気を配って、良いリリースエンジニアリングをしましょう。
宣伝
ウォーターセル株式会社では、「ネイティブアプリ開発はある程度経験したし、そろそろJS覚えてハイブリッドアプリ開発とかしてみたいなー」という挑戦的なエンジニアを募集しています。