Skip to main content

Migration Guide

This guide takes an existing integration to the current iOS SDK version, 1.3.0. Start at the section for the version your app uses now and follow the sections below it in order. Full list of changes: Changelog.

Your versionStart at
0.7.x0.7.x to 1.0.0
1.0.01.0.0 to 1.1.x
1.1.0, 1.1.11.1.x to 1.2.0
1.2.01.2.x to 1.3.0

To update, change the version to 1.3.0 in Xcode (Package Dependencies, Exact Version) or in your Podfile (:tag => '1.3.0'), then run pod update UserSDK for CocoaPods.


0.7.x to 1.0.0​

Version 1.0.0 removes Firebase and Gifu from the SDK. Your app owns Firebase and passes the FCM token to the SDK. This is a breaking change.

1. Dependencies​

  • Swift Package Manager: remove firebase-ios-sdk and Gifu if you added them only for the SDK. Keep Firebase Messaging if your app uses it, which it needs for push notifications.
  • CocoaPods: the pod no longer pulls in Firebase. Add it to your own Podfile:
pod 'UserSDK', :git => 'https://github.com/UserEngage/iOS-SDK.git', :tag => '1.3.0'
pod 'FirebaseMessaging'
  • Import: use import UserComSDK.

2. FCM token​

The SDK no longer configures Firebase or fetches the token. Configure Firebase in your app and pass every token to the SDK:

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
guard let fcmToken else { return }
UserSDK.default?.setFcmToken(fcmToken)
}

Details and alternatives: Firebase and FCM Token.

3. Notification handling​

The SDK no longer calls FirebaseApp.configure() and is no longer the delegate of Firebase Messaging. Your app configures Firebase and sets its own MessagingDelegate, as shown in step 2. Notification permission and the notification center delegate work as before: the SDK handles them only when you call registerForRemoteNotifications(options:notificationDelegate:).

  • If your app has its own notification code, keep your delegate and forward notifications to the SDK: from 1.3.0, taps to handleNotificationClick(_:) and received notifications to handleNotification(_:). See Push Notifications, Option A.
  • If not, call registerForRemoteNotifications(options:notificationDelegate:), which requests permission and sets the SDK as the delegate.

In both cases, forward application(_:didReceiveRemoteNotification:fetchCompletionHandler:) to the SDK, otherwise in-app messages are not shown.

4. Logout​

logout takes the token to remove from the contact who is leaving:

0.7.x1.0.0 and later
logout { success, error in }logout(fcmToken: token) { success, error in }

Pass nil to skip the removal. Up to 1.2.x the anonymous ping after logout carried no token. From 1.3.0 it carries the same token, see 1.2.x to 1.3.0.

API summary​

0.7.x1.0.0 and later
UserSDK(application:apiKey:baseURL:shouldTrackActivities:)Same, plus an optional fcmToken:
Token fetched by the SDKsetFcmToken(_:), ping(fcmToken:_:), fcmToken: in the initializer
logout(_:)logout(fcmToken:_:)
Objective-C pingWithCompletion:pingWithFcmToken:completion:, or ping without a completion
Objective-C logoutWithCompletion:logoutWithFcmToken:completion:
Firebase and Gifu bundledNo external dependencies

Everything else keeps its name and signature.


1.0.0 to 1.1.x​

No API changes. One behavior change to check.

Changed in 1.1.0

sendEvent, trackScreen, sendProductEvent, setUserData and setCustomUserData call completion(false, error) when the backend rejects a request with a 4xx status, for example 400 or 401. Before 1.1.0 they called completion(true, nil) regardless of the response. Server errors (5xx) and network errors are retried before the completion reports a failure.

What to do:

  1. Find code that treats true as proof of delivery, for example code that removes data from your own retry storage.
  2. Make sure a false result does not trigger an endless retry loop in your app. The SDK already retries what can be retried.

Other changes in 1.1.x that need no action:

  • Failed requests retry with a growing backoff and no longer block other queued events.
  • In-app messages are presented through the active foreground scene, which fixes apps with multiple scenes.
  • In-app button clicks are always reported, also for links handled by your inAppNotificationClickDelegate. In 1.1.1, clicks are counted in the panel again.
  • shouldTrackActivities is deprecated. It never enabled automatic screen tracking.

1.1.x to 1.2.0​

No breaking API changes. Two behavior changes to check.

Changed in 1.2.0: product event params

sendProductEvent sends each param as a separate product attribute. Before 1.2.0, params were nested under custom_data and stored as one JSON attribute.

What to do:

  1. Rebuild segments and automations that use the custom_data attribute on the individual attributes.
  2. Use a fixed set of param keys with stable value types, because every new key creates a new product attribute.
Changed in 1.2.0: logout event

logout records a logout event for the contact who is leaving.

What to do: if your app sends its own logout event, remove it to avoid counting logouts twice.

