# 4.x -> 4.3

 There's a new version available!

These pages cover version 4 of our SDK, but a newer version is available. In general, we suggest that you update to the latest version to take advantage of new features and fixes.

*   Are you new to our SDKs? [Check out the latest docs.](/integrations/sdk/react-native/getting-started)
*   Otherwise, [learn about updating to the latest version](/integrations/sdk/react-native/whats-new/)

Version 4.3 of the Customer.io React Native SDK introduces a new `CioAppDelegateWrapper` pattern for iOS that simplifies push notification setup and eliminates the need for method swizzling.

## Key Changes[](#key-changes)

The primary change in version 4.3 is the introduction of the wrapper pattern for handling push notifications on iOS. This change:

*   **Eliminates method swizzling**: No more automatic method replacement
*   **Simplifies setup**: Less boilerplate code required
*   **Improves reliability**: More predictable behavior

See the instructions below to update your app depending on whether you send push notifications with APN or FCM and whether you use UIKit or SwiftUI.

## Update with APN (Apple Push Notification service)[](#update-appdelegate-apn)

### UIKit[](#uikit-apn)

Update your `AppDelegate.swift` file to use the new `CioAppDelegateWrapper` pattern. See the *Before* sample to see what needs to change and the *After* sample to see the new pattern.

 Before (4.x)

#### Before (4.x)[](#Before \(4.x\))

```swift
import UIKit
import CioMessagingPushAPN
import UserNotifications

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, 
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize push 
        MessagingPushAPN.initialize(withConfig: MessagingPushConfigBuilder().build())

        // Register for push notifications
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
            if granted {
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
        
        return true
    }
    
    // Manual push handling methods
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        MessagingPush.shared.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        MessagingPush.shared.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        MessagingPush.shared.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
    }
}
```

 After (4.3)

#### After (4.3)[](#After \(4.3\))

```swift
import UIKit
import CioMessagingPushAPN
import UserNotifications

@main
class AppDelegateWithCioIntegration: CioAppDelegateWrapper<AppDelegate> {}

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, 
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize push with wrapper - handles all push methods automatically
        MessagingPushAPN.initialize(withConfig: MessagingPushConfigBuilder().build())
        
        // Register for push notifications
        // You can move this line to any part of your app. It's not critical to call it in this method.
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
            if granted {
                // Remove this, as Customer.io SDK handles this automatically
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
        
        return true
    }
    
    // No manual push methods needed - CioAppDelegateWrapper handles everything
}
```

### SwiftUI[](#swiftui-apn)

If you’re using SwiftUI, you’ll need to use the `@UIApplicationDelegateAdaptor` instead of the `@main` attribute. See the *Before* sample to see what needs to change and the *After* sample to see the new pattern.

 Before (4.x)

#### Before (4.x)[](#Before \(4.x\))

```swift
import SwiftUI
import CioMessagingPushAPN
import UserNotifications

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {
    // Similar manual push handling as UIKit example above
}
```

 After (4.3)

#### After (4.3)[](#After \(4.3\))

```swift
import SwiftUI
import CioMessagingPushAPN
import UserNotifications

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(CioAppDelegateWrapper<AppDelegate>.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication,
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize push with wrapper
        MessagingPushAPN.initialize(withConfig: MessagingPushConfigBuilder().build())
        
        return true
    }
    
    // No manual push methods needed
}
```

## Update with FCM (Firebase Cloud Messaging)[](#update-appdelegate-fcm)

### UIKit[](#uikit-fcm)

Update your `AppDelegate.swift` file to use the new `CioAppDelegateWrapper` pattern. See the *Before* sample to see what needs to change and the *After* sample to see the new pattern.

 Before (4.x)

#### Before (4.x)[](#Before \(4.x\))

```swift
import UIKit
import CioMessagingPushFCM
import UserNotifications
import Firebase
import FirebaseMessaging

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, 
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Configure Firebase
        FirebaseApp.configure()
        
        // Set FCM messaging delegate
        Messaging.messaging().delegate = self
        
        // Register for push notifications
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
            if granted {
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
        
        return true
    }
    
    // Manual push handling methods
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Messaging.messaging().apnsToken = deviceToken
        MessagingPush.shared.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        MessagingPush.shared.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        MessagingPush.shared.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
    }
}

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        // Handle FCM token
    }
}
```

 After (4.3)

#### After (4.3)[](#After \(4.3\))

```swift
import UIKit
import CioMessagingPushFCM
import UserNotifications
import Firebase
import FirebaseMessaging

@main
class AppDelegateWithCioIntegration: CioAppDelegateWrapper<AppDelegate> {}

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, 
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Configure Firebase
        FirebaseApp.configure()
        
        // Set FCM messaging delegate
        Messaging.messaging().delegate = self
        
        // Initialize push FCM with wrapper - handles all push methods automatically
        MessagingPushFCM.initialize(withConfig: MessagingPushConfigBuilder().build())
        
        // Register for push notifications
        // You can move this line to any part of your app. It's not critical to call it in this method.
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in
            if granted {
                // Remove this, as Customer.io SDK handles this automatically
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
        
        return true
    }
    
    // No manual push methods needed - wrapper handles everything
}

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        // Handle FCM token - Customer.io SDK will also receive this automatically
    }
}
```

### SwiftUI[](#swiftui-fcm)

If you’re using SwiftUI, you’ll need to use the `@UIApplicationDelegateAdaptor` instead of the `@main` attribute. See the *Before* sample to see what needs to change and the *After* sample to see the new pattern.

 Before (4.x)

#### Before (4.x)[](#Before \(4.x\))

```swift
import SwiftUI
import CioMessagingPushFCM
import UserNotifications

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {
    // Similar manual push handling as UIKit example above
}
```

 After (4.3)

#### After (4.3)[](#After \(4.3\))

```swift
import SwiftUI
import CioMessagingPushFCM
import UserNotifications

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(CioAppDelegateWrapper<AppDelegate>.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication,
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize push with wrapper
        MessagingPushAPN.initialize(withConfig: MessagingPushConfigBuilder().build())
        
        return true
    }
    
    // No manual push methods needed
}
```

## Important Notes[](#important-notes)

1.  **Manual push handling methods are not required**: the `CioAppDelegateWrapper` automatically records information from following methods. But you can still use these methods if you want to add custom push handling:
    
    *   `didRegisterForRemoteNotificationsWithDeviceToken`
    *   `didFailToRegisterForRemoteNotificationsWithError`
    *   `didReceiveRemoteNotification`
    *   All other push-related delegate methods
2.  **The `@main` attribute** - Must be on the wrapper class, not your AppDelegate.
    

## Troubleshooting[](#troubleshooting)

If push notifications stop working after you update your implementation:

1.  Make sure that you’ve added the `@main` attribute to the wrapper class
2.  Verify that you’ve removed `@main` from your original AppDelegate
3.  Check that you’re calling `MessagingPushAPN.initialize()` or `MessagingPushFCM.initialize()`
4.  If you encounter some unexpected behavior and want to test is it related to new Push Notification tracking system, just comment the following line and compare `class AppDelegateWithCioIntegration: CioAppDelegateWrapper<AppDelegate> {}` with the original AppDelegate.