InMobi Native Ads support both static and video ads. You can opt for In-Feed, Splash, or Pre-Roll formats. The steps for creating a native ad placement are given below.
InMobi Native Ads support both static and video ads. You can opt for In-Feed, Splash , or Pre-Roll formats. The steps for creating a native ad placement are given below.
Once the native placement is created, you will be able to see the placement ID.
The IMNative Class contains the following objects:
NSString* adTitle
- Returns the title for the ad.NSString* adDescription
- Returns the description for the ad.UIImage* adIcon
- Returns icon image for the ad.NSString* adCtaText
- Returns click to action text for the ad.NSString* adRating
- Returns rating for the ad (optional).NSURL* adLandingPageUrl
- Returns landing URL for the ad.BOOL isAppDownload
- Returns whether the ad is for downloading an app.NSString* customAdContent
- This will have additional information (description, image URL, etc.), which can be used to create custom UI around the primary view of ad.The IMNative Class supports the following functions:
-(UIView*)primaryViewOfWidth:(CGFloat)width
- Returns a UIView of specified width. This is the main ad content in your native ad. It will return a view of the same aspect ratio that you selected on the InMobi dashboard while creating the native placement. All impression render events are also fired automatically when this primary view is displayed on the screen. (void)load
- Function to load an ad into memory. (BOOL)isReady
- True implies that the ad is ready to be displayed. -(void)reportAdClickAndOpenLandingPage
- This function fires the click events and opens the landing page. You need not open landing page on your own while using this function. -(void)recyclePrimaryView
- Call this function whenever the ad goes out of the visible area on the screen. Also, call this before loading a native ad again on the same object. Import the InMobi SDK header files.
#import <InMobiSDK/InMobiSDK.h>
import InMobiSDK
Declare an ad position in your feed where you want to show ad. Example is to show ad at 4th position.
#define IM_AD_INSERTION_POSITION 4
let adInsertionPosition = 4
Declare a native Ad instance in your ViewController.m
.
@interface TableViewController () <IMNativeDelegate>
@property(nonatomic,strong) IMNative *InMobiNativeAd;
@end
class ViewController: UIViewController, IMNativeDelegate {
var inMobiNativeAd: IMNative?
Your final ViewDidLoad
Code should look like:
- (void)viewDidLoad {
[super viewDidLoad];
self.InMobiNativeAd = [[IMNative alloc] initWithPlacementId:<Insert InMobi placement ID here>];
self.InMobiNativeAd.delegate = self;
[self.InMobiNativeAd load];
//Your app content
}
override func viewDidLoad() {
super.viewDidLoad()
inMobiNativeAd = IMNative(placementId: <Insert InMobi plc id> )
inMobiNativeAd?.delegate = self
inMobiNativeAd?.load()
// Your app content
}
Implement IMNativeDelegate
methods for the success callback. The success callback indicates that the ad is ready to be shown on the screen. Here you should add the InMobiNativeAd Object to your TableView's data source.
-(void)nativeDidFinishLoading:(IMNative*)native{
[self.tableData insertObject:native atIndex:IM_AD_INSERTION_POSITION];
[self.tableView reloadData];
NSLog(@"Native Ad did finish loading");
}
func nativeDidFinishLoading(_ native: IMNative!) {
self.tableData.insert(native, at: IM_AD_INSERTION_POSITION)
self.tableView.reloadData()
NSLog("InMobi Native Did finished loading");
}
You have successfully received a native ad when you get the callback nativeAdDidFinishLoading
. The following example shows how to fetch the adView in your tableView delegate cellForRowAtIndexPath
.
Impression events will be fired only when the Native Ad's primary view is in visible area of the screen.
Implement the below custom cell class using storyboard.
#import
@interface InFeedTableCell : UITableViewCell
@property (nonatomic, strong) IBOutlet UIImage *iconImage;
@property (nonatomic, strong) IBOutlet UILabel *titleLabel;
@property (nonatomic, strong) IBOutlet UILabel *subTitleLabel;
@property (nonatomic, strong) IBOutlet UILabel *descriptionLabel;
@property (nonatomic, strong) IBOutlet UILabel *ctaLabel;
@property (nonatomic, strong) IBOutlet UIView *adView;
@end
class InFeedTableViewCell: UITableViewCell {
@IBOutlet var iconImage : UIImage?
@IBOutlet var titleLabel : UILabel?
@IBOutlet var subtitleLabel : UILabel?
@IBOutlet var descriptionLabel : UILabel?
@IBOutlet var ctaLabel : UILabel?
@IBOutlet var adView : UIView?
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
InFeedTableCell *cell = ( *)[tableView dequeueReusableCellWithIdentifier:@"InFeedTableCell"];
id nativeAd = [self.tableData objectAtIndex:indexPath.row];
if ([nativeAd isKindOfClass:[IMNative Class]]]) {
IMNative * currentNativeAd = nativeAd;
cell.iconImage = currentNativeAd.adIcon;
cell.titleLabel.text = currentNativeAd.adTitle;
cell.subTitleLabel.text = @"Sponsored";
cell.descriptionLabel.text = currentNativeAd.adDescription;
cell.ctaLabel.text = currentNativeAd.adCtaText;
//Calculate your feed's primaryImageViewWidth and use it to fetch and
Ad Primary view of same width.
UIView* = [currentNativeAd
primaryViewOfWidth:primaryImageViewWidth];
//Set the frame of Ad Primary View same as that of your feed's Primary View
cell.adView = adView;
UITapGestureRecognizer *singleTapAndOpenLandingPage =
[[UITapGestureRecognizer alloc] initWithTarget:currentNativeAd
action:@selector(reportAdClickAndOpenLandingPage)];
cell.ctaLabel.userInteractionEnabled = YES;
[cell.ctaLabel addGestureRecognizer:singleTapAndOpenLandingPage];
}
else{
//Your App’s TableCell implementation
}
return cell;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (tableView.dequeueReusableCell(withIdentifier: "InFeedTableCell")! as! InFeedTableViewCell)
if let currentNativeAd = self.tableData?[indexPath.row] as? IMNative {
cell.iconImageView.image! = currentNativeAd.adIcon
cell.titleLabel!.text! = currentNativeAd.adTitle
cell.subtitleLabel?.text! = "Sponsored"
cell.descriptionLabel.text! = currentNativeAd.adDescription
cell.ctaLabel?.text! = currentNativeAd.adCtaText
//Calculate your feed’s primaryImageViewWidth and use it to fetch and Ad Primary view of same width.
if let adPrimaryViewOfCorrectWidth =
currentNativeAd.primaryView(ofWidth: primaryImageViewWidth) {
cell.addSubview(adPrimaryViewOfCorrectWidth)
}
let singleTapAndOpenLandingPage = UITapGestureRecognizer(target:currentNativeAd, action: #selector(self.reportAdClickAndOpenLandingPage))
cell.ctaLabel?.isUserInteractionEnabled = true
cell.ctaLabel?.addGestureRecognizer(singleTapAndOpenLandingPage)
}
else {
// Your app's Table Cell implementations
}
return cell
}
You need to recycle the Native Ad's Primary view, every time your ad goes out of the screen area. This is to optimize memory usage as well as ensuring that the AdView does not conflict with your app’s native views. Call recyclePrimaryView
method on the InMobiNativeAd
object every time the ad goes out of the visible area. In a TableView, this can be called in the didEndDisplayingCell
Method:
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
id nativeAd = [self.tableData objectAtIndex:indexPath.row]
if([nativeAdself isKindOfClass:[IMNative Class]]){
IMNative *currentNativeAd = nativeAd;
[currentNativeAd recyclePrimaryView];
}
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if (tableData?[indexPath.row] as? UIView) != nil {
inMobiNativeAd?.recyclePrimaryView()
}
}
After calling the recyclePrimaryView
, if you want to add the view again on the screen, you must fetch it from [self.InMobiNativeAd primaryViewOfWidth:<custom width="">]</custom>
as the previous view would have been recycled. If you have added it in the cellForRowAtIndexPath delegate (as mentioned in step 8), you don’t have to do anything here.
Refreshing the ad - You will need to refresh the ad at various points to optimize ad exposure to your users. To refresh the ad, you will need to call the following functions in the same order.
-(void)refreshInMobiStrandAd {
[self.tableData removeObject:self.InMobiNativeAd];
[self.tableView reloadData];
[self.InMobiNativeAd recyclePrimaryView];
self.InMobiNativeAd = [[IMNative alloc] initWithPlacementId:<Insert InMobi placement ID here>];
self.InMobiNativeAd.delegate = self;
[self.InMobiNativeAd load];
}
func refreshInMobiStrandAd() {
tableData = tableData?.filter({ (obj) -> Bool in
if obj is IMNative {
return false
}
return true
})
tableView.reloadData()
inMobiNativeAd?.recyclePrimaryView()
inMobiNativeAd = IMNative(placementId: )
inMobiNativeAd?.delegate = self
inMobiNativeAd?.load()
}
IMNative
object from your tableData
and destroy the current ad object. Then you need to create a new object and call load on it. Also, you should recycle the Primary View before destroying your existing object. [self.InMobiNativeAd primaryViewOfWidth:<custom width="">]</custom>
method again to replace the current Ad Primary View with the new view.You should set the InMobiNativeAd
object and its delegate to nil in the dealloc
method of your ViewController
class. Do ensure you recycle the view before deallocating to remove all references to the adView.
-(void)dealloc {
[self.InMobiNativeAd recyclePrimaryView];
self.InMobiNativeAd.delegate = nil;
self.InMobiNativeAd = nil;
}
deinit {
inMobiNativeAd?.recyclePrimaryView()
inMobiNativeAd?.delegate = nil
inMobiNativeAd = nil
}
self.InMobiNativeAd.isReady
function to determine if the ad is ready to be shown. Sometimes, your main thread may be occupied and hence you may not receive nativeDidFinishLoading
in time. Hence, it is better to proactively check if the ad is ready just after your cut-off time has elapsed.IMPORTANT: You should NOT dismiss the ad if the second screen of the ad is in display. You can check this in the nativeWillPresentScreen
and not dismiss the ad if this delegate is fired. Sample implementation is as follows:
@property(nonatomic,strong) bool *isSecondScreenDisplayed;// Use this to check if second screen has to be shown or not
-(void)nativeWillPresentScreen:(IMNative*)native{
NSLog(@"Native Ad will present screen");
isSecondScreenDisplayed = YES;
}
var isSecondScreenDisplayed: Bool = false// Use this to check if second screen has to be shown or not
func nativeWillPresentScreen(_ native: IMNative) {
print("Native Ad will present screen")
isSecondScreenDisplayed = true
}
You should recycle the Primary View before dismissing the ad. This can be implemented as follows:
@property (nonatomic, strong) UIView* SplashAdView; // Use this view to check for visibility of splash screen
-(void)dismissAd{
if(isSecondScreenDisplayed){
NSLog(@"DO NOT DISMISS THE AD WHILE THE SCREEN IS BEING DISPLAYED");
}
else{
self.SplashAdView.hidden = true;
[self.InMobiNativeAd recyclePrimaryView];
self.InMobiNativeAd = nil;
}
}
var splashAdView: UIView? // Use this to check visibility of second screen
func dismissAd() {
if isSecondScreenDisplayed {
print("DO NOT DISMISS THE AD WHILE THE SCREEN IS BEING DISPLAYED")
}
else {
splashAdView?.isHidden = true
inMobiNativeAd?.recyclePrimaryView()
inMobiNativeAd = nil
}
}
Pre-Roll Video experience can be implemented using the same IMNative Class. You will need to dismiss the ad view in the following delegate:
-(void)nativeDidFinishPlayingMedia:(IMNative *)native{
[self dismissAd];
}
func nativeDidFinishPlayingMedia(_ native: IMNative) {
self.dismissAd()
}
The Pre-Roll ad can be dismissed as follows:
@property (nonatomic, strong) UIView* PrerollAdView; //Use this to store the primaryView returned by the IMNative instance.
-(void)dismissAd{
self.PrerollAdView.hidden = true;
[self.InMobiNativeAd recyclePrimaryView];
self.InMobiNativeAd = nil;
}
var prerollAdView: UIView? // Use this to store the primaryView returned by the IMNative instance.
func dismissAd() {
prerollAdView?.isHidden = true
inMobiNativeAd?.recyclePrimaryView()
inMobiNativeAd = nil
}
You can perform the following steps to get additional callbacks. Implement the following delegate methods in your ViewController.m
file:
-(void)nativeDidFinishLoading:(IMNative*)native{
NSLog(@"Native Ad load Successful"); // Ad is ready to be displayed
}
-(void)native:(IMNative*)native didFailToLoadWithError:(IMRequestStatus*)error{
NSLog(@"Native Ad load Failed"); // No Fill or error
}
-(void)nativeWillPresentScreen:(IMNative*)native{
NSLog(@"Native Ad will present screen"); //Full Screen experience is about to be presented
}
-(void)nativeDidPresentScreen:(IMNative*)native{
NSLog(@"Native Ad did present screen"); //Full Screen experience has been presented
}
-(void)nativeWillDismissScreen:(IMNative*)native{
NSLog(@"Native Ad will dismiss screen"); //Full Screen experience is going to be dismissed
}
-(void)nativeDidDismissScreen:(IMNative*)native{
NSLog(@"Native Ad did dismiss screen"); //Full Screen experience has been dismissed
}
-(void)userWillLeaveApplicationFromNative:(IMNative*)native{
NSLog(@"User leave"); //User is about to leave the app on clicking the ad
}
-(void)native:(IMNative *)native didInteractWithParams:(NSDictionary *)params{
NSLog(@"User clicked"); // Called when the user clicks on the ad.
}
-(void)nativeAdImpressed:(IMNative *)native{
NSLog(@"User viewed the ad"); // Called when impression event is fired.
}
-(void)nativeDidFinishPlayingMedia:(IMNative*)native{
NSLog(@"The Video has finished playing"); // Called when the video has finished playing. Used for preroll use-case
}
-(void)userDidSkipPlayingMediaFromNative:(IMNative*) native {
NSLog(@"User has skipped playing media"); // Called when the user has opted to skip the media being shown.
}
-(void)native:(IMNative*)native adAudioStateChanged:(BOOL)audioStateMuted {
if (audioStateMuted) {
NSLog(@"Inline video-ad audio state changed to mute");
}
else {
NSLog(@"Inline video-ad audio state changed to unmute");
}
//This is called when inline video audio state changes.
}
func nativeDidFinishLoading(_ native: IMNative) {
print("Native Ad load Successful") // Ad is ready to be displayed
}
func native(_ native: IMNative, didFailToLoadWithError error: IMRequestStatus) {
print("Native Ad load Failed") // No Fill or error
}
func nativeWillPresentScreen(_ native: IMNative) {
print("Native Ad will present screen") //Full Screen experience is about to be presented
}
func nativeDidPresentScreen(_ native: IMNative) {
print("Native Ad did present screen") //Full Screen experience has been presented
}
func nativeWillDismissScreen(_ native: IMNative) {
print("Native Ad will dismiss screen") //Full Screen experience is going to be dismissed
}
func nativeDidDismissScreen(_ native: IMNative) {
print("Native Ad did dismiss screen") //Full Screen experience has been dismissed
}
func userWillLeaveApplicationFromNative(_ native: IMNative) {
print("User leave") //User is about to leave the app on clicking the ad
}
func native(_ native: IMNative, didInteractWithParams params: [String : Any]?) {
print("User clicked") // Called when the user clicks on the ad.
}
func nativeAdImpressed(_ native: IMNative) {
print("User viewed the ad") // Called when impression event is fired.
}
func nativeDidFinishPlayingMedia(_ native: IMNative) {
print("The Video has finished playing") // Called when the video has finished playing. Used for preroll use-case
}
func userDidSkipPlayingMediaFromNative(_ native: IMNative) {
print("User has skipped playing the media") // Called when the user has opted to skip the media being shown.
}
func native(_ native: IMNative, adAudioStateChanged audioStateMuted: Bool) {
if (audioStateMuted) {
print("Inline state changed to mute")
}
else {
print("Inline state changed to unmute")
}
}
InMobi's SDK can run both HTML and native units against your native placement. You can run the following ad sizes depending on the real-estate reserved for your native placement.
To switch this on, you need to reach out to your respective partner manager with the preferred backfill size. Also, you will need to handle this in your code as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
InFeedTableCell *cell = (InFeedTableCell *)[tableView
dequeueReusableCellWithIdentifier:@"InFeedTableCell"];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"InFeedTableCell"
owner:self options:nil];
cell = [nib objectAtIndex:0];
id slide = [self.tableData objectAtIndex:indexPath.row];
if ([self isAdAtIndexPath:indexPath]) {
IMNative *currentNativeAd = slide;
NSString *customJSONstring = currentNativeAd.customAdContent;
NSData *data = [customJSONstring dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
BOOL isBackFillBanner = [[jsonDict objectForKey:@"isHTMLResponse"] boolValue];
if (isBackFillBanner) {
IMNative * currentNativeAd = slide;
//Depending on the selected backfill size, provide accurate width below
UIView* AdPrimaryViewOfCorrectWidth = [currentNativeAd primaryViewOfWidth:250];
AdPrimaryViewOfCorrectWidth.frame = CGRectMake((_screenWidth-300)/2, 0, 300, 250);
[cell addSubview:AdPrimaryViewOfCorrectWidth];
}
else
{
//continue with the current native implementation
IMNative * currentNativeAd = slide;
cell.iconImageView.image = currentNativeAd.adIcon;
cell.titleLabel.text = currentNativeAd.adTitle;
cell.subTitleLabel.text = @"Sponsored";
cell.descriptionLabel.text = currentNativeAd.adDescription;
cell.ctaLabel.text = currentNativeAd.adCtaText;
//Calculate your feed's primaryImageViewWidth and use it to fetch and Ad Primary view of same width.
UIView* AdPrimaryViewOfCorrectWidth = [currentNativeAd primaryViewOfWidth:primaryImageViewWidth];
//Set the frame of Ad Primary View same as that of your feed's Primary View
AdPrimaryViewOfCorrectWidth.frame = primaryImageViewFrame;
[cell addSubview:AdPrimaryViewOfCorrectWidth];
UITapGestureRecognizer *singleTapAndOpenLandingPage =
[[UITapGestureRecognizer alloc] initWithTarget:currentNativeAd
action:@selector(reportAdClickAndOpenLandingPage)];
cell.ctaLabel.userInteractionEnabled = YES;
[cell.ctaLabel addGestureRecognizer:singleTapAndOpenLandingPage];
}
}
else {
//Your App’s TableCell implementation
}
return cell;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (tableView.dequeueReusableCell(withIdentifier: "InFeedTableCell")! as! InFeedTableViewCell)
if let currentNativeAd = self.tableData?[indexPath.row] as? IMNative {
let customJSONstring = currentNativeAd.customAdContent
if let data = customJSONstring?.data(using: .utf8) {
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let isBackFillBanner = json["isHTMLResponse"] as? Bool, isBackFillBanner {
//Depending on the selected backfill size, provide accurate width below
let adPrimaryViewOfCorrectWidth: UIView = currentNativeAd.primaryView(ofWidth: 250)
adPrimaryViewOfCorrectWidth.frame = CGRect(x: (_screenWidth-300)/2, y: 0, width: 300, height: 250)
cell.addSubview(adPrimaryViewOfCorrectWidth)
} else {
//continue with the current native implementation
cell.iconImageView.image = currentNativeAd.adIcon
cell.titleLabel.text = currentNativeAd.adTitle
cell.subtitleLabel.text = "Sponsored"
cell.descriptionLabel.text = currentNativeAd.description
cell.ctaLabel?.text = currentNativeAd.adCtaText
//Calculate your feed's primaryImageViewWidth and use it to fetch and Ad Primary view of same width.
let adPrimaryViewOfCorrectWidth: UIView = currentNativeAd.primaryView(ofWidth: primaryImageViewWidth)
//Set the frame of Ad Primary View same as that of your feed's Primary View
let singleTapAndOpenLandingPage = UITapGestureRecognizer(target:currentNativeAd, action: #selector(self.reportAdClickAndOpenLandingPage))
cell.ctaLabel?.isUserInteractionEnabled = true
cell.ctaLabel?.addGestureRecognizer(singleTapAndOpenLandingPage)
}
}
} catch let error as NSError {
print("Failed to load: \(error.localizedDescription)")
}
}
}
return cell }
isHTMLResponse
.By installing this SDK update, you agree that your Children Privacy Compliance setting remains accurate or that you will update that setting, whenever there is a change in your app's audience. You may update the app's Children Privacy Compliance settings at https://publisher.inmobi.com/my-inventory/app-and-placements.