Skip to content

Ease Live Bridge iOS SDK

This is a guide for customers/developers to get up and running with the Ease Live Bridge SDK for iOS.

Customers that have a native app and want to integrate it with Ease Live need a convenient way to do so. They may have their own player or a specific player they want to use. Players generally have a custom way of reading timecodes from their streams. With the Ease Live Bridge SDK the customer can do this the easiest and fastest way possible.

Requirements

  • iOS 13.0 or newer
  • tvOS 13.0 or newer
  • visionOS 1.0 or newer
  • Xcode 16.0 or newer
  • Swift 6.0 toolchain with Swift 5 or 6 language version

Architecture

Alt text

The main components in the SDK are:

  • EaseLive bridge SDK: responsible for
    • loading the EaseLive url into a proper View
    • create the communication layer between the Player and the EL web app
    • handle EL SDK lifecycle
  • Player: responsible for the playback and for reading the metadata that the stream includes.
  • PlayerPlugin: responsible for the communication between the EL SDK and the player.

SDK and example project

Download the SDK and example project

Get started

Swift Package Manager

  1. In the project navigator, select the project
  2. In the project editor, select the project
  3. In the Package Dependencies pane, Add Package Dependency
  4. Enter URL https://github.com/ease-live/ease-live-bridge-ios-spm.git
  5. Add EaseLiveSDK package

Cocoapod

  1. run pod repo add ease-live-bridge-ios-pod https://github.com/ease-live/ease-live-bridge-ios-pod
  2. modify your podfile with the following changed:
    • be sure of having use_frameworks! in the podfile
    • add the source source 'https://github.com/ease-live/ease-live-bridge-ios-pod.git'
    • add the statement pod 'EaseLiveSDK', it's also possible to specify the version adding , '~> 2.20.0' as a parameter
  3. run pod install
  4. open the .xcworkspace file

Manual install

  1. In the project navigator, select the project
  2. In the project editor, select the app target
  3. In the General pane, drag and drop EaseLiveSDK.xcframework into the Frameworks, Libraries, and Embedded Content list

The EaseLive instance

Every Ease Live Bridge application starts by creating a new EaseLive instance with one of the constructor functions. The initialization of the EaseLive bridge will start when the create() method is called on the EaseLive object.

Swift
import EaseLiveSDK

easeLive = EaseLive(parentView: easeLiveView, // view in which the Ease Live overlay will render
                     // project and environment to load
                     accountId: "tutorials",
                     projectId: "0346ae3e-7a91-4760-bcd3-cd84bb6790dd",
                     programId: "2d2711ff-6ff2-41c1-a141-060e9ffa2c38",
                     env: "prod",
                     // Optional Stream ID used for timecode settings. Defaults to "main"
                     streamId: "stream-1",
                     // optional query parameters added to the URL loaded from the environment
                     params: [
                        "customValue": 1 
                     ],
                     playerPlugin: playerPlugin)

The values in the code above will load in an SDK installation UI that will help to verify your implementation.

By default the available environments are: "prod", "staging" and "dev". Environments can be configured in project settings.

See PlayerPlugin for implementation of a plugin for a custom player.

Lifecycle diagram

Alt text

Create

The method EaseLive#create() should be called when the EL SDK need to be created and to initialise any object needed by the plugins.

Create should usually be called from viewDidLoad in your UIViewController.

Load

The method EaseLive#load() should be called on the EL SDK object when the app need to start executing its internal behaviour. For example a PlayerPlugin should call load to start loading the url where the video stream is located.

Load should usually be called from viewWillAppear in your UIViewController.

Pause

The method EaseLive#pause() should be called on the EL SDK object when the app goes in foreground, so when it's not visible but not in focus anymore.

Pause should usually be called from viewWillDisappear in your UIViewController.

Destroy

The method EaseLive#destroy() should be called when the app goes in background or the app is destroyed. This method takes care of calling the destroy method on each of the plugins, and this method takes care of removing the objects and listeners safely.

Destroy should usually be called from deinit in your UIViewController.

Change program

The method EaseLive#setProgram(projectId: String?, programId: String, env: String?, params: [String: Any]?) can be called when the app wants to change the loaded program in the current EaseLive instance. The typical case to use this is when the app loads a new video stream in the current video player or a different program starts in the current stream.

Change stream

