Loading...
Loading...
Adds home screen widgets to a Flutter app for Android and iOS. Use when providing glanceable app information or quick actions on the device home screen.
npx skill4agent add flutter/skills flutter-adding-home-screen-widgetsUserDefaultsSharedPreferenceshome_widgetHomeWidget.setAppGroupId('<YOUR_APP_GROUP>')initState()HomeWidget.saveWidgetData<T>('key', value)HomeWidget.updateWidget(iOSName: 'YourIOSWidget', androidName: 'YourAndroidWidget')ios/Runner.xcworkspaceTimelineEntrygetSnapshotgetTimelineUserDefaults(suiteName: "<YOUR_APP_GROUP>")userDefaults?.string(forKey: "your_key")TimelineEntryViewTimelineEntryandroidres/layout/<widget_name>.xmlRelativeLayoutTextViewImageViewAppWidgetProvideronUpdateHomeWidgetPlugin.getData(context)widgetData.getString("your_key", null)RemoteViewssetTextViewTextsetImageViewBitmapappWidgetManager.updateAppWidget(appWidgetId, views)GlobalKeyHomeWidget.renderFlutterWidget()UserDefaultsUIImage(contentsOfFile:)ImageSharedPreferencesBitmapFactory.decodeFile()setImageViewBitmap()CTFontManagerRegisterFontsForURLFont.custom()import 'package:home_widget/home_widget.dart';
const String appGroupId = 'group.com.example.app';
const String iOSWidgetName = 'NewsWidgets';
const String androidWidgetName = 'NewsWidget';
Future<void> 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,
);
}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)
}
}
}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
)
}