Skip to content

Commit edb3206

Browse files
authored
Merge pull request #614 from AppsFlyerSDK/releases/6.x.x/6.16.x/6.16.2-rc1
Releases/6.x.x/6.16.x/6.16.2 rc1
2 parents d8aefbb + 53a0de1 commit edb3206

24 files changed

Lines changed: 414 additions & 198 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 6.16.2
2+
Release date: *2025-03-19*
3+
4+
- SDK > React Native plugin > No enum constant com.appsflyer.MediationNetwork.xxx" error on Android with some mediation networks' names have _ (underscore) character
5+
- React Native >> Update Plugin to v6.16.2
6+
17
## 6.15.3
28
Release date: *2025-01-8*
39

Docs/RN_CMP.md

Lines changed: 96 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -59,81 +59,123 @@ A CMP compatible with TCF v2.2 collects DMA consent data and stores it in NSUser
5959
}
6060
},[])
6161
```
62-
## Manually collect consent data
63-
If your app does not use a CMP compatible with TCF v2.2, use the SDK API detailed below to provide the consent data directly to the SDK.
64-
65-
### When GDPR applies to the user
66-
If GDPR applies to the user, perform the following:
67-
68-
1. Given that GDPR is applicable to the user, determine whether the consent data is already stored for this session.
69-
1. If there is no consent data stored, show the consent dialog to capture the user consent decision.
70-
2. If there is consent data stored continue to the next step.
71-
2. To transfer the consent data to the SDK create an AppsFlyerConsent object using `forGDPRUser` method that accepts the following parameters:<br>
72-
`hasConsentForDataUsage: boolean` - Indicates whether the user has consented to use their data for advertising purposes.<br>
73-
`hasConsentForAdsPersonalization: boolean` - Indicates whether the user has consented to use their data for personalized advertising.
74-
3. Call `appsFlyer.setConsentData(consentData)` with the AppsFlyerConsent object.
75-
4. Call `appsFlyer.initSdk()`.
62+
63+
### Manually Collecting Consent Data
64+
65+
If your app does not use a TCF v2.2-compatible CMP, you must manually provide the consent data using the SDK API.
66+
67+
How to Set Consent Data: </br>
68+
1. Determine GDPR Applicability:
69+
* If GDPR applies, check whether consent data is already stored.
70+
* If not stored, show a consent dialog to obtain user consent.
71+
2. Create an AppsFlyerConsent object with the relevant parameters.
72+
3. Pass the consent data to the SDK using appsFlyer.setConsentData(consentData).
73+
4. Initialize the SDK with appsFlyer.initSdk().
74+
75+
#### Setting Consent Data for Users
76+
77+
<b>When GDPR Applies</b>
78+
79+
If GDPR applies to the user, create an AppsFlyerConsent object with the user’s preferences.
7680
```javascript
77-
import appsFlyer, {AppsFlyerConsent} from 'react-native-appsflyer';
81+
import appsFlyer, { AppsFlyerConsent } from 'react-native-appsflyer';
7882

7983
useEffect(() => {
8084
const option = {
81-
isDebug: true,
82-
devKey: 'UxXxXxXxXd',
83-
onInstallConversionDataListener: true,
84-
onDeepLinkListener: true,
85-
timeToWaitForATTUserAuthorization: 10,
85+
isDebug: true,
86+
devKey: 'UxXxXxXxXd',
87+
onInstallConversionDataListener: true,
88+
onDeepLinkListener: true,
89+
timeToWaitForATTUserAuthorization: 10,
8690
};
8791

88-
// user consent data
89-
let consentData = AppsFlyerConsent.forGDPRUser(true, false);
92+
// User has given consent
93+
const consentData = new AppsFlyerConsent(true, true, true, true);
9094

95+
// Send consent data to the SDK
9196
appsFlyer.setConsentData(consentData);
9297

93-
//start appsflyer
98+
// Start AppsFlyer SDK
9499
appsFlyer.initSdk(
95-
option,
96-
res => {
97-
console.log(res);
98-
},
99-
err => {
100-
console.log(err);
101-
},
100+
option,
101+
res => console.log(res),
102+
err => console.log(err)
102103
);
103-
},[])
104+
}, []);
104105
```
105-
### When GDPR does not apply to the user
106106

107-
If GDPR doesn’t apply to the user perform the following:
108-
1. Create an AppsFlyerConsent object using `forNonGDPRUser` method that doesn't accepts any parameters
109-
2. Call `appsFlyer.setConsentData(consentData)` with the AppsFlyerConsent object.
110-
3. Call `appsFlyer.initSdk()`.
107+
<b>When GDPR Does Not Apply</b>
108+
109+
If GDPR does not apply to the user, simply mark it as such in the AppsFlyerConsent object.
111110
```javascript
112-
import appsFlyer, {AppsFlyerConsent} from 'react-native-appsflyer';
111+
import appsFlyer, { AppsFlyerConsent } from 'react-native-appsflyer';
113112

