关于协议税务和银行业务的资料填写以及申请我就不写了,自己Google+百度吧。毕竟各位大神写的也是蛮详细的。直接上代码了,需要的说明我会以注释的形式大概说一下,当然有什么不对的地方欢迎拍砖😝😝(swift2.2,不要问我为什么不升级)
- 1、导入
StoreKit.framework
库(target -> General -> Linked Frameworks and Libraries -> 加号...) - 2、导入头文件
import StoreKit
- 3、去开发者账号申请产品ID(iTunes Connect -> 我的APP -> 功能 -> APP内购买项目 -> 点击加号填写相关的信息 -> 填写完会生成一个
产品 ID
) - 4、代码:
class InAppPurchaseViewController: UIViewController, SKPaymentTransactionObserver, SKProductsRequestDelegate{
// 判断是否在测试环境下(用于客户端自己去苹果服务器验证付款信息,当然不推荐这么做,最好是由服务器去验证,然后返回给客户端)
private let appStoreUrl = "https://sandbox.itunes.apple.com/verifyReceipt"// 测试环境(沙盒账号付款)
private let appStoreUrl = "https://buy.itunes.apple.com/verifyReceipt"
override func viewDidLoad() {
super.viewDidLoad()
// 开启内购检测
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
}
func purchaseBtnClick(sender: AnyObject) {
if SKPaymentQueue.canMakePayments() {
reuqestProductData("在第三步申请的产品ID")
}else{
print("您已设置不允许程序内购买")
}
}
private func reuqestProductData(type: String) {
let product = [type]
let set = NSSet(array: product as [AnyObject])
let request = SKProductsRequest(productIdentifiers: set as! Set<String>)
request.delegate = self
request.start()
}
// 监听购买结果
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for tran in transactions {
// print(tran.error?.description)
switch tran.transactionState {
case .Purchased:
print("购买成功")
commitSeversSucceeWithTransaction(tran)
SKPaymentQueue.defaultQueue().finishTransaction(tran)
case .Purchasing:
print("用户正在购买")
case .Restored:
print("已经购买过商品")
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(tran)
print("失败")
default:
break
}
}
}
// 收到产品返回的信息
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
if response.products.count == 0 {
print("没有商品")
}
var prod: SKProduct?
for pro in response.products {
print("------------------")
print(pro.localizedDescription)
print(pro.localizedTitle)
print(pro.price)
print(pro.productIdentifier)
print("------------------")
if pro.productIdentifier == "在第三步申请的产品ID" {
prod = pro
}
}
// 发送购买请求
if let produ = prod {
let payment = SKPayment(product: produ)
SKPaymentQueue.defaultQueue().addPayment(payment)
}
}
// 验证(1、客户端自己验证。2、由后台去验证,推荐这个)
private func commitSeversSucceeWithTransaction(transation: SKPaymentTransaction) {
let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL
let receiveData = NSData(contentsOfURL: receiptUrl!)
// 最好转成Base64,万一返回结果有特殊字符
let receiptString = receiveData!.base64EncodedStringWithOptions(.EncodingEndLineWithLineFeed)
// 保存本地(dict随你自己的需求写就好)
let dict = ["account_id": account, "receipt": "\(receiptString)"]
userDefault.setObject(dict, forKey: UserDefaultKey.appInPurchase)
userDefault.synchronize()
// 客户端自己去苹果服务器验证付款信息
let bodyString = "{\"receipt-data\" : \"\(receiptString)\"}"
let bodyData = bodyString.dataUsingEncoding(NSUTF8StringEncoding)
let url = NSURL(string: appStoreUrl)
let reuqest: NSMutableURLRequest = NSMutableURLRequest(URL: url!)
reuqest.HTTPBody = bodyData
reuqest.HTTPMethod = "POST"
// 请原谅我懒,毕竟我只是写给自己测试的(上线的时候就是由后台去验证的了),就直接强制try了。如果你们真的是要客户端自己验证的话,就乖乖的do - catch 抛异常吧。
let responseData = try? NSURLConnection.sendSynchronousRequest(reuqest, returningResponse: nil)
let dic: NSDictionary = try! NSJSONSerialization.JSONObjectWithData(responseData!, options: .AllowFragments) as! NSDictionary
// let statusCode: Int = dic["status"] as! Int
// 我打包装到手机(即连到苹果正式验证环境,因为苹果审核的时候就是用你提供的沙盒账号测试的)测试支付的时候发现dic就直接等于21007了,但是debug的时候dic返回很多相关的信息(可能这里命名不应该叫dic,表示有点不太懂为什么会这样)
// status请参考下面的状态码表
// 由自己的服务器去验证
把交易成功后获取的凭证receiptString传给后台,让后台去苹果的服务器验证,然后客户端根据后台返回的数据来处理业务(比如刷新UI,设置为会员等等操作)
validateForServer(receiptString) // 自定义方法
}
// 其他代理方法(请求失败,请求成功等等的返回,根据具体的需求自己处理吧)
}
-
5、添加沙盒测试账号(iTunes Connect -> 用户和智能 -> 点击加号添加即可),然后就自己测试支付吧。
-
6、需要注意的几点:
1)在监听购买结果后,一定要调用SKPaymentQueue.defaultQueue().finishTransaction(tran);来允许你从支付队列中移除交易
2)沙盒环境测试appStore内购流程的时候,请使用未越狱的设备
3)请务必使用真机来测试,一切以真机为准
4)真机测试的时候,一定要退出原来的账号,才能用沙盒测试账号,否则会报错连接不到iTunes
5)开发环境下也需要有证书才能测试,请确保项目的BundleID需要与您申请AppID时填写的bundleID一致
6)价格不能在后台获取,只能在申请产品ID的时候选择,有多个价格?那就多申请几个产品ID咯。
7)为保证审核的通过,需要在客户端或server进行双重验证,即,先以线上交易验证地址进行验证,如果苹果正式验证服务器的返回验证码code为21007,则再一次连接沙盒测试服务器进行验证即可。在应用提审时,苹果IAP提审验证时是在沙盒环境的进行的,即:苹果在审核App时,只会在sandbox环境购买,其产生的购买凭证,也只能连接苹果的测试验证服务器,如果没有做双验证,需要特别注意此问题,否则会被拒。
8)代码仅供参考😁😁😁
-
7、关于漏单的处理
// 我还需要理清逻辑+调试代码,端午节后补充吧,已经提前给自己放假,无心写代码。(端午已完,三天假过得飞快有木有)
关于漏单:用户已经支付了money,但是我们并没有将用户设置为会员或者发放道具等等相关的操作。原因?可能是验证的时候出了问题,也可能是没等到验证完成用户就直接退出app了,可能...(脑补吧,毕竟bug总是千奇百怪,防不胜防)
我的做法是保存到本地即 NSUserDefaults(代码见上面,我最后还是放弃了这种方法,用了下面内购文里的方法)
然后一进程序就看看有没有漏单推荐一篇关于内购文,写的比我这好多了,各位猿媛请移步吧。
-
8、越狱手机无解
网上资料比较少,目前我可能就先这样了,如果点进来的你已经处理了的话,欢迎补充。
我们的APP一直在用微信支付和支付宝支付。产品说以防万一(我觉得被拒的概率很小),先提前做好。刚知道这个需求的时候特想说句mmp。后来还是自己默默的翻遍了网上的内购文。恩,总算可以支付了,后期如果有什么问题,我会继续补充的。
鉴于网上的图文博客比较多,我基本都是以文字的形式大概说明了一下操作流程。
网友评论