# 2.x -> 2.2

Version 2.2 of the Customer.io Flutter 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 2.2 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 Flutter app’s iOS configuration.

## Upgrading to SDK 2.2[](#upgrading-to-sdk-22)

Update your dependencies:

1.  Update your `pubspec.yaml` file:
    
    ```yaml
    dependencies:
      customer_io: ^2.2.0
    ```
    
2.  Run dependency update:
    
    ```bash
    flutter pub get && cd ios && pod install --repo-update && cd ..
    ```
    

## Update with FCM (Firebase Cloud Messaging)[](#update-appdelegate-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 (2.x)

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

```swift
import UIKit
import Flutter
import CioMessagingPushFCM
import FirebaseMessaging
import FirebaseCore

@main
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        
        Messaging.messaging().delegate = self
        
        MessagingPushFCM.initialize(
            withConfig: MessagingPushConfigBuilder()
                .build()
        )
        
        UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate

        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    func application(application: UIApplication,
                    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Messaging.messaging().setAPNSToken(deviceToken, type: .unknown);
    }
    
    override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        MessagingPush.shared.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
    }
}

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        MessagingPush.shared.messaging(messaging, didReceiveRegistrationToken: fcmToken)
    }
}
```

 After (2.2)

#### After (2.2)[](#After \(2.2\))

```swift
import UIKit
import Flutter
import CioMessagingPushFCM
import FirebaseMessaging
import FirebaseCore

@main
class AppDelegateWithCioIntegration: CioAppDelegateWrapper<AppDelegate> {}

class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        
        // Initialize push with wrapper - handles all push methods automatically
        MessagingPushFCM.initialize(
            withConfig: MessagingPushConfigBuilder()
                .build()
        )

        // Optional: Add only if you want custom control over notifications
        UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
        
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    override func application(_ application: UIApplication,
                              didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
        
        Messaging.messaging().apnsToken = deviceToken
    }
    
    // No manual push methods needed - CioAppDelegateWrapper handles everything
}
```

## Configuration Options[](#configuration-options)

You can customize the push behavior when you initialize your push package:

```swift
MessagingPushFCM.initialize(
    withConfig: MessagingPushConfigBuilder()
        .showPushAppInForeground(true)  // Show push when app is in foreground
        .autoTrackPushEvents(true)       // Automatically track push metrics
        .build()
)
```

## 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`
    *   All other push-related delegate methods
2.  **The `@main` attribute** - Must be on the wrapper class, not your AppDelegate.
    
3.  **Flutter-specific**: Your Flutter app’s main.dart file doesn’t need any changes.
    
4.  **NotificationService.swift remains unchanged** - Your notification service extension configuration works the same with both approaches.
    

## 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 `MessagingPushFCM.initialize()`
4.  Run `flutter clean` followed by `pod install --repo-update --project-directory=ios`
5.  Test on a physical device (push notifications don’t work on simulators)