📘

FlutterFragment で admob が表示されない問題

2024/03/12に公開

問題

FutterFragment で admob を表示しようとしたところ表示されず、ログを見ると下記エラーが発生していました。

2024-03-11 19:39:43.207 17033-17180 flutter
E  [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method create on channel flutter/platform_views)
#0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:313:7)
<asynchronous suspension>
#1      SurfaceAndroidViewController._sendCreateMessage (package:flutter/src/services/platform_views.dart:1045:9)
<asynchronous suspension>
#2      AndroidViewController.create (package:flutter/src/services/platform_views.dart:818:5)
<asynchronous suspension>

原因

admob では PlatformView の機能を利用しているが、これを登録するための処理が内部で実行されていない様子。

登録処理は FlutterEngineConnectionRegistry.attachToActivityInternal(Activity, Lifecycle) で実行されているがFlutterFragment でこの処理がスキップされている。

ちなみにこのエラーに関するコメントが実装に記されている。

    // Activate the PlatformViewsController. This must happen before any plugins attempt
    // to use it, otherwise an error stack trace will appear that says there is no
    // flutter/platform_views channel.
    flutterEngine
        .getPlatformViewsController()
        .attach(activity, flutterEngine.getRenderer(), flutterEngine.getDartExecutor());

この処理が実行されるかどうかは shouldAttachEngineToActivity というフラグを見ている。

  /**
   * See {@link NewEngineFragmentBuilder#shouldAttachEngineToActivity()} and {@link
   * CachedEngineFragmentBuilder#shouldAttachEngineToActivity()}.
   *
   * <p>Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate}
   */
  @Override
  public boolean shouldAttachEngineToActivity() {
    return getArguments().getBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY);
  }

このフラグがやや曲者で NewEngineFragmentBuilder や CachedEngineFragmentBuilder を利用して FlutterFragment インスタンスを生成した場合のデフォルト値は true になるが、それ以外の場合は false になる。

builder 以外の生成方法では ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY のフラグが設定されないことで getBoolean(String) がフォールバックされて false が返されてしまう。

なので本来的にはこのような処理が正しいのでは。(shouldAttachEngineToActivity は FlutterFragment のメンバ変数で true を設定しているので、それをフォールバックとして設定)

  @Override
  public boolean shouldAttachEngineToActivity() {
    return getArguments().getBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY, shouldAttachEngineToActivity);
  }

いずれにしてもここを true で返せば問題なさそう。

対応

FlutterFragment に shouldAttachEngineToActivity() を継承して true を返すようにしました。

    override fun shouldAttachEngineToActivity(): Boolean {
        return true
    }

HogeFragment : FlutterFragment() のような実装だったのでこのような対応をしましたが、それ以外の場合は NewEngineFragmentBuilder や CachedEngineFragmentBuilder を利用して FlutterFragment を生成する方法にすればいいと思います。

Discussion