diff --git a/.github/workflows/build-apps-workflow.yml b/.github/workflows/build-apps-workflow.yml index 8e88e8a9..01eb0270 100644 --- a/.github/workflows/build-apps-workflow.yml +++ b/.github/workflows/build-apps-workflow.yml @@ -5,20 +5,27 @@ on: jobs: Build-RN-android: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: install react-native-appsflyer on an Android app - run: | - cd demos/appsflyer-react-native-app - yarn install - yarn add ../../ --save - - name: Build apk - run: | - cd demos/appsflyer-react-native-app/android - chmod +x ./gradlew - ./gradlew assembleRelease - + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up JDK 17 + uses: actions/setup-java@v2 + with: + java-version: '17' + distribution: 'adopt' + + - name: install react-native-appsflyer on an Android app + run: | + cd demos/appsflyer-react-native-app + yarn install + yarn add ../../ --save + + - name: Build apk + run: | + cd demos/appsflyer-react-native-app/android + chmod +x ./gradlew + ./gradlew assembleRelease # Build-RN-ios: # runs-on: macos-latest # steps: diff --git a/.github/workflows/scripts/updateReadme.sh b/.github/workflows/scripts/updateReadme.sh index d2a5dc32..23c706e3 100755 --- a/.github/workflows/scripts/updateReadme.sh +++ b/.github/workflows/scripts/updateReadme.sh @@ -1,6 +1,6 @@ #!/bin/bash -ios_sdk_version=$(cat react-native-appsflyer.podspec | grep '\'AppsFlyerFramework\' | grep -Eo '[0-9].[0-9]+.[0-9]+') -android_sdk_version=$(cat android/build.gradle | grep 'com.appsflyer:af-android-sdk' | grep -Eo '[0-9].[0-9]+.[0-9]+') -sed -i -e -r "s/Android AppsFlyer SDK \*\*v[0-9].[0-9]+.[0-9]+\*\*/Android AppsFlyer SDK \*\*v$android_sdk_version\*\*/g" README.md -sed -i -e -r "s/iOS AppsFlyer SDK \*\*v[0-9].[0-9]+.[0-9]+\*\*/iOS AppsFlyer SDK \*\*v$ios_sdk_version\*\*/g" README.md \ No newline at end of file +ios_sdk_version=$(cat react-native-appsflyer.podspec | grep '\'AppsFlyerFramework\' | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+') +android_sdk_version=$(cat android/build.gradle | grep 'com.appsflyer:af-android-sdk' | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+') +sed -i -r "s/Android AppsFlyer SDK \*\*v[0-9]+\.[0-9]+\.[0-9]+\*\*/Android AppsFlyer SDK \*\*v$android_sdk_version\*\*/g" README.md +sed -i -r "s/iOS AppsFlyer SDK \*\*v[0-9]+\.[0-9]+\.[0-9]+\*\*/iOS AppsFlyer SDK \*\*v$ios_sdk_version\*\*/g" README.md diff --git a/.gitignore b/.gitignore index 8cfdc82a..ec07aad8 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,5 @@ demos/appsflyer-expo-app/android demos/appsflyer-expo-app/.expo demos/appsflyer-expo-app/node_modules demos/appsflyer-expo-app/yarn.lock + +demos/appsflyer-react-native-app/ios/AppsFlyerExample.xcodeproj/project.pbxproj diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f4c90ff..a0741ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 6.15.1 + Release date: *2024-09-15* + +- React Native >> Update Plugin to v6.15.1 +- React native plugin >> UDL failed deferred deep linking + ## 6.14.3 Release date: *2024-04-28* diff --git a/Docs/RN_API.md b/Docs/RN_API.md index 9ac21ca4..64eeb6cb 100644 --- a/Docs/RN_API.md +++ b/Docs/RN_API.md @@ -37,6 +37,7 @@ The list of available methods for this plugin is described below. - [disableAdvertisingIdentifier](#disableAdvertisingIdentifier) - [enableTCFDataCollection](#enableTCFDataCollection) - [setConsentData](#setConsentData) + - [logAdRevenue](#logAdRevenue) - [Android Only APIs](#android-only-apis) - [setCollectAndroidID](#setcollectandroidid) - [setCollectIMEI](#setcollectimei) @@ -797,6 +798,45 @@ let GDPRUser = AppsFlyerConsent.forGDPRUser(true, false); appsFlyer.setConsentData(nonGDPRUser /**or**/ GDPRUser); ``` +### logAdRevenue - Since 6.15.1 +`logAdRevenue(data: AFAdRevenueData): void` + +Use this method to log your ad revenue.
+By attributing ad revenue, app owners gain the complete view of user LTV and campaign ROI. +Ad revenue is generated by displaying ads on rewarded videos, offer walls, interstitials, and banners in an app. + +#### Parameters + +| Param | Type | +| -------------- | ---------------------------------------------------------- | +| **`data`** | `AFAdRevenueData` | + +#### Usage Example for React Native: + +```javascript +const adRevenueData = { + monetizationNetwork: 'AF-AdNetwork', + mediationNetwork: MEDIATION_NETWORK.IRONSOURCE, + currencyIso4217Code: 'USD', + revenue: 1.23, + additionalParameters: { + customParam1: 'value1', + customParam2: 'value2', + } +}; + +appsFlyer.logAdRevenue(adRevenueData); +``` + +Here's how you use `appsFlyer.logAdRevenue` within a React Native app: + +1. Prepare the `adRevenueData` object as shown, including any additional parameters you wish to track along with the ad revenue event. +2. Call the `appsFlyer.logAdRevenue` method with the `adRevenueData` object. + +By passing all the required fields in `AFAdRevenueData`, you help ensure accurate tracking within the AppsFlyer platform. This enables you to analyze your ad revenue alongside other user acquisition data to optimize your app's overall monetization strategy. + +**Note:** The `additionalParameters` object is optional. You can add any additional data you want to log with the ad revenue event in this object. This can be useful for detailed analytics or specific event tracking later on. Make sure that the custom parameters follow the data types and structures specified by AppsFlyer in their documentation. + ## Android Only APIs ### setCollectAndroidID diff --git a/README.md b/README.md index 13cecf0d..60091f8e 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ ## ❗❗ Breaking changes when updating to v6.x.x❗❗ +- From version `6.15.1`, upgraded to targetSDKVersion 34, Java 17, and Gradle 8.7 in [AppsFlyer Android SDK v6.15.1](https://support.appsflyer.com/hc/en-us/articles/115001256006-AppsFlyer-Android-SDK-release-notes). + +- From version `6.15.1`, iOS Minimum deployment target is set to 12.0. + - From version `6.3.0`, we use `xcframework` for iOS platform. Then you need to use cocoapods version >= 1.10 - From version `6.2.30`, `logCrossPromotionAndOpenStore` api will register as `af_cross_promotion` instead of `af_app_invites` in your dashboard.
diff --git a/android/build.gradle b/android/build.gradle index 7d44b321..47b22e87 100755 --- a/android/build.gradle +++ b/android/build.gradle @@ -12,7 +12,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' + classpath 'com.android.tools.build:gradle:7.2.2' } } @@ -20,12 +20,12 @@ buildscript { apply plugin: 'com.android.library' android { - compileSdkVersion safeExtGet('compileSdkVersion', 28) - buildToolsVersion safeExtGet('buildToolsVersion', '29.0.2') + compileSdkVersion safeExtGet('compileSdkVersion', 34) + buildToolsVersion safeExtGet('buildToolsVersion', '34.0.0') defaultConfig { minSdkVersion safeExtGet('minSdkVersion', 16) - targetSdkVersion safeExtGet('targetSdkVersion', 28) + targetSdkVersion safeExtGet('targetSdkVersion', 34) versionCode 1 versionName "1.0" ndk { @@ -54,5 +54,5 @@ repositories { dependencies { implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}" implementation "com.android.installreferrer:installreferrer:${safeExtGet('installReferrerVersion', '2.1')}" - api "com.appsflyer:af-android-sdk:${safeExtGet('appsflyerVersion', '6.14.0')}" + api "com.appsflyer:af-android-sdk:${safeExtGet('appsflyerVersion', '6.15.1')}" } diff --git a/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java b/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java index 094ccaf7..4e88d25f 100755 --- a/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java +++ b/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java @@ -6,7 +6,7 @@ public class RNAppsFlyerConstants { - final static String PLUGIN_VERSION = "6.14.3"; + final static String PLUGIN_VERSION = "6.15.1"; final static String NO_DEVKEY_FOUND = "No 'devKey' found or its empty"; final static String UNKNOWN_ERROR = "AF Unknown Error"; final static String SUCCESS = "Success"; @@ -52,5 +52,11 @@ public class RNAppsFlyerConstants { final static String VALIDATE_SUCCESS = "In-App Purchase Validation success"; final static String VALIDATE_FAILED = "In-App Purchase Validation failed with error: "; + final static String MONETIZATION_NETWORK = "monetizationNetwork"; + final static String CURRENCY_ISO4217_CODE = "currencyIso4217Code"; + final static String AF_REVENUE = "revenue"; + final static String AF_MEDIATION_NETWORK = "mediationNetwork"; + final static String AF_ADDITIONAL_PARAMETERS = "additionalParameters"; + } diff --git a/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java b/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java index 90989a67..3892ba5d 100755 --- a/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java +++ b/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java @@ -31,6 +31,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableType; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.modules.core.DeviceEventManagerModule; @@ -362,6 +363,59 @@ public void onError(int i, @NonNull String s) { } } +@ReactMethod + public void logAdRevenue(ReadableMap adRevenueDictionary) { + if (adRevenueDictionary == null || !adRevenueDictionary.keySetIterator().hasNextKey()) { + Log.d("AppsFlyer", "adRevenueData is missing, the data is mandatory to use this API."); + return; + } + + String monetizationNetwork = adRevenueDictionary.getString(MONETIZATION_NETWORK); + if (monetizationNetwork == null) { + Log.d("AppsFlyer", "monetizationNetwork is missing"); + return; + } + + String currencyIso4217Code = adRevenueDictionary.getString(CURRENCY_ISO4217_CODE); + if (currencyIso4217Code == null) { + Log.d("AppsFlyer", "currencyIso4217Code is missing"); + return; + } + + if (!adRevenueDictionary.hasKey(AF_REVENUE) || adRevenueDictionary.getType(AF_REVENUE) != ReadableType.Number) { + Log.d("AppsFlyer", "revenue is missing or not a number"); + return; + } + double revenue = adRevenueDictionary.getDouble(AF_REVENUE); + + ReadableMap additionalParameters = null; + if (adRevenueDictionary.hasKey(AF_ADDITIONAL_PARAMETERS) && adRevenueDictionary.getType(AF_ADDITIONAL_PARAMETERS) == ReadableType.Map) { + additionalParameters = adRevenueDictionary.getMap(AF_ADDITIONAL_PARAMETERS); + } + + String mediationNetworkValue = adRevenueDictionary.getString(AF_MEDIATION_NETWORK); + if (mediationNetworkValue == null || mediationNetworkValue.isEmpty()) { + Log.d("AppsFlyer", "mediationNetwork is missing"); + return; + } + + MediationNetwork mediationNetwork = MediationNetwork.valueOf(mediationNetworkValue.toUpperCase()); + if (mediationNetwork == null) { + Log.d("AppsFlyer", "Invalid mediation network"); + return; + } + + AFAdRevenueData adRevenueData = new AFAdRevenueData( + monetizationNetwork, + mediationNetwork, + currencyIso4217Code, + revenue + ); + + // Log the ad revenue to the AppsFlyer SDK + AppsFlyerLib.getInstance().logAdRevenue(adRevenueData, RNUtil.toMap(additionalParameters)); + } + @ReactMethod public void getAppsFlyerUID(Callback callback) { String appId = AppsFlyerLib.getInstance().getAppsFlyerUID(getReactApplicationContext()); diff --git a/demos/appsflyer-react-native-app/android/app/build.gradle b/demos/appsflyer-react-native-app/android/app/build.gradle index 3ba15486..58aa614a 100644 --- a/demos/appsflyer-react-native-app/android/app/build.gradle +++ b/demos/appsflyer-react-native-app/android/app/build.gradle @@ -182,6 +182,7 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" // From node_modules + implementation 'org.jetbrains:annotations:16.0.2' implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" diff --git a/demos/appsflyer-react-native-app/android/app/src/main/java/com/appsflyerexample/MainApplication.java b/demos/appsflyer-react-native-app/android/app/src/main/java/com/appsflyerexample/MainApplication.java index 3398fbd1..e6427425 100644 --- a/demos/appsflyer-react-native-app/android/app/src/main/java/com/appsflyerexample/MainApplication.java +++ b/demos/appsflyer-react-native-app/android/app/src/main/java/com/appsflyerexample/MainApplication.java @@ -10,6 +10,12 @@ import com.facebook.soloader.SoLoader; import java.lang.reflect.InvocationTargetException; import java.util.List; +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Build; +import org.jetbrains.annotations.Nullable; +import android.content.Context; public class MainApplication extends Application implements ReactApplication { @@ -40,6 +46,15 @@ public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) { + if (Build.VERSION.SDK_INT >= 34 && getApplicationInfo().targetSdkVersion >= 34) { + return super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED); + } else { + return super.registerReceiver(receiver, filter); + } + } + @Override public void onCreate() { super.onCreate(); diff --git a/demos/appsflyer-react-native-app/android/build.gradle b/demos/appsflyer-react-native-app/android/build.gradle index e5f20a04..002b28af 100644 --- a/demos/appsflyer-react-native-app/android/build.gradle +++ b/demos/appsflyer-react-native-app/android/build.gradle @@ -2,10 +2,10 @@ buildscript { ext { - buildToolsVersion = "30.0.2" + buildToolsVersion = "34.0.0" minSdkVersion = 21 - compileSdkVersion = 32 - targetSdkVersion = 32 + compileSdkVersion = 34 + targetSdkVersion = 34 ndkVersion = "20.1.5948944" } repositories { @@ -13,7 +13,8 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:4.2.1") + //classpath("com.android.tools.build:gradle:4.2.1") + classpath("com.android.tools.build:gradle:7.1.3") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/demos/appsflyer-react-native-app/android/gradle.properties b/demos/appsflyer-react-native-app/android/gradle.properties index 3bfa93bb..f1419d1e 100644 --- a/demos/appsflyer-react-native-app/android/gradle.properties +++ b/demos/appsflyer-react-native-app/android/gradle.properties @@ -10,7 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m -org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=4g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/demos/appsflyer-react-native-app/android/gradle/wrapper/gradle-wrapper.properties b/demos/appsflyer-react-native-app/android/gradle/wrapper/gradle-wrapper.properties index 7665b0fa..45a9c1f4 100644 --- a/demos/appsflyer-react-native-app/android/gradle/wrapper/gradle-wrapper.properties +++ b/demos/appsflyer-react-native-app/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Sun Sep 01 10:19:20 IDT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/demos/appsflyer-react-native-app/components/AppsFlyer.js b/demos/appsflyer-react-native-app/components/AppsFlyer.js index d0f39551..683a8ecf 100644 --- a/demos/appsflyer-react-native-app/components/AppsFlyer.js +++ b/demos/appsflyer-react-native-app/components/AppsFlyer.js @@ -1,4 +1,4 @@ -import appsFlyer from 'react-native-appsflyer'; +import appsFlyer , {MEDIATION_NETWORK} from 'react-native-appsflyer'; import {Platform} from 'react-native'; // events @@ -29,4 +29,20 @@ export function AFInit() { // Sends in-app events to AppsFlyer servers. name is the events name ('simple event') and the values are a JSON ({info: 'fff', size: 5}) export function AFLogEvent(name, values) { appsFlyer.logEvent(name, values, null, null); + AFLogAdRevenue(); +} + +export function AFLogAdRevenue(){ + const adRevenueData = { + monetizationNetwork: 'AF-AdNetwork', + mediationNetwork: MEDIATION_NETWORK.IRONSOURCE, + currencyIso4217Code: 'USD', + revenue: 1.23, + additionalParameters : { + customParam1: 'value1', + customParam2: 'value2', + } + }; + + appsFlyer.logAdRevenue(adRevenueData); } diff --git a/demos/appsflyer-react-native-app/ios/.xcode.env b/demos/appsflyer-react-native-app/ios/.xcode.env new file mode 100644 index 00000000..3d5782c7 --- /dev/null +++ b/demos/appsflyer-react-native-app/ios/.xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/demos/appsflyer-react-native-app/package.json b/demos/appsflyer-react-native-app/package.json index be5716ad..ad68af26 100644 --- a/demos/appsflyer-react-native-app/package.json +++ b/demos/appsflyer-react-native-app/package.json @@ -14,11 +14,11 @@ "@react-navigation/stack": "^6.0.7", "react": "18.1.0", "react-native": "0.70.6", - "react-native-appsflyer": "file:../..", + "react-native-appsflyer": "../../", "react-native-elements": "^3.4.2", "react-native-gesture-handler": "^1.10.3", "react-native-safe-area-context": "^3.3.2", - "react-native-screens": "3.7.2", + "react-native-screens": "^3.34.0", "react-native-vector-icons": "8.1.0" }, "devDependencies": { diff --git a/index.d.ts b/index.d.ts index d6d8442e..0345af26 100644 --- a/index.d.ts +++ b/index.d.ts @@ -125,6 +125,33 @@ declare module "react-native-appsflyer" { hasConsentForAdsPersonalization?: boolean; } + //Log Ad Revenue Section + export enum MEDIATION_NETWORK { + IRONSOURCE , + APPLOVIN_MAX , + GOOGLE_ADMOB , + FYBER , + APPODEAL , + ADMOST , + TOPON , + TRADPLUS, + YANDEX , + CHARTBOOST , + UNITY , + TOPON_PTE , + CUSTOM_MEDIATION , + DIRECT_MONETIZATION_NETWORK + } + + //Interface representing ad revenue information + export interface AFAdRevenueData { + monetizationNetwork: string; + mediationNetwork: MEDIATION_NETWORK; + currencyIso4217Code: string; + revenue: number; + additionalParameters?: StringMap; + } + const appsFlyer: { onInstallConversionData(callback: (data: ConversionData) => any): () => void; onInstallConversionFailure(callback: (data: ConversionData) => any): () => void; @@ -164,7 +191,7 @@ declare module "react-native-appsflyer" { startSdk(): void enableTCFDataCollection(enabled: boolean): void setConsentData(consentData: AppsFlyerConsentType): void - + logAdRevenue(adRevenueData: AFAdRevenueData) : void /** * For iOS Only * */ diff --git a/index.js b/index.js index 07a297c8..7a4d3797 100755 --- a/index.js +++ b/index.js @@ -57,6 +57,30 @@ function logEvent(eventName, eventValues, success, error): Promise { appsFlyer.logEvent = logEvent; + +export const MEDIATION_NETWORK = Object.freeze({ + IRONSOURCE : "ironsource", + APPLOVIN_MAX : "applovinmax", + GOOGLE_ADMOB : "googleadmob", + FYBER : "fyber", + APPODEAL : "appodeal", + ADMOST : "Admost", + TOPON : "Topon", + TRADPLUS : "Tradplus", + YANDEX : "Yandex", + CHARTBOOST : "chartboost", + UNITY : "Unity", + TOPON_PTE : "toponpte", + CUSTOM_MEDIATION : "customMediation", + DIRECT_MONETIZATION_NETWORK : "directMonetizationNetwork" +}); + +function logAdRevenue(adRevenueData) { + RNAppsFlyer.logAdRevenue(adRevenueData); +} + +appsFlyer.logAdRevenue = logAdRevenue + /** * Manually record the location of the user * diff --git a/ios/AFAdRevenueData.h b/ios/AFAdRevenueData.h new file mode 100644 index 00000000..2025468a --- /dev/null +++ b/ios/AFAdRevenueData.h @@ -0,0 +1,68 @@ +// +// AFAdRevenueData.h +// AppsFlyerLib +// +// Created by Veronica Belyakov on 26/06/2024. +// + +typedef NS_CLOSED_ENUM(NSUInteger, AppsFlyerAdRevenueMediationNetworkType) { + AppsFlyerAdRevenueMediationNetworkTypeGoogleAdMob = 1, + AppsFlyerAdRevenueMediationNetworkTypeIronSource = 2, + AppsFlyerAdRevenueMediationNetworkTypeApplovinMax= 3, + AppsFlyerAdRevenueMediationNetworkTypeFyber = 4, + AppsFlyerAdRevenueMediationNetworkTypeAppodeal = 5, + AppsFlyerAdRevenueMediationNetworkTypeAdmost = 6, + AppsFlyerAdRevenueMediationNetworkTypeTopon = 7, + AppsFlyerAdRevenueMediationNetworkTypeTradplus = 8, + AppsFlyerAdRevenueMediationNetworkTypeYandex = 9, + AppsFlyerAdRevenueMediationNetworkTypeChartBoost = 10, + AppsFlyerAdRevenueMediationNetworkTypeUnity = 11, + AppsFlyerAdRevenueMediationNetworkTypeToponPte = 12, + AppsFlyerAdRevenueMediationNetworkTypeCustom = 13, + AppsFlyerAdRevenueMediationNetworkTypeDirectMonetization = 14 +} NS_SWIFT_NAME(MediationNetworkType); + +#define kAppsFlyerAdRevenueMonetizationNetwork @"monetization_network" +#define kAppsFlyerAdRevenueMediationNetwork @"mediation_network" +#define kAppsFlyerAdRevenueEventRevenue @"event_revenue" +#define kAppsFlyerAdRevenueEventRevenueCurrency @"event_revenue_currency" +#define kAppsFlyerAdRevenueCustomParameters @"custom_parameters" +#define kAFADRWrapperTypeGeneric @"adrevenue_sdk" + +//Pre-defined keys for non-mandatory dictionary + +//Code ISO 3166-1 format +#define kAppsFlyerAdRevenueCountry @"country" + +//ID of the ad unit for the impression +#define kAppsFlyerAdRevenueAdUnit @"ad_unit" + +//Format of the ad +#define kAppsFlyerAdRevenueAdType @"ad_type" + +//ID of the ad placement for the impression +#define kAppsFlyerAdRevenuePlacement @"placement" + + +@interface AFAdRevenueData : NSObject + +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)new NS_UNAVAILABLE; + +@property (strong, nonnull, nonatomic) NSString *monetizationNetwork; +@property AppsFlyerAdRevenueMediationNetworkType mediationNetwork; +@property (strong, nonnull, nonatomic) NSString *currencyIso4217Code; +@property (strong, nonnull, nonatomic) NSNumber *eventRevenue; + +/** +* @param monetizationNetwork network which monetized the impression (@"facebook") +* @param mediationNetwork mediation source that mediated the monetization network for the impression (AppsFlyerAdRevenueMediationNetworkTypeGoogleAdMob) +* @param currencyIso4217Code reported impression’s revenue currency ISO 4217 format (@"USD") +* @param eventRevenue reported impression’s revenue (@(0.001994303)) +*/ +- (instancetype _Nonnull )initWithMonetizationNetwork:(NSString *_Nonnull)monetizationNetwork + mediationNetwork:(AppsFlyerAdRevenueMediationNetworkType)mediationNetwork + currencyIso4217Code:(NSString *_Nonnull)currencyIso4217Code + eventRevenue:(NSNumber *_Nonnull)eventRevenue; + +@end diff --git a/ios/AppsFlyerLib.h b/ios/AppsFlyerLib.h index 34ee5f01..5207ca75 100644 --- a/ios/AppsFlyerLib.h +++ b/ios/AppsFlyerLib.h @@ -13,6 +13,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -470,6 +471,15 @@ NS_SWIFT_NAME(setPluginInfo(plugin:version:additionalParams:)); completionHandler:(void (^ _Nullable)(NSDictionary * _Nullable dictionary, NSError * _Nullable error))completionHandler NS_SWIFT_NAME(logEvent(name:values:completionHandler:)); +/** + Logs ad revenue data to AppsFlyer. + + Use this method to send monetization information along with optional additional parameters for detailed tracking. + + @param adRevenueData The object containing ad revenue details. + */ +- (void)logAdRevenue:(AFAdRevenueData *)adRevenueData NS_SWIFT_NAME(logAdRevenue(adRevenueData:)); + /** To log and validate in app purchases you can call this method from the completeTransaction: method on your `SKPaymentTransactionObserver`. diff --git a/ios/RNAppsFlyer.h b/ios/RNAppsFlyer.h index 9337713f..8a4123f0 100755 --- a/ios/RNAppsFlyer.h +++ b/ios/RNAppsFlyer.h @@ -22,7 +22,7 @@ @end -static NSString *const kAppsFlyerPluginVersion = @"6.14.3"; +static NSString *const kAppsFlyerPluginVersion = @"6.15.1"; static NSString *const NO_DEVKEY_FOUND = @"No 'devKey' found or its empty"; static NSString *const NO_APPID_FOUND = @"No 'appId' found or its empty"; static NSString *const NO_EVENT_NAME_FOUND = @"No 'eventName' found or its empty"; diff --git a/ios/RNAppsFlyer.m b/ios/RNAppsFlyer.m index 43e48f78..6dd5dfa1 100755 --- a/ios/RNAppsFlyer.m +++ b/ios/RNAppsFlyer.m @@ -79,6 +79,11 @@ -(NSError *) callSdkInternal:(NSDictionary*)initSdkOptions { error = [NSError errorWithDomain:NO_APPID_FOUND code:1 userInfo:nil]; } + //DELIVERY-58378 + [AppsFlyerLib shared].appleAppID = appId; + [AppsFlyerLib shared].appsFlyerDevKey = devKey; + [AppsFlyerLib shared].isDebug = isDebug; + if(error != nil){ return error; } @@ -100,9 +105,7 @@ -(NSError *) callSdkInternal:(NSDictionary*)initSdkOptions { pluginVersion:kAppsFlyerPluginVersion additionalParams:nil]; - [AppsFlyerLib shared].appleAppID = appId; - [AppsFlyerLib shared].appsFlyerDevKey = devKey; - [AppsFlyerLib shared].isDebug = isDebug; + //post notification for the deep link object that the bridge is initialized and he can handle deep link [[AppsFlyerAttribution shared] setRNAFBridgeReady:YES]; @@ -160,6 +163,74 @@ -(NSError *) callSdkInternal:(NSDictionary*)initSdkOptions { }]; } + +RCT_EXPORT_METHOD(logAdRevenue:(NSDictionary *)adRevenueDictionary) +{ + // Verify if the adRevenueDictionary is not empty + if (adRevenueDictionary.count == 0) { + NSLog(@"adRevenueData is missing, the data is mandatory to use this API."); + return; + } + + // Parse the fields from the adRevenueData object + NSString *monetizationNetwork = adRevenueDictionary[@"monetizationNetwork"]; + if (!monetizationNetwork) { + NSLog(@"monetizationNetwork is missing"); + return; + } + NSString *currencyIso4217Code = adRevenueDictionary[@"currencyIso4217Code"]; + if (!currencyIso4217Code) { + NSLog(@"currencyIso4217Code is missing"); + return; + } + NSNumber *revenue = adRevenueDictionary[@"revenue"]; + if (!revenue) { + NSLog(@"revenue is missing or not a number"); + return; + } + NSString *mediationNetworkString = adRevenueDictionary[@"mediationNetwork"]; + if (!mediationNetworkString) { + NSLog(@"mediationNetwork is missing"); + return; + } + + // Use literals to map the mediation network string to the corresponding enum value + NSDictionary *mediationNetworkMappings = @{ + @"googleadmob": @(AppsFlyerAdRevenueMediationNetworkTypeGoogleAdMob), + @"ironsource": @(AppsFlyerAdRevenueMediationNetworkTypeIronSource), + @"applovinmax": @(AppsFlyerAdRevenueMediationNetworkTypeApplovinMax), + @"fyber": @(AppsFlyerAdRevenueMediationNetworkTypeFyber), + @"appodeal": @(AppsFlyerAdRevenueMediationNetworkTypeAppodeal), + @"admost": @(AppsFlyerAdRevenueMediationNetworkTypeAdmost), + @"topon": @(AppsFlyerAdRevenueMediationNetworkTypeTopon), + @"tradplus": @(AppsFlyerAdRevenueMediationNetworkTypeTradplus), + @"yandex": @(AppsFlyerAdRevenueMediationNetworkTypeYandex), + @"chartboost": @(AppsFlyerAdRevenueMediationNetworkTypeChartBoost), + @"unity": @(AppsFlyerAdRevenueMediationNetworkTypeUnity), + @"toponpte": @(AppsFlyerAdRevenueMediationNetworkTypeToponPte), + @"custom": @(AppsFlyerAdRevenueMediationNetworkTypeCustom), + @"directmonetization": @(AppsFlyerAdRevenueMediationNetworkTypeDirectMonetization), + }; + + NSNumber *mediationNetworkEnumNumber = mediationNetworkMappings[mediationNetworkString.lowercaseString]; + if (!mediationNetworkEnumNumber) { + NSLog(@"Invalid mediation network"); + return; + } + + AppsFlyerAdRevenueMediationNetworkType mediationNetworkEnum = (AppsFlyerAdRevenueMediationNetworkType)[mediationNetworkEnumNumber integerValue]; + + // If AFAdRevenueData class is available and has the appropriate initializer: + AFAdRevenueData *adRevenueData = [[AFAdRevenueData alloc] initWithMonetizationNetwork:monetizationNetwork + mediationNetwork:mediationNetworkEnum + currencyIso4217Code:currencyIso4217Code + eventRevenue:revenue]; + + NSDictionary *additionalParameters = adRevenueDictionary[@"additionalParameters"]; + // Log the ad revenue to the AppsFlyer SDK + [[AppsFlyerLib shared] logAdRevenue:adRevenueData additionalParameters:additionalParameters]; +} + RCT_EXPORT_METHOD(getAppsFlyerUID: (RCTResponseSenderBlock)callback) { NSString *uid = [[AppsFlyerLib shared] getAppsFlyerUID]; callback(@[[NSNull null], uid]); diff --git a/package.json b/package.json index 347dc8f6..bbaec1eb 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-appsflyer", - "version": "6.14.3", + "version": "6.15.1", "description": "React Native Appsflyer plugin", "main": "index.js", "types": "index.d.ts", diff --git a/react-native-appsflyer.podspec b/react-native-appsflyer.podspec index 3641bfdd..e97da63c 100644 --- a/react-native-appsflyer.podspec +++ b/react-native-appsflyer.podspec @@ -11,20 +11,20 @@ Pod::Spec.new do |s| s.author = pkg["author"] s.source = { :git => pkg["repository"]["url"] } s.source_files = 'ios/**/*.{h,m}' - s.platform = :ios, "9.0" + s.platform = :ios, "12.0" s.static_framework = true s.dependency 'React' # AppsFlyerFramework if defined?($RNAppsFlyerStrictMode) && ($RNAppsFlyerStrictMode == true) Pod::UI.puts "#{s.name}: Using AppsFlyerFramework/Strict mode" - s.dependency 'AppsFlyerFramework/Strict', '6.14.3' + s.dependency 'AppsFlyerFramework/Strict', '6.15.1' s.xcconfig = {'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) AFSDK_NO_IDFA=1' } else if !defined?($RNAppsFlyerStrictMode) Pod::UI.puts "#{s.name}: Using default AppsFlyerFramework. You may require App Tracking Transparency. Not allowed for Kids apps." Pod::UI.puts "#{s.name}: You may set variable `$RNAppsFlyerStrictMode=true` in Podfile to use strict mode for kids apps." end - s.dependency 'AppsFlyerFramework', '6.14.3' + s.dependency 'AppsFlyerFramework', '6.15.1' end end