You've already forked Commercialization.tapadn
Add iOS support for TapADN package
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#import "DirichletMediationUnityBridge.h"
|
||||
#import <DirichletMediationSDK/DirichletMediationSDK.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||||
|
||||
// Unity callback interface
|
||||
extern "C" void UnitySendMessage(const char* obj, const char* method, const char* msg);
|
||||
@@ -119,6 +120,88 @@ static NSDictionary* ParseExtras(const char* extrasJson) {
|
||||
return error ? nil : dict;
|
||||
}
|
||||
|
||||
static void SendLoadErrorToUnity(NSString* handleId, NSString* adType, NSError* error, NSString* fallbackMessage) {
|
||||
NSInteger code = error ? error.code : -1;
|
||||
NSString* message = error.localizedDescription ?: fallbackMessage ?: @"Unknown error";
|
||||
NSDictionary* errorData = @{
|
||||
@"code": @(code),
|
||||
@"message": message
|
||||
};
|
||||
SendLoadCallbackToUnity(handleId, @"load_error", adType, errorData);
|
||||
}
|
||||
|
||||
static void SendShowErrorToUnity(NSString* handleId, NSString* adType, NSInteger code, NSString* message) {
|
||||
NSDictionary* errorData = @{
|
||||
@"code": @(code),
|
||||
@"message": message ?: @"Ad failed to show"
|
||||
};
|
||||
SendEventToUnity(handleId, @"show_error", adType ?: @"unknown", errorData);
|
||||
}
|
||||
|
||||
static UIViewController* TopViewController(UIViewController* rootViewController) {
|
||||
UIViewController* top = rootViewController;
|
||||
while (top.presentedViewController) {
|
||||
top = top.presentedViewController;
|
||||
}
|
||||
|
||||
if ([top isKindOfClass:[UINavigationController class]]) {
|
||||
return TopViewController(((UINavigationController*)top).visibleViewController);
|
||||
}
|
||||
|
||||
if ([top isKindOfClass:[UITabBarController class]]) {
|
||||
return TopViewController(((UITabBarController*)top).selectedViewController);
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
static UIViewController* CurrentRootViewController(void) {
|
||||
UIWindow* keyWindow = nil;
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
for (UIScene* scene in [UIApplication sharedApplication].connectedScenes) {
|
||||
if (scene.activationState != UISceneActivationStateForegroundActive ||
|
||||
![scene isKindOfClass:[UIWindowScene class]]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UIWindowScene* windowScene = (UIWindowScene*)scene;
|
||||
for (UIWindow* window in windowScene.windows) {
|
||||
if (window.isKeyWindow) {
|
||||
keyWindow = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyWindow) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keyWindow) {
|
||||
keyWindow = [UIApplication sharedApplication].keyWindow;
|
||||
}
|
||||
|
||||
return TopViewController(keyWindow.rootViewController);
|
||||
}
|
||||
|
||||
static NSString* AdTypeForObject(id ad) {
|
||||
if ([ad isKindOfClass:[DRMRewardVideoAd class]]) {
|
||||
return @"reward_video";
|
||||
}
|
||||
if ([ad isKindOfClass:[DRMInterstitialAd class]]) {
|
||||
return @"interstitial";
|
||||
}
|
||||
if ([ad isKindOfClass:[DRMBannerAd class]]) {
|
||||
return @"banner";
|
||||
}
|
||||
if ([ad isKindOfClass:[DRMSplashAd class]]) {
|
||||
return @"splash";
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
#pragma mark - Ad Instance Manager
|
||||
|
||||
@interface DirichletMediationInstanceManager : NSObject
|
||||
@@ -336,6 +419,7 @@ bool DirichletMediationUnityBridge_Initialize(
|
||||
// Check if SDK is already initialized
|
||||
if ([DirichletMediation isInitialized]) {
|
||||
NSLog(@"[DirichletMediationUnityBridge] SDK already initialized");
|
||||
SendInitCallbackToUnity(YES, nil, @"already_initialized");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -388,8 +472,29 @@ bool DirichletMediationUnityBridge_Initialize(
|
||||
}
|
||||
|
||||
void DirichletMediationUnityBridge_RequestPermissionIfNeeded(void) {
|
||||
// iOS 14+ ATT permission is handled internally by the SDK
|
||||
NSLog(@"[DirichletMediationUnityBridge] RequestPermissionIfNeeded called");
|
||||
|
||||
if (@available(iOS 14.0, *)) {
|
||||
void (^requestBlock)(void) = ^{
|
||||
ATTrackingManagerAuthorizationStatus status = [ATTrackingManager trackingAuthorizationStatus];
|
||||
if (status != ATTrackingManagerAuthorizationStatusNotDetermined) {
|
||||
NSLog(@"[DirichletMediationUnityBridge] ATT status already determined: %lu", (unsigned long)status);
|
||||
return;
|
||||
}
|
||||
|
||||
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
||||
NSLog(@"[DirichletMediationUnityBridge] ATT request completed with status: %lu", (unsigned long)status);
|
||||
}];
|
||||
};
|
||||
|
||||
if ([NSThread isMainThread]) {
|
||||
requestBlock();
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), requestBlock);
|
||||
}
|
||||
} else {
|
||||
NSLog(@"[DirichletMediationUnityBridge] ATT is not required below iOS 14");
|
||||
}
|
||||
}
|
||||
|
||||
const char* DirichletMediationUnityBridge_GetSdkVersion(void) {
|
||||
@@ -438,11 +543,7 @@ const char* DirichletMediationUnityBridge_LoadRewardVideoAd(long long spaceId, c
|
||||
SendLoadCallbackToUnity(handleId, @"load_success", @"reward_video", nil);
|
||||
} else {
|
||||
NSLog(@"[DirichletMediationUnityBridge] RewardVideoAd load failed: %@", error.localizedDescription);
|
||||
NSDictionary* errorData = @{
|
||||
@"code": @(error.code),
|
||||
@"message": error.localizedDescription ?: @"Unknown error"
|
||||
};
|
||||
SendLoadCallbackToUnity(handleId, @"load_error", @"reward_video", errorData);
|
||||
SendLoadErrorToUnity(handleId, @"reward_video", error, @"RewardVideoAd load failed");
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -475,11 +576,7 @@ const char* DirichletMediationUnityBridge_LoadInterstitialAd(long long spaceId,
|
||||
SendLoadCallbackToUnity(handleId, @"load_success", @"interstitial", nil);
|
||||
} else {
|
||||
NSLog(@"[DirichletMediationUnityBridge] InterstitialAd load failed: %@", error.localizedDescription);
|
||||
NSDictionary* errorData = @{
|
||||
@"code": @(error.code),
|
||||
@"message": error.localizedDescription ?: @"Unknown error"
|
||||
};
|
||||
SendLoadCallbackToUnity(handleId, @"load_error", @"interstitial", errorData);
|
||||
SendLoadErrorToUnity(handleId, @"interstitial", error, @"InterstitialAd load failed");
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -520,11 +617,7 @@ const char* DirichletMediationUnityBridge_LoadBannerAd(long long spaceId, const
|
||||
SendLoadCallbackToUnity(handleId, @"load_success", @"banner", nil);
|
||||
} else {
|
||||
NSLog(@"[DirichletMediationUnityBridge] BannerAd load failed: %@", error.localizedDescription);
|
||||
NSDictionary* errorData = @{
|
||||
@"code": @(error.code),
|
||||
@"message": error.localizedDescription ?: @"Unknown error"
|
||||
};
|
||||
SendLoadCallbackToUnity(handleId, @"load_error", @"banner", errorData);
|
||||
SendLoadErrorToUnity(handleId, @"banner", error, @"BannerAd load failed");
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -565,11 +658,7 @@ const char* DirichletMediationUnityBridge_LoadSplashAd(long long spaceId, const
|
||||
SendLoadCallbackToUnity(handleId, @"load_success", @"splash", nil);
|
||||
} else {
|
||||
NSLog(@"[DirichletMediationUnityBridge] SplashAd load failed: %@", error.localizedDescription);
|
||||
NSDictionary* errorData = @{
|
||||
@"code": @(error.code),
|
||||
@"message": error.localizedDescription ?: @"Unknown error"
|
||||
};
|
||||
SendLoadCallbackToUnity(handleId, @"load_error", @"splash", errorData);
|
||||
SendLoadErrorToUnity(handleId, @"splash", error, @"SplashAd load failed");
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -584,12 +673,16 @@ bool DirichletMediationUnityBridge_ShowAd(const char* handleId, const char* extr
|
||||
NSLog(@"[DirichletMediationUnityBridge] ShowAd failed: Ad not found for handle %@", nsHandleId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure show is always called on main thread (aligned with Ad Unity implementation)
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIViewController* rootVC = [[[UIApplication sharedApplication] keyWindow] rootViewController];
|
||||
|
||||
__block BOOL didStartShow = NO;
|
||||
NSString* adType = AdTypeForObject(ad);
|
||||
NSDictionary* extrasDict = ParseExtras(extras);
|
||||
|
||||
void (^showBlock)(void) = ^{
|
||||
UIViewController* rootVC = CurrentRootViewController();
|
||||
if (!rootVC) {
|
||||
NSLog(@"[DirichletMediationUnityBridge] ShowAd failed: Root view controller not found");
|
||||
SendShowErrorToUnity(nsHandleId, adType, -2, @"Root view controller not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -597,52 +690,86 @@ bool DirichletMediationUnityBridge_ShowAd(const char* handleId, const char* extr
|
||||
DRMRewardVideoAd* rewardAd = (DRMRewardVideoAd*)ad;
|
||||
if ([rewardAd isReady]) {
|
||||
[rewardAd showFromViewController:rootVC];
|
||||
didStartShow = YES;
|
||||
NSLog(@"[DirichletMediationUnityBridge] Showing reward video ad: %@", nsHandleId);
|
||||
} else {
|
||||
SendShowErrorToUnity(nsHandleId, @"reward_video", -3, @"Reward video ad is not ready");
|
||||
}
|
||||
} else if ([ad isKindOfClass:[DRMInterstitialAd class]]) {
|
||||
DRMInterstitialAd* interstitialAd = (DRMInterstitialAd*)ad;
|
||||
if ([interstitialAd isReady]) {
|
||||
[interstitialAd showFromViewController:rootVC];
|
||||
didStartShow = YES;
|
||||
NSLog(@"[DirichletMediationUnityBridge] Showing interstitial ad: %@", nsHandleId);
|
||||
} else {
|
||||
SendShowErrorToUnity(nsHandleId, @"interstitial", -3, @"Interstitial ad is not ready");
|
||||
}
|
||||
} else if ([ad isKindOfClass:[DRMBannerAd class]]) {
|
||||
DRMBannerAd* bannerAd = (DRMBannerAd*)ad;
|
||||
UIView* bannerView = bannerAd.view;
|
||||
if (bannerView) {
|
||||
// Banner 广告需要将 view 添加到视图控制器上
|
||||
// 注意:Unity 侧需要通过 Unity UI 系统来处理 Banner 视图
|
||||
// 这里我们发送一个事件通知 Unity 侧,让 Unity 侧来处理视图的展示
|
||||
// 或者直接将视图添加到根视图控制器上(临时方案)
|
||||
[bannerView removeFromSuperview];
|
||||
[rootVC.view addSubview:bannerView];
|
||||
bannerView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
// 设置约束,让 Banner 显示在底部
|
||||
|
||||
NSInteger baseline = [extrasDict[@"banner_baseline"] integerValue];
|
||||
CGFloat offset = extrasDict[@"banner_offset"] ? [extrasDict[@"banner_offset"] floatValue] : 0;
|
||||
NSLayoutYAxisAnchor* verticalAnchor = baseline == 0
|
||||
? rootVC.view.safeAreaLayoutGuide.topAnchor
|
||||
: rootVC.view.safeAreaLayoutGuide.bottomAnchor;
|
||||
NSLayoutConstraint* verticalConstraint = baseline == 0
|
||||
? [bannerView.topAnchor constraintEqualToAnchor:verticalAnchor constant:offset]
|
||||
: [bannerView.bottomAnchor constraintEqualToAnchor:verticalAnchor constant:-offset];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[bannerView.leadingAnchor constraintEqualToAnchor:rootVC.view.leadingAnchor],
|
||||
[bannerView.trailingAnchor constraintEqualToAnchor:rootVC.view.trailingAnchor],
|
||||
[bannerView.bottomAnchor constraintEqualToAnchor:rootVC.view.safeAreaLayoutGuide.bottomAnchor],
|
||||
[bannerView.centerXAnchor constraintEqualToAnchor:rootVC.view.centerXAnchor],
|
||||
[bannerView.widthAnchor constraintLessThanOrEqualToAnchor:rootVC.view.widthAnchor],
|
||||
verticalConstraint,
|
||||
[bannerView.heightAnchor constraintEqualToConstant:bannerAd.size.height > 0 ? bannerAd.size.height : 50]
|
||||
]];
|
||||
didStartShow = YES;
|
||||
NSLog(@"[DirichletMediationUnityBridge] Showing banner ad: %@", nsHandleId);
|
||||
} else {
|
||||
NSLog(@"[DirichletMediationUnityBridge] Banner ad view not available: %@", nsHandleId);
|
||||
SendShowErrorToUnity(nsHandleId, @"banner", -4, @"Banner ad view not available");
|
||||
}
|
||||
} else if ([ad isKindOfClass:[DRMSplashAd class]]) {
|
||||
DRMSplashAd* splashAd = (DRMSplashAd*)ad;
|
||||
if ([splashAd isReady]) {
|
||||
[splashAd showFromViewController:rootVC];
|
||||
didStartShow = YES;
|
||||
NSLog(@"[DirichletMediationUnityBridge] Showing splash ad: %@", nsHandleId);
|
||||
} else {
|
||||
SendShowErrorToUnity(nsHandleId, @"splash", -3, @"Splash ad is not ready");
|
||||
}
|
||||
} else {
|
||||
NSLog(@"[DirichletMediationUnityBridge] ShowAd failed: Ad not ready or unknown type");
|
||||
SendShowErrorToUnity(nsHandleId, @"unknown", -5, @"Unknown ad type");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if ([NSThread isMainThread]) {
|
||||
showBlock();
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), showBlock);
|
||||
}
|
||||
|
||||
return true;
|
||||
return didStartShow;
|
||||
}
|
||||
|
||||
void DirichletMediationUnityBridge_DestroyAd(const char* handleId) {
|
||||
NSString* nsHandleId = CreateNSString(handleId);
|
||||
NSLog(@"[DirichletMediationUnityBridge] Destroying ad: %@", nsHandleId);
|
||||
|
||||
id ad = [[DirichletMediationInstanceManager shared] adForHandle:nsHandleId];
|
||||
if ([ad isKindOfClass:[DRMBannerAd class]]) {
|
||||
DRMBannerAd* bannerAd = (DRMBannerAd*)ad;
|
||||
if (bannerAd.view.superview) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[bannerAd.view removeFromSuperview];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Remove ad instance
|
||||
[[DirichletMediationInstanceManager shared] removeAdForHandle:nsHandleId];
|
||||
@@ -679,4 +806,3 @@ bool DirichletMediationUnityBridge_IsAdValid(const char* handleId) {
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user