Upgrade from 3.x to 3.9.0

Updated

This page introduces a new CioAppDelegateWrapper pattern for iOS that simplifies push notification setup and eliminates the need for method swizzling.

Key Changes

The primary change in version 3.9.0 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 APNs

UIKit

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.

import UIKit
import CioMessagingPushAPN

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // Initialize the Customer.io SDK 
        let cdpApiKey = "YOUR_CDP_API_KEY"
        let siteId = "YOUR_SITE_ID"
        let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
            // If your account is in the EU region, uncomment the next line
            // .region(.EU)
            .migrationSiteId(siteId) // only required if you used version 2.x or earlier
            .autoTrackUIKitScreenViews() // Set auto tracking of UIKit screen views
            .logLevel(CioLogLevel.debug) // Add this to troubleshoot issues - disable debug in production
        CustomerIO.initialize(withConfig: config.build())

        return true
    }
}
import UIKit
import CioMessagingPushAPN

@main
class AppDelegateWithCioIntegration: CioAppDelegateWrapper<AppDelegate> {}

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // Initialize the Customer.io SDK 
        let cdpApiKey = "YOUR_CDP_API_KEY"
        let siteId = "YOUR_SITE_ID"
        let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
            // If your account is in the EU region, uncomment the next line
            // .region(.EU)
            .migrationSiteId(siteId) // only required if you used version 2.x or earlier
            .autoTrackUIKitScreenViews() // Set auto tracking of UIKit screen views
            .logLevel(CioLogLevel.debug) // Add this to troubleshoot issues - disable debug in production
        CustomerIO.initialize(withConfig: config.build())

        return true
    }
}

SwiftUI

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.

import SwiftUI
import CioMessagingPushAPN

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

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize the Customer.io SDK 
        let cdpApiKey = "YOUR_CDP_API_KEY"
        let siteId = "YOUR_SITE_ID"
        let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
            // If your account is in the EU region, uncomment the next line
            // .region(.EU)
            .migrationSiteId(siteId) // only required for migration
            .autoTrackUIKitScreenViews() // Set auto tracking of UIKit screen views
            .logLevel(CioLogLevel.debug) // Add this to troubleshoot issues - disable debug in production
        CustomerIO.initialize(withConfig: config.build())

        return true
    }
}
import SwiftUI
import CioMessagingPushAPN

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

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize the Customer.io SDK 
        let cdpApiKey = "YOUR_CDP_API_KEY"
        let siteId = "YOUR_SITE_ID"
        let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
            // If your account is in the EU region, uncomment the next line
            // .region(.EU)
            .migrationSiteId(siteId) // only required for migration
            .autoTrackUIKitScreenViews() // Set auto tracking of UIKit screen views
            .logLevel(CioLogLevel.debug) // Add this to troubleshoot issues - disable debug in production
        CustomerIO.initialize(withConfig: config.build())

        return true
    }
}

Update with FCM

UIKit

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.

import UIKit
import CioMessagingPushFCM
import Firebase
import FirebaseMessaging

@main
class AppDelegate: NSObject, UIApplicationDelegate {
 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
     // Initialize the Firebase SDK.
     FirebaseApp.configure()

     let siteId = YOUR_SITE_ID
     let cdpApiKey = YOUR_CDP_API_KEY

     // Configure and initialize the Customer.io SDK
     let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
         .migrationSiteId(siteId)
         .autoTrackUIKitScreenViews()
         .autoTrackDeviceAttributes(true)
  
     CustomerIO.initialize(withConfig: config.build())

     // Initialize messaging features after initializing Customer.io SDK        
     MessagingPushFCM.initialize(
         withConfig: MessagingPushConfigBuilder()
             // optionally, configure the push module by calling functions on the builder. Such as: 
             .autoFetchDeviceToken(true)
             // See section below to find all the configuration options you can set. 
             .build()
     )

     return true
 }
}
import UIKit
import CioMessagingPushFCM
import Firebase
import FirebaseMessaging

@main
class AppDelegateWithCioIntegration: CioAppDelegateWrapper<AppDelegate> {}

class AppDelegate: NSObject, UIApplicationDelegate {
 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
     // Initialize the Firebase SDK.
     FirebaseApp.configure()

     let siteId = YOUR_SITE_ID
     let cdpApiKey = YOUR_CDP_API_KEY

     // Configure and initialize the Customer.io SDK
     let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
         .migrationSiteId(siteId)
         .autoTrackUIKitScreenViews()
         .autoTrackDeviceAttributes(true)
  
     CustomerIO.initialize(withConfig: config.build())

     // Initialize messaging features after initializing Customer.io SDK        
     MessagingPushFCM.initialize(
         withConfig: MessagingPushConfigBuilder()
             // optionally, configure the push module by calling functions on the builder. Such as: 
             .autoFetchDeviceToken(true)
             // See section below to find all the configuration options you can set. 
             .build()
     )

     return true
 }
}

SwiftUI

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.

import SwiftUI
import CioMessagingPushFCM
import UserNotifications

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

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize the Customer.io SDK 
        let cdpApiKey = "YOUR_CDP_API_KEY"
        let siteId = "YOUR_SITE_ID"
        let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
            // If your account is in the EU region, uncomment the next line
            // .region(.EU)
            .migrationSiteId(siteId) // only required for migration
            .autoTrackUIKitScreenViews() // Set auto tracking of UIKit screen views
            .logLevel(CioLogLevel.debug) // Add this to troubleshoot issues - disable debug in production
        CustomerIO.initialize(withConfig: config.build())

        return true
    }
}
import SwiftUI
import CioMessagingPushFCM
import UserNotifications

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

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize the Customer.io SDK 
        let cdpApiKey = "YOUR_CDP_API_KEY"
        let siteId = "YOUR_SITE_ID"
        let config = SDKConfigBuilder(cdpApiKey: cdpApiKey)
            // If your account is in the EU region, uncomment the next line
            // .region(.EU)
            .migrationSiteId(siteId) // only required for migration
            .autoTrackUIKitScreenViews() // Set auto tracking of UIKit screen views
            .logLevel(CioLogLevel.debug) // Add this to troubleshoot issues - disable debug in production
        CustomerIO.initialize(withConfig: config.build())

        return true
    }
}

Important Notes

  1. 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
    • userNotificationCenter(_:willPresent:withCompletionHandler:)
    • userNotificationCenter(_:didReceive:withCompletionHandler:)
    • All other push-related delegate methods
  2. The @main attribute must be on the wrapper class, not your AppDelegate.

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()
Copied to clipboard!
  Contents
Version
Is this page helpful?