ios 内购正式环境_iOS内购集成

In-App Purchase:应用内购买服务,简称IAP。是苹果为App内的虚拟商品和服务的交易定制的系统。

所谓应用内购买,是指在操作虚拟商品交易的时候,不允许使用类似微信/支付宝/Apple Pay第三方支付手段,如果通过另类方式避开的话,会被下架。

配置内购信息

创建商品类型

消耗型:使用一次并耗尽,可以重复购买。类似于宝箱,武器皮肤

非消耗型:只需购买一次,不会过期。类似于地图,电子书

自动续期订阅:购买一次后服务或内容会自动续订,直到用户决定取消。类似于Apple music

非续期订阅:购买一次后,不会自动续订,并且可以再次购买,等同于购买一段时间的服务可以叠加。类似于会员,一定数量钻石

StoreKit

通过StoreKit框架使应用程序连接到App Store,以提示并安全地处理付款。

先遵循SKProductsRequestDelegate,SKPaymentTransactionObserver协议。

//添加支付监听

SKPaymentQueue.default().add(self)

//移除监听

SKPaymentQueue.default().remove(self)复制代码

点击购买

//是否允许付款(通过权限限制购买的人群)

if SKPaymentQueue.canMakePayments() {

pid:这里指的是选择套餐对应的id,从苹果后台的套餐配置生成,App服务端获取

let set = NSSet(array: [pid])

//检索本地化商品信息

let request = SKProductsRequest(productIdentifiers: set as! Set)

request.delegate = self

request.start()

}else {

print("禁止购买")

}复制代码

恢复购买,这里的作用是持久化我们的订单信息,下次重新监听支付队列的时候会重新调用

恢复之前的购买

SKPaymentQueue.default().restoreCompletedTransactions()//非续订订阅型和消耗型无法恢复

购买历史记录的事务,添加回队列出错回调

func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {

print("错误恢复: \(error)")

}

恢复购买,成功添加队列回调

func paymentQueueRestoreCompletedTransactionsFinished(_ queue:SKPaymentQueue){

}复制代码

产品要求代理

收到产品信息的响应

func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {

}

请求失败

func request(_ request: SKRequest, didFailWithError error: Error) {

}

请求完成

func requestDidFinish(_ request: SKRequest) {

}复制代码

付款交易观察代理

监听交易状态

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {

for tran in transactions {

switch tran.transactionState {

case .purchased:

//交易完成,调起验证购买

//1.从沙盒获取持久化订单信息

//2.将收据上传到App服务器,成功后结束交易

//3.删除保存的订单信息

case .purchasing:

//交易中

case .restored:

//已经购买过

case .failed:

//交易失败

break

default:

break

}

}

}

交易结束

private func payFinish(transaction:SKPaymentTransaction) {

}复制代码

代码

import UIKit

import StoreKit

// MARK: - swift title: IAP应用内购买

// MARK: - 点击购买

class UserIAPBuy: NSObject,SKProductsRequestDelegate,SKPaymentTransactionObserver {​

func startBuyInnerProduct(_ type: String) -> () {​

SKPaymentQueue.default().add(self as SKPaymentTransactionObserver)​ ​

localRequest(type)​

}​ ​

func localRequest(_ type: String) -> () {​ ​

if SKPaymentQueue.canMakePayments() {​

let set = NSSet(array: [type])​

//检索本地化商品信息​

let request = SKProductsRequest(productIdentifiers: set as! Set)​

request.delegate = self​

request.start()​

}else {​

print("禁止购买")​

}​ ​

}​

}

// MARK: - 恢复购买

extension UserIAPBuy {​

func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {​

print("错误恢复 code: (error)")​

}​ ​

func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {​

//恢复购买获取成功回调​

var array = String​

print("received restored transactions: (queue.transactions.count)")​

for pay:SKPaymentTransaction in queue.transactions {​

let productID = pay.payment.productIdentifier​

array.append(productID)​

print("message: (array)")​

}​

}​

//恢复之前购买​

@objc func replyToBuy() {​

SKPaymentQueue.default().restoreCompletedTransactions()​

}

}

// MARK: - 代理:商品 SKProductsRequestDelegate

