Skip to content

Commit

Permalink
Ios multiple ads fix (#21)
Browse files Browse the repository at this point in the history
* Changed c# code to send the adUnit InstanceID, and the iOS code to receive it.

* Changed the iOS plugin to properly send callbacks for correct AdUnit

* Removed events that are not being expected by the unity code

* Updated the iOS app to be in portrait

* Added the function to remove the NimbusManager from the dictionary (dealloc it) when the ad is destroyed or when an error occurs

* Changed delegate visibility to internal

* Removed unnecessary method

* Updated the sample app to use Nimbus SDK v1.10.2
  • Loading branch information
brugg authored Jun 23, 2021
1 parent b716174 commit 6090879
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 93 deletions.
37 changes: 19 additions & 18 deletions package/Runtime/Plugins/iOS/NimbusBinding.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,40 @@ void _initializeSDKWithPublisher(const char* publisher,
NSString* publishString = GetStringParam(publisher);
NSString* apiKeyString = GetStringParam(apikey);

[[NimbusManager shared] initializeNimbusSDKWithPublisher: publishString
apiKey: apiKeyString
enableSDKInTestMode: enableSDKInTestMode
enableUnityLogs: enableUnityLogs];
[NimbusManager initializeNimbusSDKWithPublisher: publishString
apiKey: apiKeyString
enableSDKInTestMode: enableSDKInTestMode
enableUnityLogs: enableUnityLogs];
}

void _showBannerAd(const char* position, float bannerFloor) {
void _showBannerAd(int adUnitInstanceId, const char* position, float bannerFloor) {
NSString* positionString = GetStringParam(position);
[[NimbusManager shared] showBannerAdWithPosition:positionString bannerFloor:bannerFloor];
[[NimbusManager nimbusManagerForAdUnityInstanceId:adUnitInstanceId] showBannerAdWithPosition:positionString
bannerFloor:bannerFloor];
}

void _showInterstitialAd(const char* position, float bannerFloor, float videoFloor, double closeButtonDelay) {
void _showInterstitialAd(int adUnitInstanceId, const char* position, float bannerFloor, float videoFloor, double closeButtonDelay) {
NSString* positionString = GetStringParam(position);
[[NimbusManager shared] showInterstitialAdWithPosition:positionString
bannerFloor:bannerFloor
videoFloor:videoFloor
closeButtonDelay:closeButtonDelay];
[[NimbusManager nimbusManagerForAdUnityInstanceId:adUnitInstanceId] showInterstitialAdWithPosition:positionString
bannerFloor:bannerFloor
videoFloor:videoFloor
closeButtonDelay:closeButtonDelay];
}

void _showRewardedVideoAd(const char* position, float videoFloor, double closeButtonDelay) {
void _showRewardedVideoAd(int adUnitInstanceId, const char* position, float videoFloor, double closeButtonDelay) {
NSString* positionString = GetStringParam(position);
[[NimbusManager shared] showRewardedVideoAdWithPosition:positionString
videoFloor:videoFloor
closeButtonDelay:closeButtonDelay];
[[NimbusManager nimbusManagerForAdUnityInstanceId:adUnitInstanceId] showRewardedVideoAdWithPosition:positionString
videoFloor:videoFloor
closeButtonDelay:closeButtonDelay];
}

void _setGDPRConsentString(const char* consent) {
NSString* consentString = GetStringParam(consent);
[[NimbusManager shared] setGDPRConsentStringWithConsent: consentString];
[NimbusManager setGDPRConsentStringWithConsent: consentString];
}

void _destroyAd() {
[[NimbusManager shared] destroyExistingAd];
void _destroyAd(int adUnitInstanceId) {
[[NimbusManager nimbusManagerForAdUnityInstanceId:adUnitInstanceId] destroyExistingAd];
}

}
108 changes: 77 additions & 31 deletions package/Runtime/Plugins/iOS/NimbusManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@ import NimbusKit

@objc public class NimbusManager: NSObject {

@objc public static let shared = NimbusManager()
private static var managerDictionary: [Int: NimbusManager] = [:]

private let kCallbackTarget = "NimbusIOSAdManager"
private let adUnitInstanceId: Int

private var nimbusAdManager: NimbusAdManager?
private var adController: AdController?

private var adView: AdView?

@objc public func initializeNimbusSDK(publisher: String,
apiKey: String,
enableSDKInTestMode: Bool,
enableUnityLogs: Bool) {
// MARK: - Class Functions

@objc public class func initializeNimbusSDK(publisher: String,
apiKey: String,
enableSDKInTestMode: Bool,
enableUnityLogs: Bool) {
Nimbus.shared.initialize(publisher: publisher, apiKey: apiKey)

Nimbus.shared.logLevel = enableUnityLogs ? .debug : .off
Expand All @@ -34,14 +36,35 @@ import NimbusKit
.forAuctionType(.static): NimbusStaticAdRenderer(),
.forAuctionType(.video): NimbusVideoAdRenderer()
]

NimbusAdManager.user = NimbusUser(age: 20, gender: .male)
}

@objc public func unityViewController() -> UIViewController? {
@objc public class func nimbusManager(forAdUnityInstanceId adUnityInstanceId: Int) -> NimbusManager {
guard let manager = managerDictionary[adUnityInstanceId] else {
let manager = NimbusManager(adUnitInstanceId: adUnityInstanceId)
managerDictionary[adUnityInstanceId] = manager
return manager
}
return manager
}

@objc public class func setGDPRConsentString(consent: String) {
var user = NimbusRequestManager.user ?? NimbusUser()
user.configureGdprConsent(didConsent: true, consentString: consent)
NimbusRequestManager.user = user
}

// MARK: - Private Functions

private init(adUnitInstanceId: Int) {
self.adUnitInstanceId = adUnitInstanceId
}

private func unityViewController() -> UIViewController? {
return UIApplication.shared.windows.first { $0.isKeyWindow }?.rootViewController
}

// MARK: - Public Functions

@objc public func showBannerAd(position: String, bannerFloor: Float) {
guard let viewController = unityViewController() else { return }

Expand Down Expand Up @@ -72,11 +95,12 @@ import NimbusKit
request.impressions[0].banner?.bidFloor = bannerFloor
request.impressions[0].video?.bidFloor = videoFloor


(Nimbus.shared.renderers[.forAuctionType(.video)] as? NimbusVideoAdRenderer)?.showMuteButton = false // false by default

nimbusAdManager = NimbusAdManager()
nimbusAdManager?.delegate = self
nimbusAdManager?.showRewardedAd(request: request,
nimbusAdManager?.showBlockingAd(request: request,
closeButtonDelay: closeButtonDelay,
adPresentingViewController: viewController)
}
Expand All @@ -96,16 +120,15 @@ import NimbusKit
adPresentingViewController: viewController)
}

@objc public func setGDPRConsentString(consent: String) {
var user = NimbusRequestManager.user ?? NimbusUser()
user.configureGdprConsent(didConsent: true, consentString: consent)
NimbusRequestManager.user = user
}

@objc public func destroyExistingAd() {
adController?.destroy()
adView?.removeFromSuperview()
adView = nil
removeReferenceFromManagerDictionary()
}

private func removeReferenceFromManagerDictionary() {
NimbusManager.managerDictionary.removeValue(forKey: adUnitInstanceId)
}

}
Expand All @@ -115,17 +138,37 @@ import NimbusKit
extension NimbusManager: NimbusAdManagerDelegate {

public func didCompleteNimbusRequest(request: NimbusRequest, ad: NimbusAd) {
// do nothing
let params: [String: Any] = [
"adUnitInstanceID": adUnitInstanceId,
"auctionId": ad.auctionId,
"bidRaw": ad.bidRaw,
"bidInCents": ad.bidInCents,
"network": ad.network,
"placementId": ad.placementId ?? ""
]

UnityBinding.sendMessage(methodName: "OnAdResponse", params: params)
}

public func didFailNimbusRequest(request: NimbusRequest, error: NimbusError) {
UnitySendMessage(kCallbackTarget, "OnError", error.localizedDescription);
let params: [String: Any] = [
"adUnitInstanceID": adUnitInstanceId,
"errorMessage": error.localizedDescription
]

UnityBinding.sendMessage(methodName: "OnError", params: params)
destroyExistingAd()
}

public func didRenderAd(request: NimbusRequest, ad: NimbusAd, controller: AdController) {
self.adController = controller
self.adController?.delegate = self
UnitySendMessage(kCallbackTarget, "OnAdRendered", "");

let params: [String: Any] = [
"adUnitInstanceID": adUnitInstanceId
]

UnityBinding.sendMessage(methodName: "OnAdResponse", params: params)
}

}
Expand All @@ -137,10 +180,8 @@ extension NimbusManager: AdControllerDelegate {
public func didReceiveNimbusEvent(controller: AdController, event: NimbusEvent) {
var method = "OnAdEvent", eventName = ""
switch event {
case .loaded:
eventName = "LOADED"
case .loadedCompanionAd(width: _, height: _):
return // Unity doesn't handle this event
case .loaded, .loadedCompanionAd(width: _, height: _), .firstQuartile, .midpoint, .thirdQuartile:
return // Unity doesn't handle these events
case .impression:
eventName = "IMPRESSION"
case .clicked:
Expand All @@ -149,26 +190,31 @@ extension NimbusManager: AdControllerDelegate {
eventName = "PAUSED"
case .resumed:
eventName = "RESUME"
case .firstQuartile:
eventName = "FIRST_QUARTILE"
case .midpoint:
eventName = "MIDPOINT"
case .thirdQuartile:
eventName = "THIRD_QUARTILE"
case .completed:
eventName = "COMPLETED"
case .destroyed:
eventName = "DESTROYED"
removeReferenceFromManagerDictionary()
@unknown default:
print("Ad Event not sent: \(event)")
return
}
UnitySendMessage(kCallbackTarget, method, eventName);

let params: [String: Any] = [
"adUnitInstanceID": adUnitInstanceId,
"eventName": eventName
]
UnityBinding.sendMessage(methodName: method, params: params)
}

/// Received an error for the ad
public func didReceiveNimbusError(controller: AdController, error: NimbusError) {
UnitySendMessage(kCallbackTarget, "OnError", error.localizedDescription);
let params: [String: Any] = [
"adUnitInstanceID": adUnitInstanceId,
"errorMessage": error.localizedDescription
]

UnityBinding.sendMessage(methodName: "OnError", params: params)
destroyExistingAd()
}
}
25 changes: 25 additions & 0 deletions package/Runtime/Plugins/iOS/UnityBinding.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// UnityBinding.swift
// Unity-iPhone
//
// Created by Bruno Bruggemann on 6/16/21.
//

import Foundation

class UnityBinding {

private static let kCallbackTarget = "NimbusIOSAdManager"

class func sendMessage(methodName: String, params: [String: Any]) {
do {
let jsonData = try JSONSerialization.data(withJSONObject: params, options: JSONSerialization.WritingOptions())
let jsonString = String(data: jsonData, encoding: .utf8)

UnitySendMessage(kCallbackTarget, methodName, jsonString);
} catch {
print("Error creating json object: \(error)")
return
}
}
}
37 changes: 37 additions & 0 deletions package/Runtime/Plugins/iOS/UnityBinding.swift.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 12 additions & 13 deletions package/Runtime/Scripts/Internal/IOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
// ReSharper disable CheckNamespace
namespace Nimbus.Runtime.Scripts.Internal {
public class IOS : NimbusAPI {
private static void OnDestroyIOSAd() {
_destroyAd();
private static void OnDestroyIOSAd(int adUnitInstanceId)
{
_destroyAd(adUnitInstanceId);
}

#region Declare external C interface
Expand All @@ -19,20 +20,20 @@ private static extern void _initializeSDKWithPublisher(string publisher,
bool enableUnityLogs);

[DllImport("__Internal")]
private static extern void _showBannerAd(string position, float bannerFloor);
private static extern void _showBannerAd(int adUnitInstanceId, string position, float bannerFloor);

[DllImport("__Internal")]
private static extern void _showInterstitialAd(string position, float bannerFloor, float videoFloor,
private static extern void _showInterstitialAd(int adUnitInstanceId, string position, float bannerFloor, float videoFloor,
double closeButtonDelay);

[DllImport("__Internal")]
private static extern void _showRewardedVideoAd(string position, float videoFloor, double closeButtonDelay);
private static extern void _showRewardedVideoAd(int adUnitInstanceId, string position, float videoFloor, double closeButtonDelay);

[DllImport("__Internal")]
private static extern void _setGDPRConsentString(string consent);

[DllImport("__Internal")]
private static extern void _destroyAd();
private static extern void _destroyAd(int adUnitInstanceId);

#endregion

Expand All @@ -53,22 +54,21 @@ internal override void InitializeSDK(ILogger logger, NimbusSDKConfiguration conf
}

internal override NimbusAdUnit LoadAndShowAd(ILogger logger, ref NimbusAdUnit nimbusAdUnit) {
_iOSAdManager.SetAdUnit(nimbusAdUnit);
_iOSAdManager.AddAdUnit(nimbusAdUnit);
nimbusAdUnit.OnDestroyIOSAd += OnDestroyIOSAd;

// iOS uses seconds

var closeButtonDelaySeconds = nimbusAdUnit.CloseButtonDelayInSeconds;
switch (nimbusAdUnit.AdType) {
case AdUnityType.Banner:
_showBannerAd(nimbusAdUnit.Position, nimbusAdUnit.BidFloors.BannerFloor);
_showBannerAd(nimbusAdUnit.InstanceID, nimbusAdUnit.Position, nimbusAdUnit.BidFloors.BannerFloor);
break;
case AdUnityType.Interstitial:
closeButtonDelaySeconds = 5;
_showInterstitialAd(nimbusAdUnit.Position, nimbusAdUnit.BidFloors.BannerFloor,
_showInterstitialAd(nimbusAdUnit.InstanceID, nimbusAdUnit.Position, nimbusAdUnit.BidFloors.BannerFloor,
nimbusAdUnit.BidFloors.VideoFloor, closeButtonDelaySeconds);
break;
case AdUnityType.Rewarded:
_showRewardedVideoAd(nimbusAdUnit.Position, nimbusAdUnit.BidFloors.VideoFloor,
_showRewardedVideoAd(nimbusAdUnit.InstanceID, nimbusAdUnit.Position, nimbusAdUnit.BidFloors.VideoFloor,
closeButtonDelaySeconds);
break;
default:
Expand All @@ -78,7 +78,6 @@ internal override NimbusAdUnit LoadAndShowAd(ILogger logger, ref NimbusAdUnit ni
return nimbusAdUnit;
}


internal override void SetGDPRConsentString(string consent) {
_setGDPRConsentString(consent);
}
Expand Down
Loading

0 comments on commit 6090879

Please sign in to comment.