This commit is contained in:
2025-12-12 14:46:38 +08:00
parent 3813974eae
commit 1eeeef266b
8 changed files with 230 additions and 56 deletions

View File

@@ -57,6 +57,7 @@
/// pay /// pay
#define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表 #define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表
#define API_INAPP_PRODUCT_LIST @"/products/inApp/list" // 查询 type=in-app-purchase 的商品列表
/// AI /// AI
#define API_AI_TALK @"/chat/talk" // 排行榜标签列表 #define API_AI_TALK @"/chat/talk" // 排行榜标签列表

View File

@@ -20,6 +20,7 @@
04122F872EC6198C00EF7AB3 /* WMDragView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F852EC6198C00EF7AB3 /* WMDragView.m */; }; 04122F872EC6198C00EF7AB3 /* WMDragView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F852EC6198C00EF7AB3 /* WMDragView.m */; };
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; }; 04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */; }; 04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */; };
04B5A1A22EEFA12300AAAAAA /* KBPayProductModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 04B5A1A12EEFA12300AAAAAA /* KBPayProductModel.m */; };
04122F8E2EC6F83F00EF7AB3 /* PayVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8D2EC6F83F00EF7AB3 /* PayVM.m */; }; 04122F8E2EC6F83F00EF7AB3 /* PayVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8D2EC6F83F00EF7AB3 /* PayVM.m */; };
04122F912EC73AF700EF7AB3 /* KBVipPay.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F902EC73AF700EF7AB3 /* KBVipPay.m */; }; 04122F912EC73AF700EF7AB3 /* KBVipPay.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F902EC73AF700EF7AB3 /* KBVipPay.m */; };
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FA92EC73C0100EF7AB3 /* KBVipPayHeaderView.m */; }; 04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FA92EC73C0100EF7AB3 /* KBVipPayHeaderView.m */; };
@@ -247,6 +248,8 @@
04122F852EC6198C00EF7AB3 /* WMDragView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WMDragView.m; sourceTree = "<group>"; }; 04122F852EC6198C00EF7AB3 /* WMDragView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WMDragView.m; sourceTree = "<group>"; };
04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IAPVerifyTransactionObj.h; sourceTree = "<group>"; }; 04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IAPVerifyTransactionObj.h; sourceTree = "<group>"; };
04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IAPVerifyTransactionObj.m; sourceTree = "<group>"; }; 04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IAPVerifyTransactionObj.m; sourceTree = "<group>"; };
04B5A1A02EEFA12300AAAAAA /* KBPayProductModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBPayProductModel.h; sourceTree = "<group>"; };
04B5A1A12EEFA12300AAAAAA /* KBPayProductModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPayProductModel.m; sourceTree = "<group>"; };
04122F8C2EC6F83F00EF7AB3 /* PayVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PayVM.h; sourceTree = "<group>"; }; 04122F8C2EC6F83F00EF7AB3 /* PayVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PayVM.h; sourceTree = "<group>"; };
04122F8D2EC6F83F00EF7AB3 /* PayVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PayVM.m; sourceTree = "<group>"; }; 04122F8D2EC6F83F00EF7AB3 /* PayVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PayVM.m; sourceTree = "<group>"; };
04122F8F2EC73AF700EF7AB3 /* KBVipPay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipPay.h; sourceTree = "<group>"; }; 04122F8F2EC73AF700EF7AB3 /* KBVipPay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipPay.h; sourceTree = "<group>"; };
@@ -625,6 +628,8 @@
children = ( children = (
04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */, 04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */,
04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */, 04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */,
04B5A1A02EEFA12300AAAAAA /* KBPayProductModel.h */,
04B5A1A12EEFA12300AAAAAA /* KBPayProductModel.m */,
); );
path = M; path = M;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1748,6 +1753,7 @@
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */, 04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */,
04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */, 04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */,
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */, 04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */,
04B5A1A22EEFA12300AAAAAA /* KBPayProductModel.m in Sources */,
04286A062ECC81B200CE730C /* KBSkinService.m in Sources */, 04286A062ECC81B200CE730C /* KBSkinService.m in Sources */,
0479204A2EDDCE25004E8522 /* KBUserSessionManager.m in Sources */, 0479204A2EDDCE25004E8522 /* KBUserSessionManager.m in Sources */,
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */, 04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */,

