HomeGuidesReferenceLearn
ArchiveExpo SnackDiscord and ForumsNewsletter

iOS AppDelegate subscribers

Learn how to subscribe to iOS system events relevant to an app, such as inbound links and notifications using Expo modules API.


To respond to certain iOS system events relevant to an app, such as inbound links and notifications, it is necessary to handle the corresponding methods in the AppDelegate.

The React Native module API does not provide any mechanism to hook into these methods, and so setup instructions for React Native libraries often include a step to copy code into the AppDelegate file. To simplify and automate setup and maintenance, the Expo Modules API provides a mechanism that allows your library to subscribe to calls to AppDelegate functions. For this to work, the app AppDelegate must inherit from ExpoAppDelegate, and this is a requirement for using Expo Modules.

ExpoAppDelegate implements most functions from UIApplicationDelegate protocol and forwards their calls to all the subscribers.

Get started

First, you need to have created an Expo module or integrated the Expo modules API in library using the React Native module API. Learn more.

Create a new public Swift class that extends ExpoAppDelegateSubscriber from ExpoModulesCore and add its name to the ios.appDelegateSubscribers array in the module config. Run pod install, and the subscriber will be generated in the ExpoModulesProvider.swift file within the application project.

Now you can subscribe to events by adding delegate functions to your subscriber class. For the full list of functions that you can subscribe to, see the functions that are overridden in ExpoAppDelegate.swift. App delegate functions that may cause side effects when provided are not supported yet (for example, application(_:viewControllerWithRestorationIdentifierPath:coder:)).

Objective-C classes are not supported.

Result values

Delegate functions that need to return a value have some additional logic to reconcile responses from multiple subscribers and try to satisfy all of them. There are two good examples of such edge cases:

application(_:didFinishLaunchingWithOptions:) -> Bool

According to the Apple documentation, you should return false if the app cannot handle the URL resource or continue a user activity, otherwise true should be returned. The return value is ignored if the app is launched because of a remote notification. In such situations, if at least one of the subscribers returns true, the ExpoAppDelegate will return true as well.

application(_:didReceiveRemoteNotification:fetchCompletionHandler:)

This method tells the app delegate that a remote notification arrived and gives the app the opportunity to fetch new data. It receives a completion block to execute when the fetch operation is completed. This block should be called with the fetch result value that best describes the results of your fetch request. Possible values are: UIBackgroundFetchResult.newData, UIBackgroundFetchResult.noData or UIBackgroundFetchResult.failed. In this scenario, ExpoAppDelegate passes a new completion block to each subscriber, waits until all are completed and collects the results before calling the original completion block. The final result depends on the results collected from the subscribers, as follows in the following order:

  • If at least one subscriber called the completion block with failed result, the delegate returns failed as well.
  • If there is at least one newData result, the delegate returns newData.
  • Otherwise noData is returned.

To check out how other functions process the result of your subscriber, we recommend reading the code directly: ExpoAppDelegate.swift.

Example

AppLifecycleDelegate.swift
import ExpoModulesCore

public class AppLifecycleDelegate: ExpoAppDelegateSubscriber {
  public func applicationDidBecomeActive(_ application: UIApplication) {
    // The app has become active.
  }

  public func applicationWillResignActive(_ application: UIApplication) {
    // The app is about to become inactive.
  }

  public func applicationDidEnterBackground(_ application: UIApplication) {
    // The app is now in the background.
  }

  public func applicationWillEnterForeground(_ application: UIApplication) {
    // The app is about to enter the foreground.
  }

  public func applicationWillTerminate(_ application: UIApplication) {
    // The app is about to terminate.
  }
}
expo-module.config.json
{
  "ios": {
    "appDelegateSubscribers": ["AppLifecycleDelegate"]
  }
}