Вызвать код Flutter (Dart) из родного виджета домашнего экрана Android

Я добавил собственный виджет домашнего экрана Android в свое приложение Flutter.

В моей реализации AppWidgetProvider я хотел бы вызвать код dart в моем onUpdate() используя канал платформы.

Это возможно? Если да, то как этого достичь?

Мой текущий код Android (Java):

package com.westy92.checkiday;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.util.Log;

import io.flutter.plugin.common.MethodChannel;
import io.flutter.view.FlutterNativeView;

public class HomeScreenWidget extends AppWidgetProvider {

    private static final String TAG = "HomeScreenWidget";
    private static final String CHANNEL = "com.westy92.checkiday/widget";

    private static FlutterNativeView backgroundFlutterView = null;
    private static MethodChannel channel = null;

    @Override
    public void onEnabled(Context context) {
        Log.i(TAG, "onEnabled!");
        backgroundFlutterView = new FlutterNativeView(context, true);
        channel = new MethodChannel(backgroundFlutterView, CHANNEL);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Log.i(TAG, "onUpdate!");
        if (channel != null) {
            Log.i(TAG, "channel not null, invoking dart method!");
            channel.invokeMethod("foo", "extraJunk");
            Log.i(TAG, "after invoke dart method!");
        }
    }
}

Код дротика:

void main() {
  runApp(Checkiday());
}

class Checkiday extends StatefulWidget {
  @override
  _CheckidayState createState() => _CheckidayState();
}

class _CheckidayState extends State<Checkiday> {
  static const MethodChannel platform = MethodChannel('com.westy92.checkiday/widget');

  @override
  void initState() {
    super.initState();
    platform.setMethodCallHandler(nativeMethodCallHandler);
  }

  Future<dynamic> nativeMethodCallHandler(MethodCall methodCall) async {
    print('Native call!');
    switch (methodCall.method) {
      case 'foo':
        return 'some string';
      default:
      // todo - throw not implemented
    }
  }

  @override
  Widget build(BuildContext context) {
    // ...
  }
}

Когда я добавляю виджет на домашний экран, я вижу:

I/HomeScreenWidget(10999): onEnabled!
I/HomeScreenWidget(10999): onUpdate!
I/HomeScreenWidget(10999): channel not null, invoking dart method!
I/HomeScreenWidget(10999): after invoke dart method!

Однако мой код дротика, похоже, не получает вызов.

Ответ 1

Сначала убедитесь, что вы вызываете FlutterMain.startInitialization() а затем FlutterMain.ensureInitializationComplete() прежде чем пытаться выполнить любой код Dart. Эти звонки необходимы для начальной загрузки Flutter.

Во-вторых, можете ли вы попробовать эту же цель с помощью нового экспериментального встраивания Android?

Вот руководство по выполнению кода Dart с использованием нового встраивания: https://github.com/flutter/flutter/wiki/Experimental:-Reuse-FlutterEngine-across-screens

Если ваш код все еще не работает должным образом с новым встраиванием Android, тогда должно быть легче отладить, в чем проблема. Пожалуйста, отправьте обратно с успехом, или любую новую информацию об ошибке.

Ответ 2

может быть, вы можете использовать invokeMethod(String method, @Nullable Object arguments, MethodChannel.Result callback) и использовать обратный вызов, чтобы получить причину сбоя.

Ответ 3

Вам нужно передать getFlutterView() из MainActivity вместо создания нового BackgroundFlutterView:

channel = new MethodChannel(MainActivity.This.getFlutterView(), CHANNEL);

"Это" как:

public class MainActivity extends FlutterActivity {
    public static MainActivity This;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        This = this;
        ...
    }