ReactNative 0.60.4、react-native-config を使って環境構築、リリースまで1

環境

  • macOS Mojave 10.14.4
  • node: v12.4.0
  • watchman:4.9.0
  • yarn:1.17.0

アプリ

  • プロジェクト名:AwesomeProject
  • bundle id / applicationId:com.c.local.awesomeproject
  • react-native:0.60.4
  • react:16.8.6
  • react-native-config: 0.11.7

事前準備

node をインストール

$ brew install node

yarn をインストール

$ brew install yarn

watchman をインストール

$ brew install watchman

react-native-cli をインストール

プロジェクトを作成

# 2019/07/22時点で最新の0.60.4
$ react-native init AwesomeProject --version 0.60.4

react-native-config インストール

# react-native-configを追加
$ yarn add react-native-config

react-native-config の設定(react-native link)

0.60.0 から Autolink とのことなので、react-native link は実行しないでみる

https://facebook.github.io/react-native/blog/2019/07/03/version-60#native-modules-are-now-autolinked

react-native linkは実行しない

react-native link は、js だけは実現できない os 毎に分けて記述された、objective-c や java のコードを自動で設定してくれる便利コマンド

# react-native-configをreact-nativeのプロジェクトに適用する
$ react-native link react-native-config

iOS の設定 (react-native-config)

  • Podfile の target ‘AwesomeProject’へ追加
    • Autolinkコマンドの代わりに、自分でPodfileに追加せねばならぬ。0.60.0から基本的に全部CocoaPodsでライブラリを管理するみたい
AwesomeProject/ios/Podfile
 

target 'AwesomeProject' do
  ...省略...
  pod 'react-native-config', :path => '../node_modules/react-native-config'
  ...省略...
end
  • Podfile の 一番下に追加
    • これを追加しないと.envファイルがネイティブを連携できない
AwesomeProject/ios/Podfile

post_install do |installer|
  installer.pods_project.targets.each do |target|
    targets_to_ignore = %w(React)

    if targets_to_ignore.include? target.name
      target.remove_from_project
    end

    if target.name == 'react-native-config'
      phase = target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
      phase.shell_script = "cd ../../"\
                           " && RNC_ROOT=./node_modules/react-native-config/"\
                           " && export SYMROOT=$RNC_ROOT/ios/ReactNativeConfig"\
                           " && export BUILD_DIR=$RNC_ROOT/ios/ReactNativeConfig"\
                           " && ruby $RNC_ROOT/ios/ReactNativeConfig/BuildDotenvConfig.ruby"

      target.build_phases << phase
      target.build_phases.move(phase,0)
    end
  end
end

# iosディレクトリ移動
$ cd ios/

# podのインストール
$ pod install

Android の設定 (react-native-config)

android/app/build.gradleにdotenv.gradleを追加する。

AwesomeProject/android/app/build.gradle


apply plugin: "com.android.application"

apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"       // この1行を追加

import com.android.build.OutputFile

環境別の定数 .env ファイルを作成する

開発版 .env ファイル作成

AwesomeProject/.env

ENV=dev
APP_ID=com.c.local.awesomeproject.dev
RN_VERSION_CODE=1
RN_VERSION_NAME=1.0.0
APP_NAME=DevAwesomeProject
API_URL=https://dev.awesomeproject.com/

  • 開発はサブドメインにdevがついている

製品版 .env.prod ファイル作成

AwesomeProject/.env.prod

ENV=prod
APP_ID=com.c.local.awesomeproject
RN_VERSION_CODE=1
RN_VERSION_NAME=1.0.0
APP_NAME=AwesomeProject
API_URL=https://awesomeproject.com/
  • ファイル名は、.env.prodにして製品版はサブドメインなしにする
  • APP_ID(ios でいう bundle Id)を開発と製品でわけようとしたが、おいおい問題が発生してやってない

環境別の定数を確認するため App.js を修正

react-native-config を import する

AwesomeProject/App.js

// react-native-configをインポート
import Config from "react-native-config";

環境別の定数を使ってみる

AwesomeProject/App.js

`<View style={styles.body}>`のなかにアプリ名とバージョン名を表示するよう修正


<View style={styles.sectionContainer}>
  <Text style={styles.sectionTitle}>
    {Config.APP_NAME}
    {Config.RN_VERSION_NAME}
  </Text>
</View>


確認

.env の設定で実行

# ios
react-native run-ios

# android
react-native run-android

.env.prod の設定で実行


# ios ENVFILE=.env.prod react-native run-ios # android ENVFILE=.env.prod react-native run-android

動作確認

DevAwesomeProject1.0.0

  dev prod
