概要
リアクトネイティブ(React Native)で開発したアンドロイドアプリ(Android App)をアンドロイドアプリストア(Google Play)に登録してみようかと思います。アンドロイドアプリ(Android App)をアンドロイドアプリストア(Google Play)に登録するためにはアンドロイド開発者登録(グーグルプレイ開発者登録)が必要です。アンドロイド開発者登録(グーグルプレイ開発者登録)をしてない方は以前のブログを参考して登録してください。(アンドロイド開発者登録)
このブログはシリーズです。下記のブログも確認してください。
準備
リアクトネイティブ(React Native)で開発したアンドロイドアプリ(Android App)をアンドロイドアプリストア(Google Play)に灯篭するためリアクトネイティブ(React Native)をアンドロイド用にビルドする必要があります。リアクトネイティブ(React Native)にアンドロイド署名キー(Android Signing Key)を登録してアンドロイド用にビルドする方法については以前のブログを参考してください。
ビルドファイルサイズ最適化
以前のブログであるアンドロイドビルドやテストでアンドロイド用にビルドされたファイルはファイルサイズの最適化がされてないです。リアクトネイティブ(React Native)で開発したアンドロイドアプリ(Android App)をアンドロイドアプリストア(Google Play)にアップロードするためにはビルドファイルサイズを最適化する必要があります。
リアクトネイティブ(React Native)プロジェクトフォルダでandroid/app/build.gradleを開いて下記のように修正します。
...
defaultConfig {
...
// ndk {
// abiFilters "armeabi-v7a", "x86"
// }
}
...
def enableSeparateBuildPerCPUArchitecture = true
def enableProguardInReleaseBuilds = true
...
buildTypes {
release {
shrinkResources true
...
}
}
..
- enableSeparateBuildPerCPUArchitecture: apkファイルビルドする時、各CPU別ファイルを分離してapkファイルを生成します。他のCPUへ必要な内容が抜けるので、ファイルサイズが小さくなります。しかし、apkファイルが複数生成されるので、アプリをデプロイする時はそのファイル全部をアップロードする必要があります。
- enableProguardInReleaseBuilds: コード難読化へ必要なProguardを使います。Proguardはコードの難読化をするし、コードのサイズも減らしてくれるのでファイルサイズが小さくなります。
- shrinkResources: いらないリソースを消してファイルサイズを小さくします。(アプリでローカルイメージが表示されない場合はこの部分をfalseで設定して使ってください。)
そして下記のコマンドを使ってリアクトネイティブ(React Native)をアンドロイド用にビルドします。
# react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle
# cd android
# ./gradlew assembleRelease
./gradlew app:assembleRelease --stacktrace
このように--stacktraceオプションを入れる理由はenableProguardInReleaseBuilds = trueを設定すると下記のようなビルドエラーが発生する場合があるからです。
...
Note: the configuration keeps the entry point 'okhttp3.internal.ws.WebSocketWriter { void writePong(okio.ByteString); }', but not the descriptor class 'okio.ByteString'
Note: the configuration keeps the entry point 'okhttp3.internal.ws.WebSocketWriter { void writeClose(int,okio.ByteString); }', but not the descriptor class 'okio.ByteString'
Note: the configuration keeps the entry point 'okhttp3.internal.ws.WebSocketWriter { void writeControlFrame(int,okio.ByteString); }', but not the descriptor class 'okio.ByteString'
Note: the configuration keeps the entry point 'okhttp3.internal.ws.WebSocketWriter$FrameSink { void write(okio.Buffer,long); }', but not the descriptor class 'okio.Buffer'
Note: the configuration keeps the entry point 'okio.AsyncTimeout { void scheduleTimeout(okio.AsyncTimeout,long,boolean); }', but not the descriptor class 'okio.AsyncTimeout'
Note: the configuration keeps the entry point 'okio.AsyncTimeout { boolean cancelScheduledTimeout(okio.AsyncTimeout); }', but not the descriptor class 'okio.AsyncTimeout'
Note: the configuration keeps the entry point 'okio.AsyncTimeout { okio.Sink sink(okio.Sink); }', but not the descriptor class 'okio.Sink'
Note: the configuration keeps the entry point 'okio.AsyncTimeout { okio.Source source(okio.Source); }', but not the descriptor class 'okio.Source'
Note: the configuration keeps the entry point 'okio.ForwardingSink { ForwardingSink(okio.Sink); }', but not the descriptor class 'okio.Sink'
Note: the configuration keeps the entry point 'okio.ForwardingSink { void write(okio.Buffer,long); }', but not the descriptor class 'okio.Buffer'
Note: the configuration keeps the entry point 'okio.ForwardingSource { ForwardingSource(okio.Source); }', but not the descriptor class 'okio.Source'
Note: the configuration keeps the entry point 'okio.ForwardingSource { long read(okio.Buffer,long); }', but not the descriptor class 'okio.Buffer'
...
* What went wrong:
Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
> Job failed, see logs for details
...
上のようにビルドエラーが出る場合、android/app/proguard-rules.proファイルを開いて下記のように追加します。 파일을 열고 하단에 아래와 같이 추가합니다.
# Note: the configuration keeps the entry point 'okio.AsyncTimeout { void scheduleTimeout(okio.AsyncTimeout,long,boolean); }', but not the descriptor class 'okio.AsyncTimeout
-dontwarn okio.**
# Note: the configuration keeps the entry point 'okhttp3.internal.ws.WebSocketWriter$FrameSink { void write(okio.Buffer,long); }', but not the descriptor class 'okio.Buffer'
-dontwarn okhttp3.**
上のエラー以外も使ってるライブラリによってもっとエラーが出る可能性もあります。そのメッセージを見ってandroid/app/proguard-rules.proを修正してください。
ビルドされたファイルは下記の位置で確認できます。
android/app/build/outputs/apk/release/app-arm64-v8a-release.apk.apk
android/app/build/outputs/apk/release/app-armeabi-v7a-release.apk.apk
android/app/build/outputs/apk/release/app-x86_64-release.apk.apk
android/app/build/outputs/apk/release/app-x86-release.apk.apk
このファイル全てをアップロードする必要があります。
include
アプリ登録
下記のリンクを押してグーグルプレイコンソル(Google Play Console)に移動します。
- グーグルプレイコンソル(Google Play Console): https://play.google.com/apps/publish/
グーグルプレイコンソル(Google Play Console)に移動したら下記の画面が見えます。