View File

@@ -45,8 +45,10 @@
[KBHUD showInfo:(sta == !KBBizCodeSuccess ? KBLocalized(@"Payment failed") : KBLocalized(@"Payment successful"))]; [KBHUD showInfo:(sta == !KBBizCodeSuccess ? KBLocalized(@"Payment failed") : KBLocalized(@"Payment successful"))];
if (sta == KBBizCodeSuccess) { if (sta == KBBizCodeSuccess) {
[[SKPaymentQueue defaultQueue] finishTransaction:transaction]; [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[KBHUD showSuccess:@"Success"];
if (handler) handler(KBLocalized(@"Success"), nil); if (handler) handler(KBLocalized(@"Success"), nil);
} else { } else {
[KBHUD showError:@"Failed"];
if (handler) handler(KBLocalized(@"Failed"), nil); if (handler) handler(KBLocalized(@"Failed"), nil);
} }
(void)weakSelf; // keep self during block life if needed (void)weakSelf; // keep self during block life if needed

View File

@@ -0,0 +1,44 @@
//
// KBPayProductModel.h
// keyBoard
//
// Created to map /products/inApp/list responses to strongly typed objects.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/// 内购商品模型
@interface KBPayProductModel : NSObject
/// 主键 id
@property (nonatomic, assign) NSInteger identifier;
/// Apple IAP 商品编号
@property (nonatomic, copy, nullable) NSString *productId;
/// 商品类型(例如 in-app-purchase
@property (nonatomic, copy, nullable) NSString *type;
/// 商品名称(如 100、1000
@property (nonatomic, copy, nullable) NSString *name;
/// 单位(如 金币)
@property (nonatomic, copy, nullable) NSString *unit;
/// 有效期数值(可能为 0
@property (nonatomic, assign) NSInteger durationValue;
/// 有效期单位(如 day/week
@property (nonatomic, copy, nullable) NSString *durationUnit;
/// 有效期天数
@property (nonatomic, assign) NSInteger durationDays;
/// 价格
@property (nonatomic, assign) double price;
/// 货币符号
@property (nonatomic, copy, nullable) NSString *currency;
/// 文案描述
@property (nonatomic, copy, nullable) NSString *productDescription;
/// 展示金币(自动拼接单位)
- (NSString *)coinsDisplayText;
/// 展示价格,保留两位小数
- (NSString *)priceDisplayText;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,38 @@
//
// KBPayProductModel.m
// keyBoard
//
#import "KBPayProductModel.h"
#import <MJExtension/MJExtension.h>
@implementation KBPayProductModel
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{
@"identifier": @"id",
@"productDescription": @"description",
};
}
- (NSString *)coinsDisplayText {
NSString *name = self.name ?: @"";
NSString *unit = self.unit ?: @"";
if (name.length && unit.length) {
return [NSString stringWithFormat:@"%@ %@", name, unit];
}
if (name.length) { return name; }
if (unit.length) { return unit; }
return @"";
}
- (NSString *)priceDisplayText {
NSString *currency = self.currency ?: @"";
double priceValue = self.price;
if (currency.length > 0) {
return [NSString stringWithFormat:@"%@%.2f", currency, priceValue];
}
return [NSString stringWithFormat:@"%.2f", priceValue];
}
@end

View File