android Screenshot_1563764948 Screenshot_1563765032
ios Simulator Screen Shot - iPhone X - 2019-07-22 at 12 09 03 Simulator Screen Shot - iPhone X - 2019-07-22 at 12 09 30

android の実行で local.properties がないと怒られることがあるみたい

  • 0.59 でプロジェクトを作成したとき同じものを置いてみた
AwesomeProject/android/local.properties


## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Jun 10 21:51:53 JST 2019
sdk.dir=/Users/ka-yamao/Library/Android/sdk

Android の環境別設定

android のパッケージ名を変更する

react-native init プロジェクト名でプロジェクトを作成すると自動でcom.プロジェクト名になる。
bundle id / applicationId をcom.c.local.awesomeprojectにするので、これ合わせてパッケージを変更する。
変更しなくて大丈夫なのだが、アプリの起動時の Activity 指定でうまくいかなかったので変更する。

  • com.awesomeproject -> com.c.local.awesomeproject へ修正
AwesomeProject/android/app/src/main/AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.c.local.awesomeproject">
<application
  android:name="com.c.local.awesomeproject.MainApplication"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:roundIcon="@mipmap/ic_launcher_round"
  android:allowBackup="false"
  android:theme="@style/AppTheme">
  <activity
    android:name="com.c.local.awesomeproject.MainActivity"
    android:label="@string/app_name"
    android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
  </activity>
  <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>

AwesomeProject/android/app/src/main/java/com/c/local/awesomeproject/MainActivity.java
AwesomeProject/android/app/src/main/java/com/c/local/awesomeproject/MainApplication.java

// パッケージの宣言を修正
package com.c.local.awesomeproject;

Android で Flavor を使う

まずリリースビルドできるよう keystore ファイル(signing key)を作成(アップロード証明書)

最近のアプリの署名は Google Play Store で署名を管理し、開発者はアップロード署名を作成するみたい。
Google Play App Signing

  • 参考サイト
    • https://support.google.com/googleplay/android-developer/answer/7384423
    • https://qiita.com/rkowase/items/90cdc4e8c6fc449d8276

こんな感じで作る

* キーストアのファイル名:"awesome.keystore"
* ストアのパスワード:"123456"
* キーのエイリアス:"awesome"
* キーのパスワード:"123456"

signing key を作成コマンド

keytool -genkey -v -keystore awesome.keystore -alias awesome -keyalg RSA -keysize 2048 -validity 10000

signing key 生成で入力した内容

キーストアのパスワードを入力してください:   # 6桁以上「123456」を入力
新規パスワードを再入力してください: # 6桁以上「123456」を入力
姓名は何ですか。
  [Unknown]:                  # 入力しない RETURNを押下
組織単位名は何ですか。
  [Unknown]:                  # 入力しない RETURNを押下
組織名は何ですか。
  [Unknown]:                  # 入力しない RETURNを押下
都市名または地域名は何ですか。
  [Unknown]:                  # 入力しない RETURNを押下
都道府県名または州名は何ですか。
  [Unknown]:                  # 入力しない RETURNを押下
この単位に該当する2文字の国コードは何ですか。
  [Unknown]:                  # 入力しない RETURNを押下
CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknownでよろしいですか。
  [いいえ]:  y                 # 「y」入力をRETURNを押下

10,000日間有効な2,048ビットのRSAの鍵ペアと自己署名型証明書(SHA256withRSA)を生成しています
        ディレクトリ名: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
<awesome>の鍵パスワードを入力してください
        (キーストアのパスワードと同じ場合はRETURNを押してください):
新規パスワードを再入力してください:   # 6桁以上「123456」を入力

dev と prod の Flavor を作成

react-native-config の設定を追加

AwesomeProject/android/app/build.gradle  3行目あたりから

apply plugin: "com.android.application"

// project.ext.envConfigFilesを追加する。「dotenv.gradle」の読み込みより前に書くこと
project.ext.envConfigFiles = [
        dev: ".env",
        prod: ".env.prod",
        anothercustombuild: ".env",
]

apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"

import com.android.build.OutputFile

アプリのあるパッケージ名を宣言

AwesomeProject/android/app/build.gradle


android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    flavorDimensions "default"    // Flavorを使うといは、こを追加
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    defaultConfig {
        applicationId project.env.get("APP_ID")                         // .envファイルのAPP_IDを使う
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode project.env.get("RN_VERSION_CODE").toInteger()      // .envファイルのRN_VERSION_CODE intじゃないとダメ
        versionName project.env.get("RN_VERSION_NAME")                  // .envファイルのRN_VERSION_NAME
        resValue "string", "build_config_package", "com.awesomeproject" // Flavorを使ってアプリをパッケージ名の違うアプリを作るとき、ビルドコンフィグのあるパッケージを指定してあげる。
    }

    ... 省略 ...

}

