Anderillo
Anderillo

Reputation: 153

Flutter workmanager with home_widget working in debug and profile, but not in Android build APK

I have a todo app built in Flutter and intended only for Android. I built a home screen widget for it (using the home_widget package in Flutter) to allow users to see a list of tasks and check them off directly from the widget.

At midnight, the tasks should reset with the new tasks for the day (I used the workmanager package to accomplish this, although I also tried the android_alarm_manager_plus package, with the same results). All of this functionality is working perfectly in debug mode, and even in profile mode (I can't test it in release mode because, according to my understanding, that would remove services and thus the home_widget would not work; however, when I do the build, that doesn't seem to be the problem because the home widget still shows up). BUT! When I build the release APK and submit it to Google Play for internal testing, then download it onto my Pixel 7 (with no power saving modes on, as far as I'm aware), the midnight function does not run. :(

Here's the relevant code:

main_prod.dart

void main() async {
  return mainGeneric('Prod Name', ProdFirebaseOptions.currentPlatform, Environment.prod);
}

main_generic.dart


/// Used for Background Updates using Workmanager Plugin
@pragma('vm:entry-point')
void workmanagerCallbackDispatcher() {
  Workmanager().executeTask((taskName, inputData) {
    if (taskName == 'widgetBackgroundUpdate') {
      try {
        return Future.wait<void>([
          // This is a static Future<void> function from a helper class that resets
          // the tasks; it seems to be working when I test it by itself, as well as
          // in debug or profile mode.
          MidnightService.resetTasks(),
        ]).then((value) {
          return Future.value(true);
        });
      } catch(err) {
        print(err.toString());
        throw Exception(err);
      }
    }
    return Future.value(true);
  });
}

void _startBackgroundUpdate() async {
  if (await MidnightService.shouldUpdateWorkManagerTasks()) {
    (await SharedPreferences.getInstance()).setInt('midnight_tasks_update_version', Constants.MIDNIGHT_TASKS_UPDATE_VERSION);
    
    await Workmanager().cancelAll();
    DateTime now = DateTime.now();
    int nowMillis = now.millisecondsSinceEpoch;
    int midnightTonightMillis = DateTime(now?.year ?? 0, now?.month ?? 0, (now?.day ?? 0) + 1).millisecondsSinceEpoch;
    int millisUntilMidnight = midnightTonightMillis - nowMillis;
    await Workmanager().registerPeriodicTask('midnightUpdate', 'widgetBackgroundUpdate', initialDelay: Duration(milliseconds: millisUntilMidnight), frequency: Duration(days: 1));
  }
}

void mainGeneric(String appName, FirebaseOptions firebaseOptions, Environment environment) async {
  // Avoid errors caused by flutter upgrade.
  WidgetsFlutterBinding.ensureInitialized();
  Workmanager().initialize(workmanagerCallbackDispatcher, isInDebugMode: kDebugMode).then((_) => _startBackgroundUpdate());
  ...
  // If this is the first time opening the app with widget functionality.
  HomeWidget.getWidgetData<String>('todays_tasks_string', defaultValue: '').then((todaysTasksString) async {
    if (todaysTasksString == '') {
      List<Task> todaysTasks = await Repositories().taskRepository.getFocusedTasks();
      await HomeWidgetUtils.setTodaysTasks(todaysTasks);
      return true;
    }
    return false;
  });

  Firebase.initializeApp(
    name: appName,
    options: firebaseOptions,
  ).then((_) async {
    ...
  });
  
  HomeWidget.registerBackgroundCallback(homeWidgetBackgroundCallback);
  runApp(AppConfig(
    child: MyApp(),
    environment: environment,
    appTitle: appName,
  ));
}

// Called when doing background work initiated from home screen widget
@pragma('vm:entry-point')
Future<void> homeWidgetBackgroundCallback(Uri uri) async {
  if (uri.host.startsWith('completetask_')) {
    String todaysTasksString = await HomeWidgetUtils.updateTaskById(uri.host.split('_')[1], true);
    await HomeWidget.saveWidgetData<String>('todays_tasks_string', todaysTasksString);
    await HomeWidget.updateWidget(androidName: 'TodaysTasksWidgetProvider');
  }
}

midnight_service.dart

class MidnightService {
  ...
  static Future<bool> shouldUpdateWorkManagerTasks() async {
    try {
      final prefs = await SharedPreferences.getInstance();
      int midnightTasksUpdateVersion = prefs.getInt('midnight_tasks_update_version');
      return Constants.MIDNIGHT_TASKS_UPDATE_VERSION > midnightTasksUpdateVersion;
    }
    catch (e) { print(e); }
    return true;
  }
}

It might also be valuable to note that, when a user checks off a task from the home screen widget, sometimes the task takes a while to actually be checked off (and sometimes requires the app to be opened before it will execute). However, I figured this is just a slowness issue or something controlled by the OS that I can't do much about.

With all of that, my question is then, why is the workmanager not executing its midnight task?

I've been smashing my head against this for days, so any help and/or advice is greatly appreciated!!

Upvotes: 2

Views: 905

Answers (0)

Related Questions