LobiのAndroidアプリ開発を Android Studio 3.0 に移行しました!

こんにちは!

ゲームコミュニティ事業部(Lobi)サービス基盤チームでアプリエンジニアをしているジェイソンです。

ついにAndroid Studio 3.0 正式版がリリースされましたね。 Android Studio 3.0 では、Kotlin の正式サポートをはじめとして様々な新機能や変更が含まれています。

というわけで、さっそくLobiのAndroidアプリ開発を、Android Studio 3.0 に移行しました。

ゲーム攻略チャットSNS、マルチ掲示板 Lobi(ロビー)

本記事では移行にあたって、Android Studio 3.0(Android Plugin for Gradle 3.0)対応のために、どういったことをしなければならないかをまとめました。 プロジェクトによって対応不要なものや、本記事に記載のない対応が必要になるかもしれませんが、参考にしていただければと思います!

Android Plugin for Gradle 3.0.0

まずは、Androd Plugin for Gradle 3.0.0 に更新しないと始まりませんよね。

top-level(root直下)の build.gradle ファイルに、以下を記載します。

dependencies {
    classpath 'com.android.tools.build:gradle:3.0.0'
}

buildToolsVersion 26.0.2

Android Plugin for Gradle 3.0.0 を使うためには、SDK Build Tools も更新しなければいけません。

モジュール単位の build.gradle ファイルに、以下を記載しましょう。

android {
    buildToolsVersion '26.0.2'
}

Gradle 4.1

Gradleも最新にする必要があります。

gradle-wrapper.properties ファイルに、以下を記載しましょう。

distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

Flavor Dimensions

Android Studio 3.0 から、すべての Flavor に対して、Flavor Dimensions の設定が必須となりました。

未設定の場合、以下のようなメッセージとともにビルドエラーとなるので注意しましょう。

Error:All flavors must now belong to a named flavor dimension.
The flavor 'flavor_name' is not assigned to a flavor dimension.

新しい dependency configuration

Android Studio 3.0 から、 compile は非推奨となり、代わりに implementationapi を使うことが推奨されています。

implemntationapi の違いについて簡単に説明すると、外部(モジュールの利用者)に対して、モジュールの依存関係を公開するかしないかで使い分けることになります。 たとえば、依存関係を外部に公開するのであれば api を、依存関係をモジュール内部でのみ使用し外部に公開しないのであれば implementation を使うということです。 同様に provided の代わりに compileOnlyを、 apk の代わりに runtimeOnly を使うことが推奨されています。

このあたりは公式ドキュメントをご覧になっていただくと、より理解が深まります。

Use the new dependency configurations - Migrate to Android Plugin for Gradle 3.0.0

Androidライブラリのビルドバリアント設定

今までは、アプリモジュールをデバッグビルドしていても、アプリモジュールはライブラリのリリースビルドを使用するのが標準でした。 もしライブラリをリリース以外のビルドタイプでビルドしたい場合、以下の二つの設定が必要です。

  1. ライブラリモジュールの build.gradlepublishNonDefault true を設定する
  2. アプリモジュールの依存関係で、以下のように追加する
dependencies {
    debugCompile project(path: ':library', configuration: 'debug')
    releaseCompile project(path: ':library', configuration: 'release')
}

Android Studio 3.0 では、モジュールの依存関係を implementation にしていると、アプリモジュールのビルドバリアントを引き継いでくれるようになりました。 なので、ライブラリをリリース以外のビルドタイプでビルドしたい場合、以下のように設定します。ちょっとだけ簡単になりましたね。

  1. ライブラリモジュールの build.gradlepublishNonDefault true を設定する
  2. アプリモジュールの依存関係で、以下のように追加する
dependencies {
    implementation project(path: ':library')
}

Android Asset Packaging Tool 2.0 (AAPT2) 対応

Android Studio 3.0 から、Android Asset Packaging Tool 2.0 (AAPT2) を使ったリソース処理がデフォルト動作となりました。

もしAAPT2を使いたくない場合は、 gradle.properties に以下を追記してください。

android.enableAapt2=false

AAPT2有効時に、Support Library がビルドエラー

AAPT2が有効の場合、Support Library でビルドエラーが発生することがあります。

