Sample workspace with example integration can be downloaded from: https://github.com/Nefta-io/NeftaSDK-iOS.

Requirements

iOS minimal deployment 11

Include the SDK

You can download the latest NeftaPlugin module from: https://github.com/Nefta-io/NeftaSDK-iOS/releases.

Unzip it and copy it inside your project, so that it will look something like this:

Then include this framework in your project go to project settings in the General tab for your Target and scroll down to Framework, Libraries and Embedded Content section and click on the + button:

In the popup window select Add Other... > From files... and select xcframework that you have copied over in the previous step:

After this the framework section should look like this:

Configuration

For this part, you will need the appId which you can get here: https://docs-adnetwork.nefta.io/docs/configuration.

Code integration

You initialize the SDK with the following code:

_plugin = NeftaPlugin_iOS.Init(appId: "5649563255832576")
#import <NeftaSDK/NeftaSDK-Swift.h>

_plugin = [NeftaPlugin_iOS InitWithAppId: @"5649563255832576"];

Do this as soon as possible in the application startup, to ensure the accurate event recording. If you leave the appId parameter nil or empty the SDK will run in demo mode. This means that it'll always show dummy ads. To test the native integration without dashboard configuration.

If you want just the events this is all that is needed. You can proceed to the implementation of the actual events: https://docs-adnetwork.nefta.io/docs/integrate-nefta-game-events.

Code integration - Ads

To start the ad logic and retrieve all the configuration (so that no resources are wasted in case you are not having ads or you don't want them straight away):

_plugin.PrepareRenderer(view: self.view) // UiView in which the ads will be rendered
_plugin.EnableAds(enable: true)
[_plugin PrepareRendererWithView: self.view];
[_plugin EnableAds: true];

To know and react to SDK behavior, you can subscribe to the following callbacks:

_plugin.OnReady = OnReady
_plugin.OnBid = OnBid
_plugin.OnLoadStart = OnStartLoad;
_plugin.OnLoadFail = OnLoadFail
_plugin.OnLoad = OnLoad
_plugin.OnBannerChange = OnBannerChange
_plugin.OnShow = OnShow
_plugin.OnClick = OnClick
_plugin.OnReward = OnReward
_plugin.OnClose = OnClose
_plugin.OnReady = ^(NSDictionary<NSString *, Placement *> * placements) { };
_plugin.OnBid = ^(Placement *placement, BidResponse *bid) { }
_plugin.OnLoadStart = ^(Placement *placement) { };
_plugin.OnLoadFail = ^(Placement *placement, NSString *error) { };
_plugin.OnLoad = ^(Placement *placement) { };
_plugin.OnBannerChange = ^(Placement *placement, NSInteger width, NSInteger height) { };
_plugin.OnShow = ^(Placement *placement, NSInteger width, NSInteger height) { };
_plugin.OnClick = ^(Placement *placement) { };
_plugin.OnReward = ^(Placement *placement) { };
_plugin.OnClose = ^(Placement *placement) { };

Bidding

In case you have just one ad SDK or don't want to deal with header bidding you can skip this step.

The load function will bid and load an ad for you in the background.

You bid on a specific placement with this function:

_plugin.Bid(id: "4922960754245632")
// or
_plugin.Bid(type: Placement.Types.Interstitial)

After which the OnBid callback will be fired with the price of the available ad or null if there is none. It is up to you to decide if you want to proceed and load this one, make another bid, go with an ad from another provider, or something else.

Loading and showing of an Ad

Before we can show an ad, we have to load it. We have two options for that. We can either load specific ad unit by its ID or type:

_plugin.Load(id: "4922960754245632")
// or
_plugin.Load(type: Placement.Types.Interstitial)
    [_plugin LoadWithId: @"4922960754245632"];
    // or
    [_plugin LoadWithType: TypesInterstitial];

After the ad loads the the OnLoad (or OnLoadFail) callback will be made. At that point IsReady function will start returning true:

_plugin.IsReady(id: "4922960754245632")
// or
_plugin.IsReady(type: Placement.Types.Interstitial)
[_plugin IsReadyWithId: @"4922960754245632"];
// or
[_plugin IsReadyWithType: TypesInterstitial];

At this point, we can show the ad:

_plugin.Show(id: "4922960754245632")
// or
_plugin.Show(type: Placement.Types.Interstitial)
[_plugin ShowWithId: @"4922960754245632"];
// or
[_plugin ShowWithType: TypesInterstitial];

Banner Ad Specifics

The easiest way to work with banners is to just toggle them on or off with the following function:

_plugin.EnableBanner(id: "4922960754245632", enable: true)
// or
_plugin.EnableBanner(enable: true)
[_plugin EnableBannerWithId: @"4922960754245632" enable: true];
// or
_plugin EnableBannerWithEnable: true];
    

With this, the SDK will take care of the constant loading and showing banner placement to maximize your earnings from this position.

Whenever the banner presentation changes (gets shown, hidden, or changes size) you will get a OnBannerChange callback with covered width and height in physical pixel size so you can correctly offset application visual elements if needed.

Video Ad Specifics

After watching the rewarded video placement till the end, the OnReward will get fired so you can reward the player.

Miscellaneous

Nefta SDK is not managing audio settings, it is all under your control. So you will probably want to pause or mute your own sounds when showing Interstitial or rewarded video. And then resume or unmute after returning from the fullscreen ad, for example:

_plugin.OnShow = OnShow
_plugin.OnClose = OnClose

func OnShow(placement: Placement, width: Int, height: Int) {
   if placement._type == .Interstitial || placement._type == .RewardedVideo {
       audioPlayer.pause()
   }
}

func OnClose(placement: Placement) {
   if placement._type == .Interstitial || placement._type == .RewardedVideo {
       audioPlayer.start()
   }
}

_plugin.OnShow = ^(Placement *placement, NSInteger width, NSInteger height) {
   if (placement._type == Placement.Types.Interstitial || placement._type == Placement.Types.RewardedVideo) {
      [self.audioPlayer pause];
   }
};

_plugin.OnClose = ^(Placement *placement) {
   if (placement._type == Placement.Types.Interstitial || placement._type == Placement.Types.RewardedVideo) {
      [self.audioPlayer play];
   }
};

In case you want to set a custom identifier for the current player, which will be sent alongside BE calls:

_plugin.SetPublisherUserId(id: "player23")
 [_plugin SetPublisherUserIdWithId: @"player23"];  

You can also verify the correct SDK behavior through logs: Testing