How to create iOS Home Widgets with Flutter

Published on

If you have ever tried to add those beautiful, interactive panels to your user's iPhone home screen using Flutter, you likely hit a wall. You expect to write Dart code and have it magically appear as a widget, just like the rest of your app.

But there is a problem with flutter home widgets.

"They don't run like normal apps. They run on a tiny little thread with strict memory limits. So small that Flutter can't run there."

So, how do we solve this? The answer lies in a hybrid approach: we render the UI using SwiftUI (native iOS) but keep using Flutter to fetch and manage the data.

In this guide, we will walk through the entire process—from the manual configuration in Xcode to automating the entire workflow with the ApparenceKit CLI.

Key Takeaways

  • Flutter cannot run directly inside a Widget Extension due to memory constraints; you must use SwiftUI for the UI.
  • App Groups are essential: They allow your main Flutter app and the Widget Extension to share data via UserDefaults.
  • Xcode Configuration is tricky: You need to manually adjust Build Phases (specifically the "Thin Binary" script) to avoid build errors.
  • Automation saves time: The ApparenceKit CLI can generate the Swift code, Dart services, and Xcode config from a single JSON file.

Understanding the Architecture

Before writing code, it is crucial to understand where your code lives. Your Flutter app runs in its own process. The Home Widget runs in a completely separate process (the Widget Extension).

Because they are separate, they cannot share memory variables. You cannot just pass a Dart object to the Widget. instead, we use a shared storage container called App Groups.

  1. Flutter App: Fetches data (API, Database) → Saves it to UserDefaults via App Groups.
  2. Widget Extension: Wakes up → Reads UserDefaults → Renders the UI with SwiftUI.

Part 1: The Manual Setup (Xcode Configuration)

If you are setting this up from scratch, get ready to spend some time in Xcode. Here is the step-by-step process.

1. Create the Widget Target

Open your project in Xcode (ios/Runner.xcworkspace).

  1. Go to File > New > Target.
  2. Search for "Widget Extension".
  3. Name it (e.g., HomeWidget).
  4. Important: Do not check "Include Live Activity" or "Configuration App Intent" for this basic tutorial.

2. Fix the "Thin Binary" Build Error

This is a common "gotcha" for Flutter developers. When you try to run the app after adding a target, it will often fail with a build error.

  • Why? The Flutter build script interferes with the extension build process.
  • The Fix: Go to your Runner Target > Build Phases. Find the script named "Thin Binary" and drag it to the very bottom of the list.

3. Enable App Groups

This is the bridge between your app and the widget.

  1. Select your Runner target > Signing & Capabilities.
  2. Click + Capability and add App Groups.
  3. Create a new group ID. The convention is usually group.your.bundle.identifier (e.g., group.io.apparence.my_app).
  4. Repeat this step for the Widget Extension target. Both targets must have the exact same App Group enabled.

"If you don't prefix the App Group with the same identifier of your app, it won't work."


Part 2: The Flutter Implementation

Now that the native side is ready, we need to communicate from Dart. We will use the home_widget package.

1. Configure the App Group in Dart

In your main.dart or initialization logic, tell the plugin which group to use.

import 'package:home_widget/home_widget.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Set the group ID you created in Xcode
  await HomeWidget.setAppGroupId('group.io.apparence.my_app');
  
  runApp(MyApp());
}

Notes :

  • replace 'group.io.apparence.my_app' with your actual App Group ID. This is critical for data sharing.
  • Make sure that your group id is prefixed with group. and the rest matches your app's bundle identifier.

2. Saving Data to the Widget

Let's say you want to display a weather temperature or a counter. You save the data using key-value pairs.

Future<void> updateWeatherWidget(int temperature, String condition) async {
  // Save data to the shared container
  await HomeWidget.saveWidgetData<String>('temperature', temperature.toString());
  await HomeWidget.saveWidgetData<String>('condition', condition);
  
  // Notify iOS to refresh the widget UI
  // 'WeatherWidget' must match the kind/name used in your Swift code
  await HomeWidget.updateWidget(
    name: 'WeatherWidget',
    iOSName: 'WeatherWidget', 
  );
}

Part 3: The SwiftUI Implementation

Now we move to the Swift file created in your extension folder (e.g., HomeWidget.swift).

By default, Apple gives you a timeline provider. You need to modify it to read from the UserDefaults suite we just populated.

struct WeatherEntry: TimelineEntry {
    let date: Date
    let temperature: String
    let condition: String
}

