因为之前做的都是基本实体的物品在自己的项目做交易的流程,所以之前也没有接触过苹果的内购,都是用的支付宝和微信,但是这次的项目是做虚拟币的交易,所以前期开会的时候,公司又想利益最大化,就想避开苹果那30%的税,前面的思路是不集成支付宝和微信的sdk做safari的跳转看能不能避开苹果的抽成,效果是做出来,不集成支付宝的sdk,通过外部的跳转到支付宝支付然后在调回自己的app(我下一篇文章说支付宝拦截h5调回自己的app)但是查看了苹果指南发现还是不行就改内购吗,但是第一次做,这里就总结一下自己踩过的坑和解决办法
前面的和苹果签署的一系列的卖身契约我这里就不详细的讲解
先说遇到的坑
- 第一个坑:获取不到订单的信息
- 第二个坑:总是链接不到iTunes Store,错误内容
Optional(Error Domain=SKErrorDomain Code=0 "无法连接到 iTunes Store" UserInfo={NSLocalizedDescription=无法连接到 iTunes Store})
- 第三个坑:因为是第一次做不知道有沙盒测试账号,写好之后测试的时候用自己的账号测试提示该账号没有权限
- 第四个坑:创建沙盒测试账号的时候不允许创建已经有的AppleID
1、Xcode工程配置
开启此选项App Strore中APP的介绍界面显示内购的相关项目,关闭则不显示
2、iTunesconnect创建产品
(1).开发者中心->App Store Connect->我的App->创建需要上线的App
这里解决第一个坑,因为这个项目是团队开发的,我在测试的时候始终拿不到订单的信息,后面才发现,队友在项目中把BundleID给我改了,强调一点在你确定你的代码没有错的时候,你必须保证你的BundleID和需要提价的App信息的BundleID一直
(2).选择你希望创建APP内购买项目
App信息->功能->App内购买项目
在这里创建你在APP项目
- 产品名称:随便写,但是最好还是写成和你项目向管理的
- 产品ID:也可以随便写,如果你的项目里面不止一个内购商品,那么最好就命名规范一下,这样可以由后台来控制
- 价格:苹果果然霸道,价格都给你定好了,最低消费都是6块起步
- 本地化版本:显示的名称和描述就是订单的信息也就是显示在你购买的时候提示用户的信息
- App Strore 推广:标明的是可选,准备一张1024*1024的推广图就可以了
-
审核信息:必须上传一张屏幕的截图,如果不是就提交不上去,我开始是用的截图然后通过qq发过来压缩了一下,结果失败了,后面通过设备传过来的,如果没有上传的话,保存之后会提示元数据丢失
注意:每个开发人员帐户可在该帐户的所有 App 中创建最多 10,000 个 App 内购买项目产品。App 内购买项目共有四种类型:消耗型、非消耗型、自动续期订阅和非续期订阅。
3、实现步骤主要包括三步
1、首先在项目工程中加入StoreKit.framework
2、加入头文件#import <StoreKit/StoreKit.h>
3、遵守代理SKPaymentTransactionObserver,SKProductsRequestDelegate
4、代码实现,我这里直接写的一个PayManager类
1)判断用户是否具备支付权限
if SKPaymentQueue.canMakePayments(){
pay(productId:productId,order_id:order_id)
}else{
let alertView = CCarAlertView.init(iconImage: nil, message: "您的手机没有打开程序内付费购买")
alertView.block = {}
}
2)、注册通知
SKPaymentQueue.default().add(self as SKPaymentTransactionObserver)
3)、创建一个商品查询的请求,productIdentifiers指需要查询的“产品ID”的数组,并且实现代理
func payMoeny(productId:String){
addSKPaymentQueue()
if productId.count == 0{
if requestErrorBlock != nil{
requestErrorBlock()
}
return
}
removeAllUncompleteTransactionsBeforeNewPurchase()
let skpay = SKProductsRequest(productIdentifiers: NSSet(object: productId) as! Set<String>)
self.productId = productId
skpay.delegate = self
skpay.start()
}
/// 结束上次未完成的交易,防止漏单的其中一种解决方案
private func removeAllUncompleteTransactionsBeforeNewPurchase(){
let transactions:NSArray = SKPaymentQueue.default().transactions as NSArray
if transactions.count >= 1 {
for transaction in transactions {
if (transaction as! SKPaymentTransaction).transactionState == .purchased || (transaction as! SKPaymentTransaction).transactionState == .restored{
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
}
}else{
print("没有历史未消耗订单")
}
}
4)、查询的结果将通过SKProductsRequestDelegate得到查询的结果
获取商品的查询结果,这里可以拿到订单的相信信息,代码比较相信,就不详细的讲解
/// 内购商品回调代理
///
/// - Parameters:
/// - request: SKProductsRequest
/// - response: SKProductsResponse
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print(response.products)
print(response.invalidProductIdentifiers)
let products = response.products
if products.count == 0{
print("没有产品信息")
if notProductsBlock != nil{
notProductsBlock()
}
removeSKPaymentQueue()
return
}
///发送购买请求
for product in products{
if product.productIdentifier == self.productId{
print("SKProduct 描述信息\(product.description)")
print("产品标题\(product.localizedTitle)")
print("产品描述信息\(product.localizedDescription)")
print("价格\(product.price)")
print("Product id\(product.productIdentifier)")
let skPayment = SKPayment(product: product)
SKPaymentQueue.default().add(skPayment)
break
}
}
}
5)、支付结果,里面有5中状态,个人客官自己看代码就能知道了
/// 内够代理回调
///
/// - Parameters:
/// - queue: SKPaymentQueue
/// - transactions: [SKPaymentTransaction]
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions{
switch transaction.transactionState {
case .purchasing://事务正在添加到服务器队列中。
print("事务正在添加到服务器队列中。")
break
case .purchased://完成支付
print("支付成功")
getAndSaveReceipt(transaction)
queue.finishTransaction(transaction)
removeSKPaymentQueue()
break
case .failed://支付失败
print("支付失败")
payFailed(transaction:transaction)
break
case .restored://已经购买过该商品
print("事务从用户的购买历史中恢复。客户应完成交易。")
queue.finishTransaction(transaction)
break
case .deferred://最终状态未确定
print("最终状态未确定")
removeSKPaymentQueue()
break
default:
break
}
}
}
说道这里我们来解决第二个坑,天坑,解决了1天,我在支付回调的时候始终拿到的都是支付失败,打印出来的错误就是无法连接到 iTunes Store,网上也查询很多资料,给我的结果就是更改Build
我不知道是不是我更错了还是怎么,但是就是不行
然后还有博主说的是重置手机,我也重置了,还是不行,后面拿到一个手机上面可以翻墙的手机成功了,然后我的解决方案就是开vpn果然解决了(如果有客官有更好的方法欢迎留言)
6)、支付完成,这个没有什么好说的,不管支付成功与否都会调用这个方法
func requestDidFinish(_ request: SKRequest) {
print("支付流程完成")
}
7)、支付失败,也没有什么好说的
func request(_ request: SKRequest, didFailWithError error: Error) {
print("支付失败")
if requestErrorBlock != nil{
requestErrorBlock()
}
}
4、测试
第三个坑,我在写完这些之后就能正常的支付了,但是支付的回调成功的时候输入AppID之后总是提示我该账号没有权限,后面百度才知道有沙盒账号的测试,关键是不需要支付钱哦,想怎么买就怎么买
创建沙盒账号的流程
App Store Connect->用户和职能->沙盒技术测试员
最后一个坑:测试的时候需要退出自己的账号用沙盒账号
设置->iTunes Strore与App Store
App Store->个人信息
如果觉得对各人客官有用就希望点赞一下,下一篇文章支付宝H5支付无法返回APP坑和解决方案