支付
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
23270C292B0E037300B9303B /* MessageConentAudioView.m in Sources */ = {isa = PBXBuildFile; fileRef = 23270C272B0E037300B9303B /* MessageConentAudioView.m */; };
|
23270C292B0E037300B9303B /* MessageConentAudioView.m in Sources */ = {isa = PBXBuildFile; fileRef = 23270C272B0E037300B9303B /* MessageConentAudioView.m */; };
|
||||||
23270C2C2B0E041300B9303B /* MessageAudioCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 23270C2B2B0E041300B9303B /* MessageAudioCenter.m */; };
|
23270C2C2B0E041300B9303B /* MessageAudioCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 23270C2B2B0E041300B9303B /* MessageAudioCenter.m */; };
|
||||||
|
23270C302B0E071B00B9303B /* MewPaymentAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23270C2F2B0E071B00B9303B /* MewPaymentAction.swift */; };
|
||||||
233757562B0CB577001D0B7F /* MessagePresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 233757262B0CB577001D0B7F /* MessagePresenter.m */; };
|
233757562B0CB577001D0B7F /* MessagePresenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 233757262B0CB577001D0B7F /* MessagePresenter.m */; };
|
||||||
233757572B0CB577001D0B7F /* MessageMenuModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2337572C2B0CB577001D0B7F /* MessageMenuModel.m */; };
|
233757572B0CB577001D0B7F /* MessageMenuModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2337572C2B0CB577001D0B7F /* MessageMenuModel.m */; };
|
||||||
233757582B0CB577001D0B7F /* ChatLimitModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2337572D2B0CB577001D0B7F /* ChatLimitModel.m */; };
|
233757582B0CB577001D0B7F /* ChatLimitModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2337572D2B0CB577001D0B7F /* ChatLimitModel.m */; };
|
||||||
@@ -197,6 +198,8 @@
|
|||||||
23270C282B0E037300B9303B /* MessageConentAudioView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageConentAudioView.h; sourceTree = "<group>"; };
|
23270C282B0E037300B9303B /* MessageConentAudioView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageConentAudioView.h; sourceTree = "<group>"; };
|
||||||
23270C2A2B0E041300B9303B /* MessageAudioCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageAudioCenter.h; sourceTree = "<group>"; };
|
23270C2A2B0E041300B9303B /* MessageAudioCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageAudioCenter.h; sourceTree = "<group>"; };
|
||||||
23270C2B2B0E041300B9303B /* MessageAudioCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageAudioCenter.m; sourceTree = "<group>"; };
|
23270C2B2B0E041300B9303B /* MessageAudioCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageAudioCenter.m; sourceTree = "<group>"; };
|
||||||
|
23270C2E2B0E071B00B9303B /* yinmeng-ios-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "yinmeng-ios-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
23270C2F2B0E071B00B9303B /* MewPaymentAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MewPaymentAction.swift; sourceTree = "<group>"; };
|
||||||
233757262B0CB577001D0B7F /* MessagePresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessagePresenter.m; sourceTree = "<group>"; };
|
233757262B0CB577001D0B7F /* MessagePresenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessagePresenter.m; sourceTree = "<group>"; };
|
||||||
233757272B0CB577001D0B7F /* MessagePresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessagePresenter.h; sourceTree = "<group>"; };
|
233757272B0CB577001D0B7F /* MessagePresenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessagePresenter.h; sourceTree = "<group>"; };
|
||||||
233757292B0CB577001D0B7F /* MessageProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageProtocol.h; sourceTree = "<group>"; };
|
233757292B0CB577001D0B7F /* MessageProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageProtocol.h; sourceTree = "<group>"; };
|
||||||
@@ -599,6 +602,16 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
23270C2D2B0E06F700B9303B /* MewIAP */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
23270C2F2B0E071B00B9303B /* MewPaymentAction.swift */,
|
||||||
|
23270C2E2B0E071B00B9303B /* yinmeng-ios-Bridging-Header.h */,
|
||||||
|
);
|
||||||
|
name = MewIAP;
|
||||||
|
path = "yinmeng-ios/Base/MewIAP";
|
||||||
|
sourceTree = SOURCE_ROOT;
|
||||||
|
};
|
||||||
233757242B0CB577001D0B7F /* Message */ = {
|
233757242B0CB577001D0B7F /* Message */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -1749,6 +1762,7 @@
|
|||||||
8C9C83C12B0C697A00A601BC /* Mew */ = {
|
8C9C83C12B0C697A00A601BC /* Mew */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
23270C2D2B0E06F700B9303B /* MewIAP */,
|
||||||
8C9C83C22B0C697A00A601BC /* Home */,
|
8C9C83C22B0C697A00A601BC /* Home */,
|
||||||
8C9C83E62B0C697A00A601BC /* Room */,
|
8C9C83E62B0C697A00A601BC /* Room */,
|
||||||
8C9C83FA2B0C697A00A601BC /* Party */,
|
8C9C83FA2B0C697A00A601BC /* Party */,
|
||||||
@@ -2157,6 +2171,7 @@
|
|||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
8C4D534B2AFD4CF600238AE6 = {
|
8C4D534B2AFD4CF600238AE6 = {
|
||||||
CreatedOnToolsVersion = 14.0;
|
CreatedOnToolsVersion = 14.0;
|
||||||
|
LastSwiftMigration = 1500;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -2357,6 +2372,7 @@
|
|||||||
8C9C845D2B0C697A00A601BC /* MewHomePresenter.m in Sources */,
|
8C9C845D2B0C697A00A601BC /* MewHomePresenter.m in Sources */,
|
||||||
2337575A2B0CB577001D0B7F /* UITableView+NIMScrollToBottom.m in Sources */,
|
2337575A2B0CB577001D0B7F /* UITableView+NIMScrollToBottom.m in Sources */,
|
||||||
8C9C84252B0C697A00A601BC /* YMMessageInfoModel.m in Sources */,
|
8C9C84252B0C697A00A601BC /* YMMessageInfoModel.m in Sources */,
|
||||||
|
23270C302B0E071B00B9303B /* MewPaymentAction.swift in Sources */,
|
||||||
8C9C82D12B0C695600A601BC /* RechargeStorage.m in Sources */,
|
8C9C82D12B0C695600A601BC /* RechargeStorage.m in Sources */,
|
||||||
8C9C84792B0C697A00A601BC /* MewLoginNumberViewController.m in Sources */,
|
8C9C84792B0C697A00A601BC /* MewLoginNumberViewController.m in Sources */,
|
||||||
8C9C841D2B0C697A00A601BC /* ThemeColor+Room.m in Sources */,
|
8C9C841D2B0C697A00A601BC /* ThemeColor+Room.m in Sources */,
|
||||||
@@ -2571,6 +2587,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "yinmeng-ios/yinmeng-ios.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "yinmeng-ios/yinmeng-ios.entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -2597,6 +2614,9 @@
|
|||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = NO;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "yinmeng-ios/Base/MewIAP/yinmeng-ios-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@@ -2607,6 +2627,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = "yinmeng-ios/yinmeng-ios.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "yinmeng-ios/yinmeng-ios.entitlements";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -2633,6 +2654,8 @@
|
|||||||
SUPPORTS_MACCATALYST = NO;
|
SUPPORTS_MACCATALYST = NO;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "yinmeng-ios/Base/MewIAP/yinmeng-ios-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 1;
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
264
yinmeng-ios/yinmeng-ios/Base/MewIAP/MewPaymentAction.swift
Normal file
264
yinmeng-ios/yinmeng-ios/Base/MewIAP/MewPaymentAction.swift
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
//
|
||||||
|
// MewPaymentAction.swift
|
||||||
|
// yinmeng-ios
|
||||||
|
//
|
||||||
|
// Created by duoban on 2023/11/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import StoreKit
|
||||||
|
|
||||||
|
@available(iOS 15.0, *)
|
||||||
|
typealias MewTransaction = StoreKit.Transaction
|
||||||
|
@available(iOS 15.0, *)
|
||||||
|
typealias MewRenewalInfo = StoreKit.Product.SubscriptionInfo.RenewalInfo
|
||||||
|
@available(iOS 15.0, *)
|
||||||
|
typealias MewRenewalState = StoreKit.Product.SubscriptionInfo.RenewalState
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum MewStoreError: Error {
|
||||||
|
|
||||||
|
|
||||||
|
// 错误回调枚举
|
||||||
|
case MewFailedVerification
|
||||||
|
case MewNoProduct
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public enum MewStoreConditionResult: Int64 { // 支付状态
|
||||||
|
case MewStart // 开始
|
||||||
|
case MewPay // 进行苹果支付
|
||||||
|
case MewVerifiedServer // 服务器校验
|
||||||
|
case MewUserCancelled // 用户取消
|
||||||
|
case MewPending // 等待(家庭用户才有的状态)
|
||||||
|
case MewUnowned
|
||||||
|
case MewNoProduct //没有商品
|
||||||
|
case MewFailedVerification //验证失败
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@available(iOS 15.0, *)
|
||||||
|
public class MewPaymentAction: NSObject {
|
||||||
|
public typealias Mew_KConditionBlock = (_ state :MewStoreConditionResult,_ param:Dictionary<String,Any>?) ->()
|
||||||
|
@objc public var Mew_ConditionBlock: Mew_KConditionBlock! // 状态回调
|
||||||
|
|
||||||
|
var Mew_updateListenerTask: Task<Void, Error>? = nil // 支付事件监听
|
||||||
|
|
||||||
|
var Mew_transactionMap :[String:Transaction] // 用于完成Id的缓存map
|
||||||
|
|
||||||
|
var Mew_name: String = "Mew_iosStore" // 单例的写法
|
||||||
|
|
||||||
|
@objc public static let shared = {
|
||||||
|
let instance = MewPaymentAction()
|
||||||
|
return instance
|
||||||
|
}()
|
||||||
|
|
||||||
|
private override init() { // 单例需要保证private的私有性质
|
||||||
|
|
||||||
|
Mew_transactionMap = [:] // 初始化
|
||||||
|
super.init()
|
||||||
|
Task {
|
||||||
|
Mew_updateListenerTask = Mew_listenForTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 退订
|
||||||
|
@objc public func Mew_refunRequest(view: UIView,transactionId:UInt64) async{
|
||||||
|
do {
|
||||||
|
if let scene = await view.window?.windowScene{
|
||||||
|
try await Transaction.beginRefundRequest(for:transactionId , in: scene)
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch{
|
||||||
|
print("iap error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 购买某个产品
|
||||||
|
@objc public func Mew_demandCommodityThing(productId:String, uuid: String) async throws {
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewStart,nil)
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
let list:[String] = [productId]
|
||||||
|
let storeProducts = try await Product.products(for: Set.init(list))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if storeProducts.count > 0 {
|
||||||
|
try await Mew_purchase(storeProducts[0],uuid)
|
||||||
|
}else {
|
||||||
|
print("iap: no found product")
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewNoProduct,nil)
|
||||||
|
}
|
||||||
|
throw MewStoreError.MewNoProduct // 没有该产品
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("Failed product request from the App Store server: \(error)")
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewNoProduct,nil)
|
||||||
|
}
|
||||||
|
throw MewStoreError.MewNoProduct // 没有该产品
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 购买
|
||||||
|
private func Mew_purchase(_ product: Product, _ uuid: String) async throws -> Transaction? {
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewPay,nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let curUUID = UUID.init(uuidString: uuid) else{
|
||||||
|
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewFailedVerification,nil)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let getUUID = Product.PurchaseOption.appAccountToken(curUUID)
|
||||||
|
let result = try await product.purchase(options: [getUUID])
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success(let verification): // 用户购买完成
|
||||||
|
let transaction = try await Mew_verifiedAndAccomplish(verification)
|
||||||
|
return transaction
|
||||||
|
case .userCancelled: // 用户取消
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewUserCancelled,nil)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case .pending: // 此次购买被挂起
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewPending,nil)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewUnowned,nil)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验
|
||||||
|
func Mew_checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
|
||||||
|
//Check whether the JWS passes StoreKit verification.
|
||||||
|
switch result {
|
||||||
|
case .unverified:
|
||||||
|
//StoreKit parses the JWS, but it fails verification.
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewFailedVerification,nil)
|
||||||
|
}
|
||||||
|
throw MewStoreError.MewFailedVerification
|
||||||
|
case .verified(let safe):
|
||||||
|
//The result is verified. Return the unwrapped value.
|
||||||
|
print("iap: verified success")
|
||||||
|
return safe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验&完成后传给服务器
|
||||||
|
func Mew_verifiedAndAccomplish(_ verification:VerificationResult<Transaction>) async throws -> Transaction?{
|
||||||
|
//Check whether the transaction is verified. If it isn't,
|
||||||
|
//this function rethrows the verification error.
|
||||||
|
let transaction = try Mew_checkVerified(verification)
|
||||||
|
// 这里将订单提交给服务器进行验证 ~~~
|
||||||
|
let transactionId = try verification.payloadValue.id
|
||||||
|
|
||||||
|
// 添加进入待完成map
|
||||||
|
let key = String(transactionId)
|
||||||
|
Mew_transactionMap[key] = transaction
|
||||||
|
await Mew_uploadServer(for: transactionId)
|
||||||
|
|
||||||
|
// 这里不触发完成,等服务器验证再触发完成逻辑
|
||||||
|
await transaction.finish()
|
||||||
|
|
||||||
|
print("iap: finish")
|
||||||
|
return transaction
|
||||||
|
}
|
||||||
|
/*All transactions:全部的购买交易订单
|
||||||
|
Latest transactions:最新的购买交易订单。(分为订阅品项和除订阅品项外的所有类型二种)
|
||||||
|
Current entitlements:当前用户有购买的权限。(全部的订阅品项、和非消耗品项)
|
||||||
|
*/
|
||||||
|
func Mew_getAllBusiness(transactionId:String) async {
|
||||||
|
|
||||||
|
let transactionIntId = UInt64(transactionId)
|
||||||
|
for await result in Transaction.all {
|
||||||
|
do {
|
||||||
|
let tran = try Mew_checkVerified(result)
|
||||||
|
let resultId = try result.payloadValue.id
|
||||||
|
if transactionIntId == resultId {
|
||||||
|
await tran.finish()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch let error {
|
||||||
|
|
||||||
|
print("error:----\(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Transaction.latest(for: "pid")
|
||||||
|
|
||||||
|
}
|
||||||
|
// 事件完成处理
|
||||||
|
|
||||||
|
@objc public func Mew_verifyBusinessAccomplish(transaction:String) async{
|
||||||
|
if(Mew_transactionMap[transaction] != nil){
|
||||||
|
await Mew_transactionMap[transaction]!.finish()
|
||||||
|
Mew_transactionMap.removeValue(forKey: transaction)
|
||||||
|
print("verifyBusinessFinish end")
|
||||||
|
}else {
|
||||||
|
await Mew_getAllBusiness(transactionId: transaction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
func Mew_uploadServer(for transactionId:UInt64) async {
|
||||||
|
let dic :Dictionary<String,Any> = ["transactionId":transactionId]
|
||||||
|
if(Mew_ConditionBlock != nil ){
|
||||||
|
Mew_ConditionBlock(MewStoreConditionResult.MewVerifiedServer,dic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支付监听事件
|
||||||
|
func Mew_listenForTransactions() -> Task<Void, Error> {
|
||||||
|
return Task.detached {
|
||||||
|
//Iterate through any transactions that don't come from a direct call to `purchase()`.
|
||||||
|
// 修改update 为 unfinished?
|
||||||
|
for await result in Transaction.updates { //会导致二次校验?
|
||||||
|
do {
|
||||||
|
print("iap: updates")
|
||||||
|
print("result:\(result)")
|
||||||
|
try await self.Mew_verifiedAndAccomplish(result)
|
||||||
|
} catch {
|
||||||
|
//StoreKit has a transaction that fails verification. Don't deliver content to the user.
|
||||||
|
print("Transaction failed verification")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//获取推广内购商品
|
||||||
|
func Mew_Promotion() async -> [SKProduct]?{
|
||||||
|
let promotion = SKProductStorePromotionController()
|
||||||
|
|
||||||
|
let prodicts = try? await promotion.promotionOrder()
|
||||||
|
return prodicts
|
||||||
|
}
|
||||||
|
// 销毁调用
|
||||||
|
deinit {
|
||||||
|
Mew_updateListenerTask?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,4 @@
|
|||||||
|
//
|
||||||
|
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||||
|
//
|
||||||
|
|
@@ -17,7 +17,7 @@ typedef NS_ENUM(NSInteger ,PaymentStatus) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@protocol YMIAPHelperDelegate <NSObject>
|
@protocol YMIAPHelperDelegate <NSObject>
|
||||||
|
@optional
|
||||||
///当前充值的状态
|
///当前充值的状态
|
||||||
- (void)rechargeProcessStatus:(PaymentStatus)status;
|
- (void)rechargeProcessStatus:(PaymentStatus)status;
|
||||||
|
|
||||||
|
@@ -18,7 +18,8 @@
|
|||||||
#import "YMMineSettingViewController.h"
|
#import "YMMineSettingViewController.h"
|
||||||
#import "MewMineCollectionViewController.h"
|
#import "MewMineCollectionViewController.h"
|
||||||
#import "MewRechargeViewController.h"
|
#import "MewRechargeViewController.h"
|
||||||
|
#import "SessionViewController.h"
|
||||||
|
#import <NIMSDK/NIMSDK.h>
|
||||||
/// Tool
|
/// Tool
|
||||||
#import "YMMacro.h"
|
#import "YMMacro.h"
|
||||||
#import "ThemeColor.h"
|
#import "ThemeColor.h"
|
||||||
@@ -238,7 +239,9 @@
|
|||||||
/// optionType: 0 - 取消关注 1 - 关注 2-聊天
|
/// optionType: 0 - 取消关注 1 - 关注 2-聊天
|
||||||
- (void)userIntrodctionViewWithUserOption:(NSInteger)optionType {
|
- (void)userIntrodctionViewWithUserOption:(NSInteger)optionType {
|
||||||
if (optionType == 2) { //聊天
|
if (optionType == 2) { //聊天
|
||||||
|
NIMSession *session = [NIMSession session:self.targetUid type:NIMSessionTypeP2P];
|
||||||
|
SessionViewController *vc = [[SessionViewController alloc] initWithSession:session];
|
||||||
|
[self.navigationController pushViewController:vc animated:YES];
|
||||||
} else {
|
} else {
|
||||||
[self.presenter attentionUser:self.targetUid state:optionType == 1];
|
[self.presenter attentionUser:self.targetUid state:optionType == 1];
|
||||||
}
|
}
|
||||||
|
@@ -12,10 +12,13 @@
|
|||||||
#import <Masonry/Masonry.h>
|
#import <Masonry/Masonry.h>
|
||||||
#import "YMMacro.h"
|
#import "YMMacro.h"
|
||||||
#import "YMIAPHelper.h"
|
#import "YMIAPHelper.h"
|
||||||
|
#import "AccountInfoStorage.h"
|
||||||
/// P
|
/// P
|
||||||
#import "MineRechargeProtocol.h"
|
#import "MineRechargeProtocol.h"
|
||||||
#import "MineRechargePresenter.h"
|
#import "MineRechargePresenter.h"
|
||||||
|
#import "YMHUDTool.h"
|
||||||
|
#import "yinmeng_ios-Swift.h"
|
||||||
|
#import "RechargeStorage.h"
|
||||||
@interface MewRechargeViewController ()<MineRechargeProtocol, MewRechargeSubViewDelegate, YMIAPHelperDelegate>
|
@interface MewRechargeViewController ()<MineRechargeProtocol, MewRechargeSubViewDelegate, YMIAPHelperDelegate>
|
||||||
@property (nonatomic, strong) UIImageView *rechargeBgImageView;
|
@property (nonatomic, strong) UIImageView *rechargeBgImageView;
|
||||||
@property (nonatomic, strong) UIButton *backButton;
|
@property (nonatomic, strong) UIButton *backButton;
|
||||||
@@ -65,16 +68,141 @@
|
|||||||
self.rechageView.rechargeModels = list;
|
self.rechageView.rechargeModels = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)requestIAPRechargeOrderSuccess:(NSString *)orderId chargeProdId:(NSString *)chargeProdId {
|
- (void)requestIAPRechargeOrderSuccess:(NSString *)orderId chargeProdId:(NSString *)chargeProdId uuid:(nonnull NSString *)uuid{
|
||||||
if (orderId.length > 0) {
|
if (orderId.length > 0) {
|
||||||
self.orderId = orderId;
|
|
||||||
|
self.orderId = orderId;
|
||||||
|
if (@available(iOS 15.0, *)) {
|
||||||
|
|
||||||
|
MewPaymentAction *iap = [MewPaymentAction shared];
|
||||||
|
[iap Mew_demandCommodityThingWithProductId:chargeProdId uuid:uuid completionHandler:^(NSError * _Nullable error) {
|
||||||
|
|
||||||
|
}];
|
||||||
|
@kWeakify(self);
|
||||||
|
iap.Mew_ConditionBlock = ^(enum MewStoreConditionResult state, NSDictionary<NSString *,id> * _Nullable result) {
|
||||||
|
@kStrongify(self);
|
||||||
|
|
||||||
|
[self rechargeNewProcessStatus:state];
|
||||||
|
switch (state) {
|
||||||
|
case MewStoreConditionResultMewVerifiedServer:
|
||||||
|
{
|
||||||
|
NSString *transactionId = result[@"transactionId"];
|
||||||
|
|
||||||
|
[self rechargeSuccess:transactionId];
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
[YMHUDTool hideHUDInView:kWindow];
|
||||||
|
[self showErrorToast:@"充值失败。当前仅支持运行iOS15及以上系统的手机进行充值,请升级系统版本后重试。"];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
[YMHUDTool hideHUDInView:kWindow];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///当前充值的状态
|
||||||
|
- (void)rechargeNewProcessStatus:(MewStoreConditionResult)status {
|
||||||
|
|
||||||
|
|
||||||
|
if (status == MewStoreConditionResultMewPay || status == MewStoreConditionResultMewStart || status == MewStoreConditionResultMewVerifiedServer) {
|
||||||
|
|
||||||
|
}else if (status == MewStoreConditionResultMewUnowned) {
|
||||||
|
[YMHUDTool hideHUDInView:kWindow];
|
||||||
|
[self showErrorToast:@"出现未知错误,请重新尝试"];
|
||||||
|
}else{
|
||||||
|
[YMHUDTool hideHUDInView:kWindow];
|
||||||
|
[self showErrorToast:@"购买失败"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///充值成功回调id
|
||||||
|
- (void)rechargeSuccess:(NSString *)transactionIdentifier {
|
||||||
|
///保存唯一凭证
|
||||||
|
[self saveRechageReciptWithTransactionIdentifier:transactionIdentifier];
|
||||||
|
///二次验证
|
||||||
|
[self.presenter checkReceiptWithOrderId:self.orderId transcationId:transactionIdentifier errorToast:YES];
|
||||||
|
}
|
||||||
|
///二次校验成功
|
||||||
|
- (void)checkReceiptSuccess:(NSString *)transcationId {
|
||||||
|
[YMHUDTool hideHUDInView:kWindow];
|
||||||
|
if (@available(iOS 15.0, *)) {
|
||||||
|
MewPaymentAction *iap = [MewPaymentAction shared];
|
||||||
|
[iap Mew_verifyBusinessAccomplishWithTransaction:[NSString stringWithFormat:@"%@",transcationId] completionHandler:^{
|
||||||
|
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
[self deleteRechageReciptWithTransactionIdentifier:transcationId];
|
||||||
|
self.orderId = nil;
|
||||||
|
//5秒之后如果没有收到开通成功的云信消息,则请求一次用户信息
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
|
||||||
|
///刷新一下用户的信息
|
||||||
|
[self.presenter getUserWalletInfo];
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
///二次校验失败
|
||||||
|
- (void)checkReceiptFailWithCode:(NSInteger)code transcationId:(NSString *)transcationId{
|
||||||
|
[YMHUDTool hideHUDInView:kWindow];
|
||||||
|
if(code == 1444){
|
||||||
|
if (@available(iOS 15.0, *)) {
|
||||||
|
MewPaymentAction *iap = [MewPaymentAction shared];
|
||||||
|
[iap Mew_verifyBusinessAccomplishWithTransaction:[NSString stringWithFormat:@"%@",transcationId] completionHandler:^{
|
||||||
|
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
[self deleteRechageReciptWithTransactionIdentifier:transcationId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///删除本地保存的
|
||||||
|
- (void)deleteRechageReciptWithTransactionIdentifier:(NSString *)transactionIdentifier {
|
||||||
|
NSString * uid = [AccountInfoStorage instance].getUid;
|
||||||
|
BOOL deleteSuccess = [RechargeStorage delegateTranscationId:transactionIdentifier uid:uid];
|
||||||
|
if (deleteSuccess) {
|
||||||
|
#warning to do 保存失败 需要埋点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///充值成功之后保存订单到钥匙串
|
||||||
|
- (void)saveRechageReciptWithTransactionIdentifier:(NSString *)transactionIdentifier {
|
||||||
|
NSData *receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
|
||||||
|
NSString *encodeStr = [receipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
|
||||||
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
|
if(transactionIdentifier != nil){
|
||||||
|
[dictionary setObject:transactionIdentifier forKey:@"transcationId"];
|
||||||
|
}
|
||||||
|
if(encodeStr != nil){
|
||||||
|
[dictionary setObject:encodeStr forKey:@"recipt"];
|
||||||
|
}
|
||||||
|
if(self.orderId != nil){
|
||||||
|
[dictionary setObject:self.orderId forKey:@"orderId"];
|
||||||
|
}
|
||||||
|
if(dictionary.allKeys.count == 0)return;
|
||||||
|
NSString *reciptJson = [dictionary toJSONString];
|
||||||
|
NSString * uid = [AccountInfoStorage instance].getUid;
|
||||||
|
BOOL saveSuccess = [RechargeStorage saveTranscationId:transactionIdentifier recipt:reciptJson uid:uid];
|
||||||
|
if (!saveSuccess) {
|
||||||
|
#warning to do 保存失败 需要埋点
|
||||||
|
}
|
||||||
|
}
|
||||||
#pragma mark - MewRechargeSubViewDelegate
|
#pragma mark - MewRechargeSubViewDelegate
|
||||||
- (void)didSelectMewRechargeChargeProdId:(NSString *)chargeProdId {
|
- (void)didSelectMewRechargeChargeProdId:(NSString *)chargeProdId {
|
||||||
|
[YMHUDTool showLoadingInView:kWindow];
|
||||||
[self.presenter requestIAPRechargeOrderWithChargeProdId:chargeProdId];
|
[self.presenter requestIAPRechargeOrderWithChargeProdId:chargeProdId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -88,6 +88,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
transcationId:(NSString *)transcationId
|
transcationId:(NSString *)transcationId
|
||||||
uid:(NSString *)uid
|
uid:(NSString *)uid
|
||||||
ticket:(NSString *)ticket;
|
ticket:(NSString *)ticket;
|
||||||
|
/// 验证凭据
|
||||||
|
/// @param completion 完成
|
||||||
|
/// @param chooseEnv @"true"
|
||||||
|
/// @param chargeRecordId 服务端生成的订单编号
|
||||||
|
/// @param transcationId 内购的唯一标识符
|
||||||
|
/// @param uid 用户uid
|
||||||
|
/// @param ticket ticket
|
||||||
|
+ (void)checkReceipt:(HttpRequestHelperCompletion)completion chooseEnv:(NSString *)chooseEnv chargeRecordId:(NSString *)chargeRecordId transcationId:(NSString *)transcationId uid:(NSString *)uid ticket:(NSString *)ticket;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
@@ -81,7 +81,7 @@
|
|||||||
/// @param deviceInfo uuid
|
/// @param deviceInfo uuid
|
||||||
/// @param clientIp ip地址
|
/// @param clientIp ip地址
|
||||||
+ (void)requestIAPRecharge:(HttpRequestHelperCompletion)completion chargeProdId:(NSString *)chargeProdId uid:(NSString *)uid ticket:(NSString *)ticket deviceInfo:(NSString *)deviceInfo clientIp:(NSString *)clientIp {
|
+ (void)requestIAPRecharge:(HttpRequestHelperCompletion)completion chargeProdId:(NSString *)chargeProdId uid:(NSString *)uid ticket:(NSString *)ticket deviceInfo:(NSString *)deviceInfo clientIp:(NSString *)clientIp {
|
||||||
[self makeRequest:@"order/placeV2" method:HttpRequestHelperMethodPOST completion:completion, __FUNCTION__,chargeProdId, uid, ticket, deviceInfo, clientIp, nil];
|
[self makeRequest:[NSString stringWithFormat:@"%@/%@",@"storeKitV2",@"placeOrder"] method:HttpRequestHelperMethodPOST completion:completion, __FUNCTION__,chargeProdId, uid, ticket, deviceInfo, clientIp, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -96,5 +96,15 @@
|
|||||||
+ (void)checkReceipt:(HttpRequestHelperCompletion)completion receipt:(NSString *)receipt chooseEnv:(NSString *)chooseEnv chargeRecordId:(NSString *)chargeRecordId transcationId:(NSString *)transcationId uid:(NSString *)uid ticket:(NSString *)ticket {
|
+ (void)checkReceipt:(HttpRequestHelperCompletion)completion receipt:(NSString *)receipt chooseEnv:(NSString *)chooseEnv chargeRecordId:(NSString *)chargeRecordId transcationId:(NSString *)transcationId uid:(NSString *)uid ticket:(NSString *)ticket {
|
||||||
[self makeRequest:@"verify/setiap" method:HttpRequestHelperMethodPOST completion:completion, __FUNCTION__,receipt, chooseEnv, chargeRecordId, transcationId, uid, ticket, nil];
|
[self makeRequest:@"verify/setiap" method:HttpRequestHelperMethodPOST completion:completion, __FUNCTION__,receipt, chooseEnv, chargeRecordId, transcationId, uid, ticket, nil];
|
||||||
}
|
}
|
||||||
|
/// 验证凭据
|
||||||
|
/// @param completion 完成
|
||||||
|
/// @param chooseEnv @"true"
|
||||||
|
/// @param chargeRecordId 服务端生成的订单编号
|
||||||
|
/// @param transcationId 内购的唯一标识符
|
||||||
|
/// @param uid 用户uid
|
||||||
|
/// @param ticket ticket
|
||||||
|
+ (void)checkReceipt:(HttpRequestHelperCompletion)completion chooseEnv:(NSString *)chooseEnv chargeRecordId:(NSString *)chargeRecordId transcationId:(NSString *)transcationId uid:(NSString *)uid ticket:(NSString *)ticket {
|
||||||
|
|
||||||
|
[self makeRequest:[NSString stringWithFormat:@"%@/%@",@"storeKitV2",@"verifyOrder"] method:HttpRequestHelperMethodPOST completion:completion, __FUNCTION__, chooseEnv, chargeRecordId, transcationId, uid, ticket, nil];
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
@@ -30,7 +30,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/// 批量验证内购掉单
|
/// 批量验证内购掉单
|
||||||
/// @param transcations 凭据的数组
|
/// @param transcations 凭据的数组
|
||||||
- (void)checkTranscationIds:(NSArray *)transcations;
|
- (void)checkTranscationIds:(NSArray *)transcations;
|
||||||
|
/// 充值成功二次验证
|
||||||
|
/// @param orderId 订单编号
|
||||||
|
/// @param transcationId 商品id
|
||||||
|
- (void)checkReceiptWithOrderId:(NSString *)orderId transcationId:(NSString *)transcationId errorToast:(BOOL)errorToast;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
@@ -48,12 +48,28 @@
|
|||||||
NSString * clientIp= [YYUtility ipAddress];
|
NSString * clientIp= [YYUtility ipAddress];
|
||||||
[Api requestIAPRecharge:[self createHttpCompletion:^(BaseModel * _Nonnull data) {
|
[Api requestIAPRecharge:[self createHttpCompletion:^(BaseModel * _Nonnull data) {
|
||||||
NSString *orderId = (NSString *)data.data[@"recordId"];
|
NSString *orderId = (NSString *)data.data[@"recordId"];
|
||||||
[[self getView] requestIAPRechargeOrderSuccess:orderId chargeProdId:chargeProdId];
|
NSString *mew_uuid = (NSString *)data.data[@"appAccountToken"];
|
||||||
|
[[self getView] requestIAPRechargeOrderSuccess:orderId chargeProdId:chargeProdId uuid:mew_uuid];
|
||||||
} fail:^(NSInteger code, NSString * _Nullable msg) {
|
} fail:^(NSInteger code, NSString * _Nullable msg) {
|
||||||
|
if(code != 50000){
|
||||||
|
[[self getView]showErrorToast:msg];
|
||||||
|
}
|
||||||
[[self getView] requestIAPRechargeOrderFail];
|
[[self getView] requestIAPRechargeOrderFail];
|
||||||
}] chargeProdId:chargeProdId uid:uid ticket:ticket deviceInfo:deviceInfo clientIp:clientIp];
|
}] chargeProdId:chargeProdId uid:uid ticket:ticket deviceInfo:deviceInfo clientIp:clientIp];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 充值成功二次验证
|
||||||
|
/// @param orderId 订单编号
|
||||||
|
/// @param transcationId 商品id
|
||||||
|
- (void)checkReceiptWithOrderId:(NSString *)orderId transcationId:(NSString *)transcationId errorToast:(BOOL)errorToast{
|
||||||
|
NSString * uid = [AccountInfoStorage instance].getUid;
|
||||||
|
NSString * ticket = [AccountInfoStorage instance].getTicket;
|
||||||
|
[Api checkReceipt:[self createHttpCompletion:^(BaseModel * _Nonnull data) {
|
||||||
|
[[self getView] checkReceiptSuccess:transcationId];
|
||||||
|
}fail:^(NSInteger code, NSString * _Nullable msg) {
|
||||||
|
[[self getView]checkReceiptFailWithCode:code transcationId:transcationId];
|
||||||
|
} showLoading:NO errorToast:errorToast] chooseEnv:@"true" chargeRecordId:orderId transcationId:transcationId uid:uid ticket:ticket];
|
||||||
|
}
|
||||||
|
|
||||||
/// 充值成功二次验证
|
/// 充值成功二次验证
|
||||||
/// @param receipt 凭据
|
/// @param receipt 凭据
|
||||||
|
@@ -10,18 +10,21 @@
|
|||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@protocol MineRechargeProtocol <NSObject>
|
@protocol MineRechargeProtocol <NSObject>
|
||||||
|
@optional
|
||||||
///请求钱包余额信息
|
///请求钱包余额信息
|
||||||
- (void)getUserWalletInfo:(WalletInfoModel *)balanceInfo;
|
- (void)getUserWalletInfo:(WalletInfoModel *)balanceInfo;
|
||||||
///请求充值列表成功
|
///请求充值列表成功
|
||||||
- (void)requestRechargeListSucccess:(NSArray *)list;
|
- (void)requestRechargeListSucccess:(NSArray *)list;
|
||||||
///请求充值id的状态成功
|
///请求充值id的状态成功
|
||||||
- (void)requestIAPRechargeOrderSuccess:(NSString *)orderId chargeProdId:(NSString *)chargeProdId;
|
- (void)requestIAPRechargeOrderSuccess:(NSString *)orderId chargeProdId:(NSString *)chargeProdId uuid:(NSString *)uuid;
|
||||||
///请求充值账单失败
|
///请求充值账单失败
|
||||||
- (void)requestIAPRechargeOrderFail;
|
- (void)requestIAPRechargeOrderFail;
|
||||||
///二次校验成功
|
///二次校验成功
|
||||||
- (void)checkReceiptSuccess:(NSString *)transcationId;
|
- (void)checkReceiptSuccess:(NSString *)transcationId;
|
||||||
///批量验证凭据成功
|
///批量验证凭据成功
|
||||||
- (void)checkTranscationIdsSuccess;
|
- (void)checkTranscationIdsSuccess;
|
||||||
|
///二次校验失败
|
||||||
|
- (void)checkReceiptFailWithCode:(NSInteger)code transcationId:(NSString *)transcationId;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
Reference in New Issue
Block a user