torikatsu923.dev

サイト内検索

    Flutterのネイティブ広告をKotlinで実装する

    先日、Google Mobile Adsのflutterプラグインが発表されました。先祖のプラグインにあたるAdmobは非常に使いづらかった印象だったので、ついにきたか!と非常にわくわくしました。

    はじめに

    先日、Google Mobile Adsのflutterプラグインが発表されました。

    ネイティブ  |  Flutter(ベータ版)  |  Google Developers

    先祖のプラグインにあたるAdmobは非常に使いづらかった印象だったので、ついにきたか!と非常にわくわくしました。 早速実装をしようと以下の公式docを参照してみたのですが、ネイティブ広告のAndroidのサンプルコードがjavaでした。

    私が開発中のプロダクトはKotlinを採用しているので、公式サンプルをKotlinに読み替えつつ、ネイティブ広告の実装方法を共有したいと思います。

    サンプル

    今回紹介するサンプルは以下のリポジトリです。 https://github.com/torikatsupg/googleads_mobile_sdk_sample

    ネイティブ広告以外の広告のサンプルもあります。もし何かの参考になれば幸いです。

    実装

    下準備

    依存関係の追加

    まずはパッケージの依存関係をpubspec.yamlに追加します。 pub.devのinstallingを参考に、適宜バージョンを読み替えてください。

    pubspec.yaml

    dependencies:
      flutter:
        sdk: flutter
    +  google_mobile_ads: ^0.11.0+1

    Admob IDの追加

    次にAdmobのIDをAndroidManifest.xmlに追加する必要があります。

    今回はサンプルの実装なので以下のIDを使用します。

    ca-app-pub-3940256099942544~3347511713 

    適宜各自のIDに読み替えてください。

    android/main/src/AndroidManifest.xml

    <manifest>
        <application>
    
            .........
    
    +        <meta-data
    +            android:name="com.google.android.gms.ads.APPLICATION_ID"
    +            android:value="ca-app-pub-3940256099942544~3347511713 "/>
        <application>
    <manifest>

    SDKの初期化

    最後にアプリ起動時にSDKの初期化をするようにします。 SDKの初期化は以下によって行います。

    MobileAds.instance.initialize();

    公式docによると初期化のタイミングはアプリ起動前がいいそうです。 今回は、run()で初期化します。

    run.dart

    import 'package:flutter/material.dart';
    import 'package:google_mobile_ads/google_mobile_ads.dart';
    import 'package:googleads_mobile_sdk_sample/app.dart';
    
    run() {
      WidgetsFlutterBinding.ensureInitialized();
    +  MobileAds.instance.initialize();
    
      return runApp(
        ProviderScope(
          child: App(),
        ),
      );

    ネイティブ広告(Android)を実装する

    ネイティブ広告の実装はざっくりとFlutter側の実装とネイティブ側の実装に別れます。

    Flutter側の実装

    ネイティブ広告は、Flutter側でウィジェットとして扱います。 なので、広告ウィジェットを作成する関数を定義し、UIに広告を組み込みます。

    初めにlistenerを作成します。 とりあえず表示したいだけなら、広告の読み込みが完了したときのonAdLoadedと、onAdClosedでのリスナの開放ぐらいを実装しておけばいいと思います。

    native_page.dart

      Widget _buildNativeAd() {
        final listener = AdListener(
          onAdLoaded: (Ad ad) => ,
          onAdFailedToLoad: (Ad ad, LoadAdError error) {
            print('Ad failed to load: $error');
          },
          onAdOpened: (Ad ad) => print('Ad opened.'),
          onAdClosed: (Ad ad) => print('Ad closed.'),
          onApplicationExit: (Ad ad) => print('Left application.'),
          onNativeAdClicked: (NativeAd ad) => print('Ad clicked.'),
          onNativeAdImpression: (NativeAd ad) => print('Ad impression.'),
        );
    
       ......

    listenerの作成が終わったら、広告を作成します。 広告の作成には以下の4つを渡してあげる必要があります。

    • 広告ユニットID 今回はサンプルとして用意されたca-app-pub-3940256099942544/2247696110を使用します。
    • このあとAndroid側で登録する任意のFactoryID(文字列)
    • AdRequestインスタンス
    • 先ほどつくったリスナ

    実装は以下のようになります。

    native_page.dart

      ......
    
      final myNative = NativeAd(
          adUnitId: 'ca-app-pub-3940256099942544/2247696110',
          factoryId: 'adFactoryExample',
          request: AdRequest(),
          listener: listener,
        );
        myNative.load();
        return AdWidget(ad: myNative);

    広告の実装ができたら、広告の読み込みを開始しつつAdWidgetに広告を渡して、広告ウィジェットを作成します。

    native_page.dart

      ......
    
      myNative.load();
      return AdWidget(ad: myNative);
    }

    Flutter側の実装は以上になります。

    ネイティブ側での実装

    初めに広告のUIを作成します。 Androidでは、UIをxml形式で記述してきます。 ここでandroid:id="...のように、Viewの要素にIDがいくつか指定されていることがわかります。 あとでこのIDをレイアウトにアクセスするときに使用します。

    android/src/main/res/layout/my_native_ad.xml

    <com.google.android.gms.ads.formats.UnifiedNativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/ad_headline"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
        <TextView
            android:id="@+id/ad_body"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>
    </com.google.android.gms.ads.formats.UnifiedNativeAdView>

    次にNativeAdFactoryを継承した、広告を作成するクラスを定義します。 今回はNativeAdFactoryExampleというクラス名にします。

    android/src/main/kotlin/com/example.googleads_mobile_sdk_sample/NativeAdFactoryExample.kt

    class NativeAdFactoryExample(private val layoutInflater: LayoutInflater) : NativeAdFactory {
    
        override fun createNativeAd(nativeAd: UnifiedNativeAd?,
                                    customOptions: MutableMap<String, Any>?): UnifiedNativeAdView {
            val adView = layoutInflater.inflate(R.layout.my_native_ad, null)
                    as UnifiedNativeAdView
            val headlineView = adView.findViewById<TextView>(R.id.ad_headline)
            val bodyView = adView.findViewById<TextView>(R.id.ad_body)
    
            headlineView.text = nativeAd?.headline
            bodyView.text = nativeAd?.body
    
            adView.setBackgroundColor(Color.YELLOW)
    
            adView.setNativeAd(nativeAd)
            adView.headlineView = headlineView
            adView.bodyView = bodyView
            return adView
        }
    }

    ここでやっていることは、レイアウトのxmlを読み込んできて、xmlに定義したID(android:id="...)を頼りに、各コンテンツを埋め込んで広告のUIを作成するといった感じです。

    次に、Flutter側で定義したFactoryIDと、先ほど作成したFactoryクラスの紐付けを行います。

    android/src/main/kotlin/com/example/googleads_mobile_sdk_sample/MainActivity.kt

    class MainActivity : FlutterActivity() {
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            flutterEngine.plugins.add(GoogleMobileAdsPlugin());
            super.configureFlutterEngine(flutterEngine)
    
    +        GoogleMobileAdsPlugin.registerNativeAdFactory(
    +                flutterEngine,
    +                "adFactoryExample",
    +                NativeAdFactoryExample(layoutInflater)
    +        )
    
        }
    
    ```GoogleMobileAdsPlugin.registerNativeAdFactory```の引数に、Flutter側で定義した```adFactoryExample```というFactoryIDと、先ほど作成した```NativeAdFactoryExample```を渡しているのがわかります。
    
    さらに、アプリ終了時に広告の削除処理を行うために```cleanUpFlutterEngine```を以下のようにオーバーライドします。
    
    android/src/main/kotlin/com/example/googleads_mobile_sdk_sample/MainActivity.kt

    ……

    override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
        super.cleanUpFlutterEngine(flutterEngine)
        GoogleMobileAdsPlugin.unregisterNativeAdFactory(
                flutterEngine, "adFactoryExample"
        )
    }
    これでネイティブ広告を表示できるようになりました!👏
    
    
    
    ## おわりに
    今回はKotlinでネイティブ広告を実装する方法を紹介しました。
    本当はIOS側の実装をswiftに読み替えて、一緒に紹介する予定でした。しかし、IOS開発やobjective-cに詳しくないために、ランタイムエラーを回避することができず断念しました。
    サンプルをみていて気づいたことがありましたらissueをあげていただけると嬉しいです。
    
    それでは良い開発ライフを!

    -––