If the video stream changes during a program, stream ID can be changed using EaseLive#setStreamId(_ streamId: String?) to apply timecode settings for the stream.

Error handling

Errors from the SDK are broadcast with the notification EaseLiveNotificationKeys.easeLiveError. The error object can be retreived from the EaseLiveNotificationKeys.errorUserInfoKey key of the notifications userInfo parameter. The error object contains information about the error level ( fatal or warning) and a string value with the verbose reason for the error.

When the SDK experiences a fatal error, the SDK should be removed from the app calling easeLive.destroy() that takes care of removing EaseLive correctly from memory.

Swift
NotificationCenter.default.addObserver(self, selector: #selector(onEaseLiveError(notification:)),
                                             name: EaseLiveNotificationKeys.easeLiveError, 
                                             object: nil)

@objc func onEaseLiveError(notification: Notification) {
    if let error = notification.userInfo?[EaseLiveNotificationKeys.errorUserInfoKey] as? EaseLiveError {
        if error.level == .fatal {
            self.easeLive?.destroy()
            self.easeLive = nil
        }
    }
}

Status handling

Listen for change in status of the loaded overlay, which can change during runtime.

If the status is "disabled" the EaseLive instance can be destroyed.

If the status is "hidden" or "disabled", when used on TV, the focus should be moved to player controls.

Swift
NotificationCenter.default.addObserver(self, selector: #selector(onEaseLiveAppStatus(notification:)),
                                             name: EaseLiveNotificationKeys.bridgeAppStatus, 
                                             object: nil)

@objc func onEaseLiveAppStatus(notification: Notification) {
    if let status = notification.userInfo?[EaseLiveNotificationKeys.statusUserInfoKey] as? String {
        if status == "disabled" {
            easeLive?.destroy()
            easeLive = nil
            easeLiveView?.isHidden = true
        } else if status == "hidden" {
            easeLiveView?.isHidden = true
        } else if status == "enabled" {
            easeLiveView?.isHidden = false
        }
        #if os(tvOS)
        // move focus out of EL if it was hidden, and focus your player controls
        setNeedsFocusUpdate()
        updateFocusIfNeeded()
        #endif
    }
});

Components

The SDK contains a few default components and plugins needed to have a fully working EaseLive instance. To allow the communication between those components, events are sent as notifications. Any additional plugins can communicate with the default components using those events.

Event dispatcher

See Events for a list of events that are emitted by the SDK and plugins.

EaseLive SDK

The EaseLive instance is responsible of calling lifecycle methods and to send the messages related to any error sent to the SDK so that the player and the app can update accordingly. Furthermore the SDK sends some messages from the UI overlay web app to the app so that the player knows when the web app want it to change state or other settings.

Player plugin

The player plugin handles the communication between the player and the EaseLive SDK. See PlayerPlugin for implementation details.

View plugin

The view plugin is used to display the overlay UI. The default implementation uses a webview to display the UI.

Bridge plugin

The bridge plugin is used to send events between the plugins and the overlay UI.

Custom plugins

Plugins can add additional functionality to the EaseLive instance. There is no strictly defined scope for a plugin, however it is usually used for adding extra functionality to the bridge by adding listeners to the lifecycle events. This is achieved by creating a class implementing the ComponentInterface and registering it using easeLive.use(plugin: ComponentInterface) before calling easeLive.create().

Widget plugin

Can be used to embed native UI inside the overlay. See Widget for implementation details.

Custom bridge messages

Custom messages can be used to send data from the app to the Ease Live overlay, and to receive data from the overlay. This can be used for custom functionality in the overlay.

Sending a message to the overlay

Swift
let jsonObject = [
    "event": "myPrefix.myEvent",
    "metadata": [
        "myCustomValue": "some data"
    ]
] as [String: Any]
let jsonData = try JSONSerialization.data(withJSONObject: jsonObject)
guard let jsonString = String(data: jsonData, encoding: .utf8) else { return }

NotificationCenter.default.post(name: EaseLiveNotificationKeys.appMessage, object: nil, userInfo: [
    EaseLiveNotificationKeys.jsonStringUserInfoKey: jsonString
])

To receive this message in the overlay configure a "Bridge message is received" trigger on the Bridge data source in the Studio project.

Receiving a message from the overlay

A message can be sent from the overlay by configuring a "Send bridge message" trigger in the Studio project.

Such messages can be received in the app by listening for it:

