“尝试向 Flutter 发送平台消息,但 FlutterJNI 与原生 C++ 分离。”启动后台服务并关闭应用程序后

问题描述 投票:0回答:6

我正在尝试构建一个使用某些包作为位置(https://pub.dev/packages/location)和指南针(https://pub.dev/packages/flutter_compass)的应用程序,并保留后台服务跟踪用户位置。 一切正常,直到我启动跟踪位置的服务。

当服务处于活动状态时,整个应用程序永远不会停止,例如,当我在没有服务的情况下关闭应用程序时,指南针也会停止,但随着服务运行,指南针也会保持运行。实际上它返回一个错误“尝试向 Flutter 发送平台消息,但 FlutterJNI 与本机 C++ 分离。无法发送。通道:hemanthraj/flutter_compass”。位置也会发生同样的情况:“尝试向 Flutter 发送平台消息,但 FlutterJNI 与本机 C++ 分离。无法发送。通道:lyokone/locationstream”。 在此之后,即使我再次打开该项目,它也不再工作了...... 我正在尝试使服务完全独立于项目的其余部分。

我将向您展示服务实现(Android)

public class CompassApplication extends FlutterApplication {

    @Override
    public void onCreate() {
        super.onCreate();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("messages", "Messages", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }
    }
}
class MainActivity: FlutterActivity() {

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine)

        val intent = Intent(this, LocationService::class.java)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent)
        } else {
            startService(intent)
        }
    }
}
public class LocationService extends Service {

    static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10 * 60 * 1000; // 10 minutes
    static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2;

    private LocationRequest mLocationRequest;
    private FusedLocationProviderClient mFusedLocationClient;
    private LocationCallback mLocationCallback;

    @Override
    public void onCreate() {
        super.onCreate();

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);
                onNewLocation(locationResult.getLastLocation());
            }
        };

        createLocationRequest();
        getLastLocation();
        requestLocationUpdates();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "messages")
                    .setSmallIcon(R.mipmap.ic_launcher_foreground);

            startForeground(101, builder.build());
        }
    }

    private void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    private void getLastLocation() {
        try {
            mFusedLocationClient.getLastLocation()
                    .addOnCompleteListener(task -> {
                        if (task.isSuccessful() && task.getResult() != null) {
                            onNewLocation(task.getResult());
                        }
                    });
        } catch (SecurityException ignored) {}
    }

    public void requestLocationUpdates() {
        Utils.setRequestingLocationUpdates(this, true);
        startService(new Intent(getApplicationContext(), LocationUpdatesService.class));
        try {
            mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
        } catch (SecurityException unlikely) {
            Utils.setRequestingLocationUpdates(this, false);
        }
    }

    private void onNewLocation(Location location) {
        // TODO: deal with current location
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

另一个问题是,即使我不关闭应用程序,它也会消耗大量电池。 谢谢!

android flutter dart service background
6个回答
4
投票

从插件包开发者角度来看:

由于您使用的软件包导致了此问题,我会提到我在我的软件包中引起了同样的问题。

就我而言,我使用了错误(或旧)方法通道。我保存了服务(广播接收器)运行时的方法通道实例,并尝试使用它与正在运行的应用程序进行通信。

在清理服务(或广播接收器)时,我“破坏了”Flutter 引擎,因此将 Flutter JNI 从 C++ 引擎中分离出来。因此,当我去使用该方法通道(它使用分离的 Flutter JNI)时,您会收到错误:

尝试向 Flutter 发送平台消息,但 FlutterJNI 与原生 C++ 分离。

我只需使用 FlutterActivity(或 FlutterFragment 或 Application)提供的 FlutterEngine 来获取新的 MethodChannel。

就我而言,我正在开发 Flutter 包插件(在 Android 上)。这意味着在插件代码内部,我不应该意外地缓存 methodChannels :

public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { final MethodChannel methodChannel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "example-method-channel-name"); }

您的问题

在您的依赖项的情况下,它们可能不支持在服务中使用:它们执行一些缓存/单例并重用不再附加的方法通道或 Flutter JNI。他们可能假设插件被实例化一次,并且在服务运行时(或应用程序在服务已经运行时启动)不会重新实例化。他们可能会注册回调以从操作系统接收数据,然后在创建具有新 Flutter 引擎的新插件时不会取消注册旧回调。

没有快速修复方法,必须构建包来支持这一点。

将以下代码添加到原生 android mainActivity.kt


2
投票

从后台关闭应用程序。
运行“颤动清洁”
运行“颤动运行”
这对我有用。

1
投票

我在使用 TFLite 检测相机上的物体时出现了这个问题。 我不太确定,但每次我注意到手机过热时,


0
投票

这是我的最佳答案: 该错误会导致当 FlutterNativeView 仍然存在时 Dart->Java 消息被丢弃。这个问题看起来涉及Java->Dart消息。


0
投票

**This helps me solve this problem.** import io.flutter.embedding.engine.FlutterJNI; private MethodChannel methodChannel = null; private EventChannel eventChannel = null; private EventChannel.EventSink eventSink; private FlutterJNI flutterJNI = new FlutterJNI(); @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { methodChannel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "sariska_media_transport_flutter"); eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "sariskaMediaTransportEvent"); if (methodChannel != null) { methodChannel.setMethodCallHandler(this); } if (eventChannel != null) { eventChannel.setStreamHandler(this); } flutterJNI.attachToNative(); applicationContext = flutterPluginBinding.getApplicationContext(); connectionPlugin = new ConnectionPlugin(flutterPluginBinding.getBinaryMessenger()); conferencePlugin = new ConferencePlugin(flutterPluginBinding.getBinaryMessenger()); trackPlugin = new TrackPlugin(flutterPluginBinding.getBinaryMessenger()); FlutterEngine flutterEngine = flutterPluginBinding.getFlutterEngine(); PlatformViewRegistry registry = flutterEngine.getPlatformViewsController().getRegistry(); registry.registerViewFactory( "DummyView", new SariskaSurfaceViewFactory(flutterPluginBinding.getBinaryMessenger())); } @Override public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { if (methodChannel != null) { methodChannel.setMethodCallHandler(null); methodChannel = null; } if (eventChannel != null) { eventChannel.setStreamHandler(null); eventChannel = null; } flutterJNI.attachToNative(); }


0
投票
© www.soinside.com 2019 - 2024. All rights reserved.