Migration Guides
Migrating to Rover 4 from Rover Campaigns 3.x and Judo 1.x - iOS
Welcome to Rover 4.
The purpose of this guide is to aid you in adopting Rover 4 from your existing Rover (sometimes referred to as Rover Campaigns) 3.x and Judo 1.x setup. The Rover 4 SDK supersedes both the Rover Campaigns 3.x and Judo 1.x SDKs.
Initialization changes from Judo to Rover 4
The Rover SDK 4.0 is the successor to the Judo SDK. Judo experiences are now included as a core component of the Rover SDK. There is no longer a need to initialize a second SDK.
To remove the Judo SDK from the project, follow these steps:
- Select the project in the Project Navigator.
- Click on the "Package Dependencies" tab.
- Select the
Judo
package. - Click on the "-" button to remove it.
Removing the package from the project will also remove the frameworks from all the targets in the project.
Remove the initialization code:
import JudoSDK
import JudoModel
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let configuration = Configuration(accessToken: "<YOUR_JUDO_SDK_TOKEN>", domain: "<YOUR_JUDO_DOMAIN>")
Judo.initialize(configuration: configuration)
}
Universal and deep link handling
Universal and deep link handling of Judo links will now be entirely handled through the Rover SDK.
Remove the existing Judo link handling:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return Judo.sharedInstance.openURL(url, animated: true)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
return Judo.sharedInstance.continueUserActivity(userActivity, animated: true)
}
Replace it with routing from the Rover SDK, if it isn't already there:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return Rover.shared.router.handle(url)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
return Rover.shared.router.handle(userActivity)
}
Add the former Judo domain to Rover's Associated Domains list
When Rover is initialized, you gave it a list of associated domains. You should now add your Judo domain to this list.
Rover.initialize(
// ...
UIAssembler(
associatedDomains: ["myapp.rover.io", "myapp.judo.app"],
// ...
),
// ...
)
Be sure that your Judo domain is the second item in the associated domains list.
Now the new Rover 4 SDK can open both Judo and Rover experiences.
User Identification Changes
Instead of calling the identify method on the Judo singleton to enable personalization, this is now provided to the Rover SDK through the user info methods. If the Judo SDK was integrated along with Rover 3, the Judo call to identify()
can simply be removed. Otherwise, in Rover 4 the required values can be passed to the Rover UserInfoManager
The previous Judo method of calling Identify with a custom object conforming to Codable
:
// Pass user ID and custom properties to Judo for personalization
struct UserTraits: Codable {
let name: String
let pointsBalance: Int
let premiumTier: Bool
let tags: [String]
}
Judo.sharedInstance.identify(
// NB: don't use an email address here!
userID: "1234567",
traits: UserTraits(
name: "John Doe",
email: "john@example.com",
pointsBalance: 50_000,
premiumTier: true,
tags: ["foo", "bar", "baz"]
)
)
In Rover 4, the UserInfoManager
is used instead with the updateUserInfo
method:
// Set custom info about the current user
Rover.shared.resolve(UserInfoManager.self)?.updateUserInfo { attributes in
attributes["userID"] = "1234567"
attributes["name"] = "John Doe"
attributes["email"] = "john@example.com"
attributes["pointsBalance"] = 50_000
attributes["premiumTier"] = true
attributes["tags"] = ["foo", "bar", "baz"]
}
This information remains persisted across app restarts, it is recommended to call it every time your user data changes (such as logging in, logging out, profile updates, etc).
Authorizers
Authorizers are no longer setup when configuring the SDK. Now, they can be setup anytime after initialization of the Rover SDK. This is done from the Rover
shared object in a similar manner to the Judo SDK. The domain is required, as well as a block that accepts the url request to add headers to.
With the previous method of setting the authorizer when configuring the Judo SDK:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var configuration = Configuration(
accessToken: "<ACCESS-TOKEN>",
domain: "myapp.judo.app"
)
configuration.authorize("api.example.com", with: { urlRequest in
urlRequest.setValue("xxx", forHTTPHeaderField: "Example-Token")
})
Judo.initialize(configuration: configuration)
}
Using the new Rover
shared object:
Rover.shared.authorize(pattern: "api.example.com") { urlRequest in
urlRequest.setValue("xxx", forHTTPHeaderField: "Example-Token")
}
Embedding View Controllers
The ExperienceViewController
remains the focal point of Experiences. The manner in which it is instantiated differs from Judo to Rover 4. Previously, a url, cache setting, optional user info and optional authorizer were required to instantiate the ExperienceViewController
. In Rover 4, all that is required is the url of the Experience.
If your experience made use of UserInfo
, this is now provided to the Rover SDK with the UserInfoManager
.
An ExperienceViewController instantiated previously in Judo:
let experienceViewController = ExperienceViewController(
url: url,
ignoreCache: false,
userInfo: userInfo,
authorize: authorizer)
In Rover 4, it is simply:
let experienceViewController = ExperienceViewController.openExperience(with: url)
//user info is now handled by the Rover UserInfoManager
//authorizers are now set in the Rover singlton
The returned view controller can be used as before, embedded within another view controller or used with SwiftUI.
Analytics
The screen viewed notification no longer uses the NotificationCenter
, so observing the Judo.screenViewedNotification
no longer works. The SDK now uses a callback that provides a ScreenViewedEvent
.
Previously, the screen viewed event was observed as follows:
screenViewedObserver = NotificationCenter.default.addObserver(
forName: Judo.screenViewedNotification,
object: nil,
queue: OperationQueue.main,
using: { notification in
let screen = notification.userInfo!["screen"] as! Screen
let experience = notification.userInfo!["experience"] as! Experience
os_log("Judo experience screen viewed: %s", type: .default, screen.name)
// MyAnalyticsSDK.trackScreen(screen.name)
}
)
Now, the callback for screen viewed events is registered:
Rover.shared.registerScreenViewedCallback { event in
let screenName = "\(event.experienceName ?? "Experience") / \(event.screenName ?? "Screen")"
os_log("Rover experience screen viewed: %s", type: .default, screenName)
// MyAnalyticsSDK.trackScreen(screenName)
}
Custom Action Handlers
Custom action handlers have changed slightly from Judo to Rover 4. The custom action handler is now set using the Rover
shared object, instead of the shared Judo
object.
With the Judo
shared object:
Judo.sharedInstance.registerCustomActionCallback { actionEvent in
switch actionEvent.metadata?.properties["behavior"] {
case "openWebsite":
UIApplication.shared.open(URL(string: "https://rover.io/")!)
case "printLogMessage":
os_log(.default, "Hello from Rover!")
default:
os_log(.error, "🤷♂️")
}
}
Using the new Rover
shared object:
Rover.shared.registerCustomActionCallback { actionEvent in
switch actionEvent.nodeProperties["behavior"] {
case "openWebsite":
UIApplication.shared.open(URL(string: "https://rover.io/")!)
case "printLogMessage":
os_log(.default, "Hello from Rover!")
default:
os_log(.error, "🤷♂️")
}
}