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.

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.

    <img src=/flutter_website/assets/images/docs/development/platform-integration/app-extensions/xcode-new-target.png height='300'>
  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.

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.
<img src=/flutter_website/assets/images/docs/development/platform-integration/app-extensions/xcode-app-groups.png class='' alt=''>

When two targets belong to the same App Group, they can read and write data 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 have a URL open a specified route in your app, you can use Deep Linking.

Creating app extension UIs with Flutter

Some app extensions display a user interface. For example, iMessage extensions allow users to access your app’s content directly from the Messages app.

<img src=/flutter_website/assets/images/docs/development/platform-integration/app-extensions/imessage-extension.png height='300'>

Flutter does not support building Flutter UI for app extensions. To create the UI for an app extension using Flutter, you must compile a custom engine and embed the FlutterViewController as described in the following section.

  1. Create a custom build of the Flutter engine that removes uses of sharedApplication and corrects the path for the bundle. Check out an example from the community on GitHub.

  2. 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.
    <img src=/flutter_website/assets/images/docs/development/platform-integration/app-extensions/xcode-configurations.png height='300'>
  3. (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 this value for this property to the name of your ViewController. For example, in an iMessage extension you would use MessageViewController.
    <img src=/flutter_website/assets/images/docs/development/platform-integration/app-extensions/extension-info.png height='300'>
  4. Embed the FlutterViewController as described in Adding a Flutter Screen. For example, you can display a specific route in your Flutter app within an iMessage extension.

     //This attribute tells the compiler that this piece of Swift code can be accessed from Objective-C.
     @objc(MessagesViewController)
    
     class MessagesViewController: MSMessagesAppViewController {
         override func viewDidLoad() {
             super.viewDidLoad()
             showFlutter()
         }
        
         @objc func showFlutter() {
             // Create a FlutterViewController with an implicit FlutterEngine
             let flutterViewController = FlutterViewController(project: nil, initialRoute: "/ext", nibName: nil, bundle: nil)
             present(flutterViewController, animated: true, completion: nil)
         }