【React Native】Google AdMob導入方法【iOS&Android両対応】

**2021/04/20 追記**
Androidにおいて、ライブラリをインストールしたときにreact-native-admobのエラーが発生することが確認できました。
参考: [react-native-admobをインストールしたときのandroidでのエラー](https://qiita.com/Takuya-Nakamura/items/2a02cd34e61ecddbe256)
修正方法を[一番下](#execution-failed-for-task-react-native-admobcompiledebugjavawithjavac)に追記しています。

---

React NativeにGoogle AdMobを導入する際、情報が古かったり同様の方法でやってもうまくいかないことが多かったので、詳細に導入方法をまとめてみます。
Google AdMobを利用する際には現時点で2つ方法があります。

- react-native-admobを利用する方法
- react-native-firebaseを利用する方法

今回はreact-native-admobを利用する方法について説明します。

#### 導入した環境
React Native 0.62.2
iOS 13.3 CocoaPods
Android 10.0
実装した広告: バナー広告

# iOS
[react-native-admob](https://github.com/sbugert/react-native-admob)のREADMEと同様に進んでいきます。

#### 1. npm or yarnでreact-native-admobをインストール
`npm i --save react-native-admob@next` 
もしくは
`yarn add react-native-admob@next`

#### 2. Google Mobile Ads SDKを追加
[Google AdMob公式](https://developers.google.com/admob/ios/quick-start#update_your_infoplist)を参考に進んでいきます。
事前にAdMobアカウントを作成・アプリ登録を済ませたあと、対象のアプリケーションにMobile Ads SDKをインポートします。
`pod 'Google-Mobile-Ads-SDK'`
をiosファイルの中にあるPodfileに書き込み、
`pod install --repo-update`
#### 3. Info.plistの更新
iosファイルの中にあるInfo.plistに `GADApplicationIdentifier` キーとAdMobアプリIDの文字列値を追加します。

```:Info.plist
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>
```

#### 4. AppDelegate.mの変更

```diff_objective_c:AppDelegate.m
+ @import GoogleMobileAds;

  @implementation AppDelegate

  - (BOOL)application:(UIApplication *)application
            didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
+    [[GADMobileAds sharedInstance] startWithCompletionHandler:nil];
     return YES;
  }

  @end
```
自分の場合、すでに何行かコードが書いてありましたが、 `@implementation AppDelegate` の直上に `@import GoogleMobileAds;` を入れ、

```diff_objective_c:AppDelegate.m(抜粋)
  UIViewController *rootViewController = [UIViewController new];
+ [[GADMobileAds sharedInstance] startWithCompletionHandler:nil];
  rootViewController.view = rootView;
```
このように追加しました。
#### 5. react-native-admobをimportし、コンポーネントを配置
`import { AdMobBanner } from 'react-native-admob';` とし、下のように配置しました。

```diff_javascript
  render() {
  return (
+  <AdMobBanner
+    adSize="fullBanner"
+    adUnitID="AdMobでアプリを登録した時に表示されるAppID"
+    testDevices={[AdMobBanner.simulatorId]}
+    onAdFailedToLoad={(error) => console.error(error)}
+  />
  ...
```

<img width="490" alt="iOS-Admob.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513327/1a72dbfb-f492-5cd9-61a9-d34348cb78ce.png">
このようにテスト広告が表示されれば成功です。

# Android

#### 1. npm or yarnでreact-native-admobをインストール
iOSと同様にインストールします。

#### 2. Google Mobile Ads SDKのインストール
android/build.gradleの中に

```diff_gradle:android/build.gradle
allprojects {
   repositories {
        google()
   }
}
```
があることを確認して、今度はandroid/app/build.gradleの中に以下のコードを追加します。

```diff_gradle:android/app/build.gradle
 dependencies {
+    implementation 'com.google.android.gms:play-services-ads:19.1.0'
 }
```
#### 3. Android Manifest.xmlの変更
次に、android/src/main/AndroidManifest.xmlに以下のようにコードを追加します。

```diff_xml:AndroidManifest.xml
  <manifest>
    <application>
          <!-- Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713 -->
+     <meta-data
+         android:name="com.google.android.gms.ads.APPLICATION_ID"
+         android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
    </application>
  </manifest>
```
GoogleMobileAds公式ページにはまだ下に手順が書かれていますが、追加するのはここまでです。
#### 4. react-native-admob/android/build.gradleのSDKバージョンを固定する
上記の方法でアプリをビルドしてみたものの失敗したので、解決策を探していたところこの方法で解決できました。
node_modules/react-native-admob/android/build.gradleを見ると、以下のように記述されていると思います。

```gradle:node_modules/react-native-admob/android/build.gradle
...
dependencies {
    implementation 'com.facebook.react:react-native:+'
    implementation 'com.google.android.gms:play-services-ads:+'
}
```
こちらの下の段、admobのSDKが更新された影響で古いAPIと互換性が無いことでビルドが失敗していたようです。([参考](https://aknow2.hatenablog.com/entry/2018/10/12/094714))
現在の最新のadmobのSDKバージョンは19.6.0のようなので、以下のように書き直します。

```diff_gradle
-  implementation 'com.google.android.gms:play-services-ads:+'
+  implementation 'com.google.android.gms:play-services-ads:19.6.0'
```
#### 5. react-native-admobをimportし、コンポーネントを配置
iOSと同様の方法で配置します。
<img width="381" alt="Android-admob.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513327/838044cb-4802-00ea-3947-c1e7b1564c82.png">
このように表示されれば成功です！

# Execution failed for task ':react-native-admob:compileDebugJavaWithJavac'.

Admobの実装が終わった後、他のライブラリをインストールし、Androidでシミュレーターを起動する時に以下のようなエラーメッセージが出ることが確認できました。

```
* What went wrong:
Execution failed for task ':react-native-admob:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.
```

こちら（[react-native-admobをインストールしたときのandroidでのエラー](https://qiita.com/Takuya-Nakamura/items/2a02cd34e61ecddbe256)）の記事によると、`node_module/react_native_admobのbuild.gradle`を修正することが書かれていました。

あれ？ [4. react-native-admob/android/build.gradleのSDKバージョンを固定する](#4-react-native-admobandroidbuildgradleのsdkバージョンを固定する)
でそこは修正したよな…？と思っていましたが、他のライブラリをインストールするとnode_modulesの部分は元のコードに戻ってしまいます。

そこで、今回は[patch-package](https://github.com/ds300/patch-package)でreact-native-admobにパッチを当てることでライブラリをインストールしても勝手に修正されないように変更します。

参考: [React Nativeのライブラリをpatch-packageで手軽に修正する方法](https://engineering.mobalab.net/2019/01/16/react-native%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92patch-package%E3%81%A7%E6%89%8B%E8%BB%BD%E3%81%AB%E4%BF%AE%E6%AD%A3%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/)

#### 1. `package.json`に追記

```diff_json:package.json
  "scripts": {
     "android": "react-native run-android --variant=developDebug --appIdSuffix=dev",
     "ios": "react-native run-ios",
     "start": "react-native start",
     "test": "jest",
     "lint": "eslint .",
+    "postinstall": "patch-package"
  }
```

#### 2. ライブラリのインストール
npmの場合は
`npm i patch-package --save-dev`
yarnの場合は
`yarn add --dev patch-package postinstall-postinstall`

#### 3. `/node_modules/react-native-admob/android/build.gradle`の内容を変更
```diff_gradle:/node_modules/react-native-admob/android/build.gradle
 dependencies {
    implementation 'com.facebook.react:react-native:+'
-   implementation 'com.google.android.gms:play-services-ads:+'
+   implementation 'com.google.android.gms:play-services-ads:19.6.0' 
 }
``` 

固定するバージョンは各自がインストールしたSDKのバージョンに合わせてください。

#### 4. パッチファイルの生成
npmの場合は
`npx patch-package react-native-admob`
yarnの場合は
`yarn patch-package react-native-admob`

すると、

```
• Creating temporary folder
• Installing react-native-admob@2.0.0-beta.6 with yarn
• Diffing your files with clean files
✔ Created file patches/react-native-admob+2.0.0-beta.6.patch
```

このようなログが表示され、`patch/react-native-admob+2.0.0-beta.6.patch` のようなファイルが生成されていることが確認できると思います。

これで新しいライブラリをインストールしたときに `node_modules/react-native-admob` の中身が変更されなくなります。
僕の実装ではこちらの修正をするだけで正常に起動するようになりました。
この修正でも起動できない場合は、こちら（[react-native-admobをインストールしたときのandroidでのエラー](https://qiita.com/Takuya-Nakamura/items/2a02cd34e61ecddbe256)）の記事を参考にするとよいかと思います。（Takuya-Nakamuraさん、情報ありがとうございます！）

# おわりに
ぱっと見そこまで複雑ではありませんが、自分はなぜか2週間くらい広告を表示させるのに手間取ってしまいました…
npmでreact-native-admobをインストールしたときに同時に古いバージョンのReactがインストールされてしまったり、podfileに記述することでライブラリをインストールしようとして失敗したり。
React Nativeで実装している記事が少なく、かつバージョンが変わるのがとても早いため、今回は備忘録としてまとめました。
React Nativeでadmobを導入する今回の記事が少しでもお役に立てれば幸いです。