CircleCIでFirebase Test Labを動かす方法
CircleCIからFirebase Test Labを動かしてみたので、その際につまずいた所を書いておこうと思います。ほとんどの設定の仕方はCircleCIの「Testing With Firebase Test Lab」に書いてあるので、そちらを参考にしてください。
CircleCIでFirebase Test Labを使うための設定
さっそくですが結果、下記のような config.yml
になりました。
version: 2 jobs: build: docker: - image: circleci/android:api-28 working_directory: ~/repo environment: JVM_OPTS: -Xmx3200m TERM: dumb steps: - checkout # Download and cache dependencies - restore_cache: keys: - v1-dependencies-{{ checksum "build.gradle" }} # fallback to using the latest cache if no exact match is found - v1-dependencies- - run: name: gradle dependencies command: ./gradlew androidDependencies - save_cache: paths: - ~/.gradle key: v1-dependencies-{{ checksum "build.gradle" }} - run: name: Build debug APK and release APK command: | ./gradlew :app:assembleDebug ./gradlew :app:assembleDebugAndroidTest - run: name: Store Google Service Account command: echo $GCLOUD_SERVICE_KEY | base64 --decode --ignore-garbage > ${HOME}/gcloud-service-key.json - run: name: Authorize gcloud and set config defaults command: | sudo gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json sudo gcloud config set project ${GOOGLE_PROJECT_ID} - run: name: Test with Firebase Test Lab command: > sudo gcloud firebase test android run \ --type instrumentation \ --app ./app/build/outputs/apk/debug/app-debug.apk \ --test ./app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \ --results-bucket cloud-test-${GOOGLE_PROJECT_ID} \ --device model=Nexus6,version=21,locale=ja,orientation=portrait \ --timeout 10m \ --use-orchestrator - run: name: Install gsutil dependency and copy test results data command: | sudo pip install -U crcmod sudo mkdir ~/firebase sudo gsutil -m cp -r -U `sudo gsutil ls gs://cloud-test-${GOOGLE_PROJECT_ID} | tail -1` ~/firebase/ | true - store_artifacts: path: ~/firebase/
以降は実際につまずいたところの解説になります。
Firebase Test Labをgcloudコマンドから使う準備をする
gcloudコマンドは image: circleci/android:api-28
に入っているのですが、Firebase Test Labにアクセスできるようにするために、プロジェクトの情報を読み込ませる必要あります。
- まずは Testing With Firebase Test Lab の1〜3に従って、Firebase Test Labにブラウザでアクセスできるようにします。
次に、Firebase Consoleのプロジェクト設定、サービスアカウントから「新しい秘密鍵の生成」を押して、JSONファイルをダウンロードします。
そして、ダウンロードしたJSONファイルを下記の手順でBase64エンコードして、そのファイルに書かれている文字列をCircleCIの環境変数「GCLOUD_SERVICE_KEY」に設定します。
openssl base64 -in [ダウンロードしたJSONファイル] -out service_key.json
これで下記の部分が動くようになって、Firebase Test Labを使う準備ができました。
- run: name: Store Google Service Account command: echo $GCLOUD_SERVICE_KEY | base64 --decode --ignore-garbage > ${HOME}/gcloud-service-key.json - run: name: Authorize gcloud and set config defaults command: | sudo gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json sudo gcloud config set project ${GOOGLE_PROJECT_ID}
Firebase Test Labをgcloudコマンドから使う
下記の部分でInstrumented Testを指定の端末で実行することができます。1つつまずいたのは「Nexus 6」のように端末名の間にスペースを入れてしまていて、Format must be ARG_FILE:ARG_GROUP_NAME Exited
のようなエラーが出てしまっていました。
- run: name: Test with Firebase Test Lab command: > sudo gcloud firebase test android run \ --type instrumentation \ --app ./app/build/outputs/apk/debug/app-debug.apk \ --test ./app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \ --results-bucket cloud-test-${GOOGLE_PROJECT_ID} \ --device model=Nexus6,version=21,locale=ja,orientation=portrait \ --timeout 10m \ --use-orchestrator
テスト結果をCircleCIのArtifactsに保存する
Firebase Test Labのテスト結果は、上記で指定したGoogle Cloud Storageのバケットにアップロードされます。そのため最新のものを一件ダウンロードして、指定のフォルダに保存します。そして、それをCircleCIのartifactsとして保存します。
- run: name: Install gsutil dependency and copy test results data command: | sudo pip install -U crcmod sudo mkdir ~/firebase sudo gsutil -m cp -r -U `sudo gsutil ls gs://cloud-test-${GOOGLE_PROJECT_ID} | tail -1` ~/firebase/ | true - store_artifacts: path: ~/firebase/
あまりまとまった記事がなかったのですが、CircleCIからFirebase Test Labを使うのはすごく簡単で、エミュレータを立ち上げたりする苦労をしなくていいのは本当に最高だなと思いました!
参考
CircleCIでInstrumented Testをする時はFirebase Test Labでよさそう
概要
アプリ側にCloud Firestoreからデータをとってくるロジックが書いてある場合に、それをCircleCIでどうやってテストしようか迷ったので、色々施行錯誤した結果を書いておきます。
結論
CircleCIが推奨しているのであれですが、Firebase Test Labを使うことにしました!無料枠も豊富にあって、超過したテスト時間しか課金されないので Instrumented Test
をする時はこれでいいんじゃないかと思います。
施行錯誤
結論に至るまにでやったことです。
CircleCIでエミュレータが立ち上がらない
Androidに依存があるテストを実施する場合、 Instrumented Testと呼ばれるテストの種類に該当し、エミュレータを立ち上げてテストを行う必要があります。Cloud FirestoreはAndroidに依存する部分(ContextやGoogle Play Serviceなど)が多いので、まずはこの方法を試してみました。
昔のCircleCIはエミュレータの立ち上げに対応していたのですが、CircleCI2になってからは公式でサポートされていません。そのため、無理やり下記の方法を試してみたのですがいずれも上手くいきませんでした。
Android Studio emulator: ERROR: detected a hanging thread QEMU2 main loop
とエラーになって、エミュレータが立ち上がらない。CircleCIがIPv6に対応していないのが原因のような気もしますが解決せず。- エミュレータの立ち上げに、
emulator64_x86
を使えばIPv6問題を回避できそう だったので試したのですが、CircleCIが対応していないようでエミュレータが立ち上がりませんでした。
他にも施行錯誤してみたのですが、結局エミュレータが立ち上がりませんでした。
RobolectricではCloud Firestoreに繋がらない
次にRobolectricを使ってCloud Firestoreに繋げられないかやってみました。Robolectricはエミュレータを立ち上げずに、JVM上でテストするためのライブラリです。Cloud FIrestoreを使うには、AndroidのViewの情報などは不要なため、Robolectricで十分テストできるのではないかと考えました。
結果、 色々やってみたのですが、Cloud FirestoreはGoogle Play Serviceに依存している部分が多いためか、Cloud Firestoreにうまく繋ぐことができませんでした。
結果
CircleCIで完結している方が分かりやすいかと思って、色々やってみたのですが、結局今後UIのテストが増えたり分かりやすさを考えると、Firebase Test Labを使うのが良いという結論に至りました!(あと実は課金形態を勘違いしていたので、気づいていればこれ一択でした...)
参考
UIScrollViewの中でUICollectionViewがスクロールしない
iOSで上下左右にスクロールさせたい時、UIScrollViewで縦スクロール、その中にUICollectioViewを置いて横スクロールをさせる方法を思いつきました。
しかし、これだけだとUIScrollViewがタッチをとってしまい、縦スクロールしか効きません。
そこで調べた所、UIScrollViewの「Direction Lock Enabled」にチェックを入れることで、縦スクロールのタッチだけに反応するようになって、UICollectionViewが横スクロールできるようになりました!
参考: ios - UIScrollView AutoLayout Vertical Only - Stack Overflow
ionicのプラグインを作る時につまずいたこと
最近、ionicのJSからiOSの機能を使えるようにするプラグインを作ることがあったので、その際にいくつかつまずいたので解決方法をまとめておきます。
何度もJSのコールバックを呼びたい
ネイティブ側から何度もJSのコールバックを呼びたい時は、CDVPluginResultに setKeepCallbackAs(true)
を呼び出す必要があります。
let result = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: "Hello") result.setKeepCallbackAs(true) commandDelegate.send(result, callbackId:command.callbackId)
通常は一度しかcallbackIdを使えないのですが、こうすることで何度もcallbackIdに対して結果を通知することができます。
あきらめかけた時に下記の記事を読んでいたら書いてありました。
Beacapp SDK を Cordova Plugin 化してみた
非同期にJSのコールバックを呼びたい
callbackIdをインスタンス変数に保存することで、非同期の処理が終わったタイミングでコールバックを呼ぶことができました。
private var saveCallbackId: String? = nil func hello(_ command: CDVInvokedUrlCommand) { saveCallbackId = command.callbackId // 非同期処理 ... { let result = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: "hello") commandDelegate.send(result, callbackId:saveCallbackId) } }
プラグインの開発、デバッグの方法
そもそもネイティブの機能を開発、デバッグをどうすればいいのか全く分からず手探りやっていました。その中で、ほどほどに速度が出て開発しやすい方法を見つけました。
- とりあえず本体のプロジェクトにプラグインをインストールする
- Xcodeで本体プロジェクトを開いて、Pluginsにあるプラグインのファイルを直接編集して開発を進めていく
- 動くようになったら、そのファイルの内容をコピーして、プラグインのファイルに貼りつけてプラグインを再インストールする
他にも方法があると思いますが、この方法だと普通にiOSの機能を開発している時と変わらず開発を進めることができました!
ionic(cordova)のプラグインの詳細をまとめた記事があまりなかったので、公式ドキュメント を読んだり、公式のcordova-plugin-geolocationやcordova-plugin-ble-centralのソースコードを読みながら開発を進めました。
今回サンプルで作ったリポジトリも置いておきます!プラグインには下記のメソッドが含まれています。
- 引数にhelloを付けて返す
- タイマーで5秒おきに処理を実行する
- ユーザーの現在地を取得する
ClearDBでmax questionsになった時の対処法
Heroku上でClearDBを使ってサービスを作っているのですが、ClearDBにめちゃくちゃ接続するタスクを heroku run
で実行してしまい、以下のエラーが出続けるようになってしまいました。
Mysql2::Error (User '...' has exceeded the 'max_questions' resource (current value: 18000))
ほとんどバックエンドの知識がないのですごく焦りましたが、Herokuをメンテナンスモードにして、コネクションが全てキャンセルされたことを確認した後で元に戻すことで解決しました。
CircleCI 2.0でAndroidアプリをビルドする
最近CircleCI 2.0のClosed Betaがリリースされました。
CirceCI 2.0ではDockerをネイティブでサポートしたので、 さっそくDockerイメージを使ってAndroidアプリをビルドしてみました。
CircleCIの設定はビルドしたいアプリのディレクトリに .circleci/config.yml
を作って以下のように書きます。今回はDockerのイメージに既にAndroidアプリのビルド環境が整っているbeevelop/androidを使いました。
version: 2 jobs: build: working_directory: ~/working_directory docker: - image: beevelop/android:latest environment: ANDROID_HOME: /opt/android steps: - checkout - run: name: System information command: | mkdir $ANDROID_HOME/licenses echo [ANDROID_SDK_LICENSE] >> $ANDROID_HOME/licenses/android-sdk-license echo y | android update sdk --no-ui --all --filter "build-tools-25.0.2" echo y | android update sdk --no-ui --all --filter "extra-android-m2repository,extra-google-m2repository" - run: name: Install dependencies command: ./gradlew dependencies - run: name: Build command: ./gradlew assembleRelease
gist5b588be52fde061900e89dbf1abff990
今回は Build Tools
や Google Repository
を追加でインストールしています。Android SDKのライセンス周りは以下の記事を参考にしました。
Circle CIでAndroid SDK周りのライセンス許諾をローカル環境に合わせる - visible true
今まではブラックボックスの部分が多かったので大変でしたが、これからはDockerfileを見ればわかったり自分で作れたりするのですごく楽になりました。
また、以下の記事のようにローカルで設定ファイルを実行できるのですごく便利です。
CircleCI 2.0はローカル環境で実行できるよ - Qiita
※CircleCI 2.0はClosed Betaなので、使う前にこちらから申請する必要があります。