SDK for iOS v. 1.5.0

v. 1.5.0
Primis IOS SDK latest version is 1.5.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.5.0, Download from here
  • 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.
599

Adding the frameworks

PrimisPlayer SDK

  1. Add the PrimisPlayer framework to your Xcode project.
851

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

b. In the center pane, click Build Phases.

867

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 two 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.
1050
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);
  ...
}

Floating Parent View

Depending on your placement configuration, when the user scrolls the player off the screen, the player will switch to floating mode.

In the next section, you will be asked to provide a floatingParentView which will be used to contain the player as a subview in floating mode.

📘

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 floatingParentView and the container view will belong to a single view controller.

  3. The floatingParentView must be provided even if the placement currently does not enable floating mode.

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,
	                    .flowParentView: YOUR_FLOATING_PARENT_VIEW ] )
    player?.add(to: self)
if (!player) {
   player = [[PrimisPlayer alloc] init];
   [player configure:@{ 	
	      @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
		@(PrimisConfigKeyContainerView): YOUR_PLAYER_CONTAINER_VIEW,
		@(PrimisConfigKeyFlowParentView): YOUR_FLOATING_PARENT_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 only on a single position (index) in the table view.
  • 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.

1413
Not Using Auto-Layout

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

502

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,
	                   .flowParentView: YOUR_FLOATING_PARENT_VIEW ] )
    player?.add(to: self)
if (!player) {
    player = [[PrimisPlayer alloc] init];
    [player configure:@{ 	
	      @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
		@(PrimisConfigKeyContainerView): YOUR_TABLE_VIEW,
		@(PrimisConfigKeyFlowParentView): YOUR_FLOATING_PARENT_VIEW 
	}];
    [player addTo: self];
}

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

YOUR_FLOATING_PARENT_VIEW should be one of the following:

a. self.view - if you are using a UIVIewController with an embedded UITableView.
b. parent.view – if your viewController is a child of another viewController (e.g a UITableViewController that is a child of UINavigationController/ UIVIewController).

  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;
    */
}

Advanced Features

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,
  .flowParentView: YOUR_FLOATING_PARENT_VIEW
  .consent: PrimisConsent("consent-string","2") ] )
[player configure:@{
   @(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
   @(PrimisConfigKeyContainerView): YOUR_PLAYER_CONTAINER_VIEW,
   @(PrimisConfigKeyFlowParentView): YOUR_FLOATING_PARENT_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,
	               .flowParentView: YOUR_FLOATING_PARENT_VIEW,
               .additionalParams: “vp_template=...&vp_content=...”] )
[player configure:@{ 	
	@(PrimisConfigKeyPlacementId): YOUR_PLACEMENT_ID_STRING,
	@(PrimisConfigKeyContainerView): YOUR_PLAYER_CONTAINER_VIEW,
	@(PrimisConfigKeyFlowParentView): YOUR_FLOATING_PARENT_VIEW, 
@(PrimisConfigKeyAdditionalParams): @“vp_template=...&vp_content=...”}
}];

📘

You may view the full list of available dynamic parameters here