- Measure App Uninstalls
- User invite
- In-app purchase validation
- Android Out of Store
- Set plugin for IOS 14
You may update the uninstall token from the native side and from the plugin side, as shown in the methods below, you do not have to implement both of the methods, but only one. You can read more about iOS Uninstall Measurement in our knowledge base and you can follow our guide for Uninstall measurement on our DevHub.
You can register the uninstall token with AppsFlyer by modifying your AppDelegate.m file, add the following function call with your uninstall token inside didRegisterForRemoteNotificationsWithDeviceToken.
Example:
@import AppsFlyerLib;
...
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// notify AppsFlyerLib
[[AppsFlyerLib shared] registerUninstall:deviceToken];
}You can register the uninstall token with AppsFlyer by calling the following API with your uninstall token:
appsFlyerSdk.updateServerUninstallToken("token");Note: When using this method on iOS, the token should be passed as a hexadecimal string representation of the device token. The plugin will automatically convert the hex string to the required
NSDataformat for the AppsFlyer SDK.If you're using the firebase_messaging plugin, you can get the APNs token on iOS using
FirebaseMessaging.instance.getAPNSToken()which returns the token as a hex string, which is the expected format for this method.
It is possible to utilize the Firebase Messaging Plugin for Flutter for everything related to the uninstall token. You can read more about Android Uninstall Measurement in our knowledge base and you can follow our guide for Uninstall measurement using FCM on our DevHub.
On the Flutter side, you can register the uninstall token with AppsFlyer by calling the following API with your uninstall token:
appsFlyerSdk.updateServerUninstallToken("token");Example using Firebase Messaging (cross-platform):
import 'dart:io' show Platform;
import 'package:firebase_messaging/firebase_messaging.dart';
// Update uninstall token for AppsFlyer
void _updateUninstallToken(appsFlyerSdk) {
if (Platform.isAndroid) {
FirebaseMessaging.instance.getToken().then((token) {
if (token != null) {
appsFlyerSdk.updateServerUninstallToken(token);
}
});
} else if (Platform.isIOS) {
FirebaseMessaging.instance.getAPNSToken().then((token) {
if (token != null) {
appsFlyerSdk.updateServerUninstallToken(token);
}
});
}
}Note:
- On Android,
getToken()returns the FCM token. - On iOS,
getAPNSToken()returns the APNs token as a hex string, suitable forupdateServerUninstallToken. - Replace
appsFlyerSdkwith your instance ofAppsflyerSdk.
A complete list of supported parameters is available here, you can also make use of the customParams field to include custom parameters of your choice.
- First define the Onelink ID either in the AppsFlyerOptions, or in the setAppInviteOneLinkID API (find it in the AppsFlyer dashboard in the onelink section):
Future<void> setAppInviteOneLinkID(String oneLinkID, Function callback)
- Utilize the AppsFlyerInviteLinkParams class to set the query params in the user invite link:
class AppsFlyerInviteLinkParams {
final String channel;
final String campaign;
final String referrerName;
final String referrerImageUrl;
final String customerID;
final String baseDeepLink;
final String brandDomain;
final Map<String?, String?>? customParams;
}- Call the generateInviteLink API to generate the user invite link. Use the success and error callbacks for handling.
Full example:
// Setting the OneLinkID
appsFlyerSdk.setAppInviteOneLinkID('OnelinkID',
(res){
print("setAppInviteOneLinkID callback: $res");
});
// Creating the required parameters of the OneLink
AppsFlyerInviteLinkParams inviteLinkParams = new AppsFlyerInviteLinkParams(
channel: "",
referrerName: "",
baseDeepLink: "",
brandDomain: "",
customerID: "",
referrerImageUrl: "",
campaign: "",
customParams: {"key":"value"}
);
// Generating the OneLink
appsFlyerSdk.generateInviteLink(inviteLinkParams,
(result){
print(result);
},
(error){
print(error);
}
);Receipt validation is a secure mechanism whereby the payment platform (e.g. Apple or Google) validates that an in-app purchase indeed occurred as reported.
Learn more - https://support.appsflyer.com/hc/en-us/articles/207032106-Receipt-validation-for-in-app-purchases
Cross-Platform V2 API (Recommended - SDK v6.17.3+):
The unified purchase validation API that works across both Android and iOS platforms:
Future<Map<String, dynamic>> validateAndLogInAppPurchaseV2(
AFPurchaseDetails purchaseDetails,
{Map<String, String>? additionalParameters})AFPurchaseDetails class:
AFPurchaseDetails(
purchaseType: AFPurchaseType, // oneTimePurchase or subscription
purchaseToken: String, // Purchase token from app store
productId: String, // Product identifier
)Example:
// Create purchase details
AFPurchaseDetails purchaseDetails = AFPurchaseDetails(
purchaseType: AFPurchaseType.oneTimePurchase,
purchaseToken: "sample_purchase_token_12345",
productId: "com.example.product",
);
// Validate purchase (works on both Android and iOS)
try {
Map<String, dynamic> result = await appsFlyerSdk.validateAndLogInAppPurchaseV2(
purchaseDetails,
additionalParameters: {"custom_param": "value"}
);
print("Validation successful: $result");
} on PlatformException catch (e) {
// Handle platform-specific errors with detailed information
print("Validation failed: ${e.message}");
print("Error code: ${e.code}");
if (e.details != null) {
// Access detailed error information
final details = e.details as Map<String, dynamic>;
print("Error details: $details");
// On iOS, additional fields may include:
// - error_code: The NSError code
// - error_domain: The NSError domain
// - error_user_info: Additional error context
}
} catch (e) {
print("Unexpected error: $e");
}Benefits of V2 API:
- ✅ Cross-platform: Single API works on both Android and iOS
- ✅ Type-safe: Uses structured data classes instead of raw strings
- ✅ Comprehensive error handling: Returns structured error information including NSError details on iOS
- ✅ Enhanced validation: Uses AppsFlyer's latest validation infrastructure
- ✅ Future-proof: Built for AppsFlyer's V2 validation endpoints
Deprecated Platform-Specific APIs:
⚠️ Deprecated: The following platform-specific APIs are deprecated and will be removed in a future version. Please migrate tovalidateAndLogInAppPurchaseV2for cross-platform support.
Android (Deprecated):
@Deprecated('Use validateAndLogInAppPurchaseV2 instead')
Future<dynamic> validateAndLogInAppAndroidPurchase(
String publicKey,
String signature,
String purchaseData,
String price,
String currency,
Map<String, String>? additionalParameters)Example:
// Deprecated - migrate to validateAndLogInAppPurchaseV2
appsFlyerSdk.validateAndLogInAppAndroidPurchase(
"publicKey",
"signature",
"purchaseData",
"price",
"currency",
{"fs": "fs"});iOS (Deprecated):
❗Important❗ for iOS - set SandBox to true
appsFlyer.useReceiptValidationSandbox(true);
@Deprecated('Use validateAndLogInAppPurchaseV2 instead')
Future<dynamic> validateAndLogInAppIosPurchase(
String productIdentifier,
String price,
String currency,
String transactionId,
Map<String, String> additionalParameters)Example:
// Deprecated - migrate to validateAndLogInAppPurchaseV2
appsFlyerSdk.validateAndLogInAppIosPurchase(
"productIdentifier",
"price",
"currency",
"transactionId",
{"fs": "fs"});Purchase validation callback:
void onPurchaseValidation(Function callback)
Example:
appsflyerSdk.onPurchaseValidation((res){
print("res: " + res.toString());
});Please make sure to go over this guide to get a general understanding of how out of store attribution is set up in AppsFlyer, and how to implement it.
- Adding the conset dialog:
There are 2 ways to add it to your app:
a. Utilize the following Library: https://pub.dev/packages/app_tracking_transparency
Or
b. Add native implementation:
-
Add
#import <AppTrackingTransparency/AppTrackingTransparency.h>in yourAppDelegate.m -
Add the ATT pop-up for IDFA collection so your
AppDelegate.mwill look like this:
- (void)applicationDidBecomeActive:(nonnull UIApplication *)application {
if (@available(iOS 14, *)) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
// native code here
}];
}
}
- Add Privacy - Tracking Usage Description inside your
.plistfile in Xcode.
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>
- Optional: Set the
timeToWaitForATTUserAuthorizationproperty in theAppsFlyerOptionsto delay the sdk initazliation for a number ofx secondsuntil the user accept the consent dialog:
AppsFlyerOptions options = AppsFlyerOptions(
afDevKey: DotEnv().env["DEV_KEY"],
appId: DotEnv().env["APP_ID"],
showDebug: true,
timeToWaitForATTUserAuthorization: 30
); For more info visit our Full Support guide for iOS 14.