startBackground method

Future<void> startBackground({
  1. required DownloadableRegion<List<Object>> region,
  2. FMTCTileProviderSettings? tileProviderSettings,
  3. bool disableRecovery = false,
  4. String backgroundNotificationTitle = 'App Running In Background',
  5. String backgroundNotificationText = "Hide this notification by holding down and opening the notification's settings. Then disable this notification only.",
  6. AndroidResource? backgroundNotificationIcon,
  7. bool showProgressNotification = true,
  8. AndroidNotificationDetails? progressNotificationConfig,
  9. String progressNotificationIcon = '@mipmap/ic_notification_icon',
  10. String progressNotificationTitle = 'Downloading Map...',
  11. String progressNotificationBody(
    1. DownloadProgress
    )?,
})

Download a specified DownloadableRegion in the background, and show a progress notification (by default)

To check the number of tiles that need to be downloaded before using this function, use check.

Only available on Android devices, due to limitations with other operating systems. Background downloading is complicated: see the documentation website for more information.

Calling this method will automatically request the necessary permissions. You may want to call requestIgnoreBatteryOptimizations beforehand, as this will allow you more control.

Uses a foreground service internally, meaning the process should be stable unless the application is force stopped/fully closed. However, you should still read the Limitations page, available in the online documentation.

Displays two notifications:

  • A service notification, informing the user that the process is running. This is unavoidable due to the system limitations, however it can be easily hidden by the user. The default text explains this process roughly.
  • A progress notification, informing the user of the current state of the download. Includes a progress bar and time estimate by default.

Configure the progress notification using:

  • showProgressNotification: set to false to disable the progress notification - not recommended
  • progressNotificationIcon: set to a string in the format '@<type>/<name>' (found in the 'android\app\src\main\res') to override the default icon ('@mipmap/ic_notification_icon': only available in the example application)
  • progressNotificationTitle: set to a String to override the default title
  • progressNotificationText: set to a String to override the default body text
  • progressNotificationConfig: use to further customise the notification properties

Configure the background notification using:

  • backgroundNotificationIcon: set to an AndroidResource to override the default icon ('@mipmap/ic_launcher': the app's launcher icon)
  • backgroundNotificationTitle: set to a String to override the default title
  • backgroundNotificationText: set to a String to override the default body text

Implementation

Future<void> startBackground({
  required DownloadableRegion region,
  FMTCTileProviderSettings? tileProviderSettings,
  bool disableRecovery = false,
  String backgroundNotificationTitle = 'App Running In Background',
  String backgroundNotificationText =
      "Hide this notification by holding down and opening the notification's settings. Then disable this notification only.",
  AndroidResource? backgroundNotificationIcon,
  bool showProgressNotification = true,
  AndroidNotificationDetails? progressNotificationConfig,
  String progressNotificationIcon = '@mipmap/ic_notification_icon',
  String progressNotificationTitle = 'Downloading Map...',
  String Function(DownloadProgress)? progressNotificationBody,
}) async {
  if (Platform.isAndroid) {
    final bool initSuccess = await FlutterBackground.initialize(
      androidConfig: FlutterBackgroundAndroidConfig(
        notificationTitle: backgroundNotificationTitle,
        notificationText: backgroundNotificationText,
        notificationIcon: backgroundNotificationIcon ??
            const AndroidResource(name: 'ic_launcher', defType: 'mipmap'),
      ),
    );
    if (!initSuccess) {
      throw StateError(
        'Failed to acquire the necessary permissions to run the background process',
      );
    }

    final bool startSuccess =
        await FlutterBackground.enableBackgroundExecution();
    if (!startSuccess) {
      throw StateError('Failed to start the background process');
    }

    final notification = FlutterLocalNotificationsPlugin();
    await notification.initialize(
      InitializationSettings(
        android: AndroidInitializationSettings(progressNotificationIcon),
      ),
    );
    await notification
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()!
        .requestPermission();

    final Stream<DownloadProgress> downloadStream = startForeground(
      region: region,
      tileProviderSettings: tileProviderSettings,
      disableRecovery: disableRecovery,
    ).asBroadcastStream();

    final AndroidNotificationDetails androidNotificationDetails =
        progressNotificationConfig?.copyWith(
              channelId: 'FMTCMapDownloader',
              ongoing: true,
            ) ??
            const AndroidNotificationDetails(
              'FMTCMapDownloader',
              'Map Download Progress',
              channelDescription:
                  'Displays progress notifications to inform the user about the progress of their map download',
              showProgress: true,
              visibility: NotificationVisibility.public,
              subText: 'Map Downloader',
              importance: Importance.low,
              priority: Priority.low,
              showWhen: false,
              playSound: false,
              enableVibration: false,
              onlyAlertOnce: true,
              autoCancel: false,
              ongoing: true,
            );

    late final StreamSubscription<DownloadProgress> subscription;

    subscription = downloadStream.listen(
      (event) async {
        if (showProgressNotification) {
          await notification.show(
            0,
            progressNotificationTitle,
            progressNotificationBody == null
                ? '${event.attemptedTiles}/${event.maxTiles} (${event.percentageProgress.round()}%)'
                : progressNotificationBody(event),
            NotificationDetails(
              android: androidNotificationDetails.copyWith(
                maxProgress: event.maxTiles,
                progress: event.attemptedTiles,
              ),
            ),
          );
        }
      },
      onDone: () async {
        if (showProgressNotification) await notification.cancel(0);
        await subscription.cancel();

        await cancel();
        if (FlutterBackground.isBackgroundExecutionEnabled) {
          await FlutterBackground.disableBackgroundExecution();
        }
      },
    );
  } else {
    throw PlatformException(
      code: 'notAndroid',
      message:
          'The background download feature is only available on Android due to internal limitations.',
    );
  }
}