114113
useEffect(() => {
115114
const option = {
116-
isDebug: true,
117-
devKey: 'UxXxXxXxXd',
118-
onInstallConversionDataListener: true,
119-
onDeepLinkListener: true,
120-
timeToWaitForATTUserAuthorization: 10,
115+
isDebug: true,
116+
devKey: 'UxXxXxXxXd',
117+
onInstallConversionDataListener: true,
118+
onDeepLinkListener: true,
119+
timeToWaitForATTUserAuthorization: 10,
121120
};
122121

123122
// GDPR does not apply to the user
124-
let consentData = AppsFlyerConsent.forNonGDPRUser();
123+
const consentData = new AppsFlyerConsent(false);
125124

126-
appsFlyer.setConsentData(consentData);
125+
// Send consent data to the SDK
126+
appsFlyer.setConsentData(consentData);
127127

128-
//start appsflyer
128+
// Start AppsFlyer SDK
129129
appsFlyer.initSdk(
130-
option,
131-
res => {
132-
console.log(res);
133-
},
134-
err => {
135-
console.log(err);
136-
},
130+
option,
131+
res => console.log(res),
132+
err => console.log(err)
137133
);
138-
},[])
139-
```
134+
}, []);
135+
```
136+
137+
### Consent Object API
138+
139+
```javascript
140+
//AppsFlyerConsent Constructor:
141+
142+
new AppsFlyerConsent(
143+
isUserSubjectToGDPR, // Boolean (optional) - Whether GDPR applies to the user
144+
hasConsentForDataUsage, // Boolean (optional) - Consent for data usage
145+
hasConsentForAdsPersonalization, // Boolean (optional) - Consent for ads personalization
146+
hasConsentForAdStorage // Boolean (optional) - Consent for ad storage
147+
);
148+
149+
//Example Cases:
150+
151+
// Full consent for GDPR user
152+
const consent1 = new AppsFlyerConsent(true, true, true, true);
153+
154+
// No consent for GDPR user
155+
const consent2 = new AppsFlyerConsent(true, false, false, false);
156+
157+
// Non-GDPR user
158+
const consent3 = new AppsFlyerConsent(false);
159+
160+
// AppsFlyerConsent object support the following cases if they are needed.
161+
const consent4 = new AppsFlyerConsent(true);
162+
const consent5 = new AppsFlyerConsent(true, true);
163+
const consent6 = new AppsFlyerConsent(null, true, true, true);
164+
const consent7 = new AppsFlyerConsent(true, null, true, true);
165+
const consent8 = new AppsFlyerConsent(true, true, null, true);
166+
const consent9 = new AppsFlyerConsent(true, true, true, null);
167+
const consent10 = new AppsFlyerConsent(true, true, false, true);
168+
const consent11 = new AppsFlyerConsent(false, true, false, false);
169+
const consent12 = new AppsFlyerConsent(null, null, null, null);
170+
const consent13 = new AppsFlyerConsent();
171+
```
172+
173+
### Deprecation Notice
174+
175+
The following methods have been deprecated since SDK version 6.16.2 and should no longer be used:
176+
```javascript
177+
// Deprecated since 6.16.2
178+
AppsFlyerConsent.forGDPRUser(true, false);
179+
AppsFlyerConsent.forNonGDPRUser();
180+
```
181+
Instead, use the new AppsFlyerConsent constructor.

