Adding iOS app extensions

iOS app extensions allow you to expand functionality outside your app. Your app could appear as a home screen widget, or you can make portions of your app available within other apps.

To learn more about app extensions, check out Apple's documentation.

iOS 18 added support for customizing a device's Control Center, including creating multiple pages. You can also create new toggles for the Control Center using the ControlCenter API, to feature your app.

How do you add an app extension to your Flutter app?

#

To add an app extension to your Flutter app, add the extension point target to your Xcode project.

  1. Open the default Xcode workspace in your project by running open ios/Runner.xcworkspace in a terminal window from your Flutter project directory.

  2. In Xcode, select File -> New -> Target from the menu bar.

    Opening the File -> New menu, then selecting Target in Xcode.
  3. Select the app extension you intend to add. This selection generates extension-specific code within a new folder in your project. To learn more about the generated code and the SDKs for each extension point, check out the resources in Apple's documentation.

To learn how to add a home screen widget to your iOS device, check out the Adding a Home Screen Widget to your Flutter app codelab.

How do Flutter apps interact with App Extensions?

#

Flutter apps interact with app extensions using the same techniques as UIKit or SwiftUI apps. The containing app and the app extension don't communicate directly. The containing app might not be running while the device user interacts with the extension. The app and your extension can read and write to shared resources or use higher-level APIs to communicate with each other.

Using higher-level APIs

#

Some extensions have APIs. For example, the Core Spotlight framework indexes your app, allowing users to search from Spotlight and Safari. The WidgetKit framework can trigger an update of your home screen widget.

To simplify how your app communicates with extensions, Flutter plugins wrap these APIs. To find plugins that wrap extension APIs, check out Leveraging Apple's System APIs and Frameworks or search pub.dev.

Sharing resources

#

To share resources between your Flutter app and your app extension, put the Runner app target and the extension target in the same App Group.

To add a target to an App Group:

  1. Open the target settings in Xcode.

  2. Navigate to the Signing & Capabilities tab.

  3. Select + Capability then App Groups.

  4. Choose which App Group you want to add the target from one of two options:

    1. Select an App Group from the list.
    2. Click + to add a new App Group.
Selecting an App Group within an Xcode Runner target configuration.

When two targets belong to the same App Group, they can read from and write to the same source. Choose one of the following sources for your data.

Background updates

#

Background tasks provide a means to update your extension through code regardless of the status of your app.

To schedule background work from your Flutter app, use the workmanager plugin.

Deep linking

#

You might want to direct users from an app extension to a specific page in your Flutter app. To open a specific route in your app, you can use Deep Linking.

Creating app extension UIs with Flutter

#

Some app extensions display a user interface.

For example, share extensions allow users to conveniently share content with other apps, such as sharing a picture to create a new post on a social media app.

An example of an entry added to the share menu by a Flutter app

As of the 3.16 release, you can build Flutter UI for an app extension, though you must use an extension-safe Flutter.xcframework and embed the FlutterViewController as described in the following section.

  1. Locate the extension-safe Flutter.xcframework file, at <path_to_flutter_sdk>/bin/cache/artifacts/engine/ios/extension_safe/Flutter.xcframework.

    • To build for release or profile modes, find the framework file under the ios-release or ios-profile folder, respectively.
  2. Drag and drop the Flutter.xcframework file into your share extension's frameworks and libraries list. Make sure the embed column says "Embed & Sign".

    The Flutter.xcframework file being marked as Embed & Sign in Xcode.
  3. Open the Flutter app project settings in Xcode to share build configurations.

    1. Navigate to the Info tab.
    2. Expand the Configurations group.
    3. Expand the Debug, Profile, and Release entries.
    4. For each of these configurations, make sure the value in the Based on configuration file drop-down menu for your extension matches the one selected for the normal app target.
    An example Xcode Runner configuration with each property set to: Based on configuration file.
  4. (Optional) Replace any storyboard files with an extension class, if needed.

    1. In the Info.plist file, delete the NSExtensionMainStoryboard property.
    2. Add the NSExtensionPrincipalClass property.
    3. Set the value for this property to the entry point of the extension. For example, for share extensions, it's usually <YourShareExtensionTargetName>.ShareViewController. If you use Objective-C to implement the extension, you should omit the <YourShareExtensionTargetName>. portion.
    Setting the NSExtensionPrincipalClass property in the Info.plist file within Xcode.
  5. Embed the FlutterViewController as described in Adding a Flutter Screen. For example, you can display a specific route in your Flutter app within a share extension.

    swift
    import UIKit
    import Flutter
    
    class ShareViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            showFlutter()
        }
    
        func showFlutter() {
            let flutterViewController = FlutterViewController(project: nil, nibName: nil, bundle: nil)
            addChild(flutterViewController)
            view.addSubview(flutterViewController.view)
            flutterViewController.view.frame = view.bounds
        }
    }

Test extensions

#

Testing extensions on simulators and physical devices have slightly different procedures.

Test on a simulator

#
  1. Build and run the main application target.
  2. After the app is launched on the simulator, press Cmd + Shift + H to minimize the app, which switches to the home screen.
  3. Launch an app that supports the share extension, such as the Photos app.
  4. Select a photo, tap the share button, then tap on the share extension icon of your app.

Test on a physical device

#

You can use the following procedure or the Testing on simulators instructions to test on physical devices.

  1. Launch the share extension target.
  2. In the popup window that says "Choose an app to run", select an app that can be used to test share extension, such as the Photos app.
  3. Select a photo, tap the share button, then tap on the share extension icon of your app.

Tutorials

#

For step-by-step instruction for using app extensions with your Flutter iOS app, check out the Adding a Home Screen Widget to your Flutter app codelab.