> 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/react-native/push-message/rn-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 the other push solution.

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

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

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

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

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

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

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

Open your project by opening the `/ios/{APP_NAME}.xcworkspace` file with 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" %}
AppDelegate configuration is required to collect push tokens, display push messages, and handle push clicks.
{% endhint %}

Modifying AppDelegate is required for push message integration.

Open your project by opening the `/ios/{APP_NAME}.xcworkspace` file with Xcode, then open the AppDelegate file.

{% hint style="info" %}
The AppDelegate file language differs depending on the React Native version.

* React Native 0.77 and above: `AppDelegate.swift`
* React Native 0.76 and below: `AppDelegate.h` & `AppDelegate.mm`
  {% endhint %}
  {% endstep %}

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

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

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

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

{% tabs %}
{% tab title="AppDelegate.swift" %}

```swift
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import Hackle

@main
class AppDelegate: RCTAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
  ) -> Bool {
    // 기존 구현된 코드 내에 추가
    ...

    // iOS 앱에서 푸시 권한 요청
    let notificationCenter = UNUserNotificationCenter.current()
    notificationCenter.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
        // Enable or disable features based on authorization.
    }
    notificationCenter.delegate = self
    application.registerForRemoteNotifications()

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  override func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
  ) {
    // 핵클 서버로 APNs 푸시 토큰 전달
    Hackle.setPushToken(deviceToken)
  }
...
}
```

{% endtab %}

{% tab title="AppDelegate.h (Objective-C)" %}

```objectivec
#import <RCTAppDelegate.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : RCTAppDelegate <UIApplicationDelegate, UNUserNotificationCenterDelegate>

@end
```

{% endtab %}

{% tab title="AppDelegate.m (Objective-C)" %}

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

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  ...
  // 기존 구현된 코드 내에 추가
  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 Messages**

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

{% hint style="warning" %}
To display pushes in the foreground, you must implement the code below.
{% endhint %}

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

{% tabs %}
{% tab title="AppDelegate.swift" %}

```swift
import Hackle

extension AppDelegate: UNUserNotificationCenterDelegate {
  // Foreground push message
  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="AppDelegate.m (Objective-C)" %}

```objectivec
// Foreground push message
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
  if ([HackleNotification userNotificationCenter:center
                         willPresentNotification: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 %}

Returns `false` if the push was not sent by Hackle.
{% endstep %}

{% step %}
**Handle Push Clicks**

{% 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 the push click rate metric will be unavailable.
{% endhint %}

Add the `handleNotification` method to handle push clicks.

{% tabs %}
{% tab title="AppDelegate.swift" %}

```swift
import Hackle

extension AppDelegate: UNUserNotificationCenterDelegate {
  // push click
  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 에서 completionHandler를 호출하지 않으니
    // 핵클 푸시 여부에 관계없이 반드시 completionHandler를 호출해야 합니다.
    completionHandler()
  }
}
```

{% endtab %}

{% tab title="AppDelegate.m (Objective-C)" %}

```objectivec
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler
{
  if ([HackleNotification userNotificationCenter:center
                              didReceiveResponse:response
                           withCompletionHandler:completionHandler]) {
    return;
  } else {
    completionHandler();
  }
}

```

{% endtab %}
{% endtabs %}

The push click function processes in the following order:

1. Verify whether the push was sent by Hackle
2. Send the push click event to the Hackle server
3. (For deep link pushes) Handle the deep link

Returns `nil` if the push was not sent by Hackle.
{% endstep %}

{% step %}
**Test Push Messages**

**Verify Token**

* Verify the token configured on an iOS device through the [User Identifier Guide](/en/development-guide/react-native/react-native-user-explorer.md).
* Verify the iOS push token assigned to a specific user through the [User Profile Guide](/en/user-view/user-profile.md).

**Test**

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

{% step %}
**Push Message Reception**

Whether push messages are received on iOS depends on the build environment.

{% hint style="info" %}
Even if the APNs Key Environment is set to `Sandbox & Production`, the scope of push message reception differs by Hackle environment and app build environment as shown below.
{% 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 on click.

For information on how to use React Native deep links in an iOS environment, refer to the [React Native Deep Link Guide](https://reactnative.dev/docs/linking?syntax=ios).

{% hint style="warning" %}
When connected to a remote JS debugger, React Native's `Linking.getInitialURL()` returns `null`, causing a [known issue](https://reactnative.dev/docs/linking?syntax=ios\&language=typescript\&ios-language=swift#getinitialurl) where the deep link URL cannot be retrieved.
{% endhint %}


---

# 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/react-native/push-message/rn-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.