画面の上にあるPUBLISH AN ANDROID APP ON GOOGLE PLAYボタンを押します。

アンドロイドアプリストア(Google Play)に表示される名前と基本言語を選択します。

アンドロイドアプリストア(Google Play)に表示される情報を入力します。
- タイトル(title): 50文字
- 要約説明(short description): 80文字
- 全体説明(full description): 4000文字
- アプリイメージ(Screenshots)
- アプリアイコン(App icon): 512x512(32-bit PNG, alpha), 1024x500(JPG or 24-bit PNG), 180x120(JPG or 24-bit PNG), 1280x720(JPG or 24-bit PNG), 4096x4096(JPG or 24-bit PNG)
- プロモーションビデオ(Promo Video)
- アプリカテゴリ(Category)
- 開発者連絡先(Contact details)
- 個人情報ポリシー(Privacy Policy)
全ての情報を入力したらapkファイルを登録する方法について説明します。
左上にあるApp releaseメニューを押したら下記の画面が見えます。

画面に見えるProduction trackのProduction項目のMANAGEを押します。

上のような画面が見えたら下のCREATE RELEASEを押します。

グーグルプレイ(Google Play)を使ってアプリ署名(App Signing)をするためFINISHボタンを押します。

上のような利用規約が表示されたら下にあるACCEPTボタンを押して同意します。

上でビルド下リアクトネイティブ(React Native)のapkファイルをアップロードします。

アプリの配布名前(Release Name)と配布ノート(Release Note)を作成して右下のSAVEボタンを押します。そしたら右のREVIEWボタンがアクティブになります。アクティブになったREVIEWボタンを押します。

アプリの登録手続きが終わってないので右下のSTART ROLLOUT TO PRODUCTIONボタンがアクティブになりません。左メニューのContent ratingを押します。

コンテンツ評価(Content Rating)を設定する画面です。CONTINUEを押します。

メール情報やアプリのカテゴリを選択します。

アプリのコンテンツ評価を決めるための情報を選択します。全て選択したら下のSAVE QUESTIONNAIREボタンを押してアクティブされたCALCULATE RATINGを押します。

入力した情報をベースでコンテンツ評価が計算されて出ます。内容を確認して下のAPPLYING RATINGを押します。

コンテンツ評価の入力を完了しました。コンテンツ評価に影響があるアップデートがあったら、コンテンツ評価を再計算する必要がありますので、上の手続きをまたしてください。

最後の手続きである料金の設定をするため左メニューのPricing & distributionを押します。

