美文网首页内购
iOS开发之内购(Swift)

iOS开发之内购(Swift)

作者: TRACER_ | 来源:发表于2017-05-27 13:55 被阅读752次

关于协议税务和银行业务的资料填写以及申请我就不写了,自己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、越狱手机无解
    网上资料比较少,目前我可能就先这样了,如果点进来的你已经处理了的话,欢迎补充。

状态码表.png

我们的APP一直在用微信支付和支付宝支付。产品说以防万一(我觉得被拒的概率很小),先提前做好。刚知道这个需求的时候特想说句mmp。后来还是自己默默的翻遍了网上的内购文。恩,总算可以支付了,后期如果有什么问题,我会继续补充的。
鉴于网上的图文博客比较多,我基本都是以文字的形式大概说明了一下操作流程。

相关文章

网友评论

    本文标题:iOS开发之内购(Swift)

    本文链接:https://www.haomeiwen.com/subject/ztdwittx.html