You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter插件创建的Isolate中第三方包无法加载的问题

在Geofence后台Isolate中访问SharedPreferences的解决方案

问题分析

你遇到的PlatformException(channel-error)是因为带有@pragma('vm:entry-point')标记的后台Isolate默认未初始化Flutter平台通信所需的绑定,且SharedPreferences基于Pigeon实现的平台通道仅在主Isolate中注册,导致后台Isolate无法建立连接。

解决步骤

1. 替换UI绑定为服务绑定

后台Isolate无需UI相关能力,应使用ServicesBinding.ensureInitialized()替代WidgetsFlutterBinding.ensureInitialized(),初始化平台通信的基础服务。

2. 使用官方SharedPreferences初始化方式

放弃SharedPreferencesAsync,直接调用官方的SharedPreferences.getInstance()获取实例,该方法会自动处理后台Isolate中的通道初始化(需先完成服务绑定)。

3. 修正异步逻辑

确保backgroundTriggerHandler中等待异步操作完成,避免未处理的Future引发异常。

修改后的完整代码

import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; // 引入ServicesBinding

import 'package:geofence_foreground_service/exports.dart';
import 'package:geofence_foreground_service/geofence_foreground_service.dart';
import 'package:geofence_foreground_service/models/zone.dart';
import 'package:geolocator/geolocator.dart';
import 'package:shared_preferences/shared_preferences.dart';

@pragma('vm:entry-point')
void callbackDispatcher() async {
  // 初始化服务绑定,支持平台通信
  ServicesBinding.ensureInitialized();
  
  // 预初始化SharedPreferences实例
  final prefs = await SharedPreferences.getInstance();

  Future<bool> trigger() async {
    Set<String> test = prefs.getKeys();
    print(test);
    return true;
  }

  GeofenceForegroundService().handleTrigger(
    backgroundTriggerHandler: (zoneID, triggerType) async {
      await trigger(); // 等待异步操作完成
      print("Trigger done");
      return true;
    },
  );
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  static final LatLng _testLocation = LatLng.degree(40.758078, -73.985640);
  bool _hasServiceStarted = false;

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  Future<void> initPlatformState() async {
    bool serviceEnabled;
    LocationPermission permission = LocationPermission.denied;

    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (serviceEnabled) {
      permission = await Geolocator.checkPermission();
      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
      }
    }

    _hasServiceStarted = await GeofenceForegroundService().startGeofencingService(
      contentTitle: 'Test app',
      contentText: 'Test app will be running to ensure seamless integration with ops team',
      notificationChannelId: 'com.app.geofencing_notifications_channel',
      serviceId: 525600,
      callbackDispatcher: callbackDispatcher,
    );

    log(_hasServiceStarted.toString(), name: 'hasServiceStarted');
  }

  Future<void> _createLondonGeofence() async {
    if (!_hasServiceStarted) {
      log('Service has not started yet', name: 'createGeofence');
      return;
    }
    await GeofenceForegroundService().addGeofenceZone(
      zone: Zone(
        id: 'TempLocation',
        radius: 1000,
        coordinates: [_testLocation],
      ),
    );
    log('Geofence created', name: 'createGeofence');
  }

  Future<void> _removeLondonGeofence() async {
    if (!_hasServiceStarted) {
      log('Service has not started yet', name: 'createGeofence');
      return;
    }
    await GeofenceForegroundService().removeGeofenceZone(zoneId: 'TempLocation');
    log('Geofence removed', name: 'createGeofence');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(onPressed: _createLondonGeofence, child: const Text('Create Temporary Geofence')),
              const SizedBox(height: 30),
              ElevatedButton(onPressed: _removeLondonGeofence, child: const Text('Remove Temporary Geofence')),
            ],
          ),
        ),
      ),
    );
  }
}

双平台适配说明

  • iOS:无需额外配置,确保已添加定位权限描述(NSLocationAlwaysAndWhenInUseUsageDescription/NSLocationWhenInUseUsageDescription)并开启后台定位模式即可。
  • Android:无需额外配置,ServicesBinding会自动处理平台通道初始化,SharedPreferences可正常在后台Isolate中访问。

内容的提问来源于stack exchange,提问作者NoahL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 01:50:54