苹果内购流程
苹果现在对应用市场的审核规则越来越严格,不仅对马甲包进行大批量下架,而且对应用内的支付也有了严格的规定,凡是虚拟商品的购买都要使用苹果内购进行支付,否则应用不能被审核通过,而且苹果还要分成30%。无奈之下,只能遵循苹果的规则,毕竟是依赖它的平台进行开发的,所以苹果内购买流程是开发者必须要掌握的技能。
一、填写协议、税务和银行业务
登录苹果开发者中心网站,选择进入App Store Connect,然后点击 “协议、税务和银行业务”,按照流程填写一些基本信息
二、添加App 内购买项目
-
选择要添加内购项目的App
-
选择功能菜单,便可添加内购项目
-
选择内购商品的类型,点击创建
-
创建产品后,填写产品的基本信息
-
下面这些就是已经创建好的内购商品
三、添加沙箱测试员账号,在测试的环境下方便测试人员购买
-
点击进入
-
填写账号信息,创建成功后就可以使用账号测试购买
四、代码实现
支付流程
从公司的服务器获取商品ID,也就是我们在开发中中心添加的内购项目的ID
根据商品ID,向苹果发送请求,请求所有可买的商品
/// 获取苹果内购商品信息
///
/// - Parameters:
/// - productId: 内购商品product_id
/// - completion: 内购商品SKProduct回调
func fetchProduct(_ productId: String?, completion: @escaping CompletionResult) {
guard let product_id = productId else {
completion(Result.failure(RxSwiftMoyaError.filterError("抱歉,商品id无效")))
return
}
// 检查用户是否允许支付
guard SKPaymentQueue.canMakePayments() == true else {
completion(Result.failure(RxSwiftMoyaError.filterError("检查是否允许支付功能或者该设备是否支持支付.")))
return
}
self.completionResult = completion
/// 请求商品信息
let set: Set<String> = [product_id]
let request = SKProductsRequest.init(productIdentifiers: set)
request.delegate = self
request.start()
}
- 在代理方法里面获取所有的可卖商品
// MARK: - 获取苹果商品对象
extension IAPService: SKProductsRequestDelegate {
/// 接收苹果商品信息回调
///
/// - Parameters:
/// - request: 请求体
/// - response: 返回结果
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let products = response.products
guard products.count > 0, let product = products.first else {
self.completionResult?(Result.failure(RxSwiftMoyaError.filterError("抱歉,商品信息无效!")))
return
}
//将商品实体回调出去,作为发起支付时的入参
self.completionResult?(Result.success(product))
}
}
- 创建票据SKPayment,将票据加入到交易队列,便可发起支付
/// 发起苹果支付
///
/// - Parameter product: 苹果内购商品对象
func purchase(_ product: SKProduct, completion: @escaping PaymentCompletionResult) {
Logger.log(product.productIdentifier)
self.paymentCompletionResult = completion
let payment = SKPayment.init(product: product)
SKPaymentQueue.default().add(payment)
}
- 在init方法中添加观察者,监听用户是否支付的各种状态
override init() {
super.init()
// 监听支付事务回调
SKPaymentQueue.default().add(self as SKPaymentTransactionObserver)
}
- 监听支付的各种事物
// MARK: - 支付事物监听
extension IAPService: SKPaymentTransactionObserver {
/// 当事务数组发生更改时发送(添加或状态更改)。客户端应该检查事务状态,并在适当的时候完成。
///
/// - Parameters:
/// - queue: 支付队列
/// - transactions: 支付事务数组
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
Logger.log("")
for transaction in transactions {
Logger.log(transaction.transactionState.rawValue)
switch transaction.transactionState {
case .purchasing: // 交易事务进行中
break
case .purchased: // 交易完成
self.handlerTransaction(transaction)
break
case .failed: // 交易失败
self.handlerTransaction(transaction)
break
case .restored: // 从用户的购买历史中恢复交易
self.handlerTransaction(transaction)
break
default:
/// 结束支付事务
SKPaymentQueue.default().finishTransaction(transaction)
break
}
}
}
/// 当事务从队列中删除时被调用
///
/// - Parameters:
/// - queue: 支付队列
/// - transactions: 支付事务数组
func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
Logger.log("")
for transaction in transactions {
Logger.log("删除事务: \(transaction.payment.productIdentifier)")
/// 结束该条支付事务: 否则出现弹框 您已购买此 App 内购买项目。此项目将免费恢复。
SKPaymentQueue.default().finishTransaction(transaction)
}
}
/// 当遇到错误时发送,同时从用户的购买历史中添加事务回到队列
///
/// - Parameters:
/// - queue: 支付队列
/// - error: 错误
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
Logger.log(error.localizedDescription)
}
/// 当用户的购买记录的所有事务都成功地添加到队列中时被调用
///
/// - Parameter queue: 支付队列
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
Logger.log("")
}
/// 当用户从应用程序商店发起IAP购买时发送
///
/// - Parameters:
/// - queue: 支付队列
/// - payment: 支付对象
/// - product: 商品信息
/// - Returns: 是否发起支付
func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
Logger.log(product.productIdentifier)
return true
}
}
- 对监听到的支付事物进行处理
/// 自定义处理支付事务
///
/// - Parameter transaction: 支付事务
func handlerTransaction(_ transaction: SKPaymentTransaction) {
let error = transaction.error as NSError?
if error?.code == SKError.paymentCancelled.rawValue {
// 用户手动取消支付
SKPaymentQueue.default().finishTransaction(transaction)
self.paymentCompletionResult?(Result.failure(RxSwiftMoyaError.filterError("已取消支付")))
}else{
switch transaction.transactionState {
case .purchased, .restored:
// 苹果订单校验
self.verifyReceipt(transaction)
break
case .failed:
SKPaymentQueue.default().finishTransaction(transaction)
if let error = transaction.error as NSError? {
self.completionResult?(Result.failure(RxSwiftMoyaError.error(error)))
}
break
default:
SKPaymentQueue.default().finishTransaction(transaction)
break
}
}
}
- 最后支付成功后,上传支付凭证到服务器