> For the complete documentation index, see [llms.txt](https://docs.hackle.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hackle.io/en/development-guide/flutter/push-message/flutter-ios-push-message.md).

# iOS Push Message Integration

{% hint style="info" %}
**Can be used alongside other push solutions**

To use alongside another push solution, you must disable the Swizzling option of that solution.

After disabling Swizzling, configure push notification handling manually by following that solution's guide.
{% endhint %}

{% hint style="danger" %}
iOS push messages via FCM are not supported.

To use iOS push messages, please integrate APNs.
{% endhint %}

{% stepper %}
{% step %}
**Configure APNs**

To use push messages in an iOS app, you need to configure the integration between the Hackle Workspace and APNs.

For details, refer to [Apple Push Notification Service Configuration](/en/external-link/crm-channels/apple-push-notification-service-integration.md).
{% endstep %}

{% step %}
**Add PushNotification Capability to App**

Open the project by opening `/ios/Runner.xcworkspace` in Xcode, then click `+ Capability` in the `Signing & Capabilities` tab of the project settings as shown below.

![](/files/7dS2ujMRVzUXJ3xs1Ngq)

Add `Push Notifications` and `Background Modes`.

![](/files/Zk4zETlTHnCGFSyEZ2K8)

![](/files/bXaDSc8S0qPKd0DGyic4)

Then enable `Remote notifications` under `Background Modes`.

![](/files/KUDu0CGgEijMdpROdkjk)
{% endstep %}

{% step %}
**Configure AppDelegate**

{% hint style="info" %}
You must configure AppDelegate to enable push token collection, push message display, and push click handling.
{% endhint %}

Modifying AppDelegate is required for push message integration.

Open the project by opening `/ios/Runner.xcworkspace` in Xcode, then open the AppDelegate file.
{% endstep %}

{% step %}
**Collect Push Token**

{% hint style="warning" %}
Push tokens are not collected automatically.

You must collect push tokens using the code below in order to receive push messages.
{% endhint %}

Add the `setPushToken` method to `AppDelegate` as shown below.

{% tabs %}
{% tab title="Swift" %}

```swift
import Flutter
import Hackle
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
      _ application: UIApplication,
      didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
      ...
      // Add inside existing implemented code
      // Request push permission in iOS app
      let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
      UNUserNotificationCenter.current().requestAuthorization(
          options: authOptions,
          completionHandler: { _, _ in }
      )
      NUserNotificationCenter.current().delegate = self
      application.registerForRemoteNotifications()
      ...
    }

    override func application(
      _ application: UIApplication,
      didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
      // Send APNs push token to Hackle server
      Hackle.setPushToken(deviceToken)
    }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>
#import Hackle

@interface AppDelegate : FlutterAppDelegate

@end
```

```objectivec
#import "AppDelegate.h"
#import <Hackle/HackleNotification.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  ...
  // Add inside existing implemented code
  UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
  [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {}];
  center.delegate = self;
  [[UIApplication sharedApplication] registerForRemoteNotifications];
  ...
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  [HackleNotification setPushToken:deviceToken];
}
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}
**Display Push Message**

{% hint style="info" %}
In the background, pushes are displayed automatically without any code implementation.
{% endhint %}

{% hint style="warning" %}
You must implement the code below to display pushes in the foreground.
{% endhint %}

Add the `userNotificationCenter` method to display foreground push messages.

{% tabs %}
{% tab title="Swift" %}

```swift
import Flutter
import Hackle
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate {
  ...
  // Add inside existing implemented code

  // Foreground push message
  override func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions
  ) -> Void) {

    if Hackle.userNotificationCenter(
      center: center, willPresent: notification, withCompletionHandler: completionHandler
    ) {
      // Succefully processed notification
      // Automatically consumed completion handler
      return
    } else {
      // Received not hackle notification or error
      print("Do something")

      if #available(iOS 14.0, *) {
        completionHandler([.list, .banner])
      } else {
        completionHandler([.alert])
      }
    }
  }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
// Foreground push message
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
    if ([Hackle userNotificationCenterWithCenter:center
                                      willPresent:notification
                             withCompletionHandler:completionHandler]) {
        // Succefully processed notification
        // Automatically consumed completion handler
        return;
    } else {
        // Received not hackle notification or error
        NSLog(@"Do something");
        completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner);
    }
}
```

{% endtab %}
{% endtabs %}

If the push was not sent by Hackle, false is returned.
{% endstep %}

{% step %}
**Handle Push Click**

{% hint style="danger" %}
If you do not call the push click handling function provided by Hackle, the push will not be processed correctly.

Additionally, the push click event will not be collected and you will not be able to use the push click rate metric.
{% endhint %}

Add the `handleNotification` method to handle push clicks.

{% tabs %}
{% tab title="Swift" %}

```swift
import Flutter
import Hackle
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate {
  ...
  // Add inside existing implemented code

  // push click
  override public func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
  ) {

    if let _ = Hackle.handleNotification(response: response) {
      // process hackle notification
    } else {
      // not hackle notification or error
      print("do something")
    }

    // handleNotification does not call completionHandler,
    // so you must call completionHandler regardless of whether it is a Hackle push.
    completionHandler()
  }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
// push click
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler
{
    if ([Hackle handleNotificationWithResponse:response] != nil) {
        // process hackle notification
    } else {
        // not hackle notification or error
        NSLog(@"do something");
    }
    // handleNotification does not call completionHandler,
    // so you must call completionHandler regardless of whether it is a Hackle push.
    completionHandler();
}
```

{% endtab %}
{% endtabs %}

The push click function processes in the following order:

1. Check if the push was sent by Hackle
2. Send the push click event to the Hackle server
3. (If it is a deep link push) Handle the deep link

If the push was not sent by Hackle, nil is returned.
{% endstep %}

{% step %}
**Test Push Message**

**Check Token**

* Check the token set on the iOS device via the [Check User Identifier guide](/en/development-guide/ios/ios-user-explorer.md).
* Check the iOS push token assigned to a specific user via the [User Profile guide](/en/user-view/user-profile.md).

**Test**

* Follow the [Push Message Test Send Guide](/en/crm-marketing/push-message-guide/create-campaign.md#id-3-1) to verify the push message on an iOS device.
  {% endstep %}

{% step %}
**Receive Push Message**

On iOS, whether push messages can be received depends on the build environment.

{% hint style="info" %}
Even when the APNs Key Environment is set to `Sandbox & Production`, the scope for receiving push messages varies by Hackle environment and app build environment as follows.
{% endhint %}

<table><thead><tr><th width="175.78125">Hackle Environment</th><th width="175.40625">APNs Environment</th><th>Build Environment</th></tr></thead><tbody><tr><td>Development Environment,<br>Development/Production test push</td><td>Sandbox</td><td>Direct run from Xcode,<br>Development provisioning</td></tr><tr><td>Production Environment</td><td>Production</td><td>TestFlight, Ad Hoc,<br>App Store distribution</td></tr></tbody></table>
{% endstep %}
{% endstepper %}

## Deep Link Navigation

Hackle push messages support deep link navigation when tapped.

When the corresponding activity is opened via a push message, you can retrieve the deep link information using the method below.

For more details about Flutter deep links, refer to the [Flutter Deep Linking Guide](https://docs.flutter.dev/ui/navigation/deep-linking).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hackle.io/en/development-guide/flutter/push-message/flutter-ios-push-message.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