Docs/RN_ExpoInstallation.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,75 @@ expo install react-native-appsflyer
3838
],
3939
...
4040
```
41+
### Fix for build failure with RN 0.76 and Expo 52
42+
To ensure seamless integration of the AppsFlyer plugin in your Expo-managed project, it’s essential to handle modifications to the AndroidManifest.xml correctly. Since direct edits to the AndroidManifest.xml aren’t feasible in the managed workflow, you’ll need to create a custom configuration to include the necessary changes.
43+
44+
### Handling dataExtractionRules Conflict
45+
46+
When building your Expo app with the AppsFlyer plugin, you might encounter a build error related to the `dataExtractionRules` attribute. This issue arises due to a conflict between the `dataExtractionRules `defined in your project’s `AndroidManifest.xml` and the one included in the AppsFlyer SDK.
47+
48+
<b>Solution:</b> Creating a Custom Plugin to Modify `AndroidManifest.xml`
49+
50+
To resolve this, you can create a custom Expo config plugin that modifies the AndroidManifest.xml during the build process. This approach allows you to adjust the manifest without directly editing it, maintaining compatibility with the managed workflow.
51+
52+
Steps to Implement the Custom Plugin:
53+
1. Create the Plugin File:
54+
- In your project’s root directory, create a file named withCustomAndroidManifest.js.
55+
2. Define the Plugin Function:
56+
- In withCustomAndroidManifest.js, define a function that uses Expo’s withAndroidManifest to modify the manifest. This function will remove the conflicting dataExtractionRules attribute.
57+
58+
```js
59+
// withCustomAndroidManifest.js
60+
const { withAndroidManifest } = require('@expo/config-plugins');
61+
62+
module.exports = function withCustomAndroidManifest(config) {
63+
return withAndroidManifest(config, async (config) => {
64+
const androidManifest = config.modResults;
65+
const manifest = androidManifest.manifest;
66+
67+
// Ensure xmlns:tools is present in the <manifest> tag
68+
if (!manifest.$['xmlns:tools']) {
69+
manifest.$['xmlns:tools'] = 'http://schemas.android.com/tools';
70+
}
71+
72+
const application = manifest.application[0];
73+
74+
// Add tools:replace attribute for dataExtractionRules and fullBackupContent
75+
application['$']['tools:replace'] = 'android:dataExtractionRules, android:fullBackupContent';
76+
77+
// Set dataExtractionRules and fullBackupContent as attributes within <application>
78+
application['$']['android:dataExtractionRules'] = '@xml/secure_store_data_extraction_rules';
79+
application['$']['android:fullBackupContent'] = '@xml/secure_store_backup_rules';
80+
81+
return config;
82+
});
83+
};
84+
85+
```
86+
87+
3. Update app.json or app.config.js:
88+
- In your app configuration file, include the custom plugin to ensure it’s executed during the build process.
89+
90+
```json
91+
// app.json
92+
{
93+
"expo": {
94+
// ... other configurations ...
95+
"plugins": [
96+
"./withCustomAndroidManifest.js",
97+
[
98+
"react-native-appsflyer",
99+
{
100+
"shouldUseStrictMode": true
101+
}
102+
]
103+
]
104+
}
105+
}
106+
```
107+
108+
By implementing this custom plugin, you can resolve the dataExtractionRules conflict without directly modifying the AndroidManifest.xml.
109+
41110
## The AD_ID permission for android apps
42111
In v6.8.0 of the AppsFlyer SDK, we added the normal permission com.google.android.gms.permission.AD_ID to the SDK's AndroidManifest,
43112
to allow the SDK to collect the Android Advertising ID on apps targeting API 33.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
1313
### <a id="plugin-build-for"> This plugin is built for
1414

15-
- Android AppsFlyer SDK **v6.15.2**
16-
- iOS AppsFlyer SDK **v6.15.3**
15+
- Android AppsFlyer SDK **v6.16.2**
16+
- iOS AppsFlyer SDK **v6.16.2**
1717
- Tested with React-Native **v0.62.0** (older versions might be supported)
1818

1919
## <a id="breaking-changes"> ❗❗ Breaking changes when updating to v6.x.x❗❗
20+
- From version `6.16.2`, `AppsFlyerConsent.forGDPRUser` and `AppsFlyerConsent.forNonGDPRUser` have been **deprecated**. Use the new `AppsFlyerConsent` constructor instead. See [Deprecation Notice](/Docs/RN_CMP.md#deprecation-notice).
2021

2122
- 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).
2223

android/.project

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,13 @@
55
<projects>
66
</projects>
77
<buildSpec>
8-
<buildCommand>
9-
<name>org.eclipse.jdt.core.javabuilder</name>
10-
<arguments>
11-
</arguments>
12-
</buildCommand>
138
<buildCommand>
149
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
1510
<arguments>
1611
</arguments>
1712
</buildCommand>
1813
</buildSpec>
1914
<natures>
20-
<nature>org.eclipse.jdt.core.javanature</nature>
2115
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
2216
</natures>
2317
<filteredResources>

android/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ buildscript {
2020
apply plugin: 'com.android.library'
2121

2222
android {
23+
namespace "com.appsflyer.reactnative"
2324
compileSdkVersion safeExtGet('compileSdkVersion', 34)
2425
buildToolsVersion safeExtGet('buildToolsVersion', '34.0.0')
2526

2627
defaultConfig {
27-
minSdkVersion safeExtGet('minSdkVersion', 16)
28+
minSdkVersion safeExtGet('minSdkVersion', 21)
2829
targetSdkVersion safeExtGet('targetSdkVersion', 34)
2930
versionCode 1
3031
versionName "1.0"
@@ -54,5 +55,5 @@ repositories {
5455
dependencies {
5556
implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
5657
implementation "com.android.installreferrer:installreferrer:${safeExtGet('installReferrerVersion', '2.1')}"
57-
api "com.appsflyer:af-android-sdk:${safeExtGet('appsflyerVersion', '6.15.2')}"
58+
api "com.appsflyer:af-android-sdk:${safeExtGet('appsflyerVersion', '6.16.2')}"
5859
}

android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerConstants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
public class RNAppsFlyerConstants {
88

9-
final static String PLUGIN_VERSION = "6.15.3";
9+
final static String PLUGIN_VERSION = "6.16.2";
1010
final static String NO_DEVKEY_FOUND = "No 'devKey' found or its empty";
1111
final static String UNKNOWN_ERROR = "AF Unknown Error";
1212
final static String SUCCESS = "Success";

android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import android.os.Bundle;
99

1010
import androidx.annotation.NonNull;
11+
import androidx.annotation.Nullable;
1112

1213
import android.util.Log;
1314

@@ -876,17 +877,41 @@ public void enableTCFDataCollection(Boolean enabled) {
876877
}
877878

878879
@ReactMethod
879-
public void setConsentData(ReadableMap consentData) {
880+
public void setConsentData(@Nullable ReadableMap consentData) {
881+
if (consentData == null) {
882+
Log.e("AppsFlyer", "consentData is null");
883+
return;
884+
}
885+
880886
JSONObject JSONConsentData = RNUtil.readableMapToJson(consentData);
881-
boolean isUserSubjectToGDPR = JSONConsentData.optBoolean("isUserSubjectToGDPR");
882-
boolean hasConsentForDataUsage = JSONConsentData.optBoolean("hasConsentForDataUsage");
883-
boolean hasConsentForAdsPersonalization = JSONConsentData.optBoolean("hasConsentForAdsPersonalization");
884-
AppsFlyerConsent consentObject;
885-
if (isUserSubjectToGDPR) {
886-
consentObject = AppsFlyerConsent.forGDPRUser(hasConsentForDataUsage, hasConsentForAdsPersonalization);
887-
} else {
888-
consentObject = AppsFlyerConsent.forNonGDPRUser();
887+
if (JSONConsentData == null) {
888+
Log.e("AppsFlyer", "Failed to convert consentData to JSON");
889+
return;
889890
}
891+
892+
Boolean isUserSubjectToGDPR = JSONConsentData.has("isUserSubjectToGDPR") && !JSONConsentData.isNull("isUserSubjectToGDPR")
893+
? JSONConsentData.optBoolean("isUserSubjectToGDPR")
894+
: null;
895+
896+
Boolean hasConsentForDataUsage = JSONConsentData.has("hasConsentForDataUsage") && !JSONConsentData.isNull("hasConsentForDataUsage")
897+
? JSONConsentData.optBoolean("hasConsentForDataUsage")
898+
: null;
899+
900+
Boolean hasConsentForAdsPersonalization = JSONConsentData.has("hasConsentForAdsPersonalization") && !JSONConsentData.isNull("hasConsentForAdsPersonalization")
901+
? JSONConsentData.optBoolean("hasConsentForAdsPersonalization")
902+
: null;
903+
904+
Boolean hasConsentForAdStorage = JSONConsentData.has("hasConsentForAdStorage") && !JSONConsentData.isNull("hasConsentForAdStorage")
905+
? JSONConsentData.optBoolean("hasConsentForAdStorage")
906+
: null;
907+
908+
AppsFlyerConsent consentObject = new AppsFlyerConsent(
909+
isUserSubjectToGDPR,
910+
hasConsentForDataUsage,
911+
hasConsentForAdsPersonalization,
912+
hasConsentForAdStorage
913+
);
914+
890915
AppsFlyerLib.getInstance().setConsentData(consentObject);
891916
}
892917

babel.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// babel.config.js
2+
module.exports = {
3+
presets: ['module:metro-react-native-babel-preset'],
4+
};

0 commit comments

Comments
 (0)