This commit is contained in:
2025-12-17 19:45:39 +08:00
parent 8bad475288
commit 886de394d0
10 changed files with 207 additions and 36 deletions

View File

@@ -24,6 +24,9 @@
#import "KBVipPay.h"
#import "KBUserSessionManager.h"
#import "KBLoginVC.h"
#import "KBConfig.h"
static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
// bundle id target
// PRODUCT_BUNDLE_IDENTIFIER
@@ -199,8 +202,36 @@
if ([action isEqualToString:@"autopay"]) {
autoPay = YES;
}
BOOL wantsPrefill = NO;
NSString *prefillFlag = params[@"prefill"];
if ([prefillFlag respondsToSelector:@selector(boolValue)] && prefillFlag.boolValue) {
wantsPrefill = YES;
}
NSString *src = params[@"src"];
if ([src isKindOfClass:NSString.class] && [src.lowercaseString isEqualToString:@"keyboard"]) {
wantsPrefill = YES;
}
NSDictionary *prefillPayload = wantsPrefill ? [self kb_consumeSubscriptionPrefillPayloadIfValid] : nil;
if ([prefillPayload isKindOfClass:NSDictionary.class]) {
NSString *payloadProductId = prefillPayload[@"productId"];
if (productId.length == 0 && [payloadProductId isKindOfClass:NSString.class]) {
productId = payloadProductId;
}
}
KBVipPay *vc = [[KBVipPay alloc] init];
[vc configureWithProductId:productId autoPurchase:autoPay];
if ([prefillPayload isKindOfClass:NSDictionary.class]) {
NSArray *productsJSON = prefillPayload[@"products"];
NSNumber *selectedIndexNumber = prefillPayload[@"selectedIndex"];
NSInteger selectedIndex = [selectedIndexNumber respondsToSelector:@selector(integerValue)] ? selectedIndexNumber.integerValue : NSNotFound;
[vc configureWithProductId:productId
autoPurchase:autoPay
prefillProductsJSON:productsJSON
selectedIndex:selectedIndex];
} else {
[vc configureWithProductId:productId autoPurchase:autoPay];
}
[KB_CURRENT_NAV pushViewController:vc animated:true];
return YES;
}
@@ -209,6 +240,23 @@
return NO;
}
- (nullable NSDictionary *)kb_consumeSubscriptionPrefillPayloadIfValid {
NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
if (!ud) { return nil; }
id obj = [ud objectForKey:AppGroup_SubscriptionPrefillPayload];
[ud removeObjectForKey:AppGroup_SubscriptionPrefillPayload];
[ud synchronize];
if (![obj isKindOfClass:NSDictionary.class]) { return nil; }
NSDictionary *payload = (NSDictionary *)obj;
NSNumber *ts = payload[@"ts"];
if (![ts respondsToSelector:@selector(doubleValue)]) { return nil; }
NSTimeInterval age = [NSDate date].timeIntervalSince1970 - ts.doubleValue;
if (age < 0 || age > kKBSubscriptionPrefillTTL) { return nil; }
id products = payload[@"products"];
if (![products isKindOfClass:NSArray.class] || ((NSArray *)products).count == 0) { return nil; }
return payload;
}
- (NSDictionary<NSString *, NSString *> *)kb_queryParametersFromURL:(NSURL *)url {
if (!url) { return @{}; }
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];

View File

@@ -15,6 +15,12 @@ NS_ASSUME_NONNULL_BEGIN
/// 通过键盘深链配置初始商品及是否自动发起购买
- (void)configureWithProductId:(nullable NSString *)productId
autoPurchase:(BOOL)autoPurchase;
/// 通过键盘扩展预填充商品列表(免二次请求)
- (void)configureWithProductId:(nullable NSString *)productId
autoPurchase:(BOOL)autoPurchase
prefillProductsJSON:(nullable NSArray *)productsJSON
selectedIndex:(NSInteger)selectedIndex;
@end
NS_ASSUME_NONNULL_END

View File