buildTypes、productFlavors の設定

Flavors によって APP_ID、パッケージ名の変更をしようとしたが

AwesomeProject/android/app/build.gradle

... 省略 ...

    // keystoreの設定をここに追加
    signingConfigs {
        release {
            storeFile file("../../awesome.keystore")
            storePassword "123456"
            keyAlias "awesome"
            keyPassword "123456"
        }
    }
    // buildTypesの設定を追加
    buildTypes {
        debug {
            versionNameSuffix '-debug'
            applicationIdSuffix ".debug"
        }
        release {
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            signingConfig signingConfigs.release
        }
    }
    // productFlavorsの設定
    productFlavors {
        dev {
            versionName = android.defaultConfig.versionName + '-dev'
        }
        prod {
            versionName = android.defaultConfig.versionName
        }
    }

... 省略 ...

buildTypes、productFlavors を指定するコマンド

# 製品版 リリース
$ react-native run-android --variant=ProdRelease
# 製品版 デバック
$ react-native run-android --variant=ProdDebug --appIdSuffix debug
# 開発版 リリース
$ react-native run-android --variant=DevRelease --appIdSuffix dev
# 開発版 デバック
$ react-native run-android --variant=DevDebug --appIdSuffix dev.debug

4パターンのパッケージ名のことなるアプリができる。

com.awesomeproject
com.awesomeproject.dev
com.awesomeproject.debug
com.awesomeproject.dev.debug

これでいったん Android の設定は完了

確認してたとき使った。便利なコマンド、パッケージ名にawesomeがつく複数のアプリを削除

adb shell pm list packages awesome | cut -d ':' -f 2 | tr -d '\r' | xargs -L1 -t adb uninstall

最新の gradle プラグインでビルドしたくないとき build.gradle

Preferences -> Experimental
□ Only sync the active variant

Only sync the active variant

https://github.com/luggit/react-native-config/issues/345

iOS の環境別設定

iOS ネイティブ側で.env を使えるよう設定

  • スクリンショットのように設定する。Info.plist Preprocessor Prefix File には$(SRCROOT)/../node_modules/react-native-config/ios/ReactNativeConfig/GeneratedInfoPlistDotEnv.hを設定する

スクリーンショット 2019-07-22 14 32 36

iOS で scheme を設定

スキーマ(scheme)を追加して読み込む .env ファイルを設定する

Manage Schemes をクリックする スクリーンショット 2019-06-12 10 51 58
AwesomeProject を選択した状態で、Duplicate で複製を作成する スクリーンショット 2019-06-12 10 52 13
スキーマー名を入力 スクリーンショット 2019-06-12 10 54 13
Build の pre-actions で New Run Script Action を押下する。 スクリーンショット 2019-06-12 10 54 51
echo “.env.prod” > /tmp/envfile を入力する。 スクリーンショット 2019-06-12 10 55 33

Product Bundle Identifier を修正

debug のときは.debugがつくようcom.awesomeproject.debugに修正、debug と release で別アプリになる

Bundle Identifier(bundle Id)の値は.env ファイルの値を設定できないので直接com.c.local.awesomeproject.debug

スキーマ、コンフィギュレーションごとの実行

# 開発版 デバック
$ react-native run-ios --scheme AwesomeProject --configuration Debug
# 開発版 リリースビルド
$ react-native run-ios --scheme AwesomeProject --configuration Release
# 製品版 デバックビルド
$ react-native run-ios --scheme AwesomeProjectProd --configuration Debug
# 製品版 デバックビルド
$ react-native run-ios --scheme AwesomeProjectProd --configuration Release

テストのスキーマーが影響して失敗する

** BUILD FAILED **


The following build commands failed:
        Ld /Users/ka-yamao/workspace/AwesomeProject/ios/build/AwesomeProject/Build/Intermediates.noindex/AwesomeProject.build/Release-iphonesimulator/AwesomeProjectTests.build/Objects-normal/x86_64/AwesomeProjectTests normal x86_64
        Ld /Users/ka-yamao/workspace/AwesomeProject/ios/build/AwesomeProject/Build/Intermediates.noindex/AwesomeProject.build/Release-iphonesimulator/AwesomeProjectTests.build/Objects-normal/i386/AwesomeProjectTests normal i386
(2 failures)
  • よくわからんが、Build のところでテストのスキーまーはチェックを外してみた

スクリーンショット 2019-07-22 15 12 27

error: Can’t find ‘node’ binary to build React Native bundle

修正前 修正後

開発版、製品版、リリース、デバックでの実行ができた。次はリリース手順についてまとめていく