Introduction

This book describes how to work with AdPlayer Lite library.

Tags

AdPlayer Lite library works with publishers and tags. Publisher is a unique ID for the whole organization, while Tag is a placement configration on the screen. There can be any number of tags but only one publisher.

Tags can be created and configured by using the admin console.

Types of Tags

Tags can be split into to categories:

  • Outstream - displays only a series of Ads
  • Instream - displays video content interleaved with Ads

The SDK is available as an SPM package on:
https://github.com/Aniview/ad-player-lite-ios-spm

For more details please refer to:
Adding package dependencies to your app

See also:
Example App

To integrate the SDK into the project you might want to:

  • Initialize SDK
  • Request tracking authorization https://developer.apple.com/documentation/apptrackingtransparency
  • Request GDPR (if applicable)
  • Add the player to UI Layout
    Please refer to the Displaying guide for more details
  • Ensure the player shows Ads / Content

Initialize SDK

The SDK must be Initialized before it's used.

Please provide the actual AppStore URL.
It's needed for proper ad impression tracking and affects monetization.

import AdPlayerLite
import UIKit

final class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        let storeURL = URL(string: Constants.storeURL)!
        AdPlayer.initSDK(storeUrl: storeURL)
        return true
    }
}

Displaying Ads / Content

This chapter covers ways to display Ads / Content

Here is how to add the Player to the UIkit layout.

Adding AdPlacementView

import UIKit
import AdPlayerLite

class YourViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let controller = AdPlayer
            .getTag(pubId: "<your pubId>", tagId: "<your tagId>")
            .newInReadController()

        let placement = AdPlacementView()
        placement.attachController(controller)

        placement.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(placement)
        NSLayoutConstraint.activate([
            placement.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            placement.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            placement.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor)
        ])
    }
}

Note: The AdPlacementView's width must be defined.

Observing Player's Height Changes

This part is optional as long as AdPlacementView resizes automatically. However it might be useful in order to implement expanding/collapsing animation

import UIKit
import AdPlayerLite

// viewDidLoad
let placement = AdPlacementView()
...
placement.delegate = self
//

extension YourViewController: AdPlacementViewLayoutDelegate {
    func onResize(height: CGFloat) {
        guard lastReportedHeight != height else {
            return
        }
        lastReportedHeight = height
        UIView.animate(withDuration: 0.3) {
            self.view.layoutIfNeeded()
        }
    }
}

See also: Basic UI Kit Example

SwiftUI view is not included in the SDK for the sake of keeping it minimalistic.
However AdPlacementView can be easily wrapped in UIViewRepresentable

Please refer to:

Launching Interstitials

Unlike in-read mode, interstitials don't require any placement view - it's presented as a modal fullscreen UIViewController.
Interstitials will be automatically closed once the first video finishes.

Here is a basic example:

AdPlayer.showInterstitial(pubId: pubId, tagId: tagId) {
    // Interstitial has been dismissed
}

Also, you might want to customise Interstitial's behaviour:

let config = InterstitialConfiguration(
    stalledVideoTimeout: 2.0,
    showCloseButtonAfterAdDuration: true
)
AdPlayer.showInterstitial(pubId: pubId, tagId: tagId, configuration: config) { }

AdPlayerController

The AdPlayerController is a key component of the AdPlayerLite SDK, designed to manage and control video playback within the AdPlacementView. This guide provides an overview of its features and how to use it effectively.
The AdPlayerController is used to interact with the player, observe its state, and control playback.

There are also more specialized controllers available:

  • AdPlayerInReadController - for working with in-read content
  • AdPlayerInterstitialController - for displaying interstitials

Creating Controller

let controller = AdPlayer
    .getTag(pubId: "<your pubId>", tagId: "<your tagId>")
    .newInReadController()

Accessing the AdPlayerController

You can obtain an AdPlayerController instance from an AdPlacementView
(but it should be attached before. Otherwise it will be nil )

let placement = AdPlacementView()
placement.attachController(controller)
...
let controller = placement.controller

Features

Player State

  • Property: state

    • Type: AdPlayerLite.AdPlayerState
    • Description: Represents the current playing state of the player.
  • Publisher: statePublisher

    • Type: AnyPublisher<AdPlayerLite.AdPlayerState, Never>
    • Description: Allows observation of the playing state over time.

Player Events

  • Publisher: eventsPublisher
    • Type: AnyPublisher<AdPlayerLite.AdPlayerEvent, Never>
    • Description: Emits player events as they occur.

Current Playing Content

  • Property: content

    • Type: AdPlayerLite.AdPlayerContent?
    • Description: The currently playing content.
  • Publisher: contentPublisher

    • Type: AnyPublisher<AdPlayerLite.AdPlayerContent?, Never>
    • Description: Allows observation of the currently playing content.

Content Playlist

  • Property: playlist

    • Type: [AdPlayerLite.AdPlayerContent]
    • Description: The content playlist managed by the player.
  • Publisher: playlistPublisher

    • Type: AnyPublisher<[AdPlayerLite.AdPlayerContent], Never>
    • Description: Allows observation of the content playlist.

Controlling Playback

Basic Controls

  • Pause Playback: pause()

    • Pauses the player if it is currently playing.
  • Resume Playback: resume()

    • Resumes playback if the player is paused.
  • Skip Playback: skipAd()

    • Skips the currently playing ad, if any.
  • Mute Playback: mute()

    • Mutes playbackd.
  • Unmute Playback: unmute()

    • Un-mutes playback.

