LoginSignup
8

More than 5 years have passed since last update.

Rocket.Chat.Android.LilyをCircle CIで自動ビルドしてFabric betaにアップロード

Last updated at Posted at 2015-12-23

先日、無事に(?)Rocket.Chat.Androidのコミッタになりました。(プロジェクト名はLily
ということで、「自分の環境だけでビルドができればいいや」みたいな考えは捨て、CircleCIでビルドできるようにしました。

Rocket.Chatチームから要望があったのでFabric betaでのアプリ配布もふくめて対応をしたのですが、案外ハマリポイントが多かったので、共有のため記事を残しておきたいと思います。

方針

  • circle.yml を作らない、なるべくCircleCIのProject Settingsで頑張る
  • Android StudioでもCIでも使えるように、環境変数の依存性は少なく
  • Fabricプラグインは邪魔くさいので使わない

CIでビルドを通すために…

JAVA_HOMEの設定

Rocket.Chat.Android.Lilyでは、retrolambdaをつかっているためか、Java 8じゃないとビルドが通りません。
Circle CIの環境はデフォルトだとJava7が設定されているので、ビルドにコケます。
環境変数のところで

NAME VALUE
JAVA_HOME /usr/lib/jvm/jdk1.8.0

と設定します。

ANDROID_HOMEの設定・・・は不要!

CIがデフォルトで入れてくれるらしい。

git submodule の設定、local.propertiesのセット

Travis CIだったら勝手に git submodule init && git submodule update ってやってくれるんですが、CircleCIではやってくれません。
あと、local.propertiesにsdk.dirってのを定義してないとビルドが通りません。

Pre-dependency commandsのところに

git submodule init && git submodule update
echo "sdk.dir="$ANDROID_HOME > local.properties 

と設定します。

ビルドコマンドに注意

Circle CIは、メモリ使用が4GBこえるとプロセス強制終了される、という動作仕様があり、

./gradlew assembleDebug だと、

> Building 93% > :app:preDexDebug

> Building 93% > :app:preDexDebug./gradlew assembleDebug --info --stacktrace died unexpectedly

みたいなかんじで突然死を食らわされることがあります。

どっかのStackOverfowで紹介されてた(わすれたw)とおり

./gradlew assembleDebug --stacktrace -Pcom.android.build.threadPoolSize=1 -Dorg.gradle.parallel=false -Dorg.gradle.jvmargs="-Xms512m -Xmx2048m" -Dorg.gradle.daemon=false

こんなかんじでビルドコマンドをかけば、強制終了することなくアプリのビルドが完了します。

Fabric SDKの組み込み

リファレンスに載ってはいますが、それなりにやることがあります。

Fabricの手動組み込み
diff --git a/build.gradle b/build.gradle
index 9e8f838..c1d3551 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,20 +3,26 @@
 buildscript {
     repositories {
         jcenter()
+        maven { url 'https://maven.fabric.io/public' }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.3.0'
+        classpath 'com.android.tools.build:gradle:1.5.0'

         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
         classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
         classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1'
+
+        // The Fabric Gradle plugin uses an open ended version to react
+        // quickly to Android tooling updates
+        classpath 'io.fabric.tools:gradle:1.+'
     }
 }

 allprojects {
     repositories {
         jcenter()
+        maven { url 'https://maven.fabric.io/public' }
     }
 }

diff --git a/app/build.gradle b/app/build.gradle
index b979a36..cd0f12f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,17 +1,22 @@
 apply plugin: 'com.android.application'
 apply plugin: 'com.neenbedankt.android-apt'
 apply plugin: 'com.jakewharton.hugo'
+apply plugin: 'io.fabric'

 android {
     compileSdkVersion 23
     buildToolsVersion "23.0.1"

+    Properties properties = new Properties()
+    properties.load(project.rootProject.file('local.properties').newDataInputStream())
+
     defaultConfig {
         applicationId "chat.rocket.android"
         minSdkVersion 16
         targetSdkVersion 23
         versionCode 1
         versionName "1.0"
+        manifestPlaceholders = [fabric_api_key:properties.getProperty("FABRIC_API_KEY", System.getenv("FABRIC_API_KEY"))]
     }
     buildTypes {
         release {
@@ -41,4 +46,9 @@ dependencies {

     compile 'com.facebook.stetho:stetho:1.2.0'
     compile 'com.facebook.stetho:stetho-okhttp:1.2.0'
+
+    // Crashlytics Kit
+    compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
+        transitive = true
+    }
 }

diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d48f872..dae2df4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,6 +32,10 @@
             android:authorities="chat.rocket.android"
             android:name=".content.RocketChatProvider"
             android:exported="true"/>
+
+        <meta-data
+            android:name="io.fabric.ApiKey"
+            android:value="${fabric_api_key}" />
     </application>

 </manifest>

FABRIC_API_KEYのところがちょっと工夫してあって、

  • local.properties に FABRIC_API_KEY=XXXxxxXXXXxxx の定義があればそれを使う
  • ↑がなければ、環境変数の $FABRIC_API_KEY を使う

という構成にしてます。前者がAndroid Studioでビルド通るようにするため、後者はCircle CIで楽するために、こういう感じにしました。

Fabric SDKの初期化処理を追加

アプリケーションクラスに Fabric.with() の呼び出しを追加すればよいです。

RocketChatApplication.java

diff --git a/app/src/main/java/chat/rocket/android/RocketChatApplication.java b/app/src/main/java/chat/rocket/android/RocketChatApplication.java
index d837b0b..62b0961 100644
--- a/app/src/main/java/chat/rocket/android/RocketChatApplication.java
+++ b/app/src/main/java/chat/rocket/android/RocketChatApplication.java
@@ -2,12 +2,15 @@ package chat.rocket.android;

 import android.app.Application;

+import com.crashlytics.android.Crashlytics;
+import com.crashlytics.android.core.CrashlyticsCore;
 import com.facebook.stetho.Stetho;
 import com.facebook.stetho.okhttp.StethoInterceptor;
 import com.squareup.picasso.OkHttpDownloader;
 import com.squareup.picasso.Picasso;

 import chat.rocket.android.api.OkHttpHelper;
+import io.fabric.sdk.android.Fabric;

 public class RocketChatApplication extends Application {
     @Override
@@ -25,5 +28,8 @@ public class RocketChatApplication extends Application {

         Picasso picasso = new Picasso.Builder(this).downloader(new OkHttpDownloader(OkHttpHelper.getClient())).build();
         Picasso.setSingletonInstance(picasso);
+
+        CrashlyticsCore core = new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build();
+        Fabric.with(this, new Crashlytics.Builder().core(core).build());
     }
 }

デバッグ中のクラッシュがバンバン報告されるのは勘弁なので、Crashlyticsをデバッグビルドでは無効化でコメント頂いたのを参考に、DEBUGビルドでは無効になるようにしてます。

Beta用の設定ファイルをつくる

app/fabric.properties
apiSecret=XXXXXXxxxXXXXXXxxxxxxXXXXXXxxxXXXXXXxxxxxx
apiKey=XXXXXXxxxXXXXXXxxxxxx

ローカルでビルドする用には、↑のようなファイルを持っておけばいいだけなんですが、こんな機密情報含んだファイルをGitHubに上げるわけにいきません。
CIでは環境変数にこういう機密情報(?)を設定しておくことができるので、それを利用します

環境変数

↑のようにFABRIC_API_KEYFABRIC_BUILD_SECRETをあらかじめ入れておいて、

スクリプト

↑のようにそれをechoしてapp/fabric.propertiesに詰め込みます。

β版配布時のリリースノート

Circle CIは、circle.ymlで制限しないかぎりは馬鹿正直に全ブランチの全コミットに対してビルドをしようとするので

  • どのブランチをビルドしたものか
  • どのコミットを取り込んだものか

くらいはリリースノートで見れないと、わりと困ったことになります。

app/build.gradle
diff --git a/app/build.gradle b/app/build.gradle
index cd0f12f..bad25e6 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,6 +3,12 @@ apply plugin: 'com.neenbedankt.android-apt'
 apply plugin: 'com.jakewharton.hugo'
 apply plugin: 'io.fabric'

+def getCurrentCommitMessage() {
+    def gitlog = 'git log origin/develop...HEAD --decorate'.execute().text
+    if (gitlog.trim().length()>0) return gitlog
+    return 'git log -n 1 --decorate'.execute().text
+}
+
 android {
     compileSdkVersion 23
     buildToolsVersion "23.0.1"
@@ -17,6 +23,8 @@ android {
         versionCode 1
         versionName "1.0"
         manifestPlaceholders = [fabric_api_key:properties.getProperty("FABRIC_API_KEY", System.getenv("FABRIC_API_KEY"))]
+        ext.betaDistributionNotifications=false
+        ext.betaDistributionReleaseNotes=getCurrentCommitMessage()
     }
     buildTypes {
         release {

とりあえず、超適当ですが、 git log --decorate で 「origin/develop〜HEADまでのコミット または 最新の1コミット」をだすようにしてみました。

Beta配布!

./gradlew crashlyticsUploadDistributionDebug

こんな感じの Post-test commands を定義して、CIでビルドをかけると・・・

キタ━━━━(゚∀゚)━━━━!!

キタ━━━━(゚∀゚)━━━━!! ってなります。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8