SDK for iOS

v. 1.6.0
Primis IOS SDK latest version is 1.6.0, Download from here

Apps built with the Primis Player SDK for iOS will obtain a fully working Primis player with most of its web functionalities.

Key Supported Features:

  • Skins
  • Layouts
  • Playlists
  • Monetization
  • Floating mode
  • Viewability detection

Requirements

  • Xcode 12 or higher
  • Objective-c or Swift
  • Your app should have a deployment target of iOS 10.0 at minimum
  • Primis Placement ID - Reach out to your Pub. Success Manager at Primis to get this information
  • Primis SDK Latest version is 1.6.0
  • Google iOS IMA SDK version 3.14.1. Download and extract from here

Basic Terms

A few terms to be familiar with before we start

  • Primis Player - a web-based Primis player running inside a WKWebView
  • Primis SDK - an XCFramework providing essential native functionality
  • Floating / Docking units - When started, the player docks in its initial position. The player will switch to a floating position when its docking unit is no longer visible.

Adding the frameworks

PrimisPlayer SDK

Swift Packages

  1. In the Xcode menu go to File -> Add Packages
  2. Paste the following URL into the search field - https://github.com/PrimisTech/PrimisPlayer-ios.git
  3. Press on the Add Package button to continue

CocoaPods

  1. Add the following dependency to your podspec:
    pod 'PrimisPlayer', '~> 1.6.0'
  2. Run pod install in the terminal

File

  1. Download Primis SDK from here
  2. Add the PrimisPlayer framework to your Xcode project.

Google IMA SDK

  1. Primis monetization services require Google IMA SDK.
    Add the Google IMA SDK framework to your Xcode project:
    a. In the left pane, click the project name.

b. In the center pane, click Build Phases.

c. Expand the Link Binary With Libraries section.
d. At the bottom of the libraries list, click the plus icon [+].
e. Click Add Other.
f. In the directory where you extracted the downloaded SDK, select GoogleInteractiveMediaAds.framework and click Open.
g. At the bottom of the libraries list, click the plus icon [+] again.
h. In the Status column, verify that GoogleInteractiveMediaAds.framework is set to Required.
i. Include the -ObjC linker flag in your build settings. For more information, see Apple QA1490.
j. In order to validate that the IMA SDK is integrated properly into your project, please follow the steps below:

  • Add the IMA framework using an import statement beneath the existing imports: Swift or Objective-C
import GoogleInteractiveMediaAds
#import <GoogleInteractiveMediaAds/GoogleInteractiveMediaAds.h>
  • Rebuild your project.
  • Remove this line after a successful build.

For further instruction and examples please refer to google documentation here.


Implementation type

According to your implementation type, please continue to one of the sections below:



ScrollView Implementation

Adding the Primis Player to a UIScrollView.

Player Container View

Using Auto-Layout

In the instructions below we'll use a storyboard example.

  1. Add a container view (of type UIView) that will contain the Primis player.
  2. Set Auto-Layout frame constraints (top, bottom, leading, trailing) in relation to your adjacent views.
  3. Add a height constraint. You can also set height = 0 to this constraint.
    The height constraint will be updated later by the player to fit the displayed content.
  4. Create an outlet for the container view in your view controller.
Not using Auto-Layout

In this type of implementation, the player will not resize its container view automatically.

The parent view controller will be responsible for resizing and laying out all elements on the screen including the player container view, according to the delegate call triggered by the Primis player.

The Primis player calls its delegate method 'playerWillDisplay' when the player is ready to be displayed, in order for you to update view locations and sizes.

🚧

Note

If the container view has a height constraint, the SDK will assume that auto-layout is being used, and the delegate method will not be called.

📘

Note

If you are using a storyboard, make sure that Auto Layout is enabled. The player uses auto-layout in its internal functionality

  1. Add a container view (of type UIView) that will contain the Primis player.
  2. Set for this container view the following:
YOUR_PLAYER_CONTAINER_VIEW .frame.size.height = 0
  1. Add protocol PrimisPlayerDelegate to your class declaration:
