This is a developers' guide for setting up a LiveLike SDK configuration for native iOS apps. We will take you through the basic technical steps for configuration and show you how to send your first widgets and chat messages. We will also provide detailed samples and instructions for a complete LiveLike integration.
Prerequisites
- An admin login and registered application on the Producer Suite (provided by LiveLike).
- Client ID - Used to initialize the SDK. See instructions for retrieving Your Client ID.
- OS: iOS 10+
Even though this guide makes use of both the chat and widget components, if desired it is possible to use only one of the components.
Installation
The SDK can be installed through package managers like Carthage or Cocoapods.
Carthage
Carthage distribution of the Engagement SDK is hosted on a private repository. You will need to provide LiveLike with your Bitbucket username and we will grant you access.
https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
Add the following to a Cartfile:
git "[email protected]:livelike/livelike-ios-sdk.git" ~> 1.0
and then run in the Terminal
carthage update --platform iOS
Follow the instructions in the βIf youβre building for iOSβ section of the Carthage README adding the following text to the xcfilelist
s mentioned therein:
$(SRCROOT)/Carthage/Build/iOS/EngagementSDK.framework
$(SRCROOT)/Carthage/Build/iOS/PubNub.framework
$(SRCROOT)/Carthage/Build/iOS/Lottie.framework
$(SRCROOT)/Carthage/Build/iOS/Mixpanel.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/EngagementSDK.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/PubNub.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Lottie.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Mixpanel.framework
CocoaPods
https://guides.cocoapods.org/using/using-cocoapods.html
Add the following to a Podfile:
target '<application-target-name>' do
use_frameworks!
pod 'EngagementSDK'
end
Initialization
For this step, you will need your Client ID to initialize the Engagement SDK. To get your ClientID, follow the instructions in Retrieving your Client ID.
Import the EngagementSDK:
import EngagementSDK
Next, create an instance of the EngagementSDK. We recommend that you create the EngagementSDK instance as early as possible for your application (for example, in the application:didFinishLaunchingWithOptions:
method of the AppDelegate
).
Concurrent instances of the EngagementSDK are not supported; only one instance should exist at any given time.
Use your Client ID to create a EngagementSDKConfig. The EngagementSDKConfig is used to initialize the EngagementSDK.
class AppDelegate: UIResponder, UIApplicationDelegate {
var engagementSDK: EngagementSDK!
func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var config = EngagementSDKConfig(clientID: "<your-client-id>")
engagementSDK = EngagementSDK(config: config)
return true
}
}
Considerations for Monthly Active User (MAU) Count
An Access Token is the unique identifier for a user and will be used to calculate the MAU of your application. We highly recommend that you override where a user's Access Token is stored to manage persistence across app installs and platforms.
By default, the EngagementSDK will fetch and store a user's Access Token in User Defaults. If an Access Token is not found we will create a new one which will count towards you MAU.
Override the Access Token storage
- Implement AccessTokenStorage protocol
- Set EngagementSDKConfig().accessTokenStorage to AccessTokenStorage implementation
class AppDelegate: UIResponder, UIApplicationDelegate {
var engagementSDK: EngagementSDK!
func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var config = EngagementSDKConfig(clientID: "<your-client-id>")
// Recommended to implement your own AccessTokenStorage for user persistence
// By default the user access token will be stored in UserDefaults if not set
config.accessTokenStorage = self
engagementSDK = EngagementSDK(config: config)
return true
}
}
extension AppDelegate: AccessTokenStorage {
func fetchAccessToken() -> String? {
// fetch an access token from your local storage or server
// if nil the EngagementSDK will generate a new access token
return "<users-access-token>"
}
func storeAccessToken(accessToken: String) {
// called when the EngagementSDK generates a new accessToken
// store the generated token in your local storage or server for user persistence
}
}
Configure Your Layout
Now you have to configure your live video screen layout and declare containers for the Engagement SDK Widget and Chat views to live inside.
Even though this guide makes use of both the chat and widget components, if desired it is possible to use only one of the components.
The first step is to add two UIViews to your view layout to serve as containers for the Engagement SDK's Widget and Chat view. Regardless of whether you use Storyboards or Programmatic UI, please follow the steps that work best for your application.
Storyboards - If you are using storyboards then you need to add two UIViews to your view hierarchy for Widget and Chat. Add any constraints for managing the size and position of the subviews. Then, create and hook up an @IBOutlet
in your ViewController for each view called widgetView
and chatView
.
If you are working in a multilayered UIView environment where the widgetView is placed above the chatView. It is best practice to instantiate the
widgetView
asPassthroughView
. This will allow user interactions on widgetView effect the chatView when there are no activate widgets.
Programmatic - If you are using programmatic UI, you need to instantiate two UIViews called widgetView
and chatView
. Add them as subviews to your ViewController's view. Add any constraints for managing the size and position of the subviews.
Then, in your ViewController, create an instance of WidgetViewController
and ChatViewController
Important: The width of the Widget view must be at least 260 and height 280. The width of the Chat view must be at least 292.
class ViewController: UIViewController {
@IBOutlet var widgetView: UIView!
@IBOutlet var chatView: UIView!
let widgetViewController = WidgetViewController()
let chatViewController = ChatViewController()
}
Finally, you need to add the WidgetViewController
and ChatViewController
as a child view controller to your ViewController. For more information on child view controllers see Apple documentation on Implementing a ContainerViewController.
In the viewDidLoad
method add the following:
override func viewDidLoad() {
super.viewDidLoad()
// Add widgetViewController as child view controller
addChild(widgetViewController)
widgetView.addSubview(widgetViewController.view)
widgetViewController.didMove(toParent: self)
// Apply constraints to fill the widgetView container
widgetViewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
widgetViewController.view.bottomAnchor.constraint(equalTo: widgetView.bottomAnchor),
widgetViewController.view.topAnchor.constraint(equalTo: widgetView.topAnchor),
widgetViewController.view.trailingAnchor.constraint(equalTo: widgetView.trailingAnchor),
widgetViewController.view.leadingAnchor.constraint(equalTo: widgetView.leadingAnchor)
])
// Add chatViewController as a child view controller
addChild(chatViewController)
chatView.addSubview(chatViewController.view)
chatViewController.didMove(toParent: self)
// Apply constraints to fill the chatView container
chatViewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
chatViewController.view.bottomAnchor.constraint(equalTo: chatView.bottomAnchor),
chatViewController.view.topAnchor.constraint(equalTo: chatView.topAnchor),
chatViewController.view.trailingAnchor.constraint(equalTo: chatView.trailingAnchor),
chatViewController.view.leadingAnchor.constraint(equalTo: chatView.leadingAnchor)
])
}
Start a Content Session
A Content Session represents a user's subscription to a particular ProgramProgram - A time-ordered sequence of widgets. A program can have extra information attached, like scheduling data and video preview URL for aiding in producing the program in the Producer Site. A widget can only be published to a single program, and only subscribers to a given program will see its widgets. (typically a live, linear TV show, game or episode). To start a Content Session you will need a Program ID. You will need to create programs within the LiveLike system, either through the API or through the Producer Suite (see Getting Started with the Producer Suite). You should then copy the Program IDs into the relevant media metadata in your own systems, so that content sessions can be started along with media playback.
Use the following resources to get started with the Producer Suite
In your ViewController, declare a variable to maintain an instance of the ContentSession
we will be creating.
Important: A reference to the
ContentSession
instance must be maintained in order for the session to remain valid and receive Widget and Chat events.
class ViewController: UIViewController {
@IBOutlet var widgetView: UIView!
@IBOutlet var chatView: UIView!
let widgetViewController = WidgetViewController()
let chatViewController = ChatViewController()
var session: ContentSession?
}
Now call the contentSession method of your instance of the EngagementSDK - passing in your Program ID. This will return a ContentSession
object. You must store this in the ContentSession
variable declared earlier.
Assign the ContentSession to the WidgetViewController so the user can begin receiving widgets published from the CMS.
Assign the ContentSession to the ChatViewController so the user will also be able to participate in the chat room.
func startContentSession(engagementSDK: EngagementSDK) {
let config = SessionConfiguration(programID: "<program-id>")
session = engagementSDK.contentSession(config: config)
widgetViewController.session = session
chatViewController.session = session
}
- (*void*)startContentSession: (LLEngagementSDK*)engagementSDK {
LLSessionConfiguration *config = [[LLSessionConfiguration alloc] initWithProgramID:@"<program-id>"];
id<LLContentSession> session = [engagementSDK contentSessionWithConfig:config];
self.session = session;
chatViewController.session = session;
widgetViewController.session = session;
}
Pause a Content Session
Content Sessions can be paused to temporarily ignore all incoming Widgets and Chat messages until resumed. This needs to be done whenever the app loses focus. It can also be useful in other scenarios, for example, if you need to display an advertisement without overlay from the Engagement SDK.
//Pause
session?.pause()
//Resume
session?.resume()
Important
Please call
ContentSession.pause()
when the user has backgrounded your application and then callContentSession.resume()
when the user has returned your application to foreground.This is to ensure that the application does not receive, and is not charged for, chat and widgets while it is not in view. For more information see Managing Your App's Life Cycle.
Close a Content Session
When the user returns to your application's home page and away from your live video screen you will want to close the ContentSession. Closing a session will disconnect from Widgets and Chat and release all the related resources.
You can also set the session reference to
nil
, this is the same as calling close
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.session?.close()
//or
self.session = nil
}
Sample Integration
The following is a summary of what the steps above look like when taken together:
import UIKit
import EngagementSDK
class ViewController: UIViewController {
@IBOutlet weak var widgetView: UIView!
@IBOutlet weak var chatView: UIView!
var engagementSDK: EngagementSDK!
//Creating the Widget and Chat ViewControllers
let widgetViewController = WidgetViewController()
let chatViewController = ChatViewController()
//Holding a reference to the session to keep it valid
var session: ContentSession?
override func viewDidLoad() {
super.viewDidLoad()
engagementSDK = EngagementSDK(clientID: "<client-id>")
// Adding widgetViewController as child view controller
addChild(widgetViewController)
widgetView.addSubview(widgetViewController.view)
widgetViewController.didMove(toParent: self)
// Applying constraints to fill the container
widgetViewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
widgetViewController.view.bottomAnchor.constraint(equalTo: widgetView.bottomAnchor),
widgetViewController.view.topAnchor.constraint(equalTo: widgetView.topAnchor),
widgetViewController.view.trailingAnchor.constraint(equalTo: widgetView.trailingAnchor),
widgetViewController.view.leadingAnchor.constraint(equalTo: widgetView.leadingAnchor)
])
// Adding chatViewController as a child view controller
addChild(chatViewController)
chatView.addSubview(chatViewController.view)
chatViewController.didMove(toParent: self)
// Applying constraints to fill the container
chatViewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
chatViewController.view.bottomAnchor.constraint(equalTo: chatView.bottomAnchor),
chatViewController.view.topAnchor.constraint(equalTo: chatView.topAnchor),
chatViewController.view.trailingAnchor.constraint(equalTo: chatView.trailingAnchor),
chatViewController.view.leadingAnchor.constraint(equalTo: chatView.leadingAnchor)
])
//Creating a Content Session
let config = SessionConfiguration(programID: "<program-id>")
session = engagementSDK.contentSession(config: config)
session.delegate = self
// Applying the Content Session to the Widget and Chat ViewControllers
widgetViewController.session = session
chatViewController.session = session
}
//Ending a session
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.session?.close()
}
}
Updated 3 months ago