extension UserIAPBuy {​

func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {​

// 收到App Store商品信息的响应​

let pro = response.products​ ​

if pro.count > 0 {​

var p: SKProduct?​

for pid in pro {​

print("描述信息: (pid.description)")​

print("产品标题: (pid.localizedTitle), 产品描述信息: (pid.localizedDescription)")​

print("价格: (pid.price)")​

p = pid​

}​

guard let pro = p else {​

return​

}​

SKPaymentQueue.default().add(SKPayment(product: p))​ ​

}else {​

// 处理无法获得商品信息的操作​

print("无法取得商品信息")​

}​

}​ ​

func requestDidFinish(_ request: SKRequest) {​

// 处理请求完成​

}​ ​

func request(_ request: SKRequest, didFailWithError error: Error) {​

// 处理请求失败​

}

}

// MARK: - 代理:付款交易观察 SKPaymentTransactionObserver

extension UserIAPBuy {​

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {​

//监听交易状态​

for tran in transactions {​

switch tran.transactionState {​

case .purchased:​

//交易完成,调起验证购买​

//1.从沙盒获取持久化订单信息​

//2.将收据上传到App服务器,成功后结束交易​

//3.删除保存的订单信息​

paymentTransactionPurchased()​

SKPaymentQueue.default().finishTransaction(tran)​

case .purchasing:​

//交易中​

paymentTransactionPurchasing()​

case .restored:​

//已经购买过​

paymentTransactionRestored()​

SKPaymentQueue.default().finishTransaction(tran)​

case .failed:​

//交易失败​

paymentTransactionFailed(tran)​

default:​

break​

}​

}​

}​ ​

func paymentTransactionPurchased() {​

// 验证购买,避免越狱软件模拟苹果请求达到非法购买问题​

guard let receiptUrl = Bundle.main.appStoreReceiptURL,let receiptData = try? Data(contentsOf: receiptUrl) else {​

// 从沙盒中获取交易凭证并且b拼接成请求提数据0​

return​

}​

let receiptStr = receiptData.base64EncodedString(options: Data.Base64EncodingOptions.endLineWithLineFeed)​

//处理订单信息​

print("订单信息: (receiptStr)")​

//删除保存的订单​

}​ ​

func paymentTransactionPurchasing() {​

print("交易中")​

}​ ​

func paymentTransactionRestored() {​

print("已经购买过")​

}​ ​

func paymentTransactionFailed(_ transaction: SKPaymentTransaction) {​

guard let err = transaction.error else {​

SKPaymentQueue.default().finishTransaction(transaction)​

return​

}​

if (err as NSError).code != SKError.paymentCancelled.rawValue {​

print("交易失败")​

}else{​

print("交易取消")​

}​

}

}复制代码

沙箱测试

沙箱账号是测试用途的Apple ID,由于内购涉及实际金钱交易,在测试阶段我们可以通过注册苹果的沙箱账号来完成内购付款。电子邮箱可以自定义。

App Store地区的选择和结算价格有关。

应用IAP权限打开

最后

技术总结:

1.在App Store后台配置内购买项目,需要先完成协议,税务银行项目。这部分可参考上一篇

2.配置具备In-App Purchase功能的App ID,并开启IAP权限。

3.通过StoreKit框架,在对应的地方实现并调整你的内购代码。

需要注意的地方:

1.有关于服务端验证收据,服务端也是有沙盒和正式两个环境,具体实现也有很多成熟的开源框架可用,这里也需要把应用套餐的信息给服务端配置。

2.苹果自带的内购买体验确实不是很好,由于本身服务器在美区,连接会比较慢,添加沙盒App ID的时候,建议不要在App内绑定,可以选择从设置-iTunesStore来绑定AppleID测试账号,绑定成功,底部会新增一个沙盒账号。

3.应用套餐也是需要审核的,把改填的地方填写清楚,问题不大,另外应用内套餐审核是伴随主App一起审核的,如果主App没有过,那么原先套餐审核通过的状态就会改变,在下一次重新提交主App的时候需要重置套餐的状态,否则,无法查找对应套餐信息。

验证购买(二次验证):

1.App将订单收据传给服务器

2.服务器收到收据后发送给App Store进行验证,并返回验证结果

这一步尽量放在服务端操作,将所有的验证交易数据放在客户端不仅不安全,而且不稳定。

服务端ruby集成的内购框架(Monza)

纯属个人分享,希望对iOS社区能有更多贡献。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部