In Feed

Scenario

  • Insert Ad into UITableView while users are scrolling it.

Ad Formats Supported

  • Card Ad

  • Native Ad

How to Integrate

CrystalExpress™ SDK provides CEInFeedHelper to simplify in-feed integration of Card Ad and Native Ad. Please follow the step below:

Step 0 : Put CEInFeedHelper folder into your project folder

Please put the whole folder of CEInFeedHelper from CrystalExpress SDK Sample code provided into the folder of your App project.

Step 1: Create appropriate CEInFeedHelper for your scenario

There are 2 ways to integrate CEInFeedHelper, placement integration and tag integration. Main difference between those 2 integrations is that tag integration is aimed to handle Ad targeting for specific channels.

Under placement integration, publishes provide the placement to helper directly. On the other hand, the helper will get placements for the tag from tag settings from our dashboard

  • Placement integration of Card Ad format:

let inFeedHelper = CEInFeedHelper(placement: "YOUR_PLACEMENT_ID", adSource: CEIFCardAdSource())
  • Placement integration of Native Ad format:

let inFeedHelper = CEInFeedHelper(placement: "YOUR_PLACEMENT_ID", adSource: CEIFNativeAdSource(layoutDelegate: self))
  • Tag integration of Card Ad format:

let inFeedHelper = CEInFeedHelper(tag: "YOUR_TAG_ID", adSource: CEIFCardAdSource())
  • Tag integration of Native Ad format:

let inFeedHelper = CEInFeedHelper(tag: "YOUR_TAG_ID", adSource: CEIFNativeAdSource(layoutDelegate: self))

Step 1-2(Native Only): Implement Native Ad Source Delegate

You can set Native Ad layout properly by implementing this delegate. Moreover, the frame of this view returned will be the same as the ad view received from the helper, so it would be better to set the width of Ad view equal to table view.

extension YOUR_INFEED_VIEWCONTROLLER : CEIFNativeAdSourceLayoutDelegate {
    func view(with nativeAd: CENativeAd!) -> UIView! {
        // Set width of Ad view
        // Instantiate MediaView
        // Get strings of title, description, and call to action
        // Customized Ad view layout
        // Register NativeAd
        // Return Ad view
        ...
        ...
    }
}

Step 2: Create CEDataSourceHelper by CEInFeedHelper

CEDataSourceHelper can help you know adjusted position and related info of Ad items on the tableview.

inFeedHelper.eventDelegate = self
self.dataSourceHelper = CEDataSourceHelper(inFeedHelper: inFeedHelper, delegate: self)

Step 3: Add the Ad count into numberOfRowsInSection

Add the number of Ad items by CEDataSourceHelper into numberOfRowsInSection.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let result = "TOTAL_ITEM_NUMBER OF ORIGINAL UITABLEVIEW" + (self.dataSourceHelper?.adCount() ?? 0)
        return result
}

Step 4: Get Ad view from CEDataSourceHelper

Case: Ad is not going to show right away

  • Get Ad view from CEDataSourceHelper by the index number you assign and get original data's height with shifted path in estimatedHeightForRowAt.

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if let adView = self.dataSourceHelper?.peekAdView(for: indexPath) {
            // ToDo
            // If receiving non-nil value, the cell should be ad cell.
            // Return the height of the ad cell according the ad view.
            // ...
        }
        return cellHeight(forPath: self.shiftedPath(indexPath), tableView: tableView)
}

Case: Ad is going to show right away

  • Get Ad view from CEDataSourceHelper by the index number you assign and get original data's height with shifted path in cellForRowAt.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let adView = self.dataSourceHelper?.getAdView(for: indexPath) {
            // ToDO
            // If receiving non-nil value, the cell should be ad cell.
            // Declare the ad cell in customized way.
            // Return the ad cell according the ad view.
            ...
            ...
        }
        return createCell(forPath: self.shiftedPath(indexPath), tableView: tableView)
}
  • Get Ad view from CEDataSourceHelper by the index number you assign and get original data's height with shifted path in heightForRowAt .

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if let adView = self.dataSourceHelper?.getAdView(for: indexPath) {
            // ToDo
            // If receiving non-nil value, the cell should be ad cell.
            // Return the height of the ad cell according the ad view.
            ...
            ...
        }
        return cellHeight(forPath: self.shiftedPath(indexPath), tableView: tableView)
}

Step 5: Get original data's height with shifted path

func shiftedPath(_ indexPath:IndexPath) -> IndexPath {
        // ObjC -> Swift optional handling.
        return self.dataSourceHelper?.shiftedPath(for: indexPath) ?? indexPath
}

Step 6: Insert new rows for just new Ads

Update the Ad count to maintain data integrity and avoid exception of UITableView.

func toInsertRows(_ rowsCount: Int) {
    guard rowsCount > 0 else {
        return
    }
    let currentRowInTable = self.table.numberOfRows(inSection: 0)
    var rows = [IndexPath]()
    for i in 0 ... (rowsCount-1) {
        rows.append(IndexPath(row: currentRowInTable + i, section: 0))
    }
    self.table.insertRows(at: rows, with:.none)
}

Step 7: Implement delegate of CEInFeedHelper (Optional *)

By implementing delegate, you can get Ad event callback from Ad source.

extension DemoInFeedSingleViewController : CEIFHelperADEventDelegate {
    func adDidImpression(_ index: UInt, ad adObj: Any!) {

    }

    func adDidClicked(_ index: UInt, ad adObj: Any!) {

    }

    func adDidMute(_ index: UInt, ad adObj: Any!) {

    }

    func adDidUnmute(_ index: UInt, ad adObj: Any!) {

    }

    func adVideoDidStart(_ index: UInt, ad adObj: Any!) {

    }

    func adVideoDidEnd(_ index: UInt, ad adObj: Any!) {

    }

    func adVideoProgress(_ index: UInt, ad adObj: Any!, duration: Int32, position: Int32) {

    }
}

Last updated