アプリの料金を設定する画面です。私たちは無料でアプリを提供する予定なので、FREEを設定して進めます。また、子供向け、アプリに広告が含まれてあるかなど情報を入力します。必須項目を全て入力したら下のSAVE DRAFTボタンを押します。
include
アプリ審査申請
アプリ審査(App Review)のための準備が終わりました。メニューのApp releaseを押します。

上で作成したProduction項目の横にあるEDIT RELEASEボタンを押します。

上で作成した情報が見えます。スクロールして下に移動して、REVIEWボタンを選択します。

上のような画面が見えたらスクロールして下に移動してSTART ROLLOUT TO PRODUCTIONを押します。

アプリ審査の準備が終わったらCONFIRMボタンを押してアプリ審査を申請します。
エラー対応
下記のコマンドでアンドロイドをビルドする時、
./gradlew assembleRelease
下記のようなエラーメッセージが出ってビルドが失敗される時があります。
Execution failed for task ':app:transformDexArchiveWithExternalLibsDexMergerForRelease'.
下記の内容をandroid/app/build.gradleに追加してもう一回ビルドします。
defaultConfig {
...
multiDexEnabled true
}
ビルドエラー対応
リアクトネイティブ(React Native)のバージョン0.58で下記のコマンドを実行したら
./gradlew assembleRelease
下記のエラーが出ます。
--auto-add-overlay\
--non-final-ids\
-0\
apk\
--no-version-vectors
Daemon: AAPT2 aapt2-3.2.1-4818971-osx Daemon #0
下記のコマンドで実行したらビルドができます。
./gradlew app:assembleRelease
権限エラー
リアクトネイティブ(React Native)のバージョン0.58でビルドしたファイルをグーグルプレイへアップロードする時android.permission.READ_PHONE_STATE権限が含めてるのでダメですのエラーが出ます。
公式サイトに解決方法があります。
https://facebook.github.io/react-native/docs/removing-default-permissions
それを見ながらやってみます。
リアクトネイティブ(React Native)プロジェクトのandroid/app/src/main/AndroidManifest.xmlのファイルを開いて下記のように修正します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="XXXXXXXX"
+ xmlns:tools="http://schemas.android.com/tools"
>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission tools:node="remove" android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission tools:node="remove" android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission tools:node="remove" android:name="android.permission.READ_EXTERNAL_STORAGE" />
...
そしてandroid/app/src/release/AndroidManifest.xmlファイルを生成して下記の内容をコピペします。(パッケージ名は自分のパッケージ名を入れてください。)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="XXXXXXX"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission tools:node="remove" android:name="android.permission.SYSTEM_ALERT_WINDOW" />
</manifest>
これでビルドしてアップロードしたら問題なくアップロードできることを確認できます。
include
Android 4.4.2 Kitkat
リアクトネイティブ(React Native) 0.58でビルドしたファイルをアンドロイド4.4.2(Kitkat)の端末でテストする時、アプリがCrashが発生して起動出来ない問題が発生しました。問題を調査した結果、multiDexEnabledの問題で下記の内容を追加して解決しました。
リアクトネイティブ(React Native)プロジェクトのandroid/app/build.gradleを開いて下記の内容を追加してください。
dependencies {
implementation project(':react-native-firebase')
...
implementation 'com.android.support:multidex:1.0.1'
}
また、MainApplication.javaを開いて下記のように修正してください。
import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;
...
public class MainApplication extends Application implements ReactApplication {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
...
}
このように修正してアンドロイド4.4.2(Kitkat)でテストしたら無事に動作することを確認出来ます。
Unoptimized APK
最近APKファイルをアップロードしてアップデートすると下記の警告メッセージが表示されます。

下記のコマンドでAPKではなくapp bundleを生成します。
./gradlew app:bundleRelease
このコマンドで生成されたファイルはandroid/app/build/outputs/bundle/release/app.aabにあります。
この1つのファイルをアップロードすれば大丈夫です。
私の場合、package.jsonへ下記のスクリプトを追加して使っています。
...
"scripts": {
...
"prebuild-android": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle",
"build-android": "cd ./android && ./gradlew app:bundleRelease --stacktrace "
}
...
下記のコマンドでビルドします。
npm run build-android
完了
アンドロイドアプリストア(Google Play)にアプリを登録するための手続きが終わりました。アプリ審査は2~3時間くらいかかります。アプリの審査が終わったら登録申請したアプリをアンドロイドアプリストア(Google Play)で検索やダウンロードができます。
私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!
アプリ広報
Dekuが開発したアプリを使ってみてください。Dekuが開発したアプリはFlutterで開発されています。興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。






