diff --git a/Shared/Localization/en.lproj/Localizable.strings b/Shared/Localization/en.lproj/Localizable.strings index 246079c..c637836 100644 --- a/Shared/Localization/en.lproj/Localizable.strings +++ b/Shared/Localization/en.lproj/Localizable.strings @@ -266,3 +266,4 @@ "Purchase cancelled." = "Purchase cancelled."; "Purchase pending approval." = "Purchase pending approval."; "Unable to obtain transaction payload." = "Unable to obtain transaction payload."; +"Resume Purchase" = "Resume Purchase"; diff --git a/Shared/Localization/zh-Hans.lproj/Localizable.strings b/Shared/Localization/zh-Hans.lproj/Localizable.strings index f930300..bc036a5 100644 --- a/Shared/Localization/zh-Hans.lproj/Localizable.strings +++ b/Shared/Localization/zh-Hans.lproj/Localizable.strings @@ -264,3 +264,4 @@ "Purchase cancelled." = "已取消购买"; "Purchase pending approval." = "购买等待确认"; "Unable to obtain transaction payload." = "无法获取交易凭据"; +"Resume Purchase" = "恢复购买"; diff --git a/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/Contents.json b/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/Contents.json new file mode 100644 index 0000000..1f445cc --- /dev/null +++ b/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "pay_resh_icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "pay_resh_icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/pay_resh_icon@2x.png b/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/pay_resh_icon@2x.png new file mode 100644 index 0000000..2c012c0 Binary files /dev/null and b/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/pay_resh_icon@2x.png differ diff --git a/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/pay_resh_icon@3x.png b/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/pay_resh_icon@3x.png new file mode 100644 index 0000000..eb39a63 Binary files /dev/null and b/keyBoard/Assets.xcassets/Pay/pay_resh_icon.imageset/pay_resh_icon@3x.png differ diff --git a/keyBoard/Class/Pay/StoreKit2Manager/KBStoreKitBridge.swift b/keyBoard/Class/Pay/StoreKit2Manager/KBStoreKitBridge.swift index ed92921..59752e4 100644 --- a/keyBoard/Class/Pay/StoreKit2Manager/KBStoreKitBridge.swift +++ b/keyBoard/Class/Pay/StoreKit2Manager/KBStoreKitBridge.swift @@ -67,6 +67,21 @@ final class KBStoreKitBridge: NSObject, StoreKitDelegate { } } + func restorePurchases(completion: @escaping (Bool, String?) -> Void) { + Task { + do { + try await self.manager.restorePurchases() + await MainActor.run { + completion(true, nil) + } + } catch { + await MainActor.run { + completion(false, error.localizedDescription) + } + } + } + } + // MARK: - Private Helpers @MainActor diff --git a/keyBoard/Class/Pay/V/KBVipPayHeaderView.m b/keyBoard/Class/Pay/V/KBVipPayHeaderView.m index d2ff5cf..3d73c90 100644 --- a/keyBoard/Class/Pay/V/KBVipPayHeaderView.m +++ b/keyBoard/Class/Pay/V/KBVipPayHeaderView.m @@ -38,7 +38,7 @@ [self.containerView addSubview:self.vipImageView]; [self.vipImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.right.left.equalTo(self.containerView).inset(KBFit(27)); - make.top.equalTo(self.containerView).offset(KB_NAV_TOTAL_HEIGHT + 10); + make.top.equalTo(self.containerView).offset(KB_NAV_TOTAL_HEIGHT + 25); make.height.mas_equalTo((269)); }]; [self.containerView addSubview:self.wanImageView]; diff --git a/keyBoard/Class/Pay/VC/KBVipPay.m b/keyBoard/Class/Pay/VC/KBVipPay.m index 77bd25f..1e51b41 100644 --- a/keyBoard/Class/Pay/VC/KBVipPay.m +++ b/keyBoard/Class/Pay/VC/KBVipPay.m @@ -23,6 +23,7 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId"; @property (nonatomic, strong) NSArray *plans; // 订阅方案数组 @property (nonatomic, assign) NSInteger selectedIndex; // 当前选中的方案索引 @property (nonatomic, strong) UIButton *closeButton; // 当前选中的方案索引 +@property (nonatomic, strong) UIButton *restoreButton; @property (nonatomic, strong) UIImageView *bgImageView; // 全屏背景图 // Header 自适应测量 @property (nonatomic, strong) KBVipPayHeaderView *sizingHeader; @@ -86,6 +87,13 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId"; make.left.equalTo(self.view).offset(15); make.width.height.mas_equalTo(36); }]; + [self.view addSubview:self.restoreButton]; + [self.restoreButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.closeButton); + make.right.equalTo(self.view).offset(-15); + make.width.mas_equalTo(123); + make.height.mas_equalTo(32); + }]; // 预计算 Header 高度(由内部约束决定) self.headerHeight = [self kb_calcHeaderHeightForWidth:KB_SCREEN_WIDTH]; @@ -217,6 +225,20 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId"; [KBHUD showInfo:KBLocalized(@"Open agreement")]; } +- (void)onTapRestoreButton { + [KBHUD show]; + __weak typeof(self) weakSelf = self; + [[KBStoreKitBridge shared] restorePurchasesWithCompletion:^(BOOL success, NSString * _Nullable message) { + dispatch_async(dispatch_get_main_queue(), ^{ + __strong typeof(weakSelf) self = weakSelf; + (void)self; + [KBHUD dismiss]; + NSString *tip = message.length ? message : (success ? KBLocalized(@"Success") : KBLocalized(@"Failed")); + [KBHUD showInfo:tip]; + }); + }]; +} + #pragma mark - UICollectionView DataSource - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { @@ -351,6 +373,25 @@ static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId"; return _closeButton; } +- (UIButton *)restoreButton { + if (!_restoreButton) { + _restoreButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _restoreButton.backgroundColor = [[UIColor colorWithHex:0xF6F7FB] colorWithAlphaComponent:0.72]; + _restoreButton.layer.cornerRadius = 8; + _restoreButton.layer.masksToBounds = YES; + UIImage *icon = [UIImage imageNamed:@"pay_resh_icon"]; + [_restoreButton setImage:icon forState:UIControlStateNormal]; + [_restoreButton setTitle:KBLocalized(@"Resume Purchase") forState:UIControlStateNormal]; + [_restoreButton setTitleColor:[UIColor colorWithHex:0x02BEAC] forState:UIControlStateNormal]; + _restoreButton.titleLabel.font = [KBFont medium:10]; + _restoreButton.contentEdgeInsets = UIEdgeInsetsMake(0, 12, 0, 12); + _restoreButton.imageEdgeInsets = UIEdgeInsetsMake(0, -4, 0, 4); + _restoreButton.titleEdgeInsets = UIEdgeInsetsMake(0, 6, 0, -6); + [_restoreButton addTarget:self action:@selector(onTapRestoreButton) forControlEvents:UIControlEventTouchUpInside]; + } + return _restoreButton; +} + - (UIButton *)payButton { if (!_payButton) { _payButton = [UIButton buttonWithType:UIButtonTypeCustom];