Skip to content

Commit

Permalink
Adding StoreKit2
Browse files Browse the repository at this point in the history
Adding to PCConfiguration storeKitVersion enum, adding logConsumableTransaction and transactionFetcher class to handle it.
  • Loading branch information
al-af committed Jan 15, 2025
1 parent 99cd680 commit 26b0a57
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ demos/appsflyer-expo-app/yarn.lock

demos/appsflyer-react-native-app/ios/.xcode.env
demos/appsflyer-react-native-app/ios/AppsFlyerExample.xcodeproj/project.pbxproj

android/bin/
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public void create(ReadableMap config) {
boolean logInApps = config.getBoolean("logInApps");
boolean sandbox = config.getBoolean("sandbox");

// Optional: Log that storeKitVersion is ignored on Android (for debugging purposes)
if (config.hasKey("storeKitVersion")) {
String storeKitVersion = config.getString("storeKitVersion");
Log.d(TAG, "storeKitVersion (" + storeKitVersion + ") is ignored on Android.");
}

MappedValidationResultListener arsListener = this.arsListener;
MappedValidationResultListener viapListener = this.viapListener;

Expand Down
7 changes: 7 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,16 @@ declare module "react-native-appsflyer" {
/**
* PurchaseConnector
*/
export const StoreKitVersion = {
SK1: "SK1",
SK2: "SK2",
};

export interface PurchaseConnectorConfig {
logSubscriptions: boolean;
logInApps: boolean;
sandbox: boolean;
storeKitVersion?: keyof typeof StoreKitVersion; // Optional property
}

export const AppsFlyerPurchaseConnectorConfig: {
Expand All @@ -180,6 +186,7 @@ declare module "react-native-appsflyer" {
create(config: PurchaseConnectorConfig): void;
startObservingTransactions(): void;
stopObservingTransactions(): void;
logConsumableTransaction(transactionId: string): void;
onSubscriptionValidationResultSuccess(
callback: (data:OnResponse<SubscriptionValidationResult>) => any
): () => void;
Expand Down
9 changes: 8 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,19 @@ AppsFlyerPurchaseConnector.OnReceivePurchaseRevenueValidationInfo = (
};
};

function logConsumableTransaction(transactionId){
PCAppsFlyer.logConsumableTransaction(transactionId);
};

AppsFlyerPurchaseConnector.logConsumableTransaction = logConsumableTransaction;

const AppsFlyerPurchaseConnectorConfig = {
setConfig: ({ logSubscriptions, logInApps, sandbox }) => {
setConfig: ({ logSubscriptions, logInApps, sandbox, storeKitVersion }) => {
return {
logSubscriptions,
logInApps,
sandbox,
storeKitVersion: storeKitVersion || StoreKitVersion.SK1, // Default to SK1 if not provided
};
},
};
Expand Down
41 changes: 40 additions & 1 deletion ios/PCAppsFlyer.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@

#if __has_include(<PurchaseConnector/PurchaseConnector.h>)
#import <PurchaseConnector/PurchaseConnector.h>
#import "RNAppsFlyer-Swift.h"

@implementation PCAppsFlyer
@synthesize bridge = _bridge;

static NSString *const logSubscriptionsKey = @"logSubscriptions";
static NSString *const logInAppsKey = @"logInApps";
static NSString *const sandboxKey = @"sandbox";
static NSString *const storeKitKey = @"storeKitVersion";
static NSString *const connectorAlreadyConfiguredMessage = @"Connector already configured";
static NSString *const connectorNotConfiguredMessage = @"Connector not configured, did you call `create` first?";

Expand Down Expand Up @@ -41,9 +43,19 @@ @implementation PCAppsFlyer
BOOL logSubscriptions = [config[logSubscriptionsKey] boolValue];
BOOL logInApps = [config[logInAppsKey] boolValue];
BOOL sandbox = [config[sandboxKey] boolValue];

NSString *storeKitVersion = config[storeKitKey];

[connector setIsSandbox:sandbox];

// Set the StoreKitVersion (default to SK1 if not provided or invalid)
if ([storeKitVersion isEqualToString:@"SK2"]) {
[connector setStoreKitVersion:AFSDKStoreKitVersionSK2];
NSLog(@"%@Configure PurchaseConnector with StoreKit2 Version", TAG);
} else {
[connector setStoreKitVersion:AFSDKStoreKitVersionSK1];
NSLog(@"%@Configure PurchaseConnector with StoreKit1 Version", TAG);
}

if (logSubscriptions && logInApps) {
[connector setAutoLogPurchaseRevenue:AFSDKAutoLogPurchaseRevenueOptionsAutoRenewableSubscriptions | AFSDKAutoLogPurchaseRevenueOptionsInAppPurchases];
}
Expand All @@ -58,6 +70,33 @@ @implementation PCAppsFlyer
resolve(nil);
}

RCT_EXPORT_METHOD(logConsumableTransaction:(NSString *)transactionId
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSLog(@"%@Logging consumable transaction with ID: %@", TAG, transactionId);

if (connector == nil) {
reject(connectorNotConfiguredMessage, connectorNotConfiguredMessage, nil);
return;
}

// Call the Swift method via the TransactionFetcher class
[TransactionFetcher fetchTransactionWithId:transactionId completion:^(AFSDKTransactionSK2 * _Nullable afTransaction) {
if (afTransaction) {
// Use the fetched transaction
[connector logConsumableTransaction:afTransaction];
NSLog(@"Logged transaction: %@", transactionId);
resolve(nil);
} else {
// Handle the case where the transaction was not found
NSError *error = [NSError errorWithDomain:@"PCAppsFlyer"
code:404
userInfo:@{NSLocalizedDescriptionKey: @"Transaction not found"}];
reject(@"transaction_not_found", @"Transaction not found", error);
}
}];
}

RCT_EXPORT_METHOD(startObservingTransactions:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSLog(@"%@Starting to observe transactions.", TAG);
Expand Down
15 changes: 15 additions & 0 deletions ios/RNAppsFlyer-Bridging-Header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// RNAppsFlyer-Bridging-Header.h
// RNAppsFlyer
//
// Created by Amit Levy on 15/01/2025.
// Copyright © 2025 Facebook. All rights reserved.
//

#ifndef _RNAppsFlyer_Bridging_Header_h
#define _RNAppsFlyer_Bridging_Header_h

#import <Foundation/Foundation.h>
#import <PurchaseConnector/PurchaseConnector.h>

#endif /* _RNAppsFlyer_Bridging_Header_h */
51 changes: 51 additions & 0 deletions ios/RNAppsFlyer.xcodeproj/project.pbxproj
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
objects = {

/* Begin PBXBuildFile section */
7E215B402D3683B60088EE50 /* PCAppsFlyer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E215B3E2D3683B60088EE50 /* PCAppsFlyer.m */; };
7E215B412D3683B60088EE50 /* TransactionFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E215B3F2D3683B60088EE50 /* TransactionFetcher.swift */; };
7E215B422D3683B60088EE50 /* AppsFlyerAttribution.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E215B372D3683B60088EE50 /* AppsFlyerAttribution.m */; };
7E215B4B2D37AFF60088EE50 /* RNAppsFlyer-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E215B492D37AEE10088EE50 /* RNAppsFlyer-Bridging-Header.h */; settings = {ATTRIBUTES = (Private, ); }; };
B3E7B58A1CC2AC0600A0062D /* RNAppsFlyer.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNAppsFlyer.m */; };
/* End PBXBuildFile section */

