FlutterのバックグラウンドでFirebaseと通信(iOS)

3 min read読了の目安(約3100字

やりたかったこと

  • Workmanagerを使ってFlutterのバックグラウンド処理を実装
  • バックグラウンド処理ではFirebaseと通信
  • (Swift知識なし)

やったこと

main.dart
void main() {
	// ...(略)
	Workmanager().initialize(
		callbackDispatcher,
		isInDebugMode: true,
	);
	runApp(new MyApp());
}

void callbackDispatcher() {
  Workmanager().executeTask((taskName, inputData) async {
    switch (taskName) {
      case Workmanager.iOSBackgroundTask:
        await Firebase.initializeApp();
        Firebase.doSomething(); // Firestoreと通信
        break;
    }
    bool success = true;
    return Future.value(success);
  });
}
AppDelegate.swift
import UIKit
import Flutter
import Firebase

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    GeneratedPluginRegistrant.register(with: self)
    UIApplication.shared.
    setMinimumBackgroundFetchInterval(TimeInterval(60*15)) // <- 追加
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

悩まされたエラー

MissingPluginException (No implementation found for method Firebase#initializeCore on channel plugins.flutter.io/firebase_core)

一応WorkmanagerのDocsにプラグインの導入についての説明はあります。こちら
しかし、import workmanagerの説明が抜けていて

Cannot find 'WorkmanagerPlugin' in scope

となったり、
それを直しても

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Duplicate plugin key: FLTFirebaseFirestorePlugin'

となったり、、、(私が英語をちゃんと読んでないのが原因かも)

でインターネットの海を彷徨っていたんですが、issuesの虱潰しを始めたら解決策が見つかりました。

結論

  • Docsのプラグイン導入のサンプルコードでは同じ実行が2度されていてDuplicateと怒られていただけでした。
  • 直接的な関係はあまりないですが、これでいいのかとなったissueはこちら
AppDelegate.swift
import UIKit
import Flutter
import Firebase
import workmanager

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    GeneratedPluginRegistrant.register(with: self)
    UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*15))
    // ▼ これでいい
    WorkmanagerPlugin.setPluginRegistrantCallback { registry in
      GeneratedPluginRegistrant.register(with: registry)
    }
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

終わり


余談ですが実機で試したら最初のbackground fetchがトリガーされるまで15時間待ちました…
Debugでは出来てるしRelease用の設定も完璧なのに実機だと一向に来ない!という方、安心して果報fetchは寝て待ちましょう。