Skip to content

Commit 14c31ed

Browse files
committed
Added onSuccess and onError callbacks to startSDK, updated iOS SDK to v6.13.2
1 parent fade75e commit 14c31ed

File tree

12 files changed

+210
-56
lines changed

12 files changed

+210
-56
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Versions
22
## 6.13.2
3-
- Added new APIs such as anonymizeUser , performOnDeepLinking
3+
- Added new APIs such as `anonymizeUser` , `performOnDeepLinking`
4+
- Added to the `startSDK` API, `onSuccess` and `onError` callbacks
5+
- Update to iOS SDK to v6.13.2
46
## 6.13.0+2
57
- Update to iOS SDK to v6.13.1
68
## 6.13.0+1
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
#Thu Jul 23 11:36:59 IDT 2020
21
distributionBase=GRADLE_USER_HOME
32
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

android/src/main/java/com/appsflyer/appsflyersdk/AppsflyerSdkPlugin.java

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import android.os.Handler;
99
import android.os.Looper;
1010
import android.util.Log;
11+
import java.util.concurrent.atomic.AtomicBoolean;
12+
import androidx.annotation.NonNull;
1113

1214
import com.appsflyer.AFLogger;
1315
import com.appsflyer.AppsFlyerConsent;
@@ -22,6 +24,7 @@
2224
import com.appsflyer.share.ShareInviteHelper;
2325
import com.appsflyer.internal.platform_extension.Plugin;
2426
import com.appsflyer.internal.platform_extension.PluginInfo;
27+
import com.appsflyer.attribution.AppsFlyerRequestListener;
2528