@@ -6,6 +6,9 @@
#import "KBJfPayCell.h" #import "KBJfPayCell.h"
#import "FGIAPProductsFilter.h" #import "FGIAPProductsFilter.h"
#import "FGIAPManager.h" #import "FGIAPManager.h"
#import "PayVM.h"
#import "KBPayProductModel.h"
#import "KBBizCode.h"
static NSString * const kKBJfPayCellId = @"kKBJfPayCellId"; static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
@interface KBJfPay () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout> @interface KBJfPay () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@@ -32,10 +35,11 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
@property (nonatomic, strong) UIButton *agreementButton; @property (nonatomic, strong) UIButton *agreementButton;
// //
@property (nonatomic, strong) NSArray<NSDictionary *> *data; // @{coins, price} @property (nonatomic, strong) NSArray<KBPayProductModel *> *data; // In-App
@property (nonatomic, assign) NSInteger selectedIndex; // @property (nonatomic, assign) NSInteger selectedIndex; //
@property (nonatomic, strong) FGIAPProductsFilter *filter; @property (nonatomic, strong) FGIAPProductsFilter *filter;
@property (nonatomic, strong) PayVM *payVM;
@end @end
@@ -44,6 +48,9 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.filter = [[FGIAPProductsFilter alloc] init]; self.filter = [[FGIAPProductsFilter alloc] init];
self.payVM = [PayVM new];
self.data = @[];
self.selectedIndex = NSNotFound;
self.bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"my_bg_icon"]]; self.bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"my_bg_icon"]];
self.bgImageView.contentMode = UIViewContentModeScaleAspectFill; self.bgImageView.contentMode = UIViewContentModeScaleAspectFill;
self.kb_navView.backgroundColor = [UIColor clearColor]; self.kb_navView.backgroundColor = [UIColor clearColor];
@@ -53,17 +60,6 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
}]; }];
self.kb_titleLabel.text = KBLocalized(@"Points Recharge"); self.kb_titleLabel.text = KBLocalized(@"Points Recharge");
//
self.data = @[
@{ @"coins": @690, @"price": @"$6.90",@"product_id" : @"100_coin" },
@{ @"coins": @1280, @"price": @"$12.90" ,@"product_id" : @"vip_a_week" },
@{ @"coins": @3290, @"price": @"$32.90" ,@"product_id" : @"100_coin" },
@{ @"coins": @4990, @"price": @"$49.90" ,@"product_id" : @"100_coin" },
@{ @"coins": @9990, @"price": @"$99.90" ,@"product_id" : @"100_coin" },
@{ @"coins": @19990,@"price": @"$199.90" ,@"product_id" : @"100_coin" },
];
self.selectedIndex = 0;
// //
[self.view addSubview:self.myPointsTitleLabel]; [self.view addSubview:self.myPointsTitleLabel];
[self.view addSubview:self.pointsLabel]; [self.view addSubview:self.pointsLabel];
@@ -139,34 +135,19 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
// //
[self.collectionView reloadData]; [self.collectionView reloadData];
// [self fetchInAppProductList];
dispatch_async(dispatch_get_main_queue(), ^{
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:0];
// 便 setSelected UI
if (ip) {
[self.collectionView selectItemAtIndexPath:ip animated:NO scrollPosition:UICollectionViewScrollPositionNone];
}
KBJfPayCell *cell = (KBJfPayCell *)[self.collectionView cellForItemAtIndexPath:ip];
if (cell) { [cell applySelected:YES animated:NO]; }
});
} }
- (void)viewDidAppear:(BOOL)animated { - (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated]; [super viewDidAppear:animated];
// reload cell [self selectItemAtCurrentIndexAnimated:NO];
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:0];
if (ip) {
[self.collectionView selectItemAtIndexPath:ip animated:NO scrollPosition:UICollectionViewScrollPositionNone];
}
KBJfPayCell *cell = (KBJfPayCell *)[self.collectionView cellForItemAtIndexPath:ip];
if (cell) { [cell applySelected:YES animated:NO]; }
} }
#pragma mark - UICollectionView Delegate (ensure first show) #pragma mark - UICollectionView Delegate (ensure first show)
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { - (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
if (![cell isKindOfClass:KBJfPayCell.class]) { return; } if (![cell isKindOfClass:KBJfPayCell.class]) { return; }
KBJfPayCell *c = (KBJfPayCell *)cell; KBJfPayCell *c = (KBJfPayCell *)cell;
BOOL sel = (indexPath.item == self.selectedIndex); BOOL sel = (self.selectedIndex != NSNotFound && indexPath.item == self.selectedIndex);
if (sel) { if (sel) {
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; [collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
} }
@@ -194,9 +175,9 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
KBJfPayCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBJfPayCellId forIndexPath:indexPath]; KBJfPayCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBJfPayCellId forIndexPath:indexPath];
NSDictionary *item = self.data[indexPath.item]; KBPayProductModel *model = self.data[indexPath.item];
NSString *coins = [NSString stringWithFormat:@"%@", item[@"coins"]]; NSString *coins = [model coinsDisplayText];
NSString *price = item[@"price"]; // "$6.90" NSString *price = [model priceDisplayText];
[cell configCoins:coins price:price]; [cell configCoins:coins price:price];
[cell applySelected:(indexPath.item == self.selectedIndex) animated:NO]; [cell applySelected:(indexPath.item == self.selectedIndex) animated:NO];
return cell; return cell;
@@ -235,30 +216,89 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
return 30; return 30;
} }
#pragma mark - Data
- (void)fetchInAppProductList {
__weak typeof(self) weakSelf = self;
[self.payVM fetchInAppProductsNeedShow:YES completion:^(NSInteger sta, NSString * _Nullable msg, NSArray<KBPayProductModel *> * _Nullable products) {
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) self = weakSelf;
if (!self) { return; }
if (sta != KBBizCodeSuccess || ![products isKindOfClass:NSArray.class]) {
self.data = @[];
self.selectedIndex = NSNotFound;
[self.collectionView reloadData];
NSString *tip = msg.length ? msg : KBLocalized(@"Failed to load products");
[KBHUD showInfo:tip];
return;
}
self.data = products ?: @[];
self.selectedIndex = self.data.count > 0 ? 0 : NSNotFound;
[self.collectionView reloadData];
[self selectItemAtCurrentIndexAnimated:NO];
});
}];
}
- (KBPayProductModel *)currentSelectedProductItem {
if (self.selectedIndex == NSNotFound) { return nil; }
if (self.selectedIndex < 0 || self.selectedIndex >= self.data.count) { return nil; }
id item = self.data[self.selectedIndex];
if (![item isKindOfClass:KBPayProductModel.class]) { return nil; }
return item;
}
- (void)selectItemAtCurrentIndexAnimated:(BOOL)animated {
if (self.selectedIndex == NSNotFound) { return; }
if (self.selectedIndex < 0 || self.selectedIndex >= self.data.count) { return; }
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:0];
if (!ip) { return; }
dispatch_async(dispatch_get_main_queue(), ^{
if (self.selectedIndex == NSNotFound) { return; }
if ([self.collectionView numberOfItemsInSection:0] <= ip.item) { return; }
[self.collectionView selectItemAtIndexPath:ip animated:animated scrollPosition:UICollectionViewScrollPositionNone];
KBJfPayCell *cell = (KBJfPayCell *)[self.collectionView cellForItemAtIndexPath:ip];
if ([cell isKindOfClass:KBJfPayCell.class]) {
[cell applySelected:YES animated:animated];
}
});
}
#pragma mark - Actions #pragma mark - Actions
- (void)onTapPayButton { - (void)onTapPayButton {
// UI KBPayProductModel *selectedItem = [self currentSelectedProductItem];
// if (self.selectedIndex >= 0 && self.selectedIndex < self.data.count) { if (!selectedItem) {
// NSDictionary *item = self.data[self.selectedIndex]; [KBHUD showInfo:KBLocalized(@"Please select a product")];
// NSString *msg = [NSString stringWithFormat:@"购买:%@ Coins %@", item[@"coins"], item[@"price"]]; return;
// [KBHUD showInfo:msg]; }
// } NSString *productId = selectedItem.productId;
NSString *productId = @"com.loveKey.nyx.1day"; if (productId.length == 0) {
/// 2. [KBHUD showInfo:KBLocalized(@"Product unavailable")];
return;
}
[KBHUD show]; [KBHUD show];
__weak typeof(self) weakSelf = self;
[self.filter requestProductsWith:[NSSet setWithObject:productId] completion:^(NSArray<SKProduct *> * _Nonnull products) { [self.filter requestProductsWith:[NSSet setWithObject:productId] completion:^(NSArray<SKProduct *> * _Nonnull products) {
// NSLog(@"====="); dispatch_async(dispatch_get_main_queue(), ^{
// if (products.count > 0) { __strong typeof(weakSelf) self = weakSelf;
// SKProduct *pro = productsp[0]; if (!self) { return; }
// } SKProduct *match = nil;
// [[FGIAPManager shared].iap buyProduct:product onCompletion:^(NSString * _Nonnull message, FGIAPManagerPurchaseRusult result) { }]; for (SKProduct *product in products) {
if ([product.productIdentifier isEqualToString:productId]) {
/// 3. match = product;
SKProduct *product = products.firstObject; break;
[[FGIAPManager shared].iap buyProduct:products.firstObject onCompletion:^(NSString * _Nonnull message, FGIAPManagerPurchaseRusult result) { }
// [self.view makeToast:message]; }
if (!match) {
[KBHUD dismiss]; [KBHUD dismiss];
[KBHUD showInfo:KBLocalized(@"Unable to load product information")];
return;
}
[[FGIAPManager shared].iap buyProduct:match onCompletion:^(NSString * _Nonnull message, FGIAPManagerPurchaseRusult result) {
dispatch_async(dispatch_get_main_queue(), ^{
[KBHUD dismiss];
});
}]; }];
});
}]; }];
} }

