Skip to content

Commit ab51f83

Browse files
authored
Merge pull request #636 from AppsFlyerSDK/dev/DELIVERY-92954/6.17.1-update
6.17.1 update
2 parents efebda7 + eca3576 commit ab51f83

File tree

7 files changed

+152
-70
lines changed

7 files changed

+152
-70
lines changed

Docs/RN_PurchaseConnector.md

Lines changed: 136 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ For more information please check the following pages:
3838
- [Subscription Purchase Data Source](#subscription-purchase-data-source)
3939
- [In-App Purchase Data Source](#in-app-purchase-data-source)
4040
- [Platform-Specific Implementation](#platform-specific-implementation)
41+
- [Logging Consumable Transactions](#logging-consumable-transactions)
4142
- [Important Notes](#important-notes)
4243

4344
## <a id="important-note"></a>Important Note ⚠️ ⚠️
4445

4546
The Purchase Connector feature of the AppsFlyer SDK depends on specific libraries provided by Google and Apple for managing in-app purchases:
4647

47-
- For Android, it depends on the [Google Play Billing Library](https://developer.android.com/google/play/billing/integrate) (Supported versions: 5.x.x - 6.x.x).
48-
- For iOS, it depends on [StoreKit](https://developer.apple.com/documentation/storekit).
48+
- For Android, it depends on the [Google Play Billing Library](https://developer.android.com/google/play/billing/integrate) (Supported versions: 5.x.x - 7.x.x).
49+
- For iOS, it depends on [StoreKit](https://developer.apple.com/documentation/storekit) (Supported versions: StoreKit1 and StoreKit2 (beta)).
4950

5051
However, these dependencies aren't actively included with the SDK. This means that the responsibility of managing these dependencies and including the necessary libraries in your project falls on you as the consumer of the SDK.
5152

@@ -86,19 +87,39 @@ To properly set up the configuration object, you must specify certain parameters
8687
- `logSubscriptions`: If set to `true`, the connector logs all subscription events.
8788
- `logInApps`: If set to `true`, the connector logs all in-app purchase events.
8889
- `sandbox`: If set to `true`, transactions are tested in a sandbox environment. Be sure to set this to `false` in production.
90+
- `storeKitVersion`: (iOS only) Specifies which StoreKit version to use. Defaults to `StoreKitVersion.SK1` if not specified. Use `StoreKitVersion.SK2` for iOS 15.0+ features.
8991

9092
Here's an example usage:
9193

9294
```javascript
9395
import appsFlyer, {
9496
AppsFlyerPurchaseConnector,
9597
AppsFlyerPurchaseConnectorConfig,
98+
StoreKitVersion,
9699
} from 'react-native-appsflyer';
97100

101+
// Example 1: StoreKit1 (default if storeKitVersion is not specified)
98102
const purchaseConnectorConfig: PurchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
99103
logSubscriptions: true,
100104
logInApps: true,
101105
sandbox: true,
106+
// storeKitVersion defaults to StoreKit1 if not specified
107+
});
108+
109+
// Example 2: Explicitly setting StoreKit1
110+
const purchaseConnectorConfigSK1: PurchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
111+
logSubscriptions: true,
112+
logInApps: true,
113+
sandbox: true,
114+
storeKitVersion: StoreKitVersion.SK1
115+
});
116+
117+
// Example 3: StoreKit2 (iOS 15.0+)
118+
const purchaseConnectorConfigSK2: PurchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
119+
logSubscriptions: true,
120+
logInApps: true,
121+
sandbox: true,
122+
storeKitVersion: StoreKitVersion.SK2
102123
});
103124

104125
//Create the object
@@ -125,6 +146,7 @@ For example:
125146
logSubscriptions: true,
126147
logInApps: true,
127148
sandbox: true,
149+
storeKitVersion: StoreKitVersion.SK1 // This will be ignored since instance already exists
128150
});
129151

130152
// purchaseConnector1 and purchaseConnector2 point to the same instance
@@ -145,15 +167,27 @@ Start the SDK instance to observe transactions. </br>
145167
import appsFlyer, {
146168
AppsFlyerPurchaseConnector,
147169
AppsFlyerPurchaseConnectorConfig,
170+
StoreKitVersion,
148171
} from 'react-native-appsflyer';
149172

150173
appsFlyer.startSdk();
174+
175+
// StoreKit1 example (default behavior)
151176
const purchaseConnectorConfig: PurchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
152-
logSubscriptions: true,
153-
logInApps: true,
154-
sandbox: true,
177+
logSubscriptions: true,
178+
logInApps: true,
179+
sandbox: true,
180+
// storeKitVersion: StoreKitVersion.SK1 // Optional - SK1 is default
155181
});
156182

183+
// StoreKit2 example (iOS 15.0+)
184+
// const purchaseConnectorConfig: PurchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
185+
// logSubscriptions: true,
186+
// logInApps: true,
187+
// sandbox: true,
188+
// storeKitVersion: StoreKitVersion.SK2
189+
// });
190+
157191
//Create the object
158192
AppsFlyerPurchaseConnector.create(purchaseConnectorConfig);
159193
//Start listening to transactions
@@ -199,10 +233,20 @@ const purchaseConnectorConfig = {
199233
And integrating both options into the example you provided would look like this:
200234

201235
```javascript
236+
// StoreKit1 configuration (default)
202237
const purchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
203238
logSubscriptions: true, // Enable automatic logging of subscription events
204239
logInApps: true, // Enable automatic logging of in-app purchase events
205240
sandbox: true, // Additional configuration option
241+
// storeKitVersion: StoreKitVersion.SK1 // Optional - defaults to SK1
242+
});
243+
244+
// StoreKit2 configuration (iOS 15.0+)
245+
const purchaseConnectorConfigSK2 = AppsFlyerPurchaseConnectorConfig.setConfig({
246+
logSubscriptions: true, // Enable automatic logging of subscription events
247+
logInApps: true, // Enable automatic logging of in-app purchase events
248+
sandbox: true, // Additional configuration option
249+
storeKitVersion: StoreKitVersion.SK2 // Required for StoreKit2
206250
});
207251
```
208252

@@ -318,15 +362,20 @@ Add following keep rules to your `proguard-rules.pro` file:
318362

319363
## <a id="full-code-example"></a>Full Code Example
320364
```javascript
321-
const purchaseConnectorConfig: PurchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
365+
import appsFlyer, {
366+
StoreKitVersion,
367+
AppsFlyerPurchaseConnector,
368+
AppsFlyerPurchaseConnectorConfig,
369+
} from 'react-native-appsflyer';
370+
371+
const purchaseConnectorConfig = AppsFlyerPurchaseConnectorConfig.setConfig({
322372
logSubscriptions: true,
323373
logInApps: true,
324374
sandbox: true,
375+
storeKitVersion: StoreKitVersion.SK2
325376
});
326377

327-
AppsFlyerPurchaseConnector.create(
328-
purchaseConnectorConfig,
329-
);
378+
AppsFlyerPurchaseConnector.create(purchaseConnectorConfig);
330379

331380
const handleValidationSuccess = (validationResult) => {
332381
console.log('>> ValidationSuccess: ', validationResult);
@@ -417,14 +466,13 @@ AppsFlyerPurchaseConnector.setPurchaseRevenueDataSource({
417466
```javascript
418467
// Set additional parameters for StoreKit2 purchases
419468
AppsFlyerPurchaseConnector.setPurchaseRevenueDataSourceStoreKit2({
420-
products: [
421-
{ product_id: 'com.app.subscription.monthly' },
422-
{ product_id: 'com.app.subscription.yearly' }
423-
],
424-
transactions: [
425-
{ transaction_id: 'transaction123' },
426-
{ transaction_id: 'transaction456' }
427-
]
469+
additionalParameters: {
470+
user_id: '12345',
471+
user_type: 'premium',
472+
purchase_source: 'app_store',
473+
custom_param1: 'value1',
474+
custom_param2: 'value2'
475+
}
428476
});
429477
```
430478

@@ -469,7 +517,7 @@ When implementing these data sources in your app, you should consider the platfo
469517

470518
```javascript
471519
import { Platform } from 'react-native';
472-
import AppsFlyerPurchaseConnector from 'react-native-appsflyer-plugin';
520+
import { AppsFlyerPurchaseConnector } from 'react-native-appsflyer';
473521

474522
const setupPurchaseDataSources = () => {
475523
if (Platform.OS === 'ios') {
@@ -484,12 +532,11 @@ const setupPurchaseDataSources = () => {
484532

485533
// iOS StoreKit2 data source (iOS 15.0+)
486534
AppsFlyerPurchaseConnector.setPurchaseRevenueDataSourceStoreKit2({
487-
products: [
488-
{ product_id: 'com.app.subscription.monthly' }
489-
],
490-
transactions: [
491-
{ transaction_id: 'transaction123' }
492-
]
535+
additionalParameters: {
536+
user_id: '12345',
537+
user_type: 'premium',
538+
purchase_source: 'app_store'
539+
}
493540
});
494541
} else if (Platform.OS === 'android') {
495542
// Android subscription data source
@@ -513,6 +560,59 @@ const setupPurchaseDataSources = () => {
513560
};
514561
```
515562

563+
564+
### <a id="logging-consumable-transactions"></a>Logging Consumable Transactions
565+
566+
On iOS 15 and above, consumable in-app purchases are handled via StoreKit 2. The behavior depends on your iOS version:
567+
568+
- **On iOS 18 and later:**
569+
Apple introduced a new Info.plist flag: `SKIncludeConsumableInAppPurchaseHistory`.
570+
- If you set `SKIncludeConsumableInAppPurchaseHistory` to `YES` in your Info.plist, automatic collection will happen.
571+
- If the flag is not present or is set to `NO`, you must manually log consumable transactions as shown below.
572+
573+
- **On iOS 15–17:**
574+
Consumable purchases must always be logged manually.
575+
576+
To manually log consumable transactions, use the `logConsumableTransaction` method after finishing the transaction:
577+
578+
```javascript
579+
import { Platform } from 'react-native';
580+
import { AppsFlyerPurchaseConnector } from 'react-native-appsflyer';
581+
582+
// Purchase update listener
583+
purchaseUpdatedListener((purchase) => {
584+
console.log("🛒 Purchase updated:", purchase.productId, "Transaction ID:", purchase.transactionId);
585+
const isConsumable = consumablesItems.includes(purchase.productId);
586+
587+
finishTransaction({ purchase, isConsumable })
588+
.then((res) => {
589+
console.log("✅ finishTransaction success:", res);
590+
console.log("🔍 Expecting AppsFlyer validation callback for:", purchase.productId);
591+
592+
// Log consumable transaction for iOS
593+
if (Platform.OS === 'ios' && isConsumable && purchase.transactionId) {
594+
AppsFlyerPurchaseConnector.logConsumableTransaction(purchase.transactionId);
595+
console.log("📝 Consumable transaction logged:", purchase.transactionId);
596+
}
597+
})
598+
.catch((error) => {
599+
console.warn("❌ Error finishing transaction:", error);
600+
});
601+
});
602+
```
603+
604+
### Method Signature
605+
606+
```javascript
607+
AppsFlyerPurchaseConnector.logConsumableTransaction(transactionId: string): void
608+
```
609+
610+
**Parameters:**
611+
- `transactionId` (string): The unique transaction identifier from the App Store transaction
612+
613+
**Note:** This method is iOS-specific and should only be called on iOS devices. On Android, consumable transactions are automatically handled by the Purchase Connector.
614+
615+
516616
### <a id="important-notes"></a>Important Notes
517617

518618
1. **iOS StoreKit2**: The StoreKit2 data source is only available on iOS 15.0 and later. Make sure to check the iOS version before using it.
@@ -525,17 +625,25 @@ const setupPurchaseDataSources = () => {
525625

526626
```javascript
527627
// 1. Create the connector
528-
await AppsFlyerPurchaseConnector.create({
628+
// StoreKit1 (default)
629+
AppsFlyerPurchaseConnector.create({
529630
logSubscriptions: true,
530631
logInApps: true,
531-
sandbox: __DEV__
632+
sandbox: __DEV__,
633+
// storeKitVersion: StoreKitVersion.SK1 // Optional - defaults to SK1
532634
});
533635

636+
// OR for StoreKit2 (iOS 15.0+)
637+
// AppsFlyerPurchaseConnector.create({
638+
// logSubscriptions: true,
639+
// logInApps: true,
640+
// sandbox: __DEV__,
641+
// storeKitVersion: StoreKitVersion.SK2
642+
// });
643+
534644
// 2. Set up data sources
535645
setupPurchaseDataSources();
536646

537647
// 3. Start observing transactions
538648
await AppsFlyerPurchaseConnector.startObservingTransactions();
539649
```
540-
541-
4. **Validation**: The parameters you set will be included in the purchase events sent to AppsFlyer. You can verify this in the AppsFlyer dashboard under the purchase events section.

README.md

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,22 @@
1313
### <a id="plugin-build-for"> This plugin is built for
1414

1515
- Android AppsFlyer SDK **v6.17.0**
16-
- iOS AppsFlyer SDK **v6.17.0**
16+
- iOS AppsFlyer SDK **v6.17.1**
1717
- Tested with React-Native **v0.62.0** (older versions might be supported)
1818

19-
## <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).
19+
## <a id="release-updates"> Release Updates
2120

22-
- 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).
21+
- Starting with version `6.17.1` the plugin supports the Purchase Connector for validating and measuring Subscription and In-app purchase events. Integration guide can be found [here](https://github.com/AppsFlyerSDK/appsflyer-react-native-plugin/blob/master/Docs/RN_PurchaseConnector.md).
2322

24-
- From version `6.15.1`, iOS Minimum deployment target is set to 12.0.
23+
- Starting with version `6.17.1` the TypeScript interfaces for Purchase Connector data sources have been simplified and are now **breaking changes**:
24+
- `PurchaseRevenueDataSource.purchaseRevenueAdditionalParametersForProducts()` function has been replaced with `additionalParameters` object
25+
- `PurchaseRevenueDataSourceStoreKit2.purchaseRevenueAdditionalParametersStoreKit2ForProducts()` function has been replaced with `additionalParameters` object
2526

26-
- From version `6.3.0`, we use `xcframework` for iOS platform. Then you need to use cocoapods version >= 1.10
27+
- Starting with 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).
2728

28-
- From version `6.2.30`, `logCrossPromotionAndOpenStore` api will register as `af_cross_promotion` instead of `af_app_invites` in your dashboard.<br>
29-
Click on a link that was generated using `generateInviteLink` api will be register as `af_app_invites`.
29+
- Starting with 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).
3030

31-
- From version `6.0.0` we have renamed the following APIs:
32-
33-
| Old API | New API |
34-
| ----------------------------- | ----------------------------- |
35-
| trackEvent | logEvent |
36-
| trackLocation | logLocation |
37-
| stopTracking | stop |
38-
| trackCrossPromotionImpression | logCrossPromotionImpression |
39-
| trackAndOpenStore | logCrossPromotionAndOpenStore |
40-
| setDeviceTrackingDisabled | anonymizeUser |
41-
| AppsFlyerTracker | AppsFlyerLib |
42-
43-
And removed the following ones:
44-
45-
- trackAppLaunch -> no longer needed. See new init guide
46-
- sendDeepLinkData -> no longer needed. See new init guide
47-
- enableUninstallTracking -> no longer needed. See new uninstall measurement guide
48-
49-
If you have used 1 of the removed APIs, please check the integration guide for the updated instructions.
31+
- Starting with version `6.15.1`, iOS Minimum deployment target is set to 12.0.
5032

5133
---
5234

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.17.01";
9+
final static String PLUGIN_VERSION = "6.17.1";
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";

index.d.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,18 +216,12 @@ declare module "react-native-appsflyer" {
216216

217217
//PurchaseRevenueDataSourceSK1
218218
export interface PurchaseRevenueDataSource {
219-
purchaseRevenueAdditionalParametersForProducts?: (
220-
products: any[], // SKProduct array
221-
transactions: any[] // SKPaymentTransaction array
222-
) => { [key: string]: any } | null;
219+
additionalParameters?: { [key: string]: any };
223220
}
224221

225222
// PurchaseRevenueDataSourceStoreKit2
226223
export interface PurchaseRevenueDataSourceStoreKit2 {
227-
purchaseRevenueAdditionalParametersStoreKit2ForProducts: (
228-
products: any[], // AFSDKProductSK2 array
229-
transactions: any[] // AFSDKTransactionSK2 array
230-
) => { [key: string]: any } | null;
224+
additionalParameters?: { [key: string]: any };
231225
}
232226

233227
// Android interfaces

ios/PCAppsFlyer.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,12 @@ @implementation PCAppsFlyer
148148
// Delegate method for StoreKit1
149149
- (NSDictionary *)purchaseRevenueAdditionalParametersForProducts:(NSSet<SKProduct *> *)products
150150
transactions:(NSSet<SKPaymentTransaction *> *)transactions {
151-
// Simply return the parameters that were set from React Native
152151
return self.purchaseRevenueParams;
153152
}
154153

155154
// Delegate method for StoreKit2
156155
- (NSDictionary<NSString *, id> *)purchaseRevenueAdditionalParametersStoreKit2ForProducts:(NSSet<AFSDKProductSK2 *> *)products
157156
transactions:(NSSet<AFSDKTransactionSK2 *> *)transactions {
158-
// Simply return the parameters that were set from React Native
159157
return self.purchaseRevenueStoreKit2Params;
160158
}
161159

ios/RNAppsFlyer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
@end
2323

2424

25-
static NSString *const kAppsFlyerPluginVersion = @"6.17.01";
25+
static NSString *const kAppsFlyerPluginVersion = @"6.17.1";
2626
static NSString *const NO_DEVKEY_FOUND = @"No 'devKey' found or its empty";
2727
static NSString *const NO_APPID_FOUND = @"No 'appId' found or its empty";
2828
static NSString *const NO_EVENT_NAME_FOUND = @"No 'eventName' found or its empty";

0 commit comments

Comments
 (0)