Web制作・アプリ開発をコストパフォーマンスで考えるなら

React Native + CircleCIでCI/CD環境を構築する

こんにちは。graphy事業部の遠藤と申します。

今回は、React NativeとCircleCIの組み合わせでCI/CD環境を構築する機会がありましたので、その詳細について記載していきたいと思います。

CIツールの選定

CIツールはCircleCI、Bitrise、TravisCIなどいろいろありますが、調査した結果、大きく以下の理由でCircleCIを選択しました。

  • ググったときの情報量が圧倒的に多い
  • iOS、Androidアプリのビルド環境に対応している
  • クライアント側・サーバー側共に同じCIツールが使える
  • 費用を安く抑えてスタートできる

CI環境の構築中にハマってしまうと、何度もビルドを繰り返すことになって非常に時間がかかってしまいます。 情報量が多いと解決策を見つけやすい為、予算や工数を大きく割けないプロジェクトにとっては、大事なポイントになってくると考えています。

準備

CircleCIのアカウント準備やGitHubとの連携の話は、公式ドキュメントで詳しく解説されていますので割愛します。

また、記載する内容でfastlaneを利用したビルドコマンドを使う部分がある為、こちらのReact Nativeにfastlaneを導入する手順の記事を読んでおくと理解がしやすいと思います。

環境構築後のイメージはこのような感じです。 テスト版アプリの配信サービスにはVisual Studio App Studioを使用しています。 CI/CD Image

CircleCIの設定ファイルを追加

React Nativeプロジェクトのルートに.circleci/config.ymlを追加します。

フォルダ構成は以下のような形になっています。 Folder Structure

以下のconfig.ymlの設定ではdevelopブランチに変更が入ったタイミングで、iOS/Androidそれぞれに対し、ビルドからデプロイまでが実行されるようになります。 ビルドからデプロイの処理は、fastlaneを使ってワンライナーで走らせられるようにしています。

# config.yml
version: 2.1
jobs:
  android:
    docker:
      - image: circleci/android:api-27-node
    steps:
      - checkout
      - run: bundle install --path vendor/bundle
      - run: npm install
      - run: bundle exec fastlane android build_dev

  ios:
    macos:
      xcode: "10.1.0"
    shell: /bin/bash --login -o pipefail
    steps:
      - checkout
      - run: bundle install --path vendor/bundle
      - run: npm install
      - run: bundle exec fastlane ios build_dev

workflows:
  android-ios:
    jobs:
      - android:
          name: android_dev
          filters:
            branches:
              only:
                - develop
      - ios:
          name: ios_dev
          filters:
            branches:
              only:
                - develop
# Fastfile
platform :ios do
  before_all do
    setup_circle_ci
  end

  lane :build_dev do
    match(
      type: "adhoc",
      app_identifier: "<BUNDLE IDENTIFIER>",
      readonly: true
    )
    gym(
      workspace: "ios/sample.xcworkspace",
      output_directory: "ios",
      scheme: "sample-dev",
      export_options: {
        method: "ad-hoc"
      }
    )
    appcenter_upload(
      api_token: "<API_TOKEN>",
      owner_name: "<OWNER_NAME>",
      app_name: "<APP_NAME>",
      ipa: "ios/sample-dev.ipa",
      notify_testers: true
    )
  end
end

platform :android do
  lane :build_dev do
    gradle(
      task: "assembleDevRelease",
      project_dir: "android"
    )
    appcenter_upload(
      api_token: "<API_TOKEN>",
      owner_name: "<OWNER_NAME>",
      app_name: "<APP_NAME>",
      apk: "android/app/build/outputs/apk/dev/sample-dev-release.apk",
      notify_testers: true
    )
  end
end

config.ymlに記載した設定は以下のような流れになるように作られています。

  1. GitHubからソースコードをクローンしてくる
  2. npmとbundlerで依存ライブラリのインストール
  3. fastlaneコマンドでビルドからデプロイ

parametersを使用して一部のステップを変更する

CircleCIを利用していると、config.ymlに記載したステップのうち一部だけ変更したいことがあります。 CircleCIのバージョン2.1ではparametersの機能を利用することで、ステップの設定で変数を利用することができるようになります。

例えば、development/staging/production環境別にアプリをビルドしたいという状況はよくありますが、そんな状況でparametersは活用できます。

環境別にビルドができるように、以下のようにFastfileを更新したとします。

# Fastfile
platform :ios do
  before_all do
    setup_circle_ci
  end

  lane :build_dev do
    # 省略
  end

  lane :build_stg do
    # 省略
  end

  lane :build_prd do
    # 省略
  end

end

platform :android do
  lane :build_dev do
    # 省略
  end

  lane :build_stg do
    # 省略
  end

  lane :build_prd do
    # 省略
  end
end

そして、parametersを利用して環境別のビルドに対応したconfig.ymlの中身は以下のようになります。

# config.yml
version: 2.1
jobs:
  android:
    # parameters追加
    parameters:
      env:
        type: enum
        enum: ["dev", "stg", "prd"]
    docker:
      - image: circleci/android:api-27-node
    steps:
      - checkout
      - run: bundle install --path vendor/bundle
      - run: npm install
      # 変数を使用したコマンドに更新
      - run: bundle exec fastlane android build_<< parameters.env >>

  ios:
    # parameters追加
    parameters:
      env:
        type: enum
        enum: ["dev", "stg", "prd"]
    macos:
      xcode: "10.1.0"
    shell: /bin/bash --login -o pipefail
    steps:
      - checkout
      - run: bundle install --path vendor/bundle
      - run: npm install
      # 変数を使用したコマンドに更新
      - run: bundle exec fastlane ios build_<< parameters.env >>

workflows:
  android-ios:
    # iOSとAndroidそれぞれに対しstaging/production用のジョブを追加し、envを使って値を定義する
    jobs:
      - android:
          name: android_dev
          env: dev
          filters:
            branches:
              only:
                - develop
      - android:
          name: android_stg
          env: stg
          filters:
            branches:
              only:
                - develop
      - android:
          name: android_prd
          env: prd
          filters:
            branches:
              only:
                - develop
      - ios:
          name: ios_dev
          env: dev
          filters:
            branches:
              only:
                - develop
      - ios:
          name: ios_stg
          env: stg
          filters:
            branches:
              only:
                - develop
      - ios:
          name: ios_prd
          env: prd
          filters:
            branches:
              only:
                - develop

workflowsの部分が少し冗長な感じになってしまいますが、この設定の状態でdevelopブランチに変更が入るとiOS/Androidそれぞれのdevelopment/staging/production用のビルドが同時に走るようになります。

開発中のアプリはdevelopment環境のアプリでチェックするのが基本だと思いますので、staging/production用のビルドはworkflows>jobs>branchesの設定をmasterブランチに設定しても良いかと思います。

まとめ

今回はReact NativeプロジェクトにCircleCIを導入して、CI/CD環境を作る手順について説明しました。

また、CircleCIはconfig.ymlに設定を記載してコードで管理できるので、メンテナンスがしやすいツールだと思いました。 React NativeでCIしたい方は、ぜひ今回の内容を参考にしてみてください。