【ReactNative】実機ビルド、APK生成で起きたトラブルシューティング～Android編～

ReactNativeを頑張っているみなさんこんにちは。ブリューアスのwebフロントエンジニアのsuginokoです。
もう年末ですね。1年というのはあっという間です。

弊社ではじわじわとReactNativeの案件にも関わるようになってきておりワタシも初めての経験でアタフタしましたが、なんとか今年のゴールにたどり着けそうです。

今回は初めてのReactNativeということで沢山のトラブルに出くわしたので、その対応トラブルシューティングを書いていこうと思います。アプリ開発に携わったことのない同じようなフロントエンジニアさんに届きますように～

## 前置き
今回1からプロジェクトを立ち上げたわけではなく、既に実装済みのReactNativeのプロジェクトを頂きました。
実装内容としましても少し古い書き方になっている箇所も多々ありましたので、そちらをリファクタを行ったり、見た目部分を修正するなど、実装自体はそこまで重くなかった対応になります。
辛かったのは最初(環境構築)と最後(実機ビルド、APK生成)です。

## 環境
* react: 16.9.0
* react-native: 0.61.5
* react-native-agora: 2.9.1-alpha.2
* react-native-firebase: 5.6.0

※パッケージはおおまかに使用したものだけ記載
基本的にはwindowsで実装してますが、expoは使用しておらず、ios開発は別途Macを用意して確認しつつの実装を行ってました。
yarnも使ってます。

お客様の環境が開発用と本番用としか分かれてなかったため、buildTypeとしては

* Debug(開発環境)
* Staging(開発環境を参照しているデプロイゲート更新用) 
* Release(本番)

このように分けました。
今回の納期までのスケジュールではもろもろのパッケージのバージョンアップは行わない方針でいったので後に書きますトラブルに見舞われた可能性があります。。

## トラブルシューティング
※エラーを無くすだけなので、その設定はちょっと・・・というのがあるかもしれませんがご了承ください。

