TL;DR
アプリをkillした状態でもcallbackの中でpluginを使いたい場合は、AppDelegate
ファイルにそのpluginを定義する必要がある!
やりたいこと
Flutterアプリで、
「ユーザーのlocationが移動するたびに、Firestoreに位置情報データを保存したい!!!!」
というのを、アプリがfore/background の時では簡単にできたが、kill(終了)している状態でも行いたい!
その前に
僕の理解では、iOSでbackground taskを行う場合、workmanager的なものを使って、最小単位15minで処理を行えるという認識だった。
だが、locationに関してのbackground taskは、Significant-change location というものを使えば、アプリをkillしていても時間の制約なしに、500 meter以上の移動を検知してその度に処理をすることができるらしい。
事前準備
- background_locator という、Significant-change location の機能を含む極めて有難いプラグインを使う
- このプラグインの基本的な使い方を参考に、基礎となる位置情報のinitiationなどのコードをかく
具体的な手順
- 位置情報の変更を検知する時に呼ばれるcallbackを定義
Future<void> callback(LocationDto locationDto) async {
print('location in dart: ${locationDto.toString()}');
// Firebase appが空だったら、初期化
if (Firebase.apps.isEmpty) {
await Firebase.initializeApp();
}
final _firebaseService = FirebaseService();
//SharedPreferencesでローカルデータを取得
final prefs = await SharedPreferences.getInstance();
if (locationDto != null) {
final myUid = await prefs.getString('uid');
final currentLatitude = locationDto.latitude;
final currentLongitude = locationDto.longitude;
//Firestoreにデータを保存
await _firebaseService.updateCurrentLocation(myUid, currentLatitude, currentLongitude);
}
final SendPort send =
IsolateNameServer.lookupPortByName('terminatedLocator_send_port');
send?.send(locationDto);
}
}
注意点
- callbackの中では、同class内で定義してる他の関数を呼び出してはいけない
- callbackがkill時に呼ばれた時、Firebase appは破棄されている可能性があるので、空だったら初期化するようにする
2.callback内で呼び出すプラグインをAppDelegate.swift
に定義
アプリがkill時に、callback内でプラグインを使いたい場合、AppDelegate
の方に追記する必要があるらしい
AppDelegate.swift
import Foundation
import Flutter
import UIKit
import cloud_firestore
import background_locator
import Firebase
import shared_preferences
func registerPlugins(registry: FlutterPluginRegistry) -> () {
if (!registry.hasPlugin("BackgroundLocatorPlugin")) {
GeneratedPluginRegistrant.register(with: registry)
}
}
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
BackgroundLocatorPlugin.setPluginRegistrantCallback(registerPlugins)
registerOtherPlugins() //callback内で使うpluginはこの関数内で定義
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func registerOtherPlugins() {
if !hasPlugin("io.flutter.plugins.firebase.cloudfirestore") {
FLTFirebaseFirestorePlugin
.register(with: registrar(forPlugin: "io.flutter.plugins.firebase.cloudfirestore") as! FlutterPluginRegistrar)
}
if !hasPlugin("io.flutter.plugins.sharedpreferences") {
FLTSharedPreferencesPlugin.register(with: registrar(forPlugin: "io.flutter.plugins.sharedpreferences") as! FlutterPluginRegistrar)
}
}
...
}
参考document: