web-dev-qa-db-ja.com

Flutter WorkmanagerプラグインとLocationプラグインを連携させる方法

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。これまでの私のコード

私は必要な機能を実装する最小限のアプリを作ろうとしました:

  1. Workmanagerプラグインを実装しました(正常に動作します)
  2. Locationプラグインを実装しました(正常に動作します)
  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
8
Tom O

これらの2つのプラグインを使用すると、1回限りのタスクをスケジュールし、現在の場所をそれに渡すことができます。

be.tramckrijte.workmanager には制限があります(すべてがサポートされているわけではありません)。また、アプリケーションが常に実行されているとは限らないため、Dartを介してこれら2つのプラグインを組み合わせても何も起こりません。動作を示す simple_callback_dispatcher_registration.Dart がある場合でも、これはFlutterエンジンにコールバックし、他のプラグインをクエリしません。

ロケーション認識ListenableWorkerの作成とスケジューリングは、タスクの実行中にGPSを修正するために利用できる最良のオプションである可能性があります-バックグラウンドで実行中にFlutterエンジンを介してLocationPluginプラグインをクエリする方法がない限り。つまり、ListenableWorkerが場所を認識している場合、他の場所で場所を取得する必要はありません。 WorkManagerのスレッド は文字通りそれを述べています:

ListenableWorkerは、WorkerCoroutineWorker、およびRxWorkerの基本クラスです。 Java=開発者コールバックベースの非同期APIと対話する必要がある人のようなものを対象としていますFusedLocationProviderClient ...

したがって、ListenableWorkerWorker、およびCoroutineWorkerは、拡張可能な適切なクラスです。 iOS実装に相当するのは、位置認識バックグラウンドサービスです。 Flutterエンジンはそれらを開始/停止し、開始パラメーターを提供するか、コールバックを受信しますが、バックグラウンドで実行されているコードは独立して実行する必要があるため、通常はDartにはなりません。

1
Martin Zeitler