Migration Guides
Migrating to Rover 4 from Rover Campaigns 3.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 setup. The Rover 4 SDK supersedes that one and this guide will walk you through the necessary changes.
Update SDK Installation
This version of the Rover SDK no longer supports Cocoapods or Carthage. Installation of the SDK must now be performed via the Swift Package Manager.
To add the Rover SDK to your Xcode project using Swift Package Manager, follow these steps:
- Open your Xcode project.
- Click on "File" > "Add Packages".
- In the "Search or Enter Package URL" text box, enter the following URL: https://github.com/roverplatform/rover-ios.git
- Set the Dependency Rule as ‘Up to Next Major Version’ with 4.0.0.
- Add to project with the correct target set.
- Click "Add Package".
The Rover SDK should now be added to your Xcode project and can be imported into your Swift code using import RoverFoundation
as well as imports for any other modules used.
Top Level API Changes
In the new version of Rover SDK, the RoverFoundation
object has been renamed to Rover
and the shared object is no longer optional. This should remove the need for many optional checks and guards.
As an example a call to set the device token:
RoverFoundation.shared?.tokenManager.setToken(deviceToken)
No longer is optional, and now refers to the Rover
shared object:
Rover.shared.tokenManager.setToken(deviceToken)
Calling the Rover shared object before initializing the Rover SDK will cause a fatal error. Make sure the SDK is initialized before calling the shared object.
Events - Event Name Changes
Event names have changed from Rover 3.x to Rover 4, prefixing the word classic in the event names. These events may continue to be observed from the default iOS NotificationCenter
.
Observing the pollAnsweredNotification
in Rover 3.x:
NotificationCenter.default.addObserver(
forName: ScreenViewController.pollAnsweredNotification,
object: nil,
queue: nil,
using: { notification in
//integrate the event with your analytics here
}
)
Observing the same event in Rover 4:
NotificationCenter.default.addObserver(
forName: ClassicScreenViewController.classicPollAnsweredNotification,
object: nil,
queue: nil,
using: { notification in
//integrate the event with your analytics here
}
)
Events - Screen Handler Replacement
Screen Viewed Events are now handled with the shared Rover
object. So the previous method of getting the screen viewed event:
NotificationCenter.default.addObserver(forName: ScreenViewController.screenPresentedNotification, object: nil, queue: nil) { notification in
let screen = notification.userInfo?[ScreenViewController.screenUserInfoKey] as! Screen
os_log("Rover experience screen viewed: %s", type: .default, screen.name)
// MyAnalyticsSDK.trackScreen(screen.name)
}
becomes:
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)
}
Other events will continue to use the previous method of adding observers to the NotificationCenter
Events - Custom Actions
The Rover SDK can now handle custom actions as defined in the provided Rover file. A recommended pattern for having multiple behaviors for different custom actions in experiences is to use a metadata property called behavior
on your experience layer with the action, and then handle it within the callback.
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, "🤷♂️")
}
}
Notification Center renamed to Inbox
In Rover 4, the notification center has been renamed to inbox.
The inbox is still a View Controller, so it is still resolved from the Rover
shared object. The name has simply been changed from notificationCenter
to inbox
.
The previous notification center was resolved from the Rover
shared object with the name notificationCenter
:
// An IBAction connected to a UIButton through Interface Builder inside a UIViewController
@IBAction func presentNotificationCenter(_ sender: Any) {
guard let notificationCenter = Rover.shared?.resolve(UIViewController.self, name: "notificationCenter") else {
return
}
present(notificationCenter, animated: true, completion: nil)
}
The name of the View Controller that is resolved has changed to inbox
:
// An IBAction connected to a UIButton through Interface Builder inside a UIViewController
@IBAction func presentInbox(_ sender: Any) {
// Resolve the Inbox view controller
guard let inbox = Rover.shared.resolve(UIViewController.self, name: "inbox") else {
return
}
present(inbox, animated: true, completion: nil)
}
When customizing the appearance of the inbox, much of the code remains the same as the previous version of Rover, with the name of the NotificationCenterViewController
and NotificationCell
being changed to InboxViewController
and InboxCell
respectively. The cell reuse identifier has also changed from notification
to inboxCell
.
From this overview of how to customize the cells of the Rover 3.x notification center:
// 1. Create custom notification center cell
public class MyNotificationCell : NotificationCell {
// ... override methods as you deem fit here.
}
// 2. Register the custom cell for reuse within the custom notification center view controller
public class MyNotificationCenterViewController : NotificationCenterViewController {
override public func registerReusableViews() {
// Rover by default has a UITableViewCell called NotificationCell. You can replace it here with your own implementation:
tableView.register(MyNotificationCell.self, forCellReuseIdentifier: "notification")
}
}
// 3. Create a custom assembler
public struct CustomNotificationCenterAssembler : Assembler {
public func assemble(container: Container) {
container.register(UIViewController.self, name: "notificationCenter") { resolver in
let presentWebsiteActionProvider: MyNotificationCenterViewController.ActionProvider = { [weak resolver] url in
resolver?.resolve(Action.self, name: "presentWebsite", arguments: url)
}
return MyNotificationCenterViewController(
dispatcher: resolver.resolve(Dispatcher.self)!,
eventQueue: resolver.resolve(EventQueue.self)!,
imageStore: resolver.resolve(ImageStore.self)!,
notificationStore: resolver.resolve(NotificationStore.self)!,
router: resolver.resolve(Router.self)!,
sessionController: resolver.resolve(SessionController.self)!,
syncCoordinator: resolver.resolve(SyncCoordinator.self)!,
presentWebsiteActionProvider: presentWebsiteActionProvider
)
}
}
}
// 4. When initializing the Rover SDK, add the custom assembler here.
Rover.initialize(assemblers: [
// ... (the other assemblers go here, as usual).
CustomNotificationCenterAssembler() // make sure you put this last in the list!
])
// 5. To use the custom notification center, resolve it as before
let customNotificationCenter = Rover.shared!.resolve(UIViewController.self, name: "notificationCenter")!
With the changes for Rover 4:
// 1. Create custom inbox cell
public class MyInboxCell : InboxCell {
// ... override methods as you deem fit here.
}
// 2. Register the custom cell for reuse within the custom inbox view controller
public class MyCustomInboxViewController : InboxViewController {
override public func registerReusableViews() {
// Rover by default has a UITableViewCell called NotificationCell. You can replace it here with your own implementation:
tableView.register(MyInboxCell.self, forCellReuseIdentifier: "inboxCell")
}
}
// 3. Create a custom assembler
public struct CustomInboxAssembler : Assembler {
public func assemble(container: Container) {
container.register(UIViewController.self, name: "inbox") { resolver in
let presentWebsiteActionProvider: MyCustomInboxViewController.ActionProvider = { [weak resolver] url in
resolver?.resolve(Action.self, name: "presentWebsite", arguments: url)
}
return MyCustomInboxViewController(
dispatcher: resolver.resolve(Dispatcher.self)!,
eventQueue: resolver.resolve(EventQueue.self)!,
imageStore: resolver.resolve(ImageStore.self)!,
notificationStore: resolver.resolve(NotificationStore.self)!,
router: resolver.resolve(Router.self)!,
sessionController: resolver.resolve(SessionController.self)!,
syncCoordinator: resolver.resolve(SyncCoordinator.self)!,
presentWebsiteActionProvider: presentWebsiteActionProvider
)
}
}
}
// 4. When initializing the Rover SDK, add the custom assembler here.
Rover.initialize(assemblers: [
// ... (the other assemblers go here, as usual).
CustomInboxAssembler() // make sure you put this last in the list!
])
// 5. To use the custom notification center, resolve it as before
let customInbox = Rover.shared.resolve(UIViewController.self, name: "inbox")!