From 8fa240b5167f0def487a41e15b70d5f685e95693 Mon Sep 17 00:00:00 2001 From: "a.blintsov" Date: Fri, 13 Feb 2026 22:29:49 +0800 Subject: [PATCH] Log ad revenue --- .../AppsFlyerSDK/AppsFlyer_UPL_Android.xml | 48 +++++++++++++ .../Private/AppsFlyerSDKBlueprint.cpp | 69 +++++++++++++++++++ .../Public/AppsFlyerSDKBlueprint.h | 29 ++++++++ 3 files changed, 146 insertions(+) diff --git a/AppsFlyerSDK/Source/AppsFlyerSDK/AppsFlyer_UPL_Android.xml b/AppsFlyerSDK/Source/AppsFlyerSDK/AppsFlyer_UPL_Android.xml index a1a2097..648e621 100644 --- a/AppsFlyerSDK/Source/AppsFlyerSDK/AppsFlyer_UPL_Android.xml +++ b/AppsFlyerSDK/Source/AppsFlyerSDK/AppsFlyer_UPL_Android.xml @@ -41,6 +41,14 @@ import com.appsflyer.internal.platform_extension.PluginInfo; import java.util.HashMap; import java.util.Map; + + import com.appsflyer.AFAdRevenueData; + import com.appsflyer.MediationNetwork; + import com.appsflyer.AppsFlyerLib; + + import java.util.Currency; + + import android.util.Log; @@ -92,6 +100,27 @@ AppsFlyerLib.getInstance().disableAppSetId(); } + public void afLogAdRevenue( + String monetizationNetwork, + int mediationNetwork, + double revenue, + String currency, + Map customData) + { + AFAdRevenueData adRevenueData = new AFAdRevenueData(monetizationNetwork, getAFMediationNetwork(mediationNetwork), currency, revenue); + + Map additionalParameters = new HashMap<>(); + + if(customData.containsKey("Country")) additionalParameters.put(AdRevenueScheme.COUNTRY, customData.get("Country")); + if(customData.containsKey("UnitID")) additionalParameters.put(AdRevenueScheme.AD_UNIT, customData.get("UnitID")); + if(customData.containsKey("AdType")) additionalParameters.put(AdRevenueScheme.AD_TYPE, customData.get("AdType")); + if(customData.containsKey("Placement")) additionalParameters.put(AdRevenueScheme.PLACEMENT, customData.get("Placement")); + + AppsFlyerLib.getInstance().logAdRevenue(adRevenueData, additionalParameters); + + Log.debug("AppsflyerLog Track ad revenue"); + } + // Deprecated public void afSetConsentData(boolean isGDPR, boolean hasConsentForDataUsage, boolean hasConsentForAdsPersonalization) { AppsFlyerConsent consent; @@ -117,6 +146,25 @@ AppsFlyerLib.getInstance().setConsentData(consent); } + + public MediationNetwork getAFMediationNetwork(int network){ + switch (network) { + case 0: return MediationNetwork.IRONSOURCE; + case 1: return MediationNetwork.APPLOVIN_MAX; + case 2: return MediationNetwork.GOOGLE_ADMOB; + case 3: return MediationNetwork.FYBER; + case 4: return MediationNetwork.APPODEAL; + case 5: return MediationNetwork.ADMOST; + case 6: return MediationNetwork.TOPON; + case 7: return MediationNetwork.TRADPLUS; + case 8: return MediationNetwork.YANDEX; + case 9: return MediationNetwork.CHARTBOOST; + case 10: return MediationNetwork.UNITY; + case 11: return MediationNetwork.CUSTOM_MEDIATION; + case 12: return MediationNetwork.DIRECT_MONETIZATION_NETWORK; + default: return MediationNetwork.CUSTOM_MEDIATION; + } + } diff --git a/AppsFlyerSDK/Source/AppsFlyerSDK/Private/AppsFlyerSDKBlueprint.cpp b/AppsFlyerSDK/Source/AppsFlyerSDK/Private/AppsFlyerSDKBlueprint.cpp index c0cb119..ca211e6 100755 --- a/AppsFlyerSDK/Source/AppsFlyerSDK/Private/AppsFlyerSDKBlueprint.cpp +++ b/AppsFlyerSDK/Source/AppsFlyerSDK/Private/AppsFlyerSDKBlueprint.cpp @@ -200,6 +200,26 @@ static void onAppOpenAttribution(NSDictionary *attributionData) { static void onAppOpenAttributionFailure(NSString *error) { NSLog(@"%@", error); } + +static AppsFlyerAdRevenueMediationNetworkType mediationNetworkIOSTypeFromEnum(EAFMediationNetwork network) { + switch (network) + { + case EAFMediationNetwork::Ironsource: return AppsFlyerAdRevenueMediationNetworkTypeIronSource; + case EAFMediationNetwork::Applovinmax: return AppsFlyerAdRevenueMediationNetworkTypeApplovinMax; + case EAFMediationNetwork::Googleadmob: return AppsFlyerAdRevenueMediationNetworkTypeGoogleAdMob; + case EAFMediationNetwork::Fyber: return AppsFlyerAdRevenueMediationNetworkTypeFyber; + case EAFMediationNetwork::Appodeal: return AppsFlyerAdRevenueMediationNetworkTypeAppodeal; + case EAFMediationNetwork::Admost: return AppsFlyerAdRevenueMediationNetworkTypeAdmost; + case EAFMediationNetwork::Topon: return AppsFlyerAdRevenueMediationNetworkTypeTopon; + case EAFMediationNetwork::Tradplus: return AppsFlyerAdRevenueMediationNetworkTypeTradplus; + case EAFMediationNetwork::Yandex: return AppsFlyerAdRevenueMediationNetworkTypeYandex; + case EAFMediationNetwork::Chartboost: return AppsFlyerAdRevenueMediationNetworkTypeChartBoost; + case EAFMediationNetwork::Unity: return AppsFlyerAdRevenueMediationNetworkTypeUnity; + case EAFMediationNetwork::CustomMediation: return AppsFlyerAdRevenueMediationNetworkTypeCustom; + case EAFMediationNetwork::DirectMonetizationNetwork: return AppsFlyerAdRevenueMediationNetworkTypeDirectMonetization; + default: return AppsFlyerAdRevenueMediationNetworkTypeCustom; + } +} #endif UAppsFlyerSDKBlueprint::UAppsFlyerSDKBlueprint(const FObjectInitializer &ObjectInitializer) : Super(ObjectInitializer) {} @@ -649,6 +669,55 @@ void UAppsFlyerSDKBlueprint::SetConsentDataTOptional( ); } +void UAppsFlyerSDKBlueprint::logAdRevenue(FString monetizationNetwork, EAFMediationNetwork mediationNetwork, float revenue, FString currency, TMap extraData) +{ +#if PLATFORM_ANDROID + JNIEnv* env = FAndroidApplication::GetJavaEnv(); + jmethodID method = FJavaWrapper::FindMethod(env, + FJavaWrapper::GameActivityClassID, + "afLogAdRevenue", + "(Ljava/lang/String;IDLjava/lang/String;Ljava/util/Map;)V", false); + + jclass mapClass = env->FindClass("java/util/HashMap"); + jmethodID mapConstructor = env->GetMethodID(mapClass, "", "()V"); + jobject map = env->NewObject(mapClass, mapConstructor); + jmethodID putMethod = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + for (const TPair& pair : extraData) { + env->CallObjectMethod(map, putMethod, env->NewStringUTF(TCHAR_TO_UTF8(*pair.Key)), env->NewStringUTF(TCHAR_TO_UTF8(*pair.Value))); + } + + jstring jNetworkName = env->NewStringUTF(TCHAR_TO_UTF8(*monetizationNetwork)); + jint jMediation = static_cast(mediationNetwork); + jstring jCurrency = env->NewStringUTF(TCHAR_TO_UTF8(*currency)); + + FJavaWrapper::CallVoidMethod(env, FJavaWrapper::GameActivityThis, method, jNetworkName, jMediation, revenue, jCurrency, map); + + env->DeleteLocalRef(jNetworkName); + env->DeleteLocalRef(jCurrency); +#elif PLATFORM_IOS + dispatch_async(dispatch_get_main_queue(), ^ { + AFAdRevenueData* AdRevenue = [[AFAdRevenueData alloc] + initWithMonetizationNetwork: monetizationNetwork.GetNSString() + mediationNetwork: mediationNetworkIOSTypeFromEnum(mediationNetwork) + currencyIso4217Code: currency.GetNSString() + eventRevenue: [NSNumber numberWithFloat: revenue] + ]; + + NSMutableDictionary* additionalParameters = [[NSMutableDictionary alloc] init]; + if (extraData.Contains("Country")) [additionalParameters setValue:extraData["Country"].GetNSString() forKey:kAppsFlyerAdRevenueCountry]; + if (extraData.Contains("AdType")) [additionalParameters setValue:extraData["AdType"].GetNSString() forKey:kAppsFlyerAdRevenueAdType]; + if (extraData.Contains("UnitID")) [additionalParameters setValue:extraData["UnitID"].GetNSString() forKey:kAppsFlyerAdRevenueAdUnit]; + if (extraData.Contains("Placement")) [additionalParameters setValue:extraData["Placement"].GetNSString() forKey:kAppsFlyerAdRevenuePlacement]; + + [[AppsFlyerLib shared] logAdRevenue:AdRevenue additionalParameters:additionalParameters]; + }); +#else + return; +#endif + + UE_LOG(LogAppsFlyerSDKBlueprint, Log, TEXT("Log ad revenue")); +} + void UAppsFlyerSDKBlueprint::ValidateAndLogInAppPurchase( const FAFSDKPurchaseDetails& PurchaseDetails, const TMap& PurchaseAdditionalDetails) diff --git a/AppsFlyerSDK/Source/AppsFlyerSDK/Public/AppsFlyerSDKBlueprint.h b/AppsFlyerSDK/Source/AppsFlyerSDK/Public/AppsFlyerSDKBlueprint.h index e93b004..83479de 100755 --- a/AppsFlyerSDK/Source/AppsFlyerSDK/Public/AppsFlyerSDKBlueprint.h +++ b/AppsFlyerSDK/Source/AppsFlyerSDK/Public/AppsFlyerSDKBlueprint.h @@ -30,6 +30,24 @@ enum class EAFValidateAndLogStatus : uint8 Error UMETA(DisplayName = "Error") }; +UENUM(BlueprintType) +enum class EAFMediationNetwork : uint8 +{ + Ironsource UMETA(DisplayName = "IronSource"), + Applovinmax UMETA(DisplayName = "ApplovinMax"), + Googleadmob UMETA(DisplayName = "GoogleAdmob"), + Fyber UMETA(DisplayName = "Fyber"), + Appodeal UMETA(DisplayName = "Appodeal"), + Admost UMETA(DisplayName = "Admost"), + Topon UMETA(DisplayName = "Topon"), + Tradplus UMETA(DisplayName = "TradPlus"), + Yandex UMETA(DisplayName = "Yandex"), + Chartboost UMETA(DisplayName = "Chartboost"), + Unity UMETA(DisplayName = "Unity"), + CustomMediation UMETA(DisplayName = "Custom Mediation"), + DirectMonetizationNetwork UMETA(DisplayName = "Direct Monetization Network") +}; + USTRUCT(BlueprintType) struct FAFSDKPurchaseDetails { @@ -137,6 +155,17 @@ class APPSFLYERSDK_API UAppsFlyerSDKBlueprint : public UBlueprintFunctionLibrary TOptional HasConsentForAdStorage ); + /*! + * Log revenue from ads + * @param monetizationNetwork - Monetization network the ad was shown by, such as AdMob, UnityAds, Facebook e.t.c. + * @param mediationNetwork - Mediation network. + * @param revenue - Ad revenue (in millions) + * @param currency - Currency code + * @param extraData - Optional extra info for ad revenue. Can have "Country", "UnitID", "AdType" and "Placement" keys. + */ + UFUNCTION(BlueprintCallable, Category = AppsFlyerSDK, DisplayName = "AppsFlyerSDK log ad revenue") + static void logAdRevenue(FString monetizationNetwork, EAFMediationNetwork mediationNetwork, float revenue, FString currency, TMap extraData); + /*! * Validates and logs an in-app purchase using the updated VAL V2 flow. * This method should be called after a successful transaction.