1。問題の説明
私の目標は、 このワークマネージャープラグイン と このロケーションプラグイン を使用して定期的な位置更新を取得するFlutterアプリを構築することです。しかし、Workmanagerコールバックが起動したときにLocationプラグインを適切にロードできません。私はこのエラーを受け取ります:
MissingPluginException(No implementation found for method getLocation on channel lyokone/location)
基本的に、問題は、WorkmanagerプラグインがDartコードを実行しようとしたときに、Locationプラグインをロードしないことです。
2。私が調査したその他のリソース
ここ 、 ここ 、および ここ が同じ問題に直面している他のユーザーを見つけました。
私が理解している限り、これらの質問に提供される解決策は要約すると:CustomApplication.Javaという名前のファイルを作成し、FlutterApplication、プラグインを登録します。次に、AndoidManifest.xmlファイル内にCustomApplication.Javaファイルを登録します。
3。これまでの私のコード
私は必要な機能を実装する最小限のアプリを作ろうとしました:
各手順で行ったことを正確に確認するには、こちらをご覧ください https://gitlab.com/tomoerlemans/workmanager_with_location/-/commits/master 。 (このリポジトリは、問題をすばやく複製するためにも使用できます)。
関連するコードファイルは次のとおりです。
main.Dart
import 'package:flutter/material.Dart';
import 'package:workmanager/workmanager.Dart';
import 'package:location/location.Dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
Workmanager.initialize(callbackDispatcher, isInDebugMode: true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
Workmanager.registerPeriodicTask(
"1", "simpleTask");
},
child: Text("Start workmanager"),
),
RaisedButton(
onPressed: () {
getLocation();
},
child: Text("Get current location"),
),
],
),
),
);
}
}
void callbackDispatcher() {
Workmanager.executeTask((task, inputData) {
print("Native called background task at ${DateTime.now().toString()}");
getLocation();
return Future.value(true);
});
}
void getLocation() async {
LocationData currentLocation;
var location = new Location();
try {
currentLocation = await location.getLocation();
} on Exception catch (e) {
print("Error obtaining location: $e");
currentLocation = null;
}
print("Location altitude: ${currentLocation.altitude}");
print("Location longitude: ${currentLocation.longitude}");
}
pubspec.yaml
name: background_location
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
workmanager: ^0.2.0
location: ^2.3.5
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
CustomApplication.Java
package io.flutter.plugins;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import be.tramckrijte.workmanager.WorkmanagerPlugin;
import com.lyokone.location.LocationPlugin;
public class CustomApplication extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback {
@Override
public void onCreate() {
super.onCreate();
WorkmanagerPlugin.setPluginRegistrantCallback(this);
}
@Override
public void registerWith(PluginRegistry registry) {
WorkmanagerPlugin.registerWith(registry.registrarFor("be.tramckrijte.workmanager.WorkmanagerPlugin"));
LocationPlugin.registerWith(registry.registrarFor("com.lyokone.location.LocationPlugin"));
}
}
AndroidManifest.xml
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
package="com.example.background_location">
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />
<application
Android:name="io.flutter.plugins.CustomApplication"
Android:label="background_location"
Android:icon="@mipmap/ic_launcher">
<activity
Android:name=".MainActivity"
Android:launchMode="singleTop"
Android:theme="@style/LaunchTheme"
Android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
Android:hardwareAccelerated="true"
Android:windowSoftInputMode="adjustResize">
<intent-filter>
<action Android:name="Android.intent.action.MAIN"/>
<category Android:name="Android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
Android:name="flutterEmbedding"
Android:value="2" />
</application>
</manifest>
最後に、Dart/Flutter/etcの次のバージョンを実行しています。
Flutter 1.12.13+hotfix.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 27321ebbad (10 weeks ago) • 2019-12-10 18:15:01 -0800
Engine • revision 2994f7e1e6
Tools • Dart 2.7.0
これらの2つのプラグインを使用すると、1回限りのタスクをスケジュールし、現在の場所をそれに渡すことができます。
be.tramckrijte.workmanager
には制限があります(すべてがサポートされているわけではありません)。また、アプリケーションが常に実行されているとは限らないため、Dartを介してこれら2つのプラグインを組み合わせても何も起こりません。動作を示す simple_callback_dispatcher_registration.Dart がある場合でも、これはFlutterエンジンにコールバックし、他のプラグインをクエリしません。
ロケーション認識ListenableWorker
の作成とスケジューリングは、タスクの実行中にGPSを修正するために利用できる最良のオプションである可能性があります-バックグラウンドで実行中にFlutterエンジンを介してLocationPlugin
プラグインをクエリする方法がない限り。つまり、ListenableWorker
が場所を認識している場合、他の場所で場所を取得する必要はありません。 WorkManagerのスレッド は文字通りそれを述べています:
ListenableWorker
は、Worker
、CoroutineWorker
、およびRxWorker
の基本クラスです。 Java=開発者コールバックベースの非同期APIと対話する必要がある人のようなものを対象としていますFusedLocationProviderClient
...
したがって、ListenableWorker
、Worker
、およびCoroutineWorker
は、拡張可能な適切なクラスです。 iOS実装に相当するのは、位置認識バックグラウンドサービスです。 Flutterエンジンはそれらを開始/停止し、開始パラメーターを提供するか、コールバックを受信しますが、バックグラウンドで実行されているコードは独立して実行する必要があるため、通常はDartにはなりません。