C:\Users\hogehoge\.gradle\caches\transforms-1\files-1.1\appcompat-v7-26.0.2.aar\fee37bff362162d6a864b5b32c15cd0e\res\values\values.xml
Error:(387, 5) error: style attribute '@android:attr/windowEnterAnimation' not found.
Error:(387, 5) error: style attribute '@android:attr/windowExitAnimation' not found.
C:\Kayac\hogehoge\app\NakamapNewUI\app\build\intermediates\incremental\mergeDevelopDebugResources\merged.dir\values\values.xml
Error:(1804) style attribute '@android:attr/windowEnterAnimation' not found.
Error:(1805) style attribute '@android:attr/windowExitAnimation' not found.
Error:failed linking references.
Error:java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
Error:java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
Error:com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
Error:Execution failed for task ':app:processDevelopDebugResources'.
> Failed to execute aapt

この場合、 @android:attr/windowEnterAnimation@android:attr/windowExitAnimation という属性が見つからないよ、というエラーのようです。

AAPT2が有効で、名前空間からリソースにアクセスしたいとき、リソース参照シンボル(@)を付与すると上記のようなエラーが発生してしまうようなので、以下のように name 属性から @ を削除することで問題が解消しました。

     <style name="Animations_Fading">
-        <item name="@android:windowEnterAnimation">@android:anim/fade_in</item>
-        <item name="@android:windowExitAnimation">@android:anim/fade_out</item>
+        <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
+        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
     </style>

これについても、 公式ドキュメント にしっかりまとまっています。

android.useDeprecatedNdk はもう使えない

android.useDeprecatedNdk を使っていると、いよいよビルドが通らなくなってしまいました。

Error:FAILURE: Build completed with 2 failures.

1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':app:compileDevelopDebugNdk'.
> Error: Flag android.useDeprecatedNdk is no longer supported and will be removed in the next version of Android Studio.  Please switch to a supported build system.
  Consider using CMake or ndk-build integration. For more information, go to:
   https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile
   To get started, you can use the sample ndk-build script the Android
   plugin generated for you at:
   C:\Kayac\project\app\hogehoge\app\build\intermediates\ndk\develop\debug\Android.mk
  Alternatively, you can use the experimental plugin:
   https://developer.android.com/r/tools/experimental-plugin.html
  To continue using the deprecated NDK compile for another 60 days, set
  android.deprecatedNdkCompileLease=1508989475208 in gradle.properties

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
==============================================================================

ただし60日間限定で、 gradle.propertiesandroid.deprecatedNdkCompileLease=1508989475208 と設定すると継続してビルドできるようです。

しかしこれはあくまで延命手段なので、抜本的な解決策を模索するのがよいでしょうね。

まとめ

本記事では、待ちに待った Android Studio 3.0 を気兼ねなく使えるよう、Android Studio 3.0(Android Plugin for Gradle 3.0)対応のために、どういったことをしなければならないかをまとめました。

Android Studio 3.0 は様々な新機能や変更が盛り込まれた、半年ぶりの大規模なアップデートでした。

本記事によって、より新しい環境にスムーズに移行できる一助ができれば幸いです!

カヤックではAndroid Studio 3.0 にアップデートしたい欲を抑えられないエンジニアを募集しています!

カヤックではKotlinに移行したくて仕方がないエンジニアも募集しています!

Dockerで開発環境構築を10倍楽にしたはなし

Lobi事業部 サービス基盤チームの長田です。

最近プロジェクト内で使用する開発環境にDockerを利用するようになったので、その紹介をします。

Dockerにしたってどういうこと?

公開済みのWebサービスに変更を加えて動作確認をする場合、本番環境でそれを行うわけにはいきません。 ほとんどの場合はローカルマシンでWebサービスの全体または一部のコピーを動かして動作確認を行うことでしょう。 その後ステージング環境などの他の開発メンバーも触ることができる環境で動作確認やQAを行い、 問題がなければ晴れて本番環境に反映、という流れが一般的かと思います。

この「ローカルマシンでWebサービスのコピーを動かす」部分にDockerを利用している、ということです。

Dockerにしてどうなった?

Before

開発環境構築に1〜2日かかっていた

After

開発環境構築がランチに行っている間に終わるようになった

利用者の声

  • 新しくジョインする方の環境セットアップが格段に楽になった
  • 以前は、開発環境に問題が起きるとその修復だけでかなり時間とられていたが、そういうことがなくなった
  • それはすてきなことです

動機

とにかく時間がかかる

Lobiは2010年にサービス開始しました。 開発環境構築にも当時からの蓄積があります。 「歴史的な理由でxxが必要」とか、「このミドルウェアのバージョンはxxじゃないとだめ」とか、 そういう細かい決まりごとのようなものが複数存在します。 これらを新しく来たエンジニアに説明するのは容易ではありません。

細かい問題を解決していくと、結局開発環境のセットアップに 丸1〜2日 かかってしまっていました。 Webサービス開発に慣れていない新人エンジニアに至っては、まともに動くようになるまで 1週間 かかった、なんてこともざらにありました。

セットアップは最初にしかやらないので、ベテランエンジニアでもやり方をすっかり忘れてしまっていたりします。 なによりこういう細かいハードルは解決してもその恩恵は自分の環境にしかないので、時間の無駄になることがほとんどでした1

各人の開発環境が微妙に異なる

かといってchefやansibleを使って開発マシンをセットアップしようとしても簡単にはいきません。 各自の開発マシンの構成は微妙に異なるため、それらの際を吸収するためのメンテナンスコストのほうが大きくなってしまいます。 「日頃の行い」のせいでその人のマシンでしか発生しない問題も・・・。

Crypt::OpenSSL::X509インストールできない問題

ピンポイントな動機としては、OSX上でPerlのモジュールであるCrypt::OpenSSL::X509がインストール出来ないという問題がありました。

https://github.com/dsully/perl-crypt-openssl-x509/issues/46

Makefileをいじったりすればなんとかなるといえばなるのですが、これもまた無駄な時間に分類するべきものでしょう。


諸々の問題を解決するために、「各種ミドルウェア・アプリケーションをDockerコンテナ上で動かす」という選択をするに至りました。

構成

Docker Composeで各アプリケーションを起動

Docker Composeで各アプリケーションごとにコンテナを用意しました。 docker-compose.ymlは以下のような感じです。 なお、説明に不要と思われるオプション値については適宜省略しています。

version: "2"

services:
  nginx:
    build: ./nginx
    image: "lobi/openresty"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ...
    depends_on:
      - app
      - memcached
      - katsubushi

  app:
    build: ./app
    image: lobi/app
    volumes:
      - "./..:/lobi"
    depends_on:
      - mysql
      - redis
      - memcached
      - katsubushi
      - gearmand
      - gearman-worker
    command: plackup -R ./lib -Ilib -E development script/app.psgi

  gearmand:
    image: lobi/app
    ports:
      - "4730:4730"
    volumes:
      - ...
    command: gearmand --port=4730

  gearman-worker:
    image: lobi/app
    volumes:
      - ...
    depends_on:
      - mysql
      - redis
      - memcached
      - katsubushi
      - gearmand
    command: perl -Ilib script/boot_gearman_worker.pl

  mysql:
    image: "mysql:5.5"
    ports:
      - "3306:3306"
    volumes:
      - "./mysql:/var/lib/mysql"

  redis:
    image: "redis:2.8"
    ports:
      - "6379:6379"
    volumes:
      - "./redis:/data"

  memcached:
    image: memcached
    ports:
      - "11211:11211"

  katsubushi:
    image: katsubushi/katsubushi

各種ミドルウェア

nginxやmysqlなどのミドルウェアは公式配布されているDocker Imageを利用すればいいので簡単ですね。

各アプリケーションには依存関係がある場合があるので(例:Perlアプリが立ち上がっていないとnginxでproxyできない)、 depends_onで起動順を指定しておきましょう。

このあたりはDocker Composeを使う際の普通の方法です。

mysqlおよびredisのデータはコンテナ外に保存しておきたいので、 各データ保存ディレクトリをvolumesでホストマシンと共有しています。

Perlアプリケーション

Perlアプリケーション用のコンテナにはamazonlinuxを使用しています。 本番環境でもAmazon Linuxを使っているので、「手元では動いたのに〜」という事が起こりにくいのも嬉しいポイントです。 問題になっていたPerlモジュールのCrypt::OpenSSL::X509もすんなりインストールできます。

Perlアプリケーションのソースコードはホストマシン上にあり、 docker-compose.ymlでvolumes指定して共有しています。 ホストマシン上で普段使っているエディタで編集すれば、コンテナからもその変更が見えるわけです。

ソースコード変更時のアプリケーション再起動は、 plackupコマンドに-Rオプションを指定すればファイル変更時に自動で行ってくれます。 Dockerを使う使わないにかかわらず、plackアプリを開発する上ではお世話になるオプションですね。 詳しくはplackのドキュメントを参照して下さい。