2629
import org.json.JSONException;
2730
import org.json.JSONObject;
@@ -80,7 +83,7 @@ public class AppsflyerSdkPlugin implements MethodCallHandler, FlutterPlugin, Act
8083
private Boolean isFacebookDeferredApplinksEnabled = false;
8184
private Boolean isSetDisableAdvertisingIdentifiersEnable = false;
8285
private Map<String, Map<String, Object>> mCallbacks = new HashMap<>();
83-
86+
8487
PluginRegistry.NewIntentListener onNewIntentListener = new PluginRegistry.NewIntentListener() {
8588
@Override
8689
public boolean onNewIntent(Intent intent) {
@@ -200,7 +203,7 @@ private void startListening(Object arguments, Result rawResult) {
200203

201204
@Override
202205
public void onMethodCall(MethodCall call, Result result) {
203-
if(activity == null){
206+
if (activity == null) {
204207
Log.d("AppsFlyer", "Activity isn't attached to the flutter engine");
205208
return;
206209
}
@@ -369,11 +372,52 @@ private void anonymizeUser(MethodCall call, Result result) {
369372
result.success(null); // indicate that the method invocation is complete
370373
}
371374

372-
private void startSDK(MethodCall call, Result result) {
373-
AppsFlyerLib instance = AppsFlyerLib.getInstance();
374-
instance.start(activity);
375-
}
375+
/**
376+
* Initiates the AppsFlyer SDK. The AtomicBoolean isResultSubmitted ensures the result is
377+
* only submitted once, preventing the "Reply already submitted" exception in Flutter.
378+
*/
379+
private void startSDK(MethodCall call, final Result result) {
380+
final AtomicBoolean isResultSubmitted = new AtomicBoolean(false);
381+
382+
try {
383+
final AppsFlyerLib instance = AppsFlyerLib.getInstance();
384+
String afDevKey = call.argument(AppsFlyerConstants.AF_DEV_KEY);
385+
instance.start(activity, afDevKey, new AppsFlyerRequestListener() {
386+
@Override
387+
public void onSuccess() {
388+
new Handler(Looper.getMainLooper()).post(new Runnable() {
389+
@Override
390+
public void run() {
391+
if (!isResultSubmitted.getAndSet(true)) {
392+
mMethodChannel.invokeMethod("onSuccess", null);
393+
result.success(null);
394+
}
395+
}
396+
});
397+
}
376398

399+
@Override
400+
public void onError(final int errorCode, final String errorMessage) {
401+
new Handler(Looper.getMainLooper()).post(new Runnable() {
402+
@Override
403+
public void run() {
404+
if (!isResultSubmitted.getAndSet(true)) {
405+
HashMap<String, Object> errorDetails = new HashMap<>();
406+
errorDetails.put("errorCode", errorCode);
407+
errorDetails.put("errorMessage", errorMessage);
408+
mMethodChannel.invokeMethod("onError", errorDetails);
409+
result.error(String.valueOf(errorCode), errorMessage, null);
410+
}
411+
}
412+
});
413+
}
414+
});
415+
} catch (Exception e) {
416+
if (!isResultSubmitted.getAndSet(true)) {
417+
result.error("UNEXPECTED_ERROR", e.getMessage(), null);
418+
}
419+
}
420+
}
377421
public void setConsentData(MethodCall call, Result result) {
378422
Map<String, Object> arguments = (Map<String, Object>) call.arguments;
379423
Map<String, Object> consentDict = (Map<String, Object>) arguments.get("consentData");
@@ -394,20 +438,21 @@ public void setConsentData(MethodCall call, Result result) {
394438

395439
result.success(null);
396440
}
441+
397442
private void enableTCFDataCollection(MethodCall call, Result result) {
398443
boolean shouldCollect = (boolean) call.argument("shouldCollect");
399444
AppsFlyerLib.getInstance().enableTCFDataCollection(shouldCollect);
400445
result.success(null);
401446
}
402447

403448
private void addPushNotificationDeepLinkPath(MethodCall call, Result result) {
404-
if(call.arguments != null){
449+
if (call.arguments != null) {
405450
ArrayList<String> depplinkPath = (ArrayList<String>) call.arguments;
406451
String[] depplinkPathArr = depplinkPath.toArray(new String[depplinkPath.size()]);
407452
AppsFlyerLib.getInstance().addPushNotificationDeepLinkPath(depplinkPathArr);
408453
}
409454
result.success(null);
410-
}
455+
}
411456

412457
private void setDisableNetworkData(MethodCall call, Result result) {
413458
boolean disableNetworkData = (boolean) call.arguments;
@@ -420,10 +465,10 @@ private void getOutOfStore(Result result) {
420465
}
421466

422467
private void setOutOfStore(MethodCall call, Result result) {
423-
String sourceName = (String) call.arguments;
424-
if (sourceName != null) {
425-
AppsFlyerLib.getInstance().setOutOfStore(sourceName);
426-
}
468+
String sourceName = (String) call.arguments;
469+
if (sourceName != null) {
470+
AppsFlyerLib.getInstance().setOutOfStore(sourceName);
471+
}
427472
result.success(null);
428473
}
429474

@@ -438,14 +483,14 @@ private void setResolveDeepLinkURLs(MethodCall call, Result result) {
438483
private void setPartnerData(MethodCall call, Result result) {
439484
String partnerId = (String) call.argument("partnerId");
440485
HashMap<String, Object> partnerData = (HashMap<String, Object>) call.argument("partnersData");
441-
if(partnerData != null){
486+
if (partnerData != null) {
442487
AppsFlyerLib.getInstance().setPartnerData(partnerId, partnerData);
443488
}
444489
result.success(null);
445490
}
446491

447492
private void setSharingFilterForPartners(MethodCall call, Result result) {
448-
if(call.arguments != null){
493+
if (call.arguments != null) {
449494
ArrayList<String> partnersInput = (ArrayList<String>) call.arguments;
450495
String[] partners = partnersInput.toArray(new String[partnersInput.size()]);
451496
AppsFlyerLib.getInstance().setSharingFilterForPartners(partners);
@@ -465,7 +510,7 @@ private void setDisableAdvertisingIdentifiers(MethodCall call, Result result) {
465510

466511
private void enableFacebookDeferredApplinks(MethodCall call, Result result) {
467512
isFacebookDeferredApplinksEnabled = (boolean) call.argument("isFacebookDeferredApplinksEnabled");
468-
513+
469514
if (isFacebookDeferredApplinksEnabled) {
470515
AppsFlyerLib.getInstance().enableFacebookDeferredApplinks(true);
471516
} else {
@@ -484,7 +529,7 @@ private void sendPushNotificationData(MethodCall call, Result result) {
484529
String errorMsg = null;
485530
Bundle bundle;
486531

487-
if(pushPayload == null){
532+
if (pushPayload == null) {
488533
Log.d("AppsFlyer", "Push payload is null");
489534
return;
490535
}
@@ -509,13 +554,14 @@ private void sendPushNotificationData(MethodCall call, Result result) {
509554
errorMsg = "The activity is null. Push payload has not been sent!";
510555
}
511556

512-
if(errorMsg != null){
557+
if (errorMsg != null) {
513558
Log.d("AppsFlyer", errorMsg);
514559
return;
515560
}
516561

517562
result.success(null);
518563
}
564+
519565
private static Bundle jsonToBundle(JSONObject jsonObject) throws JSONException {
520566
Bundle bundle = new Bundle();
521567
Iterator iter = jsonObject.keys();
@@ -526,6 +572,7 @@ private static Bundle jsonToBundle(JSONObject jsonObject) throws JSONException {
526572
}
527573
return bundle;
528574
}
575+
529576
private void setOneLinkCustomDomain(MethodCall call, Result result) {
530577
ArrayList<String> brandDomains = (ArrayList<String>) call.arguments;
531578
String[] brandDomainsArray = brandDomains.toArray(new String[brandDomains.size()]);
@@ -768,11 +815,11 @@ private void setAdditionalData(MethodCall call, Result result) {
768815
private void setUserEmails(MethodCall call, Result result) {
769816
List<String> emails = call.argument("emails");
770817
int cryptTypeInt = call.argument("cryptType");
771-
818+
772819
AppsFlyerProperties.EmailsCryptType cryptType = null;
773-
if (cryptTypeInt == 0){
820+
if (cryptTypeInt == 0) {
774821
cryptType = AppsFlyerProperties.EmailsCryptType.NONE;
775-
} else if (cryptTypeInt == 1){
822+
} else if (cryptTypeInt == 1) {
776823
cryptType = AppsFlyerProperties.EmailsCryptType.SHA256;
777824
} else {
778825
throw new InvalidParameterException("You can use only NONE or SHA256 for EmailsCryptType on android");

doc/API.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,11 @@ Future<bool?> logEvent(String eventName, Map? eventValues) async {
205205
## Other functionalities:
206206
**<a id="anonymizeUser"> `anonymizeUser(shouldAnonymize)`**
207207

208-
It is possible to anonymize specific user identifiers within AppsFlyer analytics. This complies with both the latest privacy requirements (GDPR, COPPA) and Facebook's data and privacy policies. To anonymize an app user.
208+
It is possible to anonymize specific user identifiers within AppsFlyer analytics.</br>
209+
This complies with both the latest privacy requirements (GDPR, COPPA) and Facebook's data and privacy policies. To anonymize an app user.
209210
| parameter | type | description |
210211
| ---------- |----------|------------------ |
211212
| shouldAnonymize | boolean | True if want Anonymize user Data (default value is false). |
212-
| callback | function | success callback |
213213

214214
_Example:_
215215
```dart

doc/BasicIntegration.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,13 @@ appsflyerSdk.initSdk(
5151
| registerOnDeepLinkingCallback | Set a listener for the [UDL](https://dev.appsflyer.com/hc/docs/unified-deep-linking-udl) response |
5252

5353
### startSdk
54-
`startSDK()`
55-
In version 6.13.0 of the appslfyer-flutter-plugin SDK we added the option of splitting between the initialization stage and start stage. All you need to do is add the property manualStart: true to the init object, and later call appsFlyer.startSdk() whenever you decide. If this property is set to false or doesn’t exist, the sdk will start after calling appsFlyer.initSdk(...).
54+
`startSDK({RequestSuccessListener? onSuccess, RequestErrorListener? onError})`
55+
Version 6.13.0+ of the AppsFlyer Flutter plugin introduces the option to manually start the SDK. </br>
56+
To utilise this feature, set the property `manualStart: true` within the initialization configuration. </br>
57+
Once the `manualStart` option is activated, you can call `appsFlyer.startSdk()` at your discretion. If the `manualStart` property is omitted or set to false, the SDK will start immediately after calling `appsFlyer.initSdk(...)`.
58+
59+
`onSuccess`: An optional callback that is triggered after a successful initialization of the SDK.
60+
`onError`: An optional callback that is fired in case of an error during SDK initialization, providing an error code and an error message.
5661

5762
```dart
5863
// SDK Options
@@ -64,12 +69,33 @@ In version 6.13.0 of the appslfyer-flutter-plugin SDK we added the option of spl
6469
manualStart: true);
6570
_appsflyerSdk = AppsflyerSdk(options);
6671
67-
// Init of AppsFlyer SDK
72+
// Initialization of the AppsFlyer SDK
6873
_appsflyerSdk.initSdk(
6974
registerConversionDataCallback: true,
7075
registerOnAppOpenAttributionCallback: true,
7176
registerOnDeepLinkingCallback: true);
7277
73-
//Here we start the SDK
74-
_appsflyerSdk.startSDK();
78+
// Starting the SDK with optional success and error callbacks
79+
_appsflyerSdk.startSDK(
80+
onSuccess: () {
81+
showMessage("AppsFlyer SDK initialized successfully.");
82+
},
83+
onError: (int errorCode, String errorMessage) {
84+
showMessage("Error initializing AppsFlyer SDK: Code $errorCode - $errorMessage");
85+
},
86+
);
7587
```
88+
89+
Use the `onSuccess` callback to perform actions after successful SDK initialization, and the `onError` callback to handle initialization errors. </br>
90+
Here's an example from the demo app.
91+
92+
```dart
93+
_appsflyerSdk.startSDK(
94+
onSuccess: () {
95+
showMessage("AppsFlyer SDK initialized successfully.");
96+
},
97+
onError: (int errorCode, String errorMessage) {
98+
showMessage("Error initializing AppsFlyer SDK: Code $errorCode - $errorMessage");
99+
},
100+
);
101+
```

example/lib/main_page.dart

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,20 @@ class MainPageState extends State<MainPage> {
3030
afDevKey: dotenv.env["DEV_KEY"]!,
3131
appId: dotenv.env["APP_ID"]!,
3232
showDebug: true,
33-
timeToWaitForATTUserAuthorization: 15,
33+
timeToWaitForATTUserAuthorization: 1,
3434
manualStart: true);
3535
_appsflyerSdk = AppsflyerSdk(options);
3636

37-
//Setting configuration to the SDK
37+
/*
38+
Setting configuration to the SDK:
3839
_appsflyerSdk.setCurrencyCode("USD");
3940
_appsflyerSdk.enableTCFDataCollection(true);
40-
// var forGdpr = AppsFlyerConsent.forGDPRUser(hasConsentForDataUsage: true, hasConsentForAdsPersonalization: true);
41-
// _appsflyerSdk.setConsentData(forGdpr);
41+
var forGdpr = AppsFlyerConsent.forGDPRUser(hasConsentForDataUsage: true, hasConsentForAdsPersonalization: true);
42+
_appsflyerSdk.setConsentData(forGdpr);
4243
var nonGdpr = AppsFlyerConsent.nonGDPRUser();
4344
_appsflyerSdk.setConsentData(nonGdpr);
45+
*/
46+
4447
// Init of AppsFlyer SDK
4548
await _appsflyerSdk.initSdk(
4649
registerConversionDataCallback: true,
@@ -87,7 +90,7 @@ class MainPageState extends State<MainPage> {
8790
});
8891

8992
//_appsflyerSdk.anonymizeUser(true);
90-
if(Platform.isAndroid){
93+
if (Platform.isAndroid) {
9194
_appsflyerSdk.performOnDeepLinking();
9295
}
9396

@@ -116,7 +119,14 @@ class MainPageState extends State<MainPage> {
116119
),
117120
ElevatedButton(
118121
onPressed: () {
119-
_appsflyerSdk.startSDK();
122+
_appsflyerSdk.startSDK(
123+
onSuccess: () {
124+
showMessage("AppsFlyer SDK initialized successfully.");
125+
},
126+
onError: (int errorCode, String errorMessage) {
127+
showMessage("Error initializing AppsFlyer SDK: Code $errorCode - $errorMessage");
128+
},
129+
);
120130
},
121131
child: Text("START SDK"),
122132
)
@@ -138,4 +148,14 @@ class MainPageState extends State<MainPage> {
138148
}
139149
return logResult;
140150
}
151+
152+
void showMessage(String message) {
153+
ScaffoldMessenger.of(context)
154+
.showSnackBar(SnackBar(
155+
content:
156+
Text(message),
157+
));
158+
}
141159
}
160+
161+

0 commit comments

Comments
 (0)