Implementing Flutter Home Screen Widgets
Contents
Architecture & Data Flow
Flutter Integration Workflow
iOS Implementation Workflow
Android Implementation Workflow
Advanced Techniques
Examples
Architecture & Data Flow
Home Screen Widgets require native UI implementation (SwiftUI for iOS, XML/Kotlin for Android). The Flutter app communicates with these native widgets via shared local storage (
UserDefaults
on iOS,
SharedPreferences
on Android) using the
home_widget
package.
Data Write:
Flutter app writes key-value pairs or renders images to a shared container.
Trigger:
Flutter app signals the native OS to update the widget.
Data Read:
Native widget wakes up, reads the key-value pairs or images from the shared container, and updates its UI.
Flutter Integration Workflow
Use this checklist to implement the Dart side of the Home Screen Widget integration.
Step 1: Initialize the App Group.
Call
HomeWidget.setAppGroupId('
updateWidgetData ( String title , String description ) async { await HomeWidget . setAppGroupId ( appGroupId ) ; await HomeWidget . saveWidgetData < String
( 'headline_title' , title ) ; await HomeWidget . saveWidgetData < String
( 'headline_description' , description ) ; await HomeWidget . updateWidget ( iOSName : iOSWidgetName , androidName : androidWidgetName , ) ; } Example: iOS SwiftUI Provider & View import WidgetKit import SwiftUI struct NewsArticleEntry : TimelineEntry { let date : Date let title : String let description : String } struct Provider : TimelineProvider { func placeholder ( in context : Context ) -> NewsArticleEntry { NewsArticleEntry ( date : Date ( ) , title : "Loading..." , description : "Loading..." ) } func getSnapshot ( in context : Context , completion : @escaping ( NewsArticleEntry ) -> ( ) ) { let userDefaults = UserDefaults ( suiteName : "group.com.example.app" ) let title = userDefaults ? . string ( forKey : "headline_title" ) ?? "No Title" let description = userDefaults ? . string ( forKey : "headline_description" ) ?? "No Description" let entry = NewsArticleEntry ( date : Date ( ) , title : title , description : description ) completion ( entry ) } func getTimeline ( in context : Context , completion : @escaping ( Timeline < Entry
) -> ( ) ) { getSnapshot ( in : context ) { ( entry ) in let timeline = Timeline ( entries : [ entry ] , policy : . atEnd ) completion ( timeline ) } } } struct NewsWidgetsEntryView : View { var entry : Provider . Entry var body : some View { VStack ( alignment : . leading ) { Text ( entry . title ) . font ( . headline ) Text ( entry . description ) . font ( . subheadline ) } } } Example: Android Kotlin Provider package com . example . app . widgets import android . appwidget . AppWidgetManager import android . appwidget . AppWidgetProvider import android . content . Context import android . widget . RemoteViews import es . antonborri . home_widget . HomeWidgetPlugin import com . example . app . R class NewsWidget : AppWidgetProvider ( ) { override fun onUpdate ( context : Context , appWidgetManager : AppWidgetManager , appWidgetIds : IntArray , ) { for ( appWidgetId in appWidgetIds ) { val widgetData = HomeWidgetPlugin . getData ( context ) val views = RemoteViews ( context . packageName , R . layout . news_widget ) . apply { val title = widgetData . getString ( "headline_title" , "No Title" ) setTextViewText ( R . id . headline_title , title ) val description = widgetData . getString ( "headline_description" , "No Description" ) setTextViewText ( R . id . headline_description , description ) } appWidgetManager . updateAppWidget ( appWidgetId , views ) } } } // Add this to your SwiftUI View struct var bundle : URL { let bundle = Bundle . main if bundle . bundleURL . pathExtension == "appex" { var url = bundle . bundleURL . deletingLastPathComponent ( ) . deletingLastPathComponent ( ) url . append ( component : "Frameworks/App.framework/flutter_assets" ) return url } return bundle . bundleURL } init ( entry : Provider . Entry ) { self . entry = entry CTFontManagerRegisterFontsForURL ( bundle . appending ( path : "/fonts/YourCustomFont.ttf" ) as CFURL , CTFontManagerScope . process , nil ) }