Also worth knowing:

  • setFcmToken(_:) sends a ping on every call, also with an unchanged token.
  • In-app messages are shown in their own window, and a message received in the background is shown on the next app open, within 6 hours.
  • In-app "displayed" is reported only when the message is on screen. Displayed numbers in the panel can drop after the upgrade and become accurate.
  • setUserData and setCustomUserData accept an optional fcmToken. Use it at login to send identity and token in one request.
  • handleNotification(userInfo:) is safe to call from any thread, a Task or an actor.

1.2.x to 1.3.0​

Existing code compiles. Renamed methods keep working and show a deprecation warning that names the new one. They stay until 2.0. The behavior changes below are worth checking.

Renamed API​

1.2.x (deprecated)1.3.0
sendEvent(with:params:_:)sendEvent(name:attributes:_:)
trackScreen(with:_:)trackScreen(name:_:)
sendProductEvent(_:eventType:name:productURL:params:_:)sendProductEvent(_:eventType:attributes:_:), with name and product_url in attributes
EventTypeProductEventType
setUserData(_:fcmToken:_:), setCustomUserData(_:fcmToken:_:)updateContact(_:fcmToken:_:) with a Contact
userIduserKey
inAppNotificationClickDelegateinAppMessageClickHandler
handleNotification(userInfo:)handleNotification(_:) for received notifications, handleNotificationClick(_:) for taps

New in 1.3.0:

  • handleEmailLink counts clicks on links from Positive User emails that open your app, and returns the target of the link.
  • UserSDK.errorHandler receives every SDK error in one place, for example to log it.
Changed in 1.3.0: received and tapped notifications are separate

Before 1.3.0 every handleNotification(userInfo:) call counted a click, also for a notification that was only received. From 1.3.0 handleNotification(_:) handles a received notification (in-app messages) and never counts a click. handleNotificationClick(_:) counts the click.

What to do:

  1. In userNotificationCenter(_:didReceive:withCompletionHandler:), call handleNotificationClick(_:).
  2. In application(_:didReceiveRemoteNotification:fetchCompletionHandler:), call handleNotification(_:).
  3. Until you switch, the old method counts clicks as before.

If the SDK is your notification center delegate (you call registerForRemoteNotifications(options:notificationDelegate:)), notifications received in the foreground are now shown as banners. Before, they only played their sound.

Changed in 1.3.0: the SDK keeps no contact data

Before 1.3.0 setUserData and setCustomUserData stored the data and every later ping sent it again. From 1.3.0 updateContact sends the data once and the backend adds it to the contact. Later pings do not repeat it. The first updateContact call also clears what the old methods stored.

What to do: replace setUserData and setCustomUserData with updateContact, at login with the FCM token. The phone number is sent as phone_number instead of phone, and the backend accepts both. A nil value never removed a field on the backend, and it still does not.

Changed in 1.3.0: logout keeps the device reachable

Before 1.3.0 the anonymous contact created after logout had no push token, so the device received no push notifications until the next login or setFcmToken(_:). From 1.3.0 the anonymous contact gets the same token. A push notification sent to the logged out contact does not reach the device.

What to do: remove a setFcmToken(_:) call after logout if you added it only for this. Turning push notifications off after logout is up to your app.

Events collected offline before logout are still sent, for the user who logged out. Contact updates of that user still waiting in the queue are dropped and end with loggedOut.

Changed in 1.3.0: errors and completions
  • Every failure is a UserSDKError. In Objective-C it is an NSError with the domain com.user.sdk.
  • Completions always run on the main thread, and never before the call returns.
  • Values JSON cannot hold (Date, URL, NaN) in attributes end with invalidData. Before 1.3.0 they crashed the app.
  • An empty, too long or HTML event name, a screen name over 128 characters and an empty product ID end with invalidName without a request.
  • A ping answered with {"success": false} (the app does not collect data) ends with notCollectingData. Before, it reported success.
  • 429 (rate limit) is retried after the time the server asks for. Before, the request was dropped.

What to do: if your completions switch to the main queue, they keep working. Check code that expects a specific error type or message. See Errors.

Pings while the phone is locked​

Before 1.3.0, when the app was woken in the background on a locked phone (a silent push, a token refresh), the SDK could not read the contact key. A ping sent then created a new anonymous contact and moved the push token to it, so push notifications to the real contact stopped reaching the device until the next ping. From 1.3.0 the contact key stays readable after the first unlock since the phone started. Right after a restart, before the first unlock, a ping waits until the phone is unlocked. Nothing to do in your app. See Duplicate anonymous contacts from one iOS device.

Device data​

The SDK no longer sends the app version, Wi-Fi, radio and carrier data or the advertising identifier: Positive User never stored them. The SDK no longer links AdSupport and CoreTelephony and no longer reads the advertising identifier.

Check

After updating, run the steps in Test your integration.