LiveLike

The LiveLike Developer Hub

Welcome to the LiveLike developer hub. You'll find comprehensive guides and documentation to help you start working with LiveLike as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    

Getting Started

Get a basic integration up and running with the iOS SDK

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

πŸ“˜

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 xcfilelists 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.

If your billing is determined by Monthly Active Users (MAUs), then at this point it is important to consider how and when the EngagementSDK will be initialized.

By default, the EngagementSDK will generate a new User Profile upon first initialization. The Access Token of the User Profile will be stored in User Defaults and may not persist across app installations, devices, and/or platforms. We recommend that you override this default behavior and manage where the User's Access Token is stored. Find out how here.

We also recommend that you initialize the SDK as late as possible in your application - just before the user accesses the EngagementSDK features.

🚧

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
  }
}

Configure Your Layout

πŸ“˜

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.

Storyboards / XIB

If you are using the user interface to build your UI, 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.

class ViewController: UIViewController {
  @IBOutlet var widgetView: UIView!
  @IBOutlet var chatView: UIView!

  let widgetViewController = WidgetPopupViewController()
  let chatViewController = ChatViewController()
  
  override func viewDidLoad() {
      super.viewDidLoad()

      // Add `chatViewController` as child view controller
      addChild(chatViewController)
      chatViewController.didMove(toParent: self)

      // Apply constraints to the `chatViewController.view`
      chatViewController.view.translatesAutoresizingMaskIntoConstraints = false
      chatView.addSubview(chatViewController.view)
      NSLayoutConstraint.activate([
          chatViewController.view.topAnchor.constraint(equalTo: chatView.topAnchor),
          chatViewController.view.trailingAnchor.constraint(equalTo: chatView.trailingAnchor),
          chatViewController.view.leadingAnchor.constraint(equalTo: chatView.leadingAnchor),
          chatViewController.view.bottomAnchor.constraint(equalTo: chatView.bottomAnchor)
      ])

      // Add `widgetViewController` as child view controller
      addChild(widgetViewController)
      widgetViewController.didMove(toParent: self)

      // Apply constraints to the `widgetViewController.view`
      widgetViewController.view.translatesAutoresizingMaskIntoConstraints = false
      widgetView.addSubview(widgetViewController.view)
      NSLayoutConstraint.activate([
          widgetViewController.view.topAnchor.constraint(equalTo: widgetView.topAnchor),
          widgetViewController.view.trailingAnchor.constraint(equalTo: widgetView.trailingAnchor),
          widgetViewController.view.leadingAnchor.constraint(equalTo: widgetView.leadingAnchor),
          widgetViewController.view.bottomAnchor.constraint(equalTo: widgetView.bottomAnchor)
      ])
  }
}

🚧

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 as PassthroughView. This will allow user interactions on widgetView effect the chatView when there are no activate widgets.

Programmatic

In your ViewController, create an instance of WidgetPopupViewController 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.

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 constraints:

override func viewDidLoad() {
    super.viewDidLoad()

    // Add `chatViewController` as child view controller
    addChild(chatViewController)
    chatViewController.didMove(toParent: self)

    // Apply constraints to the `chatViewController.view`
    chatViewController.view.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(chatViewController.view)
    NSLayoutConstraint.activate([
        chatViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
        chatViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        chatViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        chatViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    ])

    // Add `widgetViewController` as child view controller
    addChild(widgetViewController)
    widgetViewController.didMove(toParent: self)

    // Apply constraints to the `widgetViewController.view`
    widgetViewController.view.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(widgetViewController.view)
    NSLayoutConstraint.activate([
        widgetViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
        widgetViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        widgetViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        widgetViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    ])
}

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 = WidgetPopupViewController()
    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 WidgetPopupViewController 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;
}

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 = WidgetPopupViewController()
    let chatViewController = ChatViewController()

    //Holding a reference to the session to keep it valid
    var session: ContentSession?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        var sdkConfig = EngagementSDKConfig(clientID: "<your-client-id>")
        engagementSDK = EngagementSDK(config: sdkConfig)
        
        // 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 17 days ago

Getting Started


Get a basic integration up and running with the iOS SDK

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.