home_widget icon indicating copy to clipboard operation
home_widget copied to clipboard

[Android] Widget is not updated when app is in terminated state

Open Gummybearr opened this issue 1 year ago • 3 comments

Hi, I want to update a widget even when the app is in terminated state, but it seems like it only works when app is on either foreground or background.

This issue might be a duplicate of this one, but I opened up a new issue to provide some code.

android side code

AndroidManifest.xml

  <!--  Home Widget  -->
 <receiver android:name="AppWidgetProvider" android:exported="true">
     <intent-filter>
         <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
     </intent-filter>
     <meta-data android:name="android.appwidget.provider"
         android:resource="@xml/task_widget_info" />
 </receiver>
 <receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver" android:exported="true">
     <intent-filter>
         <action android:name="es.antonborri.home_widget.action.BACKGROUND" />
     </intent-filter>
 </receiver>
 <service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
     android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/>
 <!--  Home Widget  -->

AppWidgetProvider.kt

class AppWidgetProvider : HomeWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray,
        widgetData: SharedPreferences
    ) {
        appWidgetIds.forEach { widgetId ->
            val views = RemoteViews(context.packageName, R.layout.task_widget_layout).apply {
                val pendingIntent = HomeWidgetLaunchIntent.getActivity(
                    context,
                    MainActivity::class.java
                )
                setOnClickPendingIntent(R.id.widget_root, pendingIntent)

                val datetimeToday = widgetData.getString("_datetime_today", "Date is not fetched")
                setTextViewText(R.id.datetime_today, datetimeToday)

                val refreshIntent = HomeWidgetBackgroundIntent.getBroadcast(
                    context,
                    Uri.parse("myapp://update_task_widget")
                )
                setOnClickPendingIntent(R.id.refresh_button, refreshIntent)

                val remainingTask1 = widgetData.getString("_remaining_task1", "Login to fetch data")
                setTextViewText(R.id.remaining_task1, remainingTask1)

                val remainingTask2 = widgetData.getString("_remaining_task2", "")
                setTextViewText(R.id.remaining_task2, remainingTask2)

                val remainingTask3 = widgetData.getString("_remaining_task3", "")
                setTextViewText(R.id.remaining_task3, remainingTask3)

                val remainingTask4 = widgetData.getString("_remaining_task4", "")
                setTextViewText(R.id.remaining_task4, remainingTask4)

            }
            appWidgetManager.updateAppWidget(widgetId, views)
        }
    }
}

flutter side code

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown,
  ]);

  await HomeWidget.registerBackgroundCallback(
    backgroundCallback,
  );
  runApp(const ProviderScope(child: App()));
}

@pragma('vm:entry-point')
Future<void> backgroundCallback(Uri? uri) async {
  if (uri?.host == 'update_task_widget') {
    DateTime now = DateTime.now();
    Response taskResponse = await getTasksOfDay(now);
    if (taskResponse is Error) {
      return;
    }

    List<Task> tasks =
        ((taskResponse as Success).data as TasksOfDayResponse).tasks;
    tasks.sort((a, b) => b.id!.compareTo(a.id!));
    List<Task> remainingTasks =
        [...tasks].where((e) => e.succeeded == false).toList();
    await updateWidget(now, remainingTasks);
  }
}

Future<void> updateWidget(DateTime datetime, List<Task> remainingTasks) async {
  // update shared preference code now shown for simplicity

  await HomeWidget.updateWidget(
    name: 'AppWidgetProvider',
    iOSName: 'AppWidgetProvider',
  );
}

pubspec.yaml

environment:
  sdk: '>=3.0.5 <4.0.0'
dependencies:
  home_widget: ^0.3.0

I want to update the widget even when the app is closed. I am not using flutter_workmanager since periodic update is not needed at this moment.

Btw, I appreciate your library!

Gummybearr avatar Oct 15 '23 05:10 Gummybearr

Any update on this, did you made it working?

dishankjindal1 avatar Oct 21 '23 12:10 dishankjindal1

No. Running background task every 15 min can be an approach, but it is not an elegant way to solve this issue.

Gummybearr avatar Oct 22 '23 01:10 Gummybearr

Android Home widgets can only be updated once an hour on the most android devices. Alarm Manager is a common method to update them more frequently. The home_widget is working, just wait 30-60 minutes ;)

offline-first avatar Nov 24 '23 19:11 offline-first