Swift
override func viewDidLoad() {
    super.viewDidLoad()
    
    NotificationCenter.default.addObserver(self, selector: #selector(onBridgeMessage(notification:)), name: EaseLiveNotificationKeys.bridgeMessage, object: nil)
    
    ...
}

@objc func onBridgeMessage(notification: Notification) {
    guard let jsonString = notification.userInfo?[EaseLiveNotificationKeys.jsonStringUserInfoKey] as? String else { return }
    guard jsonString.contains("myPrefix.") else { return }
    do {
        guard let json = try JSONSerialization.jsonObject(with: Data(jsonString.utf8)) as? [String: Any] else { return }
        if let event = json["event"] as? String {
            if event == "myPrefix.myEvent" {
                if let metadata = json["metadata"] as? [String: Any] {
                    if let myCustomValue = metadata["myCustomValue"] as? String {
                        print("myCustomValue", myCustomValue)
                    }
                }
            }
        }
    } catch {
    }
}

iOS

Follow instructions on WebView API for Ads to add Google Mobile Ads SDK to your app.

Instead of the steps for adding and registering a new WebView, register the WebView that is created by EaseLive:

Swift
override func viewDidLoad() {
    super.viewDidLoad()
    
    // listen for EaseLive creating a webview
    NotificationCenter.default.addObserver(self,
        selector: #selector(onEaseLiveViewCreated(notification:)),
        name: EaseLiveNotificationKeys.viewCreated,
        object: nil)

    // rest of the EaseLive setup
}

// EaseLive has created a webview. Register it with the Google ads instance
@objc func onEaseLiveViewCreated(notification: Notification) {
    if let webView = easeLive?.viewPlugin?.view() as? WKWebView {
        GADMobileAds.sharedInstance().register(webView)
    }
}

tvOS

On tvOS the ad is loaded using tagless request, so not all Ad Manager features can be used. Contact us for more info on ad setup.

Advertising identifier

If your ad requires resettable device identifier for tracking, the app can pass the advertising identifier as a String in params with key advertisingIdentifier to the EaseLive constructor, and it will be included as rdid query parameter in the tagless request.

Swift
// request user's permission for tracking
if ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
    await ATTrackingManager.requestTrackingAuthorization()
}

// pass advertisingIdentifier in EaseLive params
let adId = ASIdentifierManager.shared().advertisingIdentifier.uuidString
self.easeLive = EaseLive(parentView:accountId:projectId:programId:
    params: ["advertisingIdentifier": adId],
    playerPlugin: ...
)

Custom ad targeting parameters

Pass dictionary of parameters in customAdTargeting to the constructor:

Swift
self.easeLive = EaseLive(parentView:accountId:projectId:programId:params:
    customAdTargeting: [
        "account.propName": "some-id"
    ],
    playerPlugin: ...
)

To change parameters during runtime call:

Swift
self.easeLive.setCustomAdTargeting([
  "account.propName": "new-id",
  "account.newProp": "123"
])

TvOS

For use on Apple TV the EaseLive instance makes available the property preferredFocusEnvironments. This can be used in the view controller to move focus to the overlay.

Example for showing and moving focus to the EaseLive overlay when the player controls are hidden:

Swift
class ViewController: UIViewController {
    var playerView: PlayerView?
    var easeLive: EaseLive?
    
    // when player controls are hidden the EaseLive overlay takes focus
    override var preferredFocusEnvironments: [UIFocusEnvironment] {
        if !playerView.areControlsShown {
            return easeLive.preferredFocusEnvironments
        }
        
        return super.preferredFocusEnvironments
    }
    
    // listen for changes in the player controls visibility
    func onControlsHide(_ event: ControlsHideEvent, view: PlayerView) {
        // show the EL overlay when player controls are hidden
        easeLiveView?.isHidden = false
        easeLivePlayerPlugin?.onControllerVisibilityChanged(visible: false)
        
        // focus update will use preferredFocusEnvironments to focus EaseLive
        setNeedsFocusUpdate()
    }
    
    func onControlsShow(_ event: ControlsShowEvent, view: PlayerView) {
        // hide the EL overlay when player controls are visible
        easeLiveView?.isHidden = true
        easeLivePlayerPlugin?.onControllerVisibilityChanged(visible: true)
        
        // focus update will use preferredFocusEnvironments to focus player controls
        setNeedsFocusUpdate()
    }
}