Migration to 4.5.0

Optional: Wrapper

For MAX Unity integration we now wrap recommended reference implementation in the SDK itself. which you can use directly to simplify integration as following:

//MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += OnAdLoadedEvent;
//MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += OnAdLoadFailedEvent;
//MaxSdkCallbacks.Interstitial.OnAdDisplayFailedEvent += OnAdDisplayFailedEvent;
//MaxSdkCallbacks.Interstitial.OnAdHiddenEvent += OnAdHiddenEvent;
//MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
//MaxSdkCallbacks.Interstitial.OnAdClickedEvent += OnAdClickedEvent;

NeftaSdk.Interstitial.InitializeDualTrack(AdUnitIdA, AdUnitIdB);
NeftaSdk.Interstitial.OnAdLoadedEvent += OnAdLoadedEvent;
NeftaSdk.Interstitial.OnAdLoadFailedEvent += OnAdLoadFailedEvent;
NeftaSdk.Interstitial.OnAdDisplayFailedEvent += OnAdDisplayFailedEvent;
NeftaSdk.Interstitial.OnAdHiddenEvent += OnAdHiddenEvent;

private void Load()
{
   //MaxSdk.LoadInterstitial(AdUnitIdA);
   NeftaSdk.LoadInterstitial(AdUnitIdA);
}

..

Native Plugins