@@ -13,6 +13,7 @@
#import "KBPayProductModel.h"
#import "KBBizCode.h"
#import "keyBoard-Swift.h"
#import <MJExtension/MJExtension.h>
static NSString * const kKBVipHeaderId = @"kKBVipHeaderId";
static NSString * const kKBVipSubscribeCellId = @"kKBVipSubscribeCellId";
@@ -37,6 +38,9 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId";
@property (nonatomic, assign) BOOL pendingAutoPurchase;
@property (nonatomic, assign) BOOL hasTriggeredAutoPurchase;
@property (nonatomic, assign) BOOL viewVisible;
@property (nonatomic, copy, nullable) NSArray *prefillProductsJSON;
@property (nonatomic, assign) NSInteger prefillSelectedIndex;
@property (nonatomic, assign) BOOL didApplyPrefillPlans;
@end
@@ -59,6 +63,7 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId";
self.payVM = [PayVM new];
self.plans = @[];
self.selectedIndex = NSNotFound;
self.prefillSelectedIndex = NSNotFound;
//
[self.view addSubview:self.collectionView];
@@ -101,9 +106,12 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId";
// Header
self.headerHeight = [self kb_calcHeaderHeightForWidth:KB_SCREEN_WIDTH];
BOOL appliedPrefill = [self kb_applyPrefillPlansIfPossible];
[self.collectionView reloadData];
[self fetchSubscriptionPlans];
[self selectCurrentPlanAnimated:NO];
if (!appliedPrefill) {
[self fetchSubscriptionPlans];
}
}
- (void)viewDidAppear:(BOOL)animated {
@@ -128,6 +136,26 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId";
[self kb_triggerAutoPurchaseIfNeeded];
}
- (void)configureWithProductId:(nullable NSString *)productId
autoPurchase:(BOOL)autoPurchase
prefillProductsJSON:(nullable NSArray *)productsJSON
selectedIndex:(NSInteger)selectedIndex {
self.pendingProductId = productId.length ? [productId copy] : nil;
self.pendingAutoPurchase = autoPurchase;
self.hasTriggeredAutoPurchase = NO;
self.prefillProductsJSON = [productsJSON isKindOfClass:NSArray.class] ? [productsJSON copy] : nil;
self.prefillSelectedIndex = selectedIndex;
self.didApplyPrefillPlans = NO;
if (self.isViewLoaded) {
BOOL ok = [self kb_applyPrefillPlansIfPossible];
if (ok) {
[self.collectionView reloadData];
[self selectCurrentPlanAnimated:NO];
}
}
[self kb_triggerAutoPurchaseIfNeeded];
}
#pragma mark - Data
- (void)fetchSubscriptionPlans {
__weak typeof(self) weakSelf = self;
@@ -154,6 +182,30 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId";
}];
}
- (BOOL)kb_applyPrefillPlansIfPossible {
if (self.didApplyPrefillPlans) {
return (self.plans.count > 0);
}
if (![self.prefillProductsJSON isKindOfClass:NSArray.class] || self.prefillProductsJSON.count == 0) {
return NO;
}
NSArray<KBPayProductModel *> *models = [KBPayProductModel mj_objectArrayWithKeyValuesArray:self.prefillProductsJSON];
if (![models isKindOfClass:NSArray.class] || models.count == 0) {
return NO;
}
self.didApplyPrefillPlans = YES;
self.plans = models;
NSInteger idx = self.prefillSelectedIndex;
if (idx != NSNotFound && idx >= 0 && idx < (NSInteger)self.plans.count) {
self.selectedIndex = idx;
} else {
self.selectedIndex = (self.plans.count > 0) ? 0 : NSNotFound;
}
[self prepareStoreKitWithPlans:self.plans];
[self kb_applyPendingPrefillIfNeeded];
return YES;
}
- (void)prepareStoreKitWithPlans:(NSArray<KBPayProductModel *> *)plans {
if (![plans isKindOfClass:NSArray.class] || plans.count == 0) { return; }
NSMutableArray<NSString *> *ids = [NSMutableArray array];