View File

@@ -5,13 +5,17 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@class KBPayProductModel;
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
/// 统一的支付回调sta 为状态码0 成功,非 0 失败msg 为后端返回的消息 /// 统一的支付回调sta 为状态码0 成功,非 0 失败msg 为后端返回的消息
typedef void(^KBPayCompletion)(NSInteger sta, NSString * _Nullable msg); typedef void(^KBPayCompletion)(NSInteger sta, NSString * _Nullable msg);
/// 统一状态码(与原 Swift 代码的 succCode / errorCode 语义一致 /// In-App 商品列表回调(返回 data 数组
typedef void(^KBPayProductsCompletion)(NSInteger sta,
NSString * _Nullable msg,
NSArray<KBPayProductModel *> * _Nullable products);
@interface PayVM : NSObject @interface PayVM : NSObject
@@ -22,7 +26,10 @@ typedef void(^KBPayCompletion)(NSInteger sta, NSString * _Nullable msg);
needShow:(BOOL)needShow needShow:(BOOL)needShow
completion:(KBPayCompletion)completion; completion:(KBPayCompletion)completion;
/// 查询 type=in-app-purchase 的商品列表
- (void)fetchInAppProductsNeedShow:(BOOL)needShow
completion:(KBPayProductsCompletion)completion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -7,6 +7,8 @@
#import "KBAPI.h" #import "KBAPI.h"
#import "KBHUD.h" #import "KBHUD.h"
#import "KBBizCode.h" #import "KBBizCode.h"
#import "KBPayProductModel.h"
#import <MJExtension/MJExtension.h>
@implementation PayVM @implementation PayVM
- (void)applePayReqWithParams:(NSDictionary *)params - (void)applePayReqWithParams:(NSDictionary *)params
@@ -28,6 +30,40 @@
}]; }];
} }
- (void)fetchInAppProductsNeedShow:(BOOL)needShow
completion:(KBPayProductsCompletion)completion {
if (needShow) { [KBHUD show]; }
NSDictionary *params = @{ @"type": @"in-app-purchase" };
[[KBNetworkManager shared] GET:API_INAPP_PRODUCT_LIST
parameters:params
headers:nil
autoShowBusinessError:NO
completion:^(NSDictionary * _Nullable json,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
if (needShow) { [KBHUD dismiss]; }
if (error) {
if (completion) {
NSInteger code = (error.code == 0 ? KBBizCodeSystemError : error.code);
completion(code, error.localizedDescription ?: KBLocalized(@"Network error"), nil);
}
return;
}
id dataObj = json[KBData] ?: json[@"data"];
if (![dataObj isKindOfClass:[NSArray class]]) {
if (completion) {
NSString *msg = [self.class extractMessageFromResponseObject:json] ?: KBLocalized(@"Invalid response");
completion(KBBizCodeSystemError, msg, nil);
}
return;
}
NSArray<KBPayProductModel *> *models = [KBPayProductModel mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
if (completion) {
completion(KBBizCodeSuccess, nil, models ?: @[]);
}
}];
}
#pragma mark - Helpers #pragma mark - Helpers
//+ (NSInteger)extractStatusFromResponseObject:(id)obj response:(NSURLResponse *)resp { //+ (NSInteger)extractStatusFromResponseObject:(id)obj response:(NSURLResponse *)resp {