In 4.5.0 a lot of unused network adapter classes were stripped. Because of this is good to double check when upgrading to remove all old files and that just the new ones are present (https://github.com/Nefta-io/NeftaMAXAdapter-Unity/tree/main/Assets/NeftaCustomAdapter/Plugins).


Init

The Init OnReady callback is now mandatory. Which makes makes it to disable back to back ad preloading only if the specific current player is group where Nefta optimization will run.

// < 4.5.0
NeftaAdapterEvents.OnReady = (InitConfiguration config) =>
{
   Debug.Log($"[NeftaPluginMAX] Should bypass Nefta optimization? {config._skipOptimization}");
};
NeftaAdapterEvents.Init(NeftaId, false);

// 4.5.0 +
NeftaAdapterEvents.InitWithAppId(_neftaAppId, (InitConfiguration config) =>
{
   Debug.Log($"[NeftaPluginMAX] Should skip Nefta optimization: {config._skipOptimization} for: {config._nuid}");

   if (!config._skipOptimization)
   {
      MaxSdk.SetExtraParameter("disable_b2b_ad_unit_ids", string.Join(",", _adUnits));   
   }
   MaxSdk.InitializeSdk();
};
// < 4.5.0
_plugin = NeftaPlugin.Init(appId: "5661184053215232")
_plugin.OnReady = { initConfig in // optional callback
}

// 4.5.0 +
ALNeftaMediationAdapter.Init(appId: "5661184053215232", onReady: { initConfig in
   ViewController._log.notice("[NeftaPluginMAX] Should skip Nefta optimization: \(initConfig._skipOptimization) for: \(initConfig._nuid)")
})
// < 4.5.0
NeftaPlugin.Init(getApplicationContext(), "5643649824063488").OnReady = (InitConfiguration config) -> {
  Log.i("NeftaPluginMAX", "Should skip Nefta optimization? " + config._skipOptimization);
};


// 4.5.0 +
NeftaMediationAdapter.InitWithAppId(getApplicationContext(), "5632029345447936", (InitConfiguration config) -> {
   Log.i("NeftaPluginMAX", "Should skip Nefta optimization: " + config._skipOptimization + " for: " + config._nuid);
});

Automatic event forwardation

With 4.5.0 the option for automatic event forwardation in MAX Unity (if you did not disable this in NeftaPlugin Init) was removed. This is now automatic only when using wrapper. But when implementing dual track manually you should now forward impression(ILRD) and click event manually:

MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
MaxSdkCallbacks.Interstitial.OnAdClickedEvent += OnAdClickedEvent;

// when implementing dual track manually (not using NeftaSDK wrapper)
// you should forward ILRD event to the SDK manually
private void OnAdRevenuePaidEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
{
   NeftaAdapterEvents.OnExternalMediationImpression(adUnitId, adInfo);
            
   Debug.Log($"NeftaPluginMAX Interstitial OnAdRevenuePaidEvent: {adInfo.Revenue}");
}

// when implementing dual track manually (not using NeftaSDK wrapper)
// you should forward ILRD event to the SDK manually
private void OnAdClickedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
{
   NeftaAdapterEvents.OnExternalMediationClick(adUnitId, adInfo);
            
   Debug.Log("NeftaPluginMAX Interstitial OnAdClickedEvent");
}


Retry delay

Retry delay is now remotely configurable.So the consecutive no fill count doesn't have to be accounted and the code is simplified as following:

// in LoadWithDelay():

// < 4.5.0
var delay = new[] { 0, 2, 4, 8, 16, 32, 64 }[Math.Min(_consecutiveAdFails, 6)];


// 4.5.0 +
var delay = NeftaAdapterEvents.GetRetryDelayInSeconds(adRequest.Insight);
// in `retryLoad()`:

// < 4.5.0
// As per MAX recommendations, retry with exponentially higher delays up to 64s
// In case you would like to customize fill rate / revenue please contact our customer support
DispatchQueue.main.asyncAfter(deadline: .now() + Double(delayInSeconds)) {
   self._state = State.Idle
   self._controller.RetryLoading()
}

// 4.5.0+
DispatchQueue.main.asyncAfter(deadline: .now() + ALNeftaMediationAdapter.GetRetryDelayInSeconds(insight: _insight)) {
   self._state = .Idle
   self._controller.RetryLoadTracks()
}
// in `RetryLoad()`:

// < 4.5.0
// As per MAX recommendations, retry with exponentially higher delays up to 64s
// In case you would like to customize fill rate / revenue please contact our customer support
long waitTimeInMs = new int[]{0, 2, 4, 8, 16, 32, 64}[Math.min(_consecutiveAdFails, 6)] * 1000L;
_handler.postDelayed(() -> {
   _state = State.Idle;
   RetryLoadTracks();
}, waitTimeInMs);


// 4.5.0+
_handler.postDelayed(() -> {
   _state = State.Idle;
   RetryLoadTracks();
}, (long)(NeftaMediationAdapter.GetRetryDelayInSeconds(_insight) * 1000));

Optionally: Ad reseting on new session

It can happen that the player has ads loaded and ready to show, but they put the app in background and resume after a long time, and he could still have previous fills available. Requesting new ads will most likely return higher value ads. To do this add the following code:

// 4.5.0 +
public class Track {
   public void Reset()
   {
      Insight = null;
      State = State.Idle;
      AdInfo = null;
   }
}

public virtual void OnNewSession()
{
   _trackA.Reset();
   _trackB.Reset();
            
   _isFirstResponseReceived = false;
   LoadTracks();
}


NeftaAdapterEvents.AddNewSessionCallback(() => {
   OnNewSession();
});
// < 4.5.0
public init(controller: Interstitial, adUnitId: String) {
   _controller = controller
   _adUnitId = adUnitId
             
   _interstitial = MAInterstitialAd(adUnitIdentifier: adUnitId)
   super.init()
}


// 4.5.0 +
public init(controller: Interstitial, adUnitId: String) {
   _controller = controller
   _adUnitId = adUnitId
             
   super.init()
   Reset()
}

public func Reset() {
   if let oldInterstitial = _interstitial {
      oldInterstitial.delegate = nil
      oldInterstitial.revenueDelegate = nil
    }
            
   _interstitial = MAInterstitialAd(adUnitIdentifier: _adUnitId)
   _interstitial.delegate = self
   _interstitial.revenueDelegate = self
            
   _state = State.Idle
   _insight = nil
   _revenue = -1
}


ALNeftaMediationAdapter.AddNewSessionCallback(callback: {
   Log("Inter on new session")
        
   _trackA.Reset()
   _trackB.Reset()
        
   UpdateShowButton()
   _isFirstResponseReceived = false
   RetryLoadTracks()
})

// < 4.5.0
public Track(String adUnit) {
   _adUnitId = adUnit;

   _interstitial = new MaxInterstitialAd(_adUnitId);
   _interstitial.setListener(this);
   _interstitial.setRevenueListener(this);
}

// 4.5.0 +
public Track(String adUnit) {
   _adUnitId = adUnit;

   Reset();
}

public void Reset() {
   if (_interstitial != null) {
      _interstitial.destroy();
   }
   _interstitial = new MaxInterstitialAd(_adUnitId);
   _interstitial.setListener(this);
   _interstitial.setRevenueListener(this);

   _state = State.Idle;
   _insight = null;
   _revenue = 0;
}

NeftaMediationAdapter.AddNewSessionCallback(() -> {
   Log("Inter on new session");
   _trackA.Reset();
   _trackB.Reset();

   UpdateShowButton();
   _isFirstResponseReceived = false;
   RetryLoadTracks();
});