Fullscreen Mode

  • Toggle Fullscreen: toggleFullscreen()
    • Moves the player to or from fullscreen mode.

Content Navigation

  • Play Next Content: playNextContent()

    • Plays the next content in the playlist if available.
  • Play Previous Content: playPrevContent()

    • Plays the previous content in the playlist if available.
  • Play Content by Index: playContentByIndex(_ index: Int)

    • Plays the content at the specified index in the playlist.

Playback Information

Ads

  • Ready Ads Count: getReadyAdsCount() async -> Int
    • Returns the number of ads ready to be displayed but not yet shown (outstream only).

Playback Positions and Durations

  • Ad Position: getAdPosition() async -> TimeInterval

    • Retrieves the current position of the ad being played.
  • Ad Duration: getAdDuration() async -> TimeInterval

    • Retrieves the total duration of the ad being played.
  • Content Position: getContentPosition() async -> TimeInterval

    • Retrieves the current position of the playing content.
  • Content Duration: getContentDuration() async -> TimeInterval

    • Retrieves the total duration of the playing content.

Observing Player State and Events

You can use the provided publishers to observe changes in the player's state, events, content, and playlist. This is particularly useful for updating the UI dynamically.

Example:

import Combine

var cancellables: Set<AnyCancellable> = []

controller.statePublisher
    .sink { state in
        print("Player state: \(state)")
    }
    .store(in: &cancellables)

controller.eventsPublisher
    .sink { event in
        print("Player event: \(event)")
    }
    .store(in: &cancellables)

Best Practices

  • Ensure to manage memory by storing publishers in a Set<AnyCancellable>.
  • Use async methods like getAdPosition or getContentDuration to retrieve information when needed.
  • Leverage the statePublisher and eventsPublisher for real-time updates and debugging.

Conclusion

The AdPlayerController provides comprehensive control over the playback of ads and content within the AdPlayerLite SDK. By understanding its features and using the provided methods and publishers, you can build a seamless and interactive video ad experience.

Fullscreen

Normally, the player transitions to full-screen mode when the user taps the full-screen button in the player’s UI (when the button is enabled).
It’s also possible to present the player in full-screen mode programmatically.

Fullscreen toggle

The following shows how to toggle full-screen mode programmatically:

let controller: AdPlayerController
controller.toggleFullscreen()

Override default fullscreen configuration

let controller = AdPlayer
    .getTag(pubId: pubId, tagId: tagId)
    .newInReadController {
        $0.fullScreenConfiguration.ignoreSafeArea = true
        $0.fullScreenConfiguration.isCloseButtonEnabled = true
        $0.fullScreenConfiguration.insets = .zero
    }

Content and Playlist

Both content and playlists are only available for insteam tags.

Managing Playlist

Playlist contains list of content videos that are played one after the other. We can read current playlist like this:

let controller: AdPlayerController = ...

let playlist = controller.playlist.value // CAUTION: might not be loaded yet
print(playlist)

One important note here is that playlist is loaded by the library asynchronously and might not be available right after the controller is created. This might result in the above API returning empty playlist. It is advised, in most cases, for the application to track when playlist changes:

cancellable = controller.playlistPublisher.sink { [weak self] playlist in
  guard let self, playlist.count > 1 else { return }

  print(playlist)
}

Currently Played Content

AdPlayerController can be used to track which content is currently playing:

let controller: AdPlayerController = ...

// reading current content
print("\(controller.content) is currently playing")

cancellable = controller.contentPublisher.sink { [weak self] content in
    guard let self else { return }

    print("\(content) is currently playing")
}

Reading playback progress

let controller: AdPlayerController = ...

Task {
    let duration = await getDuration(isContent: isContent)
    let position = isContent ? await controller.getContentPosition() : await controller.getAdPosition()
    print("Current position \(position) / \(duration)")
}

Choosing Content to Play

In order to play different video from the playlist we can use these functions:

let controller: AdPlayerController = ...

// play next video
controller.playNextContent()

// play previous video
controller.playPrevContent()

// play specific video
controller.playContentByIndex(3)

See also:
Time Indicator Example

Instream: Overriding defaults

To change some predefined In-Stream settings:

let tag = AdPlayer.getTag(...)
let controller = tag.newInReadController {
    // override in-stream content by using CmsId
    $0.contentOverride = .cmsId("<custom video cms id>")

    // override in-stream content by using direct video url
    $0.contentOverride = .directUrls(["<custom video URL>"])

    // disable in-stream video ads
    $0.disableVideoAds = true
}

// Attach new controller to the placement view
let placement = AdPlacementView()
placement.attachController(controller)

Player Controls Visibility

Available since 1.3.0

Visibility of some buttons displayed by the player can be changed if required.

Changing Visibility

Each button can be hidden or shown:

let controller: AdPlayerController
controller.showPlayButton.value = false
controller.showSoundButton.value = false
controller.showFullscreenButton.value = false

Visibility Default Values

Visibility states are represented as a nullable Bool? type.
This allows seamless rollback to default value by passing a null value.

val controller: AdPlayerController
controller.showPlayButton.value = true        // visible
controller.showSoundButton.value = false      // invisible
controller.showFullscreenButton.value = nil  // default value

Example App is available here: Example App