内购功能开发,配置内购商品
This commit is contained in:
parent
6d690cc471
commit
337c25baaf
@ -208,6 +208,11 @@
|
|||||||
BFF5B25A2DF13BE50044227A /* VPGiveCoinRecordsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2592DF13BE50044227A /* VPGiveCoinRecordsCell.swift */; };
|
BFF5B25A2DF13BE50044227A /* VPGiveCoinRecordsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2592DF13BE50044227A /* VPGiveCoinRecordsCell.swift */; };
|
||||||
BFF5B25C2DF13F850044227A /* Date+VPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B25B2DF13F850044227A /* Date+VPAdd.swift */; };
|
BFF5B25C2DF13F850044227A /* Date+VPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B25B2DF13F850044227A /* Date+VPAdd.swift */; };
|
||||||
BFF5B25E2DF1423F0044227A /* VPWalletBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B25D2DF1423F0044227A /* VPWalletBaseCell.swift */; };
|
BFF5B25E2DF1423F0044227A /* VPWalletBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B25D2DF1423F0044227A /* VPWalletBaseCell.swift */; };
|
||||||
|
BFF5B2612DF16B430044227A /* JXIAPManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B25F2DF16B430044227A /* JXIAPManager.swift */; };
|
||||||
|
BFF5B2642DF16C380044227A /* VPIAPManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2632DF16C380044227A /* VPIAPManager.swift */; };
|
||||||
|
BFF5B2662DF16CF60044227A /* VPWaitRestoreModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2652DF16CF60044227A /* VPWaitRestoreModel.swift */; };
|
||||||
|
BFF5B2682DF16EA30044227A /* VPIAPOrderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2672DF16EA30044227A /* VPIAPOrderModel.swift */; };
|
||||||
|
BFF5B26A2DF170DD0044227A /* VPIAPVerifyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2692DF170DD0044227A /* VPIAPVerifyModel.swift */; };
|
||||||
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
|
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@ -421,6 +426,11 @@
|
|||||||
BFF5B2592DF13BE50044227A /* VPGiveCoinRecordsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPGiveCoinRecordsCell.swift; sourceTree = "<group>"; };
|
BFF5B2592DF13BE50044227A /* VPGiveCoinRecordsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPGiveCoinRecordsCell.swift; sourceTree = "<group>"; };
|
||||||
BFF5B25B2DF13F850044227A /* Date+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+VPAdd.swift"; sourceTree = "<group>"; };
|
BFF5B25B2DF13F850044227A /* Date+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+VPAdd.swift"; sourceTree = "<group>"; };
|
||||||
BFF5B25D2DF1423F0044227A /* VPWalletBaseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWalletBaseCell.swift; sourceTree = "<group>"; };
|
BFF5B25D2DF1423F0044227A /* VPWalletBaseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWalletBaseCell.swift; sourceTree = "<group>"; };
|
||||||
|
BFF5B25F2DF16B430044227A /* JXIAPManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXIAPManager.swift; sourceTree = "<group>"; };
|
||||||
|
BFF5B2632DF16C380044227A /* VPIAPManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPIAPManager.swift; sourceTree = "<group>"; };
|
||||||
|
BFF5B2652DF16CF60044227A /* VPWaitRestoreModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWaitRestoreModel.swift; sourceTree = "<group>"; };
|
||||||
|
BFF5B2672DF16EA30044227A /* VPIAPOrderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPIAPOrderModel.swift; sourceTree = "<group>"; };
|
||||||
|
BFF5B2692DF170DD0044227A /* VPIAPVerifyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPIAPVerifyModel.swift; sourceTree = "<group>"; };
|
||||||
E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = "<group>"; };
|
E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@ -498,6 +508,7 @@
|
|||||||
1B056E352DDAC1DE007EE38D /* Libs */ = {
|
1B056E352DDAC1DE007EE38D /* Libs */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
BFF5B2622DF16BE10044227A /* VPIAPManager */,
|
||||||
BFF5B2352DF013020044227A /* Alert */,
|
BFF5B2352DF013020044227A /* Alert */,
|
||||||
BF5E75D92DE5B89300DE9DFE /* MarqueeView */,
|
BF5E75D92DE5B89300DE9DFE /* MarqueeView */,
|
||||||
BF5E75B42DE46D9500DE9DFE /* Empty */,
|
BF5E75B42DE46D9500DE9DFE /* Empty */,
|
||||||
@ -715,6 +726,7 @@
|
|||||||
BF0FA6E82DDC5F6F00C9E5F2 /* Thirdparty */ = {
|
BF0FA6E82DDC5F6F00C9E5F2 /* Thirdparty */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
BFF5B2602DF16B430044227A /* JXIAPManager */,
|
||||||
BF5E75CA2DE5692D00DE9DFE /* JXTransition */,
|
BF5E75CA2DE5692D00DE9DFE /* JXTransition */,
|
||||||
BF0FA7932DE16E9300C9E5F2 /* JXTagView */,
|
BF0FA7932DE16E9300C9E5F2 /* JXTagView */,
|
||||||
BF0FA6ED2DDC5F8700C9E5F2 /* JXUUID */,
|
BF0FA6ED2DDC5F8700C9E5F2 /* JXUUID */,
|
||||||
@ -1174,6 +1186,25 @@
|
|||||||
path = Alert;
|
path = Alert;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
BFF5B2602DF16B430044227A /* JXIAPManager */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
BFF5B25F2DF16B430044227A /* JXIAPManager.swift */,
|
||||||
|
);
|
||||||
|
path = JXIAPManager;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
BFF5B2622DF16BE10044227A /* VPIAPManager */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
BFF5B2632DF16C380044227A /* VPIAPManager.swift */,
|
||||||
|
BFF5B2652DF16CF60044227A /* VPWaitRestoreModel.swift */,
|
||||||
|
BFF5B2672DF16EA30044227A /* VPIAPOrderModel.swift */,
|
||||||
|
BFF5B2692DF170DD0044227A /* VPIAPVerifyModel.swift */,
|
||||||
|
);
|
||||||
|
path = VPIAPManager;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -1321,6 +1352,7 @@
|
|||||||
BF0FA6DC2DDC5CD700C9E5F2 /* VPTokenModel.swift in Sources */,
|
BF0FA6DC2DDC5CD700C9E5F2 /* VPTokenModel.swift in Sources */,
|
||||||
BF0FA7572DDF159B00C9E5F2 /* VPExploreViewController.swift in Sources */,
|
BF0FA7572DDF159B00C9E5F2 /* VPExploreViewController.swift in Sources */,
|
||||||
1B056E772DDB3641007EE38D /* VPTabBarItemNormalVew.swift in Sources */,
|
1B056E772DDB3641007EE38D /* VPTabBarItemNormalVew.swift in Sources */,
|
||||||
|
BFF5B2662DF16CF60044227A /* VPWaitRestoreModel.swift in Sources */,
|
||||||
1B056E4B2DDAC6BA007EE38D /* VPDefine.swift in Sources */,
|
1B056E4B2DDAC6BA007EE38D /* VPDefine.swift in Sources */,
|
||||||
BFF5B2302DEFEF0C0044227A /* VPDeleteAccountNormalView.swift in Sources */,
|
BFF5B2302DEFEF0C0044227A /* VPDeleteAccountNormalView.swift in Sources */,
|
||||||
1B056E702DDB019B007EE38D /* VPTabBarItemContainer.swift in Sources */,
|
1B056E702DDB019B007EE38D /* VPTabBarItemContainer.swift in Sources */,
|
||||||
@ -1359,6 +1391,7 @@
|
|||||||
BFF5AFA42DE6F15E0044227A /* VPMeVipCell.swift in Sources */,
|
BFF5AFA42DE6F15E0044227A /* VPMeVipCell.swift in Sources */,
|
||||||
BFF5AFB02DE7F9A80044227A /* VPVipViewController.swift in Sources */,
|
BFF5AFB02DE7F9A80044227A /* VPVipViewController.swift in Sources */,
|
||||||
BF0FA75D2DDF208400C9E5F2 /* VPExplorePlayerControlView.swift in Sources */,
|
BF0FA75D2DDF208400C9E5F2 /* VPExplorePlayerControlView.swift in Sources */,
|
||||||
|
BFF5B2682DF16EA30044227A /* VPIAPOrderModel.swift in Sources */,
|
||||||
BFF5B21C2DEEDE130044227A /* VPWebViewController+Script.swift in Sources */,
|
BFF5B21C2DEEDE130044227A /* VPWebViewController+Script.swift in Sources */,
|
||||||
BF5E75CB2DE5692D00DE9DFE /* UINavigationController+JXTransition.swift in Sources */,
|
BF5E75CB2DE5692D00DE9DFE /* UINavigationController+JXTransition.swift in Sources */,
|
||||||
BF5E75CC2DE5692D00DE9DFE /* JXTransitionDefine.swift in Sources */,
|
BF5E75CC2DE5692D00DE9DFE /* JXTransitionDefine.swift in Sources */,
|
||||||
@ -1429,6 +1462,7 @@
|
|||||||
BFF5AFA82DE704DC0044227A /* VPMeCoinCell.swift in Sources */,
|
BFF5AFA82DE704DC0044227A /* VPMeCoinCell.swift in Sources */,
|
||||||
BFF5AFAE2DE717BB0044227A /* VPVipPageViewController.swift in Sources */,
|
BFF5AFAE2DE717BB0044227A /* VPVipPageViewController.swift in Sources */,
|
||||||
BFF5B2502DF12FBC0044227A /* VPConsumptionRecordsViewController.swift in Sources */,
|
BFF5B2502DF12FBC0044227A /* VPConsumptionRecordsViewController.swift in Sources */,
|
||||||
|
BFF5B2642DF16C380044227A /* VPIAPManager.swift in Sources */,
|
||||||
BF0FA70E2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift in Sources */,
|
BF0FA70E2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift in Sources */,
|
||||||
BF0FA6D72DDC5BE100C9E5F2 /* VPURLPath.swift in Sources */,
|
BF0FA6D72DDC5BE100C9E5F2 /* VPURLPath.swift in Sources */,
|
||||||
1B056E5B2DDACD80007EE38D /* UIColor+VPAdd.swift in Sources */,
|
1B056E5B2DDACD80007EE38D /* UIColor+VPAdd.swift in Sources */,
|
||||||
@ -1470,11 +1504,13 @@
|
|||||||
BFF5AFAC2DE70CE20044227A /* VPMeToolCell.swift in Sources */,
|
BFF5AFAC2DE70CE20044227A /* VPMeToolCell.swift in Sources */,
|
||||||
BF5E75B32DE465EC00DE9DFE /* Dictionary+SPAdd.swift in Sources */,
|
BF5E75B32DE465EC00DE9DFE /* Dictionary+SPAdd.swift in Sources */,
|
||||||
BF0FA7162DDC78FF00C9E5F2 /* ZKCycleScrollViewFlowLayout.swift in Sources */,
|
BF0FA7162DDC78FF00C9E5F2 /* ZKCycleScrollViewFlowLayout.swift in Sources */,
|
||||||
|
BFF5B2612DF16B430044227A /* JXIAPManager.swift in Sources */,
|
||||||
BF0FA7172DDC78FF00C9E5F2 /* ZKCycleScrollView.swift in Sources */,
|
BF0FA7172DDC78FF00C9E5F2 /* ZKCycleScrollView.swift in Sources */,
|
||||||
BF0FA7612DDFFE7100C9E5F2 /* VPVideoDetailModel.swift in Sources */,
|
BF0FA7612DDFFE7100C9E5F2 /* VPVideoDetailModel.swift in Sources */,
|
||||||
BFF5AFD22DE9A58A0044227A /* VPVIPRecordViewController.swift in Sources */,
|
BFF5AFD22DE9A58A0044227A /* VPVIPRecordViewController.swift in Sources */,
|
||||||
BFF5AFDA2DEE90350044227A /* VPVideoLockView.swift in Sources */,
|
BFF5AFDA2DEE90350044227A /* VPVideoLockView.swift in Sources */,
|
||||||
BF5E75B82DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift in Sources */,
|
BF5E75B82DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift in Sources */,
|
||||||
|
BFF5B26A2DF170DD0044227A /* VPIAPVerifyModel.swift in Sources */,
|
||||||
BF0FA6D52DDC5B5D00C9E5F2 /* VPApi.swift in Sources */,
|
BF0FA6D52DDC5B5D00C9E5F2 /* VPApi.swift in Sources */,
|
||||||
BF0FA7C12DE45D5D00C9E5F2 /* VPUserInfo.swift in Sources */,
|
BF0FA7C12DE45D5D00C9E5F2 /* VPUserInfo.swift in Sources */,
|
||||||
BF0FA7392DDECF8900C9E5F2 /* VPHomeListViewController.swift in Sources */,
|
BF0FA7392DDECF8900C9E5F2 /* VPHomeListViewController.swift in Sources */,
|
||||||
|
@ -14,6 +14,27 @@ extension AppDelegate {
|
|||||||
UIView.vp_Awake()
|
UIView.vp_Awake()
|
||||||
|
|
||||||
VPToast.config()
|
VPToast.config()
|
||||||
|
|
||||||
|
congifNavigation()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AppDelegate {
|
||||||
|
|
||||||
|
private func congifNavigation() {
|
||||||
|
|
||||||
|
let barButtonItem = UIBarButtonItem.appearance()
|
||||||
|
|
||||||
|
barButtonItem.setTitleTextAttributes([
|
||||||
|
.foregroundColor : UIColor.colorFFFFFF(),
|
||||||
|
], for: .normal)
|
||||||
|
|
||||||
|
barButtonItem.setTitleTextAttributes([
|
||||||
|
.foregroundColor : UIColor.colorFFFFFF()
|
||||||
|
], for: .highlighted)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
|
|
||||||
VPLoginManager.manager.updateUserInfo(completer: nil)
|
VPLoginManager.manager.updateUserInfo(completer: nil)
|
||||||
|
|
||||||
|
let _ = JXIAPManager.manager
|
||||||
|
|
||||||
self.registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
|
self.registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -15,3 +15,6 @@ let kVPLoginTokenDefaultsKey = "kVPLoginTokenDefaultsKey"
|
|||||||
|
|
||||||
///用户信息
|
///用户信息
|
||||||
let kVPLoginUserInfoDefaultsKey = "kSPLoginUserInfoDefaultsKey"
|
let kVPLoginUserInfoDefaultsKey = "kSPLoginUserInfoDefaultsKey"
|
||||||
|
|
||||||
|
///待恢复数据
|
||||||
|
let kVPWaitRestoreIAPDefaultsKey = "kVPWaitRestoreIAPDefaultsKey"
|
||||||
|
@ -20,6 +20,21 @@ class VPWalletAPI {
|
|||||||
param.method = .get
|
param.method = .get
|
||||||
|
|
||||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPPayTemplateModel>) in
|
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPPayTemplateModel>) in
|
||||||
|
/*
|
||||||
|
if let data = response.data {
|
||||||
|
var vipList: [VPPayTemplateItem] = []
|
||||||
|
data.list_sub_vip?.forEach({
|
||||||
|
if $0.vip_type_key == .quarter {
|
||||||
|
vipList.append($0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
data.list_sub_vip = vipList
|
||||||
|
completer?(data)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
completer?(nil)
|
||||||
|
}
|
||||||
|
*/
|
||||||
completer?(response.data)
|
completer?(response.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,4 +95,46 @@ class VPWalletAPI {
|
|||||||
completer?(response.data)
|
completer?(response.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///创建内购订单
|
||||||
|
static func requestCreateOrder(payId: String, shortPlayId: String, videoId: String, completer: ((_ orderModel: VPIAPOrderModel?) -> Void)?) {
|
||||||
|
var param = VPNetworkParameters(path: "/createOrder")
|
||||||
|
param.isToast = false
|
||||||
|
param.parameters = [
|
||||||
|
"payment_channel" : "apple",
|
||||||
|
"short_play_id" : shortPlayId,
|
||||||
|
"video_id" : videoId,
|
||||||
|
"pay_setting_id" : payId
|
||||||
|
]
|
||||||
|
|
||||||
|
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPIAPOrderModel>) in
|
||||||
|
if let message = response.data?.message, message.count > 0 {
|
||||||
|
if response.data?.code == 30007 {
|
||||||
|
VPToast.show(text: "kVipToast01".localized)
|
||||||
|
} else {
|
||||||
|
VPToast.show(text: message)
|
||||||
|
}
|
||||||
|
|
||||||
|
completer?(nil)
|
||||||
|
} else {
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///校验内购
|
||||||
|
static func requestVerifyOrder(orderCode: String, payId: String, productId: String, purchaseToken: String, completer: ((_ model: VPIAPVerifyModel?) -> Void)?) {
|
||||||
|
var param = VPNetworkParameters(path: "/applePaid")
|
||||||
|
param.parameters = [
|
||||||
|
"order_code" : orderCode,
|
||||||
|
"pay_setting_id" : payId,
|
||||||
|
"pkg_name" : kVPAPPBundleIdentifier,
|
||||||
|
"transaction_id" : productId,
|
||||||
|
"purchases_token" : purchaseToken
|
||||||
|
]
|
||||||
|
|
||||||
|
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPIAPVerifyModel>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,10 +40,16 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController {
|
|||||||
///选集
|
///选集
|
||||||
private weak var episodeView: VPEpisodeView?
|
private weak var episodeView: VPEpisodeView?
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.delegate = self
|
self.delegate = self
|
||||||
self.dataSource = self
|
self.dataSource = self
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(buyVipFinishNotification), name: VPIAPManager.buyVipFinishNotification, object: nil)
|
||||||
|
|
||||||
requestDetailData()
|
requestDetailData()
|
||||||
|
|
||||||
vp_setupUI()
|
vp_setupUI()
|
||||||
@ -157,10 +163,25 @@ extension VPDetailPlayerViewController {
|
|||||||
|
|
||||||
///打开充值页面
|
///打开充值页面
|
||||||
private func onRecharge() {
|
private func onRecharge() {
|
||||||
|
guard let videoInfo = self.viewModel.currentPlayer?.videoInfo else { return }
|
||||||
|
|
||||||
let view = VPPlayerRechargeView()
|
let view = VPPlayerRechargeView()
|
||||||
|
view.shortPlayId = videoInfo.short_play_id
|
||||||
|
view.videoId = videoInfo.short_play_video_id
|
||||||
view.present(in: nil)
|
view.present(in: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
///成功开通会员
|
||||||
|
@objc private func buyVipFinishNotification() {
|
||||||
|
guard VPLoginManager.manager.userInfo?.is_vip == true else { return }
|
||||||
|
|
||||||
|
self.detailModel?.episodeList?.forEach({
|
||||||
|
$0.is_lock = false
|
||||||
|
})
|
||||||
|
|
||||||
|
self.reloadData { [weak self] in
|
||||||
|
self?.play()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@ class VPPlayerCoinBuyView: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
private lazy var selectedIndex = 0
|
private lazy var selectedIndex = 0
|
||||||
|
|
||||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||||
@ -100,6 +103,12 @@ extension VPPlayerCoinBuyView: UICollectionViewDelegate, UICollectionViewDataSou
|
|||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
self.selectedIndex = indexPath.row
|
self.selectedIndex = indexPath.row
|
||||||
collectionView.reloadData()
|
collectionView.reloadData()
|
||||||
|
|
||||||
|
VPIAPManager.manager.start(model: dataArr[indexPath.row], shortPlayId: self.shortPlayId, videoId: self.videoId) { finish in
|
||||||
|
if finish {
|
||||||
|
VPLoginManager.manager.updateUserInfo(completer: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,19 @@ import UIKit
|
|||||||
|
|
||||||
class VPPlayerRechargeView: HWPanModalContentView {
|
class VPPlayerRechargeView: HWPanModalContentView {
|
||||||
|
|
||||||
|
var shortPlayId: String? {
|
||||||
|
didSet {
|
||||||
|
vipView.shortPlayId = shortPlayId
|
||||||
|
coinView.shortPlayId = shortPlayId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var videoId: String? {
|
||||||
|
didSet {
|
||||||
|
vipView.videoId = videoId
|
||||||
|
coinView.videoId = videoId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: UI属性
|
//MARK: UI属性
|
||||||
private lazy var bgView: UIImageView = {
|
private lazy var bgView: UIImageView = {
|
||||||
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
|
let imageView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||||
@ -48,8 +61,15 @@ class VPPlayerRechargeView: HWPanModalContentView {
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(updateCoin), name: VPLoginManager.userInfoUpdateNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(buyVipFinishNotification), name: VPIAPManager.buyVipFinishNotification, object: nil)
|
||||||
|
|
||||||
vp_setupUI()
|
vp_setupUI()
|
||||||
|
|
||||||
updateCoin()
|
updateCoin()
|
||||||
@ -111,7 +131,7 @@ class VPPlayerRechargeView: HWPanModalContentView {
|
|||||||
|
|
||||||
extension VPPlayerRechargeView {
|
extension VPPlayerRechargeView {
|
||||||
|
|
||||||
private func updateCoin() {
|
@objc private func updateCoin() {
|
||||||
let coinCountStr = "\(VPLoginManager.manager.userInfo?.totalCoin ?? 0)"
|
let coinCountStr = "\(VPLoginManager.manager.userInfo?.totalCoin ?? 0)"
|
||||||
let text = String(format: "Coins: %@".localized, coinCountStr)
|
let text = String(format: "Coins: %@".localized, coinCountStr)
|
||||||
let coinRange = text.ocString().range(of: coinCountStr)
|
let coinRange = text.ocString().range(of: coinCountStr)
|
||||||
@ -122,6 +142,13 @@ extension VPPlayerRechargeView {
|
|||||||
|
|
||||||
coinLabel.attributedText = string
|
coinLabel.attributedText = string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func buyVipFinishNotification() {
|
||||||
|
if VPLoginManager.manager.userInfo?.is_vip == true {
|
||||||
|
self.dismiss(animated: true) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VPPlayerRechargeView {
|
extension VPPlayerRechargeView {
|
||||||
|
@ -15,6 +15,9 @@ class VPPlayerVipBuyView: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
private lazy var currentIndex: Int = 0
|
private lazy var currentIndex: Int = 0
|
||||||
|
|
||||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||||
@ -140,5 +143,10 @@ extension VPPlayerVipBuyView: UICollectionViewDelegate, UICollectionViewDataSour
|
|||||||
self.collectionView.reloadData()
|
self.collectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VPIAPManager.manager.start(model: dataArr[indexPath.row], shortPlayId: self.shortPlayId, videoId: self.videoId) { finish in
|
||||||
|
if finish {
|
||||||
|
VPLoginManager.manager.updateUserInfo(completer: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,21 +42,24 @@ class VPVideoLockView: UIView {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var coinCountLabel: UILabel = {
|
private lazy var coinCountLabel: UILabel = {
|
||||||
let userInfo = VPLoginManager.manager.userInfo
|
|
||||||
|
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .fontRegular(ofSize: 12)
|
label.font = .fontRegular(ofSize: 12)
|
||||||
label.textColor = .colorB5B5B5()
|
label.textColor = .colorB5B5B5()
|
||||||
label.text = String(format: "Balance: %@ Coins | %@ Bonus".localized, "\(userInfo?.coin_left_total ?? 0)", "\(userInfo?.send_coin_left_total ?? 0)")
|
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: VPLoginManager.userInfoUpdateNotification, object: nil)
|
||||||
|
|
||||||
backgroundColor = .color000000(alpha: 0.8)
|
backgroundColor = .color000000(alpha: 0.8)
|
||||||
|
|
||||||
|
userInfoUpdateNotification()
|
||||||
|
|
||||||
vp_setupUI()
|
vp_setupUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +71,12 @@ class VPVideoLockView: UIView {
|
|||||||
self.clickUnlockButton?()
|
self.clickUnlockButton?()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func userInfoUpdateNotification() {
|
||||||
|
let userInfo = VPLoginManager.manager.userInfo
|
||||||
|
|
||||||
|
coinCountLabel.text = String(format: "Balance: %@ Coins | %@ Bonus".localized, "\(userInfo?.coin_left_total ?? 0)", "\(userInfo?.send_coin_left_total ?? 0)")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VPVideoLockView {
|
extension VPVideoLockView {
|
||||||
|
@ -73,11 +73,16 @@ class VPCoinsViewController: VPViewController {
|
|||||||
label.text = "kStoreTips".localized
|
label.text = "kStoreTips".localized
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.bgImageView.isHidden = true
|
self.bgImageView.isHidden = true
|
||||||
self.view.backgroundColor = .clear
|
self.view.backgroundColor = .clear
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: VPLoginManager.userInfoUpdateNotification, object: nil)
|
||||||
|
|
||||||
updateCoin()
|
updateCoin()
|
||||||
vp_setupUI()
|
vp_setupUI()
|
||||||
@ -112,6 +117,10 @@ class VPCoinsViewController: VPViewController {
|
|||||||
self.collectionView.reloadData()
|
self.collectionView.reloadData()
|
||||||
CATransaction.commit()
|
CATransaction.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func userInfoUpdateNotification() {
|
||||||
|
updateCoin()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VPCoinsViewController {
|
extension VPCoinsViewController {
|
||||||
@ -176,5 +185,14 @@ extension VPCoinsViewController: UICollectionViewDelegate, UICollectionViewDataS
|
|||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
self.selectedIndex = indexPath.row
|
self.selectedIndex = indexPath.row
|
||||||
collectionView.reloadData()
|
collectionView.reloadData()
|
||||||
|
|
||||||
|
VPIAPManager.manager.start(model: dataArr[indexPath.row]) { finish in
|
||||||
|
if finish {
|
||||||
|
VPLoginManager.manager.updateUserInfo(completer: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,7 +95,9 @@ class VPVipPageViewController: VPViewController {
|
|||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
let rightBar = UIBarButtonItem(title: "Restore".localized, style: .plain, target: self, action: #selector(handleRestore))
|
||||||
|
self.navigationItem.rightBarButtonItem = rightBar
|
||||||
|
|
||||||
vp_setupUI()
|
vp_setupUI()
|
||||||
|
|
||||||
requestData()
|
requestData()
|
||||||
@ -115,6 +117,14 @@ class VPVipPageViewController: VPViewController {
|
|||||||
button.setBackgroundImage(UIImage(named: "vip_menu_right_selected"), for: .selected)
|
button.setBackgroundImage(UIImage(named: "vip_menu_right_selected"), for: .selected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func handleRestore() {
|
||||||
|
VPIAPManager.manager.restore(isLoding: true) { isFinish in
|
||||||
|
if isFinish {
|
||||||
|
VPLoginManager.manager.updateUserInfo(completer: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VPVipPageViewController {
|
extension VPVipPageViewController {
|
||||||
|
@ -219,5 +219,11 @@ extension VPVipViewController: UICollectionViewDelegate, UICollectionViewDataSou
|
|||||||
self.collectionView.reloadData()
|
self.collectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VPIAPManager.manager.start(model: dataArr[indexPath.row]) { finish in
|
||||||
|
if finish {
|
||||||
|
VPLoginManager.manager.updateUserInfo(completer: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
193
Veloria/Libs/VPIAPManager/VPIAPManager.swift
Normal file
193
Veloria/Libs/VPIAPManager/VPIAPManager.swift
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
//
|
||||||
|
// VPIAPManager.swift
|
||||||
|
// Veloria
|
||||||
|
//
|
||||||
|
// Created by 湖南秦九 on 2025/6/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VPIAPManager {
|
||||||
|
|
||||||
|
typealias CompletionHandler = ((_ finish: Bool) -> Void)
|
||||||
|
///内购模版前缀
|
||||||
|
static let IAPPrefix = "veloria."
|
||||||
|
|
||||||
|
|
||||||
|
static let manager = VPIAPManager()
|
||||||
|
|
||||||
|
///成功回调
|
||||||
|
private var completionHandler: CompletionHandler?
|
||||||
|
|
||||||
|
private lazy var iapManager: JXIAPManager = {
|
||||||
|
let manager = JXIAPManager()
|
||||||
|
manager.delegate = self
|
||||||
|
return manager
|
||||||
|
}()
|
||||||
|
|
||||||
|
private var orderCode: String?
|
||||||
|
private var payId: String?
|
||||||
|
|
||||||
|
///恢复购买使用
|
||||||
|
///等待恢复的数据
|
||||||
|
private var waitRestoreModel: VPWaitRestoreModel? = UserDefaults.vp_object(forKey: kVPWaitRestoreIAPDefaultsKey, as: VPWaitRestoreModel.self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///开始内购
|
||||||
|
func start(model: VPPayTemplateItem, shortPlayId: String? = nil, videoId: String? = nil, handler: CompletionHandler? = nil) {
|
||||||
|
|
||||||
|
if let _ = self.waitRestoreModel {
|
||||||
|
VPToast.show(text: "kIapErrorToast01".localized)
|
||||||
|
handler?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let payId = model.id else {
|
||||||
|
handler?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.completionHandler = handler
|
||||||
|
self.waitRestoreModel = VPWaitRestoreModel()
|
||||||
|
self.waitRestoreModel?.buyType = model.buy_type
|
||||||
|
|
||||||
|
let productId = VPIAPManager.IAPPrefix + (model.ios_template_id ?? "")
|
||||||
|
|
||||||
|
VPHUD.show()
|
||||||
|
|
||||||
|
VPWalletAPI.requestCreateOrder(payId: payId, shortPlayId: shortPlayId ?? "0", videoId: videoId ?? "0") { orderModel in
|
||||||
|
guard let orderModel = orderModel else {
|
||||||
|
VPHUD.dismiss()
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
self.completionHandler?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.orderCode = orderModel.order_code
|
||||||
|
self.payId = payId
|
||||||
|
self.waitRestoreModel?.payId = payId
|
||||||
|
self.waitRestoreModel?.orderCode = orderModel.order_code
|
||||||
|
|
||||||
|
self.iapManager.start(productId: productId, orderId: self.orderCode ?? "")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func restore(isLoding: Bool = true, completer: ((_ isFinish: Bool) -> Void)?) {
|
||||||
|
guard let waitRestoreModel = self.waitRestoreModel,
|
||||||
|
let orderCode = waitRestoreModel.orderCode,
|
||||||
|
let payId = waitRestoreModel.payId,
|
||||||
|
let productId = waitRestoreModel.productId,
|
||||||
|
let receipt = waitRestoreModel.receipt
|
||||||
|
else {
|
||||||
|
if isLoding {
|
||||||
|
VPToast.show(text: "kIapErrorToast03".localized)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLoding {
|
||||||
|
VPHUD.show()
|
||||||
|
}
|
||||||
|
VPWalletAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, purchaseToken: receipt) { model in
|
||||||
|
if isLoding {
|
||||||
|
VPHUD.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let model = model else {
|
||||||
|
completer?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let buyType = self.waitRestoreModel?.buyType
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
UserDefaults.vp_setObject(self.waitRestoreModel, forKey: kVPWaitRestoreIAPDefaultsKey)
|
||||||
|
|
||||||
|
if model.status == "success" {
|
||||||
|
if buyType == .subVip {
|
||||||
|
VPLoginManager.manager.userInfo?.is_vip = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isLoding {
|
||||||
|
VPToast.show(text: "Success".localized)
|
||||||
|
}
|
||||||
|
completer?(true)
|
||||||
|
if buyType == .subVip {
|
||||||
|
NotificationCenter.default.post(name: VPIAPManager.buyVipFinishNotification, object: nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completer?(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- JXIAPManagerDelegate --------------
|
||||||
|
extension VPIAPManager: JXIAPManagerDelegate {
|
||||||
|
|
||||||
|
func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?) {
|
||||||
|
guard let orderCode = self.orderCode, let payId = self.payId else {
|
||||||
|
self.orderCode = nil
|
||||||
|
self.payId = nil
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
self.completionHandler?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.waitRestoreModel?.productId = productId
|
||||||
|
self.waitRestoreModel?.receipt = receipt
|
||||||
|
|
||||||
|
UserDefaults.vp_setObject(self.waitRestoreModel, forKey: kVPWaitRestoreIAPDefaultsKey)
|
||||||
|
|
||||||
|
VPWalletAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, purchaseToken: receipt) { model in
|
||||||
|
VPHUD.dismiss()
|
||||||
|
|
||||||
|
self.orderCode = nil
|
||||||
|
self.payId = nil
|
||||||
|
|
||||||
|
guard let model = model else {
|
||||||
|
self.completionHandler?(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let buyType = self.waitRestoreModel?.buyType
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
UserDefaults.vp_setObject(self.waitRestoreModel, forKey: kVPWaitRestoreIAPDefaultsKey)
|
||||||
|
|
||||||
|
if model.status == "success" {
|
||||||
|
if buyType == .subVip {
|
||||||
|
VPLoginManager.manager.userInfo?.is_vip = true
|
||||||
|
}
|
||||||
|
|
||||||
|
VPToast.show(text: "Success".localized)
|
||||||
|
self.completionHandler?(true)
|
||||||
|
if buyType == .subVip {
|
||||||
|
NotificationCenter.default.post(name: VPIAPManager.buyVipFinishNotification, object: nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.completionHandler?(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func jx_iapPayFailed(productId: String, code: JXIAPManagerCode) {
|
||||||
|
self.orderCode = nil
|
||||||
|
self.payId = nil
|
||||||
|
self.waitRestoreModel = nil
|
||||||
|
|
||||||
|
VPHUD.dismiss()
|
||||||
|
|
||||||
|
if code == .noProduct {
|
||||||
|
VPToast.show(text: "kIapErrorToast02".localized)
|
||||||
|
}
|
||||||
|
self.completionHandler?(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension VPIAPManager {
|
||||||
|
///成功购买会员
|
||||||
|
@objc static let buyVipFinishNotification = NSNotification.Name(rawValue: "VPIAPManager.buyVipFinishNotification")
|
||||||
|
|
||||||
|
}
|
19
Veloria/Libs/VPIAPManager/VPIAPOrderModel.swift
Normal file
19
Veloria/Libs/VPIAPManager/VPIAPOrderModel.swift
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// VPIAPOrderModel.swift
|
||||||
|
// Veloria
|
||||||
|
//
|
||||||
|
// Created by 湖南秦九 on 2025/6/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class VPIAPOrderModel: VPModel, SmartCodable {
|
||||||
|
|
||||||
|
var code: Int?
|
||||||
|
var message: String?
|
||||||
|
var money: String?
|
||||||
|
var order_code: String?
|
||||||
|
var is_backhaul: String?
|
||||||
|
|
||||||
|
}
|
17
Veloria/Libs/VPIAPManager/VPIAPVerifyModel.swift
Normal file
17
Veloria/Libs/VPIAPManager/VPIAPVerifyModel.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// VPIAPVerifyModel.swift
|
||||||
|
// Veloria
|
||||||
|
//
|
||||||
|
// Created by 湖南秦九 on 2025/6/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class VPIAPVerifyModel: VPModel, SmartCodable {
|
||||||
|
|
||||||
|
var code: String?
|
||||||
|
var status: String?
|
||||||
|
var money: String?
|
||||||
|
var is_backhaul: String?
|
||||||
|
}
|
45
Veloria/Libs/VPIAPManager/VPWaitRestoreModel.swift
Normal file
45
Veloria/Libs/VPIAPManager/VPWaitRestoreModel.swift
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// VPWaitRestoreModel.swift
|
||||||
|
// Veloria
|
||||||
|
//
|
||||||
|
// Created by 湖南秦九 on 2025/6/5.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class VPWaitRestoreModel: VPModel, NSSecureCoding {
|
||||||
|
|
||||||
|
var orderCode: String?
|
||||||
|
var payId: String?
|
||||||
|
var productId: String?
|
||||||
|
var receipt: String?
|
||||||
|
var buyType: VPWalletAPI.BuyType?
|
||||||
|
|
||||||
|
|
||||||
|
required init() { }
|
||||||
|
|
||||||
|
static var supportsSecureCoding: Bool {
|
||||||
|
get {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(with coder: NSCoder) {
|
||||||
|
coder.encode(orderCode, forKey: "orderCode")
|
||||||
|
coder.encode(payId, forKey: "payId")
|
||||||
|
coder.encode(productId, forKey: "productId")
|
||||||
|
coder.encode(receipt, forKey: "receipt")
|
||||||
|
coder.encode(buyType?.rawValue, forKey: "buyType")
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init()
|
||||||
|
orderCode = coder.decodeObject(of: NSString.self, forKey: "orderCode") as? String
|
||||||
|
payId = coder.decodeObject(of: NSString.self, forKey: "payId") as? String
|
||||||
|
productId = coder.decodeObject(of: NSString.self, forKey: "productId") as? String
|
||||||
|
receipt = coder.decodeObject(of: NSString.self, forKey: "receipt") as? String
|
||||||
|
if let type = coder.decodeObject(of: NSString.self, forKey: "buyType") as? String {
|
||||||
|
buyType = VPWalletAPI.BuyType(rawValue: type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -84,6 +84,8 @@
|
|||||||
"Check in" = "Check in";
|
"Check in" = "Check in";
|
||||||
"Expires in %@ days" = "Expires in 30 days";
|
"Expires in %@ days" = "Expires in 30 days";
|
||||||
"Expired" = "Expired";
|
"Expired" = "Expired";
|
||||||
|
"Success" = "Success";
|
||||||
|
"Restore" = "Restore";
|
||||||
|
|
||||||
"kHomeTitleText" = "10,000+ addictive shorts await!";
|
"kHomeTitleText" = "10,000+ addictive shorts await!";
|
||||||
"kSearchPlaceholderText1" = "Search dramas";
|
"kSearchPlaceholderText1" = "Search dramas";
|
||||||
@ -103,6 +105,13 @@
|
|||||||
"kLockPreviousEpisodeText" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
|
"kLockPreviousEpisodeText" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
|
||||||
//解锁失败
|
//解锁失败
|
||||||
"kLockFailText" = "Purchase failed, please try again later!";
|
"kLockFailText" = "Purchase failed, please try again later!";
|
||||||
|
//已是会员
|
||||||
|
"kVipToast01" = "You are already a member!";
|
||||||
|
//还有未完成购买
|
||||||
|
"kIapErrorToast01" = "You have unfinished in-app purchases, please restore them first.";
|
||||||
|
"kIapErrorToast02" = "Invalid in-app purchase";
|
||||||
|
///没有可恢复购买
|
||||||
|
"kIapErrorToast03" = "There are no in-app purchases to restore.";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
207
Veloria/Thirdparty/JXIAPManager/JXIAPManager.swift
vendored
Normal file
207
Veloria/Thirdparty/JXIAPManager/JXIAPManager.swift
vendored
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
//
|
||||||
|
// JXIAPManager.swift
|
||||||
|
// BoJia
|
||||||
|
//
|
||||||
|
// Created by 火山传媒 on 2024/6/3.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import StoreKit
|
||||||
|
|
||||||
|
@objc protocol JXIAPManagerDelegate {
|
||||||
|
/// 获取到可购买商品列表
|
||||||
|
@objc optional func jx_iapPayGotProducts(productIds: [String])
|
||||||
|
/// 购买成功
|
||||||
|
@objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?)
|
||||||
|
/// 购买失败
|
||||||
|
@objc optional func jx_iapPayFailed(productId: String, code: JXIAPManagerCode)
|
||||||
|
/// 恢复商品(仅限永久有效商品)
|
||||||
|
@objc optional func iapPayRestore(productIds: [String], transactionIds: [String])
|
||||||
|
// /// 加载
|
||||||
|
// @objc optional func iapPayShowHud()
|
||||||
|
// /// 系统错误
|
||||||
|
// @objc optional func iapSysWrong()
|
||||||
|
// /// 验证成功
|
||||||
|
// @objc optional func verifySuccess()
|
||||||
|
// /// 验证失败
|
||||||
|
// @objc optional func verifyFailed()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc enum JXIAPManagerCode: Int {
|
||||||
|
///未知错误
|
||||||
|
case unknown
|
||||||
|
///取消交易
|
||||||
|
case cancelled
|
||||||
|
///没有商品
|
||||||
|
case noProduct
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class JXIAPManager: NSObject {
|
||||||
|
|
||||||
|
static let manager: JXIAPManager = JXIAPManager()
|
||||||
|
|
||||||
|
weak var delegate: JXIAPManagerDelegate?
|
||||||
|
|
||||||
|
private var payment: SKPayment?
|
||||||
|
|
||||||
|
private var product: SKProduct?
|
||||||
|
private var productId: String?
|
||||||
|
private var orderId: String?
|
||||||
|
private var applicationUsername: String? {
|
||||||
|
get {
|
||||||
|
let id = "00000000-0000-0000-0000-000000000000"
|
||||||
|
guard let orderId = orderId else { return nil }
|
||||||
|
var string = ""
|
||||||
|
for i in 0..<orderId.length() {
|
||||||
|
if i == 12 || i == 16 || i == 20 || i == 24 {
|
||||||
|
string.insert("-", at: string.startIndex)
|
||||||
|
}
|
||||||
|
let s = orderId[orderId.index(orderId.endIndex, offsetBy: -(i + 1))]
|
||||||
|
string.insert(s, at: string.startIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
let length = id.length()
|
||||||
|
let stringLength = string.length()
|
||||||
|
|
||||||
|
if stringLength <= length {
|
||||||
|
let range = NSRange(location: length - string.length(), length: string.length())
|
||||||
|
return id.ocString().replacingCharacters(in: range, with: string)
|
||||||
|
} else {
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
SKPaymentQueue.default().add(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func start(productId: String, orderId: String) {
|
||||||
|
self.product = nil
|
||||||
|
self.productId = productId
|
||||||
|
self.orderId = orderId
|
||||||
|
|
||||||
|
let set = Set([productId])
|
||||||
|
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||||
|
productsRequest.delegate = self
|
||||||
|
productsRequest.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 购买商品
|
||||||
|
private func buyProduct() {
|
||||||
|
guard let product = self.product else { return }
|
||||||
|
|
||||||
|
// 要购买商品,开个小票
|
||||||
|
let payment = SKMutablePayment(product: product)
|
||||||
|
payment.applicationUsername = applicationUsername
|
||||||
|
|
||||||
|
self.payment = payment
|
||||||
|
// 去收银台排队,准备购买
|
||||||
|
SKPaymentQueue.default().add(payment)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- SKProductsRequestDelegate --------------
|
||||||
|
extension JXIAPManager: SKProductsRequestDelegate {
|
||||||
|
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||||
|
guard let product = response.products.first else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let productId = self.productId {
|
||||||
|
self.productId = nil
|
||||||
|
self.delegate?.jx_iapPayFailed?(productId: productId, code: .noProduct)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.product = product
|
||||||
|
|
||||||
|
self.buyProduct()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- SKPaymentTransactionObserver --------------
|
||||||
|
extension JXIAPManager: SKPaymentTransactionObserver {
|
||||||
|
///购买回调
|
||||||
|
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
||||||
|
|
||||||
|
for transaction in transactions {
|
||||||
|
switch transaction.transactionState {
|
||||||
|
case .purchased:
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.completeTransaction(transaction: transaction)
|
||||||
|
}
|
||||||
|
SKPaymentQueue.default().finishTransaction(transaction)
|
||||||
|
|
||||||
|
case .failed:
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.failedTransaction(transaction: transaction)
|
||||||
|
}
|
||||||
|
SKPaymentQueue.default().finishTransaction(transaction)
|
||||||
|
// case .restored:
|
||||||
|
// self.restoreTransaction(transaction: transaction)
|
||||||
|
|
||||||
|
case .purchasing:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
SKPaymentQueue.default().finishTransaction(transaction)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// 恢复购买回调
|
||||||
|
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension JXIAPManager {
|
||||||
|
private func completeTransaction(transaction: SKPaymentTransaction) {
|
||||||
|
//自动续费
|
||||||
|
// if let _ = transaction.original, transaction.payment.applicationUsername == nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//重新开通自动续费
|
||||||
|
// if let _ = transaction.original, transaction.payment.applicationUsername != nil {
|
||||||
|
// self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
guard let productId = self.productId, productId == transaction.payment.productIdentifier else { return }
|
||||||
|
self.productId = nil
|
||||||
|
|
||||||
|
guard let receiptURL = Bundle.main.appStoreReceiptURL else { return }
|
||||||
|
let receiptData = NSData(contentsOf: receiptURL)
|
||||||
|
guard let encodeStr = receiptData?.base64EncodedString(options: .endLineWithLineFeed) else { return }
|
||||||
|
guard let transactionIdentifier = transaction.transactionIdentifier else { return }
|
||||||
|
|
||||||
|
self.delegate?.jx_iapPaySuccess?(productId: productId, receipt: encodeStr, transactionIdentifier: transactionIdentifier)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func failedTransaction(transaction: SKPaymentTransaction) {
|
||||||
|
let error = transaction.error as? SKError
|
||||||
|
guard let productId = self.productId else { return }
|
||||||
|
self.productId = nil
|
||||||
|
|
||||||
|
switch error?.code {
|
||||||
|
case SKError.paymentCancelled:
|
||||||
|
self.delegate?.jx_iapPayFailed?(productId: productId, code: .cancelled)
|
||||||
|
default:
|
||||||
|
self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user