### error E:\my-gridsome-site\node_modules\sharp: Command failed.Command: (node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)...
1から実装したものでは無くて、他のプロジェクトを取り込む際に起こるエラーなようです。
nodeのバージョンを適切なバージョンに上げて解決。(多分このエラーの下の方に適切なnodeバージョンが書いてあった気がする)
Macでは
[sharp: Command failed · Issue #585 · gridsome/gridsome · GitHub](https://github.com/gridsome/gridsome/issues/585)
上記だと解消するらしいです。


### nodistを入れていたらnpxが使えなくなった話
Windows限定な話な気がしますが
[Nodist を入れたら npx が使えなくなったので手動でインストール / Twin Turbo Computing](https://tt-computing.com/npx-install)
こちらで解決。

### Task :app:processDebugGoogleServices FAILED
```
cd `{project_name}`
cd android && ./gradlew clean
```
たまに、上記の対応で直ることがありますが、
firebaseのgoogle-services.jsonが原因の可能性もあります。
環境にdebugとrelease以外の環境が存在するとこのエラーに巡り合えます。
`applicationIdSuffix`　を指定しているかにもよりますが、指定していない場合は


{projectName}/android/app/google-services.json からコピーして
{projectName}/android/app/src/debug/google-services.json を作成します。
パッケージ名はandroid/app/src/main/AndroidManifest.xmlに書いているpackageNameを見ます。
`applicationIdSuffix`を設定していなければmainに記載している名称と同じで問題ありませんが、設定している場合は
`{packageName}.{applicationIdSuffix}` になります。これでエラーが無くなります。
applicationIdSuffixを指定している場合はStaging環境にもgoogle-services.jsonが必要だったと思います。

```
{
  "project_info": {
    "project_number": "...",
    "firebase_url": "...",
    "project_id": "...",
    "storage_bucket": "..."
  },
  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "...",
        "android_client_info": {
          "package_name": "←ここを環境ごとに合わせる"
        }
      },
・・・
```
参照：https://noy.hatenablog.jp/entry/2018/02/15/121431

### No matching client found for package name 
`Task :app:processDebugGoogleServices FAILED` と同様の対応でなくなりました。
google-services.jsonが適切な場所にないのと、正しいpackage nameになってないことが問題でした。


### What went wrong: Execution failed for task ':app:mergeReleaseResources'.
重複エラーだそうです。今思えば
{project_name}/android/app/src/main/assetsに`index.android.bundle`が存在しなかったことが原因でしたが以下の方法で解決。
参照：[reactjs - React Native 0.57.1 Android Duplicate Resources - Stack Overflow](https://stackoverflow.com/questions/52632950/react-native-0-57-1-android-duplicate-resources)

1. {project_name}/android/app/build 全部削除
2. {project_name}/android/build　全部削除
3. 実行 rm -rf $HOME/.gradle/caches/
4. {project_name}/android/app/src/main/assetsのindex.android.bundle　を削除(この時点で自分のプロジェクトには存在しなかったのでパス)
5. 以下を実行

```
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
```
この時結構不要なファイルも出たから削除した気がする・・・・
jsonファイルやnode_modulesのもろもろも色々出てきてビルドには不要だったんで削除しました。


### Task :app:transformClassesAndResourcesWithR8ForRelease FAILED
transformClassesAndResourcesWithR8ForReleaseの実行に失敗している。
調べてみると諸々のパッケージバージョンが合わないことで発生しているケースがあるらしいです。(多分色々古かったパッケージもあった。バージョンアップはリスキーなので断念)
R8の設定をtrueにすることで難読化や最適化を行ってくれるそうですが、ここではfalseにしていきます。

{project_name}/android/gradle.properties
追記

```
#Disables R8 for Android Library modules only.
android.enableR8.libraries = false
#Disables R8 for all modules.
android.enableR8 = false
```
参照：https://developer.android.com/studio/releases

### Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'. java.io.IOException: Please correct the above warnings first.
以下続き

```
Warning: there were 1649 unresolved references to classes or interfaces.
         You may need to add missing library jars or update their versions.
         If your code works fine without the missing classes, you can suppress
         the warnings with '-dontwarn' options.
```
         
Staging用APKを生成するときに出たエラーです。
Proguard 関連の処理が原因らしいです。この辺を-dontwarnを使って制御することができるらしいです。
とはいえ、1649件もなんかバージョンアップしてないとか、クラスに欠陥があるとか、不足ライブラリがあるらしいものを一気になんとかできるのか。。。(調べてみると、件数が少ないと1個1個バージョンアップやらすることで解消することもあるそうです)
実機ビルドでは普通にアプリが動いていることから、-dontwarnなどをproguard-rules.proを解消できそうであると考え、以下の対応を行っています。

{project_name}/android/app/build.gradleのbuildTypeにstagingで起きたエラーなので、
stagingに `proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"` を追加
これでproguard-rulesを見に行きます。(多分ここまでたどり着くのに2日くらい)

```
buildTypes {
        debug {
　　　　　　・・・
        }
        staging {
             ・・・
　　　　　　　// add
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
        release {
            ・・・
        }
    }
```

次にproguard-rulesの設定。
{project_name}/android/app/proguard-rules.pro
元々の専任の方が書いてあった記述にプラスしてReactNative系の処理とWarningはスルー、もろもろの処理をスルーしますよ的な書き方だったりを追記。

```
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:
-keep class io.agora.**{*;}

# THIS IS VERY VERY BAD. REMOVE AS SOON AS VERSIONING IS FIXED
-dontwarn **


-dontnote **

-keep class host.exp.exponent.generated.AppConstants { *; }

##### Crashlytics #####
-keepattributes SourceFile,LineNumberTable

##### React Native #####
-keep,allowobfuscation @interface **.facebook.proguard.annotations.KeepGettersAndSetters
-keep,allowobfuscation @interface **.facebook.react.bridge.ReadableType


-keepclassmembers @**.facebook.proguard.annotations.KeepGettersAndSetters class * {
  void set*(***);
  *** get*();
}

-keep class * extends **.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends **.facebook.react.bridge.NativeModule { *; }
-keepclassmembers class *  { @**.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class *  { @**.facebook.react.uimanager.ReactProp <methods>; }
-keepclassmembers class *  { @**.facebook.react.uimanager.ReactPropGroup <methods>; }


##### Versioned React Native #####
-keep class **.facebook.** { *; }
-keep class abi** { *; }
-keep class versioned** { *; }
```

本当はもっと書いてあったけど、いらなそうなのがあったんでその辺は削除。
多分、先人がReactNativeのバージョンとか上げてしまったり、その他のパッケージとかもものすごく古いパッケージとかもあったし、色々な苦労が見えた結果かなと思う。これが正しかったのかわからないけど、このエラーはこうすることで消えました。(proguardの設定も意味がわからなくて2日くらいかかって合わせて4日くらいかかってしまった。。)

### Execution failed for task ':react-native-orientation:verifyReleaseResources
自分でreact-native-orientationを入れた記憶がないので先人のものでしょう。
参考：[Execution failed for task ':react-native-orientation:verifyReleaseResources' · Issue #290 · yamill/react-native-orientation · GitHub](https://github.com/yamill/react-native-orientation/issues/290)

{project_name}/android/gradle.bundle　に以下を追加

```
buildscript{ ...}

allprojects { ...}

subprojects {
    afterEvaluate { project ->
        if (project.hasProperty("android")) {
            android {
                compileSdkVersion 28        // version of compile sdk used for project
                buildToolsVersion '28.0.3'    // version of build tool used for project
            }
        }
    }
}
```
これは同じ{project_name}/android/gradle.bundleに記載しているbuildscriptにある、`compileSdkVersion`と`buildToolsVersion`を合わせないといけないです。
ちなみに、こちらのバージョンも28以上でないといけなかったらしいです。こちらのプロジェクトでは偶然28以上を使ってたので、問題ありませんでした。

### Task :@react-native-community_async-storage:generateDebugBuildConfig FAILED
cd android && ./gradlew clean で解消
キャッシュが残っていることがあるらしいです。


### Execution failed for task ':app:installDebug'. > com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: INSTALL_FAILED_VERSION_DOWNGRADE
cd android && ./gradlew cleanだけでは直らず、普段実機ビルドできているのにどうして？というエラー
PC再起動で直りました。

### Task :app:mergeDebugResources FAILED
このエラーの前後にエラーの原因となっているログが書いているはずで、自分の記憶にないエラー内容だと、
cd android
./gradlew clean
で解決することがある

でも大概は「あ、これ自分触ったやつ」っていうエラーもあるので、そちらに問題があることもあったりしました。


### Task 〇〇：app：packageDebug FAILED
cd android
./gradlew clean
で解決することがあるが、この場合はAndroidStudioがメモリを食っていて出来ない場合もあったので、AndroidStudioで
1.キャッシュ消しての再起動
2.build>clean projectで解消

### 以上。
開発期間が短かったので出来る限りのことをやろうと思って必死に調べました。
使っているパッケージやライブラリが古く、もうドキュメントすら残されてないのが多い中での対応だったので、そこが一番しんどかったです。でもこれでAndroid設定周りの対応学べた気がしますね

次はiOS編を書いていきます。(Androidほどは無いかもしれない)
⇒書きました。　[【ReactNative】実機ビルド、テストアプリビルド(Archive)で起きたトラブルシューティング～IOS編～](https://qiita.com/suginoko/items/9a12b0e7b091363d3c6a)