func getTimeline(...) {
    // Access the shared App Group
    let prefs = UserDefaults(suiteName: "group.io.apparence.my_app")
    
    // Read the data sent from Flutter
    let temp = prefs?.string(forKey: "temperature") ?? "0"
    let cond = prefs?.string(forKey: "condition") ?? "Sunny"

    let entry = WeatherEntry(date: Date(), temperature: temp, condition: cond)
    
    // Create the timeline (update immediately)
    let timeline = Timeline(entries: [entry], policy: .atEnd)
    completion(timeline)
}

Once the data is retrieved, you use standard SwiftUI Text() or Image() views to display it.


Part 4: Automating the Pain with ApparenceKit CLI

If the manual process above felt tedious—creating targets, managing bundle IDs, syncing strings between Dart and Swift—you are not alone. It is error-prone and slow.

This is why I added a dedicated automation tool to ApparenceKit. You can generate your entire flutter home widget setup from a single JSON file.

1. Create the Config File

Create a file named home_widget_config.json in your project root.

{
  "widgets": [
    {
      "name": "Weather",
      "description": "Shows current temperature",
      "iosSizes": ["systemSmall", "systemMedium"],
      "metadata": {
        "temperature": {
          "type": "string",
          "default": "20"
        },
        "condition": {
          "type": "string",
          "default": "Sunny"
        }
      }
    }
  ]
}

2. Run the Generator

Run the following command in your terminal:

dart run apparence_cli widget

This command automatically:

  1. Creates the Swift UI code with the correct TimelineProvider.
  2. Generates a Dart service (HomeWidgetWeatherService) to easily update data.
  3. Handles the Xcode target creation and App Group association.

3. Use the Generated Service

Now, updating your widget in Flutter becomes incredibly simple:

// The CLI generated this service for you
final weatherService = HomeWidgetWeatherService();

await weatherService.update(
  temperature: "24°C",
  condition: "Cloudy",
);

You no longer have to worry about typos in key strings or App Group IDs.


Designing with AI

If you are a Flutter developer, you might not be an expert in SwiftUI. That is okay.

Since the CLI generates the basic structure, you can copy the generated WeatherWidgetView struct into an AI tool like Claude or ChatGPT and ask:

"Here is my SwiftUI widget code. Can you redesign it to look like a modern weather card with a gradient background and SF Symbols?"

Paste the result back into your project, and you have a professional-looking widget without learning the intricacies of SwiftUI layout systems.


Conclusion

Creating flutter home widgets on iOS requires breaking out of the Flutter sandbox. You have to embrace the native platform constraints by using SwiftUI for rendering and App Groups for data transfer.

While you can do this manually, configuring Xcode targets and ensuring both sides speak the same language can be frustrating. Using the ApparenceKit CLI transforms this from a multi-hour task into a 5-minute job.

If you want to build scalable Flutter apps faster, check out ApparenceKit—the Flutter Starter Kit designed to save you months of development time.

You can also watch the full Youtube video tutorial here

Save 3 months of work

One command. Pick your modules. Firebase or Supabase auto-configured. Start building what matters.

kickstarter for flutter apps

Frequently Asked Questions

Why can't Flutter run directly inside iOS Home Widgets?

iOS Home Widgets run in a Widget Extension with strict memory limits that are too small for the Flutter engine to operate. This is why you must use SwiftUI for the widget UI while using Flutter only to fetch and store the data that the widget displays.

What are App Groups and why are they required for Flutter Home Widgets?

App Groups are a shared storage container that allows your main Flutter app and the Widget Extension to communicate. Since they run in separate processes and cannot share memory, App Groups enable data sharing through UserDefaults. Both the main app and the widget extension must have the same App Group ID configured.

How do I fix the 'Thin Binary' build error when adding a Widget Extension?

The Thin Binary build error occurs because Flutter's build script interferes with the extension build process. To fix it, go to your Runner Target > Build Phases in Xcode, find the script named 'Thin Binary', and drag it to the very bottom of the list.

How do I send data from Flutter to an iOS Home Widget?

Use the home_widget package to save data via HomeWidget.saveWidgetData() with key-value pairs. The data is stored in the shared App Group container. Then call HomeWidget.updateWidget() to notify iOS to refresh the widget UI. On the Swift side, read the data using UserDefaults with the same App Group suite name.

Can I design iOS Home Widgets without learning SwiftUI?

Yes, you can use AI tools like Claude or ChatGPT to help design your SwiftUI widget views. Generate the basic structure using the ApparenceKit CLI, then paste the code into an AI tool and ask it to redesign the layout. This approach lets Flutter developers create professional-looking widgets without deep SwiftUI knowledge.

Read more
You may also be interested in
Made by Logo de Pal
ApparenceKit is a flutter template generator tool by Apparence.io © 2026.
All rights reserved