flutter_background_fetch icon indicating copy to clipboard operation
flutter_background_fetch copied to clipboard

[BUG] No implementation found for method listen

Open JannieT opened this issue 2 years ago • 6 comments

After upgrading to Flutter 3.3 and doing some refactorings on our app we are seeing some very high incidents of background crashes for Android users.

Environment

  • Plugin version: 1.1.0 to 1.1.2
  • Platform: Android
  • OS version: Android 5 to 13
  • Device manufacturer / model: Samsung, Google and others
  • Flutter info (flutter info, flutter doctor): [✓] Flutter (Channel stable, 3.3.6, on macOS 12.6 21G115 darwin-x64, locale en-GB) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) [✓] Xcode - develop for iOS and macOS (Xcode 14.0.1) [✓] Chrome - develop for the web [✓] Android Studio (version 2020.3) [✓] VS Code (version 1.73.0) [✓] Connected device (2 available) [✓] HTTP Host Availability
  • Plugin config: see below

To Reproduce We can't reproduce the error, but we get about 40 thousand crashes daily affecting about 13 thousand Android users of our app. These crashes all report the following:

Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: MissingPluginException(No implementation found for method listen on channel com.transistorsoft/flutter_background_fetch/events). Error thrown Instance of 'ErrorDescription'.
       at MethodChannel._invokeMethod(platform_channel.dart:294)
       at EventChannel.receiveBroadcastStream.<fn>(platform_channel.dart:637)

The config is as follows:

import 'dart:async';
import 'dart:io';
import 'dart:ui';

import 'package:background_fetch/background_fetch.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart';

import '../../service_locator.dart';
import 'store_service.dart';
import 'download_service.dart';

class ScheduleService extends StatefulWidget {
  final Widget? child;

  const ScheduleService({Key? key, this.child}) : super(key: key);

  @override
  _ScheduleServiceState createState() => _ScheduleServiceState();
}

class _ScheduleServiceState extends State<ScheduleService> {
  @override
  Widget build(BuildContext context) {
    return widget.child!;
  }

  Future<void> _onTimeout(String taskId) async {
    BackgroundFetch.finish(taskId);
  }

  Future<void> _onFetch(String taskId) async {
    await locator<DownloadService>().runBackgroundTask();
    BackgroundFetch.finish(taskId);
  }

  Future<void> _initPlatformState() async {
    final store = locator<StoreService>();
    final config = BackgroundFetchConfig(
      minimumFetchInterval: 60, // 60 minutes
      enableHeadless: true,
      requiresBatteryNotLow: false,
      requiresCharging: false,
      requiresStorageNotLow: false,
      requiresDeviceIdle: true,
      requiredNetworkType:
          store.useMobileData ? NetworkType.ANY : NetworkType.UNMETERED,
    );

    // from the docs: "There is no such thing as stopOnTerminate: false for iOS"
    if (!Platform.isIOS) {
      config.stopOnTerminate = false;
    }

    try {
      await BackgroundFetch.configure(config, _onFetch, _onTimeout);
    } catch (e, s) {
      FirebaseCrashlytics.instance
          .recordError(e, s, reason: 'BackgroundFetch.configure');
    }
  }

  @override
  void initState() {
    super.initState();
    BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);

    // do some async setup
    Future.delayed(const Duration(seconds: 3), () async {
      await _initPlatformState();
    });
  }
}

/// This "Headless Task" is run when app is terminated.
@pragma('vm:entry-point')
Future<void> backgroundFetchHeadlessTask(HeadlessTask task) async {
  if (task.timeout) {
    BackgroundFetch.finish(task.taskId);
    return;
  }

  /// temporary workaround till Flutter 2.11+
  /// https://github.com/flutter/flutter/issues/99155#issuecomment-1060956399
  // if (Platform.isAndroid) PathProviderAndroid.registerWith();
  // if (Platform.isIOS) PathProviderIOS.registerWith();

  DartPluginRegistrant.ensureInitialized();

  await Firebase.initializeApp();
  await setupHeadlessServiceLocator(await StoreService.instance());

  if (!locator<StoreService>().hasStartDate) {
    BackgroundFetch.finish(task.taskId);
    return;
  }

  await locator<DownloadService>().runBackgroundTask();

  BackgroundFetch.finish(task.taskId);
}

JannieT avatar Nov 18 '22 07:11 JannieT

@override
  void initState() {
    super.initState();
    BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);

You must not .registerHeadlessTask within a Widget. You must do that in your lib/main.dart.

See API docs

christocracy avatar Nov 18 '22 13:11 christocracy

Thank you for your quick response @christocracy . We will refactor asap and check.

JannieT avatar Nov 18 '22 14:11 JannieT

You must not .registerHeadlessTask within a Widget

can I do it in static method?

ivanesi avatar Dec 27 '22 15:12 ivanesi

Just follow the instructions exactly and put it in main.dart as directed.

christocracy avatar Dec 27 '22 15:12 christocracy

Still Facing same issue.

chirag-chopra avatar Oct 14 '23 09:10 chirag-chopra

Same issue for me

klipsedeville avatar Oct 18 '23 12:10 klipsedeville

This issue is stale because it has been open for 30 days with no activity.

github-actions[bot] avatar Apr 17 '24 01:04 github-actions[bot]

This issue was closed because it has been inactive for 14 days since being marked as stale.

github-actions[bot] avatar May 01 '24 01:05 github-actions[bot]