Expand All @@ -24,6 +28,18 @@

/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRNAppsFlyer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNAppsFlyer.a; sourceTree = BUILT_PRODUCTS_DIR; };
7E215B352D3683B60088EE50 /* AFAdRevenueData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AFAdRevenueData.h; sourceTree = "<group>"; };
7E215B362D3683B60088EE50 /* AppsFlyerAttribution.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppsFlyerAttribution.h; sourceTree = "<group>"; };
7E215B372D3683B60088EE50 /* AppsFlyerAttribution.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppsFlyerAttribution.m; sourceTree = "<group>"; };
7E215B382D3683B60088EE50 /* AppsFlyerConsent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppsFlyerConsent.h; sourceTree = "<group>"; };
7E215B392D3683B60088EE50 /* AppsFlyerDeepLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppsFlyerDeepLink.h; sourceTree = "<group>"; };
7E215B3A2D3683B60088EE50 /* AppsFlyerDeepLinkObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppsFlyerDeepLinkObserver.h; sourceTree = "<group>"; };
7E215B3B2D3683B60088EE50 /* AppsFlyerDeepLinkResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppsFlyerDeepLinkResult.h; sourceTree = "<group>"; };
7E215B3C2D3683B60088EE50 /* AppsFlyerLib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppsFlyerLib.h; sourceTree = "<group>"; };
7E215B3D2D3683B60088EE50 /* PCAppsFlyer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PCAppsFlyer.h; sourceTree = "<group>"; };
7E215B3E2D3683B60088EE50 /* PCAppsFlyer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PCAppsFlyer.m; sourceTree = "<group>"; };
7E215B3F2D3683B60088EE50 /* TransactionFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionFetcher.swift; sourceTree = "<group>"; };
7E215B492D37AEE10088EE50 /* RNAppsFlyer-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RNAppsFlyer-Bridging-Header.h"; sourceTree = "<group>"; };
943704C6209F6734005B3A22 /* AppsFlyerShareInviteHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppsFlyerShareInviteHelper.h; sourceTree = "<group>"; };
943704C7209F6734005B3A22 /* AppsFlyerLinkGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppsFlyerLinkGenerator.h; sourceTree = "<group>"; };
943704C9209F6735005B3A22 /* AppsFlyerCrossPromotionHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppsFlyerCrossPromotionHelper.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -53,22 +69,54 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
7E215B352D3683B60088EE50 /* AFAdRevenueData.h */,
7E215B362D3683B60088EE50 /* AppsFlyerAttribution.h */,
7E215B372D3683B60088EE50 /* AppsFlyerAttribution.m */,
7E215B382D3683B60088EE50 /* AppsFlyerConsent.h */,
7E215B392D3683B60088EE50 /* AppsFlyerDeepLink.h */,
7E215B3A2D3683B60088EE50 /* AppsFlyerDeepLinkObserver.h */,
7E215B3B2D3683B60088EE50 /* AppsFlyerDeepLinkResult.h */,
7E215B3C2D3683B60088EE50 /* AppsFlyerLib.h */,
7E215B3D2D3683B60088EE50 /* PCAppsFlyer.h */,
7E215B3E2D3683B60088EE50 /* PCAppsFlyer.m */,
7E215B3F2D3683B60088EE50 /* TransactionFetcher.swift */,
943704C9209F6735005B3A22 /* AppsFlyerCrossPromotionHelper.h */,
943704C7209F6734005B3A22 /* AppsFlyerLinkGenerator.h */,
943704C6209F6734005B3A22 /* AppsFlyerShareInviteHelper.h */,
B3E7B5881CC2AC0600A0062D /* RNAppsFlyer.h */,
B3E7B5891CC2AC0600A0062D /* RNAppsFlyer.m */,
7E215B492D37AEE10088EE50 /* RNAppsFlyer-Bridging-Header.h */,
134814211AA4EA7D00B7C361 /* Products */,
7E215B4C2D37B0770088EE50 /* Frameworks */,
);
sourceTree = "<group>";
};
7E215B4C2D37B0770088EE50 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
7E215B4A2D37AFE20088EE50 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
7E215B4B2D37AFF60088EE50 /* RNAppsFlyer-Bridging-Header.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */

/* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RNAppsFlyer */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNAppsFlyer" */;
buildPhases = (
7E215B4A2D37AFE20088EE50 /* Headers */,
58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */,
58B511D91A9E6C8500147676 /* CopyFiles */,
Expand Down Expand Up @@ -121,6 +169,9 @@
buildActionMask = 2147483647;
files = (
B3E7B58A1CC2AC0600A0062D /* RNAppsFlyer.m in Sources */,
7E215B402D3683B60088EE50 /* PCAppsFlyer.m in Sources */,
7E215B412D3683B60088EE50 /* TransactionFetcher.swift in Sources */,
7E215B422D3683B60088EE50 /* AppsFlyerAttribution.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
27 changes: 27 additions & 0 deletions ios/TransactionFetcher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Foundation
import StoreKit
import PurchaseConnector

@objc class TransactionFetcher: NSObject {
@objc static func fetchTransaction(withId transactionId: String, completion: @escaping (AFSDKTransactionSK2?) -> Void) {
Task {
if #available(iOS 15.0, *) {
do {
let allTransactions = try await Transaction.all
if let matchingTransaction = allTransactions.first(where: { $0.id == UInt64(transactionId) }) {
let afTransaction = AFSDKTransactionSK2(transaction: matchingTransaction)
completion(afTransaction)
} else {
completion(nil)
}
} catch {
print("Error fetching transactions: \(error)")
completion(nil)
}
} else {
print("StoreKit 2 is not available on this iOS version.")
completion(nil)
}
}
}
}

0 comments on commit 26b0a57

Please sign in to comment.