// // UIViewController+Purchase.cpp // Unity-iPhone // // Created by Hl Zhang on 2023/3/21. // #import "UIViewController+Purchase.h" #import "UIViewController+Wallet.h" #import "Utilities.h" #import "StoreManager.h" #import "StoreObserver.h" #import "AppConfiguration.h" #import #import "SKProduct+SKProductAdditions.h" #include #import "NSString+Customer.h" #include "JcWallet.h" static Utilities *utility = nil; @interface UIViewController (Purchase) @property (nonatomic) NSString *currentFunId; @end @implementation UIViewController (Purchase) -(void)initPurchaseEnv { utility = [[Utilities alloc] init]; // [[NSNotificationCenter defaultCenter] addObserver:self // selector:@selector(handleProductRequestNotification:) // name:PCSProductRequestNotification // object:[StoreManager sharedInstance]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePurchaseNotification:) name:PCSPurchaseNotification object:[StoreObserver sharedInstance]]; } #pragma mark - Query products /// Retrieves product information from the App Store. - (void)queryProducts:(NSString *) funId products: (NSString *) products { if (utility == nil) { [self initPurchaseEnv]; } if (products == nil || [products isEqualToString:@""]) { NSLog(@"queryProducts with empty products: %@", products); [self nativeCb:funId hasErr:YES dataStr:@"queryProducts with empty products"]; return; } // split products to array NSArray *identifiers = [products componentsSeparatedByString:@","]; // First, let's check whether the user is allowed to make purchases. Proceed if they are allowed. Display an alert, otherwise. if ([StoreObserver sharedInstance].isAuthorizedForPayments) { // Fetch the product information. [[StoreManager sharedInstance] fetchProductsMatchingIdentifiers:identifiers completionBlock: ^(PCSProductRequestStatus status, NSMutableArray *storeResponse){ if (status == PCSStoreResponse) { // define json array to return NSMutableArray *jsonArray = [[NSMutableArray alloc] init]; for (Section *section in storeResponse) { NSArray *content = section.elements; if ([section.name isEqualToString:PCSProductsAvailableProducts]) { for (SKProduct *product in content) { NSMutableDictionary *json = [[NSMutableDictionary alloc] init]; [json setObject:product.productIdentifier forKey:@"id"]; [json setObject:product.localizedTitle forKey:@"name"]; [json setObject:product.localizedDescription forKey:@"description"]; [json setObject:product.priceLocale.currencyCode forKey:@"currencyCode"]; [json setObject:product.price.stringValue forKey:@"priceValue"]; [json setObject:product.regularPrice forKey:@"priceShow"]; [jsonArray addObject:json]; } } else if ([section.name isEqualToString:PCSProductsInvalidIdentifiers]) { // if there are invalid product identifiers, show them. NSLog(@"Invalid product identifiers: %@", section.name); // [self nativeCb:funId hasErr:YES dataStr: section.name]; } } NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonArray options:NSJSONWritingPrettyPrinted error:&error]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; if (!jsonData) { NSLog(@"Got an error: %@", error); [self nativeCb:funId hasErr:YES dataStr: [NSString stringWithFormat:@"%@", error]]; } else { NSLog(@"jsonString: %@", jsonString); [self nativeCb:funId hasErr:NO dataStr: jsonString]; } } else if (status == PCSRequestFailed) { NSLog(@"Product request failed with message: %@", [StoreManager sharedInstance].message); [self nativeCb:funId hasErr:YES dataStr: [StoreManager sharedInstance].message]; } }]; } else { // Warn the user that they are not allowed to make purchases. NSLog(@"User is not allowed to make payments (Payments are disabled in Settings)."); [self nativeCb:funId hasErr:YES dataStr: [NSString stringWithFormat:@"%@", PCSMessagesCannotMakePayments]]; } } #pragma mark - Query Purchase - (void)queryPurchase:(NSString *)funId { if (utility == nil) { [self initPurchaseEnv]; } NSArray *transations = [[StoreObserver sharedInstance] queryPendingTransactions]; // convert to json string NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:transations options:NSJSONWritingPrettyPrinted error:&error]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; [self nativeCb:funId hasErr:NO dataStr:jsonString]; } #pragma mark - Begin Buy Product - (void)beginBuy:(NSString *)funId productId:(NSString *)productId orderId:(NSString *)orderId { if (utility == nil) { [self initPurchaseEnv]; } if (productId == nil || [productId isEqualToString:@""]) { NSLog(@"beginBy with empty productId: %@", productId); [self nativeCb:funId hasErr:YES dataStr:@"beginBy with empty productId"]; return; } // check if currentFunId is empty if (self.currentFunId != nil && ![self.currentFunId isEqualToString:@""]) { NSLog(@"beginBy with currentFunId: %@", self.currentFunId); [self nativeCb:funId hasErr:YES dataStr:@"other purchase is processing"]; return; } self.currentFunId = funId; SKProduct *product = [[StoreManager sharedInstance] productMatchingIdentifier: productId]; if (product == nil) { NSLog(@"beginBy with empty product: %@", productId); self.currentFunId = nil; [self nativeCb:funId hasErr:YES dataStr:@"beginBy with empty product"]; return; } if (orderId == nil || [orderId isEqualToString:@""]) { NSLog(@"beginBy with empty orderId: %@", orderId); self.currentFunId = nil; [self nativeCb:funId hasErr:YES dataStr:@"beginBy with empty orderId"]; return; } [[StoreObserver sharedInstance] buy:product orderId: orderId]; } #pragma mark - Finish Transaction - (void)finishTransaction:(NSString *)funId transactionId: (NSString *) transactionId { [[StoreObserver sharedInstance] finishTransaction: transactionId]; [self nativeCb:funId hasErr:NO dataStr:@""]; } /// Creates and displays an alert. -(void)alertWithTitle:(NSString *)title message:(NSString *)message { UIAlertController *alertController = [utility alertWithTitle:title message:message]; [self.navigationController presentViewController:alertController animated:YES completion:nil]; } #pragma mark - Handle PCSProductRequest Notification /// Updates the UI according to the product request notification result. -(void)handleProductRequestNotification:(NSNotification *)notification { StoreManager *productRequestNotification = (StoreManager*)notification.object; PCSProductRequestStatus status = (PCSProductRequestStatus)productRequestNotification.status; NSLog(@"handleProductRequestNotification status: %ld", (long)status); } #pragma mark - Handle PCSPurchase Notification /// Updates the UI according to the purchase request notification result. -(void)handlePurchaseNotification:(NSNotification *)notification { NSDictionary* dic = notification.userInfo; NSNumber *errcode = dic[@"errcode"]; NSLog(@"handlePurchaseNotification status: %@", errcode); // check if errcode is zero or not self.currentFunId = nil; if (errcode != nil && [errcode intValue] != 0) { [self nativeCb:self.currentFunId hasErr:YES dataStr: [NSString stringWithFormat:@"%@", dic[@"errmsg"]]]; } else { NSString *tid = dic[@"dataid"]; NSMutableArray *transactions = [[NSMutableArray alloc] init]; [transactions addObject:tid]; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:transactions options:NSJSONWritingPrettyPrinted error:&error]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; [self nativeCb:self.currentFunId hasErr:NO dataStr: jsonString]; } } #pragma mark - Handle Restored Transactions /// Handles succesful restored transactions. Switches to the Purchases view. -(void)handleRestoredSucceededTransaction { utility.restoreWasCalled = YES; // Refresh the Purchases view with the restored purchases. // [self switchToViewController:ParentViewControllerSegmentPurchases]; // [self.purchases reloadWithData:self.utility.dataSourceForPurchasesUI]; // self.segmentedControl.selectedSegmentIndex = ParentViewControllerSegmentPurchases; } @end