スクリプト&テスト実行

開発中に必要なスクリプト(サンプルデータの生成とか)やテストの実行もコンテナ上で行います。 基本的にはdocker-compose runにコマンドを渡せばOK。

$ docker-compose run --rm app $command

よく使うコマンド実行には専用の実行スクリプトを用意していたりします。 たとえばテスト実行するために以下のようなスクリプトを用意して、

#!/bin/bash

test="$1"
cd path/to/docker/dir
docker-compose run --rm app carton exec -- prove -lr $test

こんな風に呼び出しています (dpvは上記スクリプトの名前2)。

$ dpv t/api/post_chat.t

メリット

ハマり所を共通の問題に

個々人の開発マシン上に直接開発環境を構築していた頃は、 その開発マシン固有の問題が発生することがありました。 インストールされているライブラリのバージョンとか、パッケージマネージャの設定とか、そういう日頃の行いによるものです。

DockerコンテナにしてDockerfile他セットアップスクリプトをリポジトリ上で共有するようになったので、 何か問題が起こった場合は誰かが解決すれば別の誰かもうれしいという状態になりました。

壊れてもすぐに作り直せる

うっかり環境をぶっ壊しても、コンテナを終了して再度立ち上げれば元通りです。 安心。

サーバーサイドエンジニア以外でも開発環境をセットアップできる

Front-end Engineerなど、サーバーサイドのコードをいじるわけではないけどサーバーアプリを動かしたいという需要がある人も、 開発環境のDocker化によって簡単に環境構築ができるようになりました。 本番環境等にアクセスしてローカルプロキシを使ってJSなどを書き換える方法もありますが、 本番未実装の機能の場合にはこの方法は使えませんし、データの用意なども手元に環境があったほうが何かと便利です。

また、

「サーバー側のコントローラーをちょっといじればいいだけなんだけど、サーバー側だから手が出ないな〜開発環境無いしな〜」

が、

「フロント直すついでにサーバー側もちょろっと直しとくか〜」

に変わりました(そのスキルがある人限定ではありますが・・・)。 もちろん本番環境に反映する前にはCIと動作確認とコードレビューが入るので、 取り返しのつかないコードが紛れ込んでしまうことはまずありません。

cpanfile.snapshotが手元でできる

Lobiではcpanモジュールのversioningにcartonを使用しています。 実行環境による影響をなくすため、以前はcpanfile.snapshotの生成をAWS上のAmazon Linuxインスタンスで行なっていました。 これをDockerコンテナ上で行うことで誰でも手元の環境で生成できるようになりました。

デメリット

Dockerの知識が必要

ただ開発環境を使うだけであればDockerのことは知らなくても済みます。 セットアップ操作は全て自動化してあるので。

ただ、何か問題が発生した場合はどのような仕組みで開発環境が動作しているのかを知る必要があります。 「共通の開発環境なので誰かが直せばみんな直る」とはいいつつも、「誰か」がいつも同じ人になってしまうというリスクはあります。

Dockerに限らず、新しいツールや手法を導入した際にセットでついてくる問題ですね。

重い

複数のコンテナを起動することになるため、ホストマシンのリソースを食いがちです。 Lobiには複数のPerlアプリケーションがあるため、それらを別々のコンテナで動かすことになります。 開発中に全てのPerlアプリケーションが必要になるわけではないので、適宜不要なコンテナをstopするなどの対処療法くらいしか無いのが現状です。

お金で解決するという手も無きにしもあらず。

Windows環境では使えない

いまは開発環境として全員Macを使っているのですが、Windowsマシンでは今回用意したDocker開発環境が動かないことがあるようです。 絶対に動かないのではなく、動かないことがある、というのがまた嫌なところです。 全員Macである以上実害はないということで、原因調査は先のばしになっています。

おわり

何事も楽になるのはよいことですが、そのための道程は険しいものです。 中途半端に手を付けてしまっては余計に手間が増えてしまうこともあります。 「Dockerによる開発環境構築」も実用レベルということで一段落はしましたが、 これからもよりよい環境にするべく改良を加えていきたいと思います。

カヤックでは開発スピードを上げたいエンジニアを募集しています!


  1. もちろん、そういう経験が後に生きるということもなくはないですが、しなくてもいい苦労は極力避けたいものです。

  2. こういうプロジェクト固有のスクリプトは、direnvを使ってPATHを通しておくと便利です。