extension ViewController: PrimisPlayerDelegate {
@interface ViewController () <PrimisPlayerDelegate>
  1. Add the following to your viewWillAppear(Animated:) method:
player?.delegate = self
player.delegate = self;
  1. Implement protocol PrimisPlayerDelegate method playerWillDisplay(CGSize):
func playerWillDisplay(playerSize: CGSize) {
  // update the player container view height
  let origin = YOUR_PLAYER_CONTAINER_VIEW.frame.origin
  primisPlayerContainer.frame = CGRect(origin: origin, Size: playerSize)
  // Optional - update the position of other subviews
  // in your scrollview accordingly
  OTHER_VIEW.frame = OTHER_VIEW.frame.offsetBy(dx: 0, dy: playerSize.height)
  ...
}
(void)playerWillDisplayWithPlayerSize:(CGSize)playerSize {
  // update the player container view height
  CGPoint origin = YOUR_PLAYER_CONTAINER_VIEW.frame.origin;
  primisPlayerContainer.frame =
    CGRectMake(origin.x, origin.y, playerSize.width, playerSize.height);
  // Optional - update the position of other subviews
  // in your scrollview accordingly
  OTHER_VIEW.frame = CGRectOffset(OTHER_VIEW.frame, 0, playerSize.height);
  ...
}

Initializing and configuring the player
  1. Add at the top of your swift ViewController class:
import PrimisPlayer
#import <PrimisPlayer/PrimisPlayer-Swift.h>
  1. Define an instance variable for the Primis player:
var player: PrimisPlayer?
PrimisPlayer *player;
  1. Add configuration to Primis player with the relevant keys. Add the following to your viewWillAppear(Animated:) method:
if player == nil {
    player = PrimisPlayer()
    player?.configure( [  .placementId: YOUR_PLACEMENT_ID_STRING,
                            .containerView: YOUR_PLAYER_CONTAINER_VIEW ] )
    player?.add(to: self)
if (!player) {
   player = [[PrimisPlayer alloc] init];
   [player configure:@{     
          @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
            @(PrimisConfigKeyContainerView): YOUR_PLAYER_CONTAINER_VIEW }];
   [player addTo: self];
}
  1. When a view controller that holds the Primis player is dismissed, release the player by using the 'remove' method.
    This is usually done in deinit (swift) / dealloc (Obj-c).
player?.remove()
[player remove];


TableView/ CollectionView Implementation

Adding the Primis Player to a UITableView

If using a collectionView use the collectionView’s delegate and data source methods instead of the tableView’s.

Table Cell and Player Container View

In the instructions below we’ll use a storyboard example.

  • Create a dedicated table cell for the player (Do not use this cell for any other purpose). Currently, only one player is supported per table view, and it may be displayed in multiple positions (indexes) inside the table view (see advanced topics).
  • Add a container view (of type UIView) to the table cell’s content view. This view will contain the Primis player.
  • Set sizes according to the next section:
Using Auto-Layout

Set Auto-Layout frame constraints (top, bottom, leading, trailing) in relation to the cell's content view.
In addition, add a height constraint.

Not Using Auto-Layout

Set the container view's frame to fit the cell's content view.

The cell's height will be updated later by the player to fit the displayed content.

Initializing and configuring the player
  1. Add at the top of your swift ViewController class:
import PrimisPlayer
#import <PrimisPlayer/PrimisPlayer-Swift.h>
  1. Define an instance variable for the Primis player:
var player: PrimisPlayer?
PrimisPlayer *player;
  1. Add configuration to Primis player with the relevant keys. Add the following to your viewWillAppear(Animated:) method:
if player == nil {
    player?.configure( [  .placementId: YOUR_PLACEMENT_ID_STRING,
                            .containerView: YOUR_TABLE_VIEW ] )
    player?.add(to: self)
if (!player) {
    player = [[PrimisPlayer alloc] init];
    [player configure:@{    
          @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
            @(PrimisConfigKeyContainerView): YOUR_TABLE_VIEW }];
    [player addTo: self];
}

YOUR_TABLE_VIEW is the UITableView you are using in your app page.

  1. Release the player by using the ‘remove’ method. We recommend adding this to deinit (swift) / dealloc (Obj-c).
player?.remove()
[player remove];
TableView DataSource and Delegate methods
  1. Edit your ‘cellForRow’ dataSource method to dequeue a player cell.
  2. Use ‘displayInCell’ method to notify the Primis player that it is about to be presented in a cell, and provide the container view to which the player will be added as a subview.
override func tableView(_ tableView: UITableView,
      cellForRowAt indexPath: IndexPath) -> UITableViewCell {

  if indexPath.row == PLAYER_INDEX {
    // Dequeue a player cell
    let playerCell = tableView.dequeueReusableCell(
      withIdentifier: "playerCell",for: indexPath) as! PlayerTableViewCell
    // Notify the Primis player that it is about to be presented in a cell,
    // and provide the container view to which the player will be added as a subview
    player?.displayInCell(playerCell, container: playerCell.playerContainer)
    return playerCell
  }

  // Display other cells
  let otherCell = tableView.dequeueReusableCell
  ...
  return otherCell
}
- (UITableViewCell *)tableView:(UITableView *)tableView
      cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  (indexPath.row == PLAYER_INDEX) {
    // Dequeue a player cell
    PlayerTableViewCell *playerCell =
    [tableView dequeueReusableCellWithIdentifier:@"playerCell" forIndexPath:indexPath];
    // Notify the Primis player that it is about to be presented in a cell,
    // and provide the container view to which the player will be added as a subview
    [player displayInCell:playerCell container:playerCell.playerContainer];
    return playerCell;
  }

  // Display other cells
  TextTableViewCell *otherCell = [tableView dequeue
  ...
  return otherCell;
}
  1. Edit your ‘heightForRowAtIndexPath’ delegate method
  2. Get Primis player height through ‘getPlayerSize’ method, and set the cell’s height accordingly.
override func tableView(_ tableView: UITableView,
      heightForRowAt indexPath: IndexPath) -> CGFloat {

  if indexPath.row == PLAYER_INDEX {
    // Primis player will provide its height when ready,
    // use this height to resize the table cell
    let size = player?.getPlayerSize() ?? .zero
    return size.height
  }

  // Other cell’s height
  return CELL_HEIGHT
}
- (CGFloat)tableView:(UITableView *)tableView
      heightForRowAtIndexPath:(NSIndexPath *)indexPath {

  if (indexPath.row == PLAYER_INDEX) {
    // Primis player will provide its height when ready,
    // use this height to resize the table cell
    CGSize size = [player getPlayerSize];
    return size.height;
  }

  // Other cell’s height
  return CELL_HEIGHT;
}

PrimisPlayerDelegate methods

Implementing the PrimisPlayerDelegate is optional.

The delegate method shouldUpdateCellHeight is called on the player height change. This occurs when the player starts displaying but can get called again later (based on your placement and template setup).

Returning true here (default) will enable the Primis Player to refresh the cell's layout automatically. Returning false requires implementing the height change of the cell and container view manually by the app.

  1. Add protocol PrimisPlayerDelegate to your class declaration:
extension ViewController: PrimisPlayerDelegate {
@interface ViewController ()
  1. Add the following to your viewWillAppear(Animated:) method:
player?.delegate = self
player.delegate = self;
  1. Implement protocol PrimisPlayerDelegate and method shouldUpdateCellHeight:
extension ViewController: PrimisPlayerDelegate {
    
    func shouldUpdateCellHeight(height: CGFloat) -> Bool {
        return true
        /*
         1. Invalidate the table/collection view layout
         2. The cell height will be updated by:
             heightForRowAtIndexPath (tableView) 
             sizeForItemAtindexPath (collectionView)
         3. Return NO;
        */
    }
}
- (BOOL)shouldUpdateCellHeightWithHeight:(CGFloat)height {
    return YES;
    /*
    OR
    1. Invalidate the table/collection view layout
    2. The cell height will be updated by:
        heightForRowAtIndexPath (tableView) 
        sizeForItemAtindexPath (collectionView)
    3. Return NO;
    */
}

WebView Implementation

Add Primis Player to a WebView presenting HTML content

Adding an HTML Div element to the page

In this type of integration, the Primis player is overlaid on top of the web content. For this to succeed the HTML page has to contain a Div element which will mark the position and width of the player. Its height will be updated later by PrimisPlayer.

  1. Add an HTML Div element to your web page with id=”primisPlayerSdkPlaceholder”
<div id="primisPlayerSdkPlaceholder"></div>

Note:
It is required that the Div element will have opening and closing tags.
Do not use <div id="primisPlayerSdkPlaceholder”/>


Initializing and configuring the player

  1. Add at the top of your ViewController class:
import PrimisPlayer
#import <PrimisPlayer/PrimisPlayer-Swift.h>
  1. Define an instance variable for the Primis player:
var player: PrimisPlayer?
PrimisPlayer *player;
  1. Implement the WKNavigationDelegate protocol method didFinishNavigation and Initialize the player inside it. The player will require a placementID string and your webView.
  • Note: YOUR_WEBVIEW is the WKWebView you are using on your app page
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { 
          ...
          if player == nil {
             player = PrimisPlayer()
             player?.configure( [  .placementId: YOUR_PLACEMENT_ID_STRING,
                                     .containerView: YOUR_WEBVIEW ] )
             player?.add(to: self)
          }
    }
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation 
{
   ...
    if (!player) {
        player = [[PrimisPlayer alloc] init];
        [player configure:@{
            @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
            @(PrimisConfigKeyContainerView): YOUR_WEBVIEW
        }];
        [player addTo: self];
         }
}
  1. When a view controller that holds the Primis player is dismissed, release the player by using the ‘remove’ method. This is usually done inside deinit (swift) / dealloc (Obj-c).
player?.remove()
[player remove];


Advanced Features

Floating Player Preset

Based on your placement configuration, when the user scrolls the player off the screen, the player will switch to floating mode.
If you need an advanced control (e.g., the place of the floatingParentView in the view tree hierarchy etc.) you will need to follow this section and provide a floating container view, which will be used to contain the player in its floating mode.

player?.configure( [  .placementId: ...,
                        .flowParentView: YOUR_FLOATING_PARENT_VIEW ] )
[player configure:@{    
          @(PrimisConfigKeyPlacementId): ...,
            @(PrimisConfigKeyFlowParentView): YOUR_FLOATING_PARENT_VIEW 
   }];

Additional instructions

  1. The floatingParentView must be of type UIView, covering the entire screen and visible during the controller’s life cycle. We suggest that you use the view controller's view, otherwise you should provide a subview that fulfills these requirements.
  2. We recommend that your custom floatingParentView and the container view will belong to a single view controller.

Single Player - multiple indexes in Table and Collection View

Primis Player may be assigned to more than one index in a TableView or CollectionView. To implement this, the app maintains a list of indexes and assigns the appropriate Cell when the player scrolls out of the screen.

Notes:

  1. Only one index can be visible at a time. Trying to display the player in multiple indexes will fail silently.
  2. Do not set a floating player in the placement configuration (in Primis dashboard) if using this mode. Enabling it in this mode may result in unexpected behavior.
  3. Use a dedicated table cell for the player. Using the player’s cell to display other content may result in unexpected behavior

Edit your cellForRowAtIndexPath to display the player on every index in your playerPositions Set.

let playerPositions: Set<Int>
  ...
  override func tableView(_ tableView: UITableView, 
                          cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
    if playerPositions.contains(indexPath.row) {
        // Dequeue a player cell
        let playerCell = tableView.dequeueReusableCell(
                                   withIdentifier: "playerCell", 
                                   for:  indexPath) as! PlayerTableViewCell
        // Notify the Primis player that it is about to be presented in a cell,
        // and provide the container view to which the player will be added as a subview
        player?.displayInCell(playerCell, container: playerCell.playerContainer)
        return playerCell
    }
        
    // Display other cells
    let otherCell = tableView.dequeueReusableCell 
    ...
    return otherCell
  }
NSSet *playerPositions
  ...
  - (UITableViewCell *)tableView:(UITableView *)tableView 
                       cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    if ([playerPositions containsObject:@(indexPath.row)]) {
        // Dequeue a player cell
        PlayerTableViewCell *playerCell = 
        [tableView dequeueReusableCellWithIdentifier:@"playerCell" forIndexPath:indexPath];
        // Notify the Primis player that it is about to be presented in a cell,
        // and provide the container view to which the player will be added as a subview
        [player displayInCell:playerCell container:playerCell.playerContainer];
        return playerCell;
    }
 
    // Display other cells
    TextTableViewCell *otherCell = [tableView dequeue 
    ...
    return otherCell;
  }

Consent management

Primis Player supports consent strings in IAB TCF format, version 2. If your app uses certified IAB CMP, the SDK will read the consent string from userDefaults according to the standard.

Otherwise, to start the Player with some predefined consent string, pass it in the configuration object by defining PrimisConsent tuple (swift) or dictionary (obj-c) as described below:

player.configure( [ .placementId: YOUR_PLACEMENT_ID_STRING,
  .containerView: YOUR_PLAYER_CONTAINER_VIEW,
  .consent: PrimisConsent("consent-string","2") ] )
[player configure:@{
   @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
   @(PrimisConfigKeyContainerView): YOUR_PLAYER_CONTAINER_VIEW,
   @(PrimisConfigKeyConsent): @{@"consent":@"consent-string", @"version":@"2"}
  }];

APP Tracking Transparency

Primis SDK is fully compliant with Apple's new tracking policy for iOS14, and will use the device IDFA accordingly.

For further information see Apple documentation: here.


Debugging

Optional - The PrimisPlayer SDK generates debug logs to indicate successful operations or potential problems. These logs may be handy during integration and you can easily disable them when releasing the app.

❗️

Our logs are disabled by default.

You can turn on/off the player's debug logs by adding '.debugLogActive: true/false' to the player's configure call.


Player Dynamic Parameters

Primis tag is a javascript tag that contains initial configuration parameters for the player. You may extend the basic tag by adding dynamic parameters in URL format with the .additionalParams field like so:

player.configure( [  .placementId: YOUR_PLACEMENT_ID_STRING,
                           .containerView: YOUR_PLAYER_CONTAINER_VIEW,
                     .additionalParams: “vp_template=...&vp_content=...”] )
[player configure:@{    
    @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
    @(PrimisConfigKeyContainerView): YOUR_PLAYER_CONTAINER_VIEW,
  @(PrimisConfigKeyAdditionalParams): @“vp_template=...&vp_content=...”}
}];

📘

You may view the full list of available dynamic parameters here


Did this page help you?