蘋(píng)果內(nèi)購(gòu)的坑和解決辦法

因?yàn)橹白龅亩际腔緦?shí)體的物品在自己的項(xiàng)目做交易的流程,所以之前也沒(méi)有接觸過(guò)蘋(píng)果的內(nèi)購(gòu),都是用的支付寶和微信,但是這次的項(xiàng)目是做虛擬幣的交易,所以前期開(kāi)會(huì)的時(shí)候,公司又想利益最大化,就想避開(kāi)蘋(píng)果那30%的稅,前面的思路是不集成支付寶和微信的sdk做safari的跳轉(zhuǎn)看能不能避開(kāi)蘋(píng)果的抽成,效果是做出來(lái),不集成支付寶的sdk,通過(guò)外部的跳轉(zhuǎn)到支付寶支付然后在調(diào)回自己的app(我下一篇文章說(shuō)支付寶攔截h5調(diào)回自己的app)但是查看了蘋(píng)果指南發(fā)現(xiàn)還是不行就改內(nèi)購(gòu)嗎,但是第一次做,這里就總結(jié)一下自己踩過(guò)的坑和解決辦法
前面的和蘋(píng)果簽署的一系列的賣(mài)身契約我這里就不詳細(xì)的講解
先說(shuō)遇到的坑

  • 第一個(gè)坑:獲取不到訂單的信息
  • 第二個(gè)坑:總是鏈接不到iTunes Store,錯(cuò)誤內(nèi)容
Optional(Error Domain=SKErrorDomain Code=0 "無(wú)法連接到 iTunes Store" UserInfo={NSLocalizedDescription=無(wú)法連接到 iTunes Store})
  • 第三個(gè)坑:因?yàn)槭堑谝淮巫霾恢烙猩澈袦y(cè)試賬號(hào),寫(xiě)好之后測(cè)試的時(shí)候用自己的賬號(hào)測(cè)試提示該賬號(hào)沒(méi)有權(quán)限
  • 第四個(gè)坑:創(chuàng)建沙盒測(cè)試賬號(hào)的時(shí)候不允許創(chuàng)建已經(jīng)有的AppleID

1、Xcode工程配置

51E95534-82D8-4130-A945-60F906DE0384.png

開(kāi)啟此選項(xiàng)App Strore中APP的介紹界面顯示內(nèi)購(gòu)的相關(guān)項(xiàng)目,關(guān)閉則不顯示

2、iTunesconnect創(chuàng)建產(chǎn)品

(1).開(kāi)發(fā)者中心->App Store Connect->我的App->創(chuàng)建需要上線的App
這里解決第一個(gè)坑,因?yàn)檫@個(gè)項(xiàng)目是團(tuán)隊(duì)開(kāi)發(fā)的,我在測(cè)試的時(shí)候始終拿不到訂單的信息,后面才發(fā)現(xiàn),隊(duì)友在項(xiàng)目中把BundleID給我改了,強(qiáng)調(diào)一點(diǎn)在你確定你的代碼沒(méi)有錯(cuò)的時(shí)候,你必須保證你的BundleID和需要提價(jià)的App信息的BundleID一直
(2).選擇你希望創(chuàng)建APP內(nèi)購(gòu)買(mǎi)項(xiàng)目
App信息->功能->App內(nèi)購(gòu)買(mǎi)項(xiàng)目


1787FF2B-2C09-47E7-9D81-7FB24BD1259E.png

CB383C02-1D30-4CBF-9AE4-29D30CAA3E25.png

在這里創(chuàng)建你在APP項(xiàng)目

  • 產(chǎn)品名稱(chēng):隨便寫(xiě),但是最好還是寫(xiě)成和你項(xiàng)目向管理的
  • 產(chǎn)品ID:也可以隨便寫(xiě),如果你的項(xiàng)目里面不止一個(gè)內(nèi)購(gòu)商品,那么最好就命名規(guī)范一下,這樣可以由后臺(tái)來(lái)控制
  • 價(jià)格:蘋(píng)果果然霸道,價(jià)格都給你定好了,最低消費(fèi)都是6塊起步
  • 本地化版本:顯示的名稱(chēng)和描述就是訂單的信息也就是顯示在你購(gòu)買(mǎi)的時(shí)候提示用戶(hù)的信息
  • App Strore 推廣:標(biāo)明的是可選,準(zhǔn)備一張1024*1024的推廣圖就可以了
  • 審核信息:必須上傳一張屏幕的截圖,如果不是就提交不上去,我開(kāi)始是用的截圖然后通過(guò)qq發(fā)過(guò)來(lái)壓縮了一下,結(jié)果失敗了,后面通過(guò)設(shè)備傳過(guò)來(lái)的,如果沒(méi)有上傳的話(huà),保存之后會(huì)提示元數(shù)據(jù)丟失


    8862B2B8-3A36-498A-AA97-60D3F9C00EAE.png

    注意:每個(gè)開(kāi)發(fā)人員帳戶(hù)可在該帳戶(hù)的所有 App 中創(chuàng)建最多 10,000 個(gè) App 內(nèi)購(gòu)買(mǎi)項(xiàng)目產(chǎn)品。App 內(nèi)購(gòu)買(mǎi)項(xiàng)目共有四種類(lèi)型:消耗型、非消耗型、自動(dòng)續(xù)期訂閱和非續(xù)期訂閱。

3、實(shí)現(xiàn)步驟主要包括三步

1、首先在項(xiàng)目工程中加入StoreKit.framework
2、加入頭文件#import <StoreKit/StoreKit.h>
3、遵守代理SKPaymentTransactionObserver,SKProductsRequestDelegate
4、代碼實(shí)現(xiàn),我這里直接寫(xiě)的一個(gè)PayManager類(lèi)
1)判斷用戶(hù)是否具備支付權(quán)限

if SKPaymentQueue.canMakePayments(){
                pay(productId:productId,order_id:order_id)
            }else{
                let alertView = CCarAlertView.init(iconImage: nil, message: "您的手機(jī)沒(méi)有打開(kāi)程序內(nèi)付費(fèi)購(gòu)買(mǎi)")
                alertView.block = {}
            }

2)、注冊(cè)通知

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

3)、創(chuàng)建一個(gè)商品查詢(xún)的請(qǐng)求,productIdentifiers指需要查詢(xún)的“產(chǎn)品ID”的數(shù)組,并且實(shí)現(xiàn)代理

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()
    }
    
    /// 結(jié)束上次未完成的交易,防止漏單的其中一種解決方案
    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("沒(méi)有歷史未消耗訂單")
        }
    }

4)、查詢(xún)的結(jié)果將通過(guò)SKProductsRequestDelegate得到查詢(xún)的結(jié)果
獲取商品的查詢(xún)結(jié)果,這里可以拿到訂單的相信信息,代碼比較相信,就不詳細(xì)的講解

/// 內(nèi)購(gòu)商品回調(diào)代理
    ///
    /// - 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("沒(méi)有產(chǎn)品信息")
            if notProductsBlock != nil{
                notProductsBlock()
            }
            removeSKPaymentQueue()
            return
        }
        ///發(fā)送購(gòu)買(mǎi)請(qǐng)求
        for product in products{
            if product.productIdentifier == self.productId{
                print("SKProduct 描述信息\(product.description)")
                print("產(chǎn)品標(biāo)題\(product.localizedTitle)")
                print("產(chǎn)品描述信息\(product.localizedDescription)")
                print("價(jià)格\(product.price)")
                print("Product id\(product.productIdentifier)")
                let skPayment = SKPayment(product: product)
                SKPaymentQueue.default().add(skPayment)
                break
            }
        }
    }

5)、支付結(jié)果,里面有5中狀態(tài),個(gè)人客官自己看代碼就能知道了

/// 內(nèi)夠代理回調(diào)
    ///
    /// - Parameters:
    ///   - queue: SKPaymentQueue
    ///   - transactions: [SKPaymentTransaction]
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions{
            switch transaction.transactionState {
            case .purchasing://事務(wù)正在添加到服務(wù)器隊(duì)列中。
                print("事務(wù)正在添加到服務(wù)器隊(duì)列中。")
                break
            case .purchased://完成支付
                print("支付成功")
                getAndSaveReceipt(transaction)
                queue.finishTransaction(transaction)
                removeSKPaymentQueue()
                break
            case .failed://支付失敗
                print("支付失敗")
                payFailed(transaction:transaction)
                break
            case .restored://已經(jīng)購(gòu)買(mǎi)過(guò)該商品
                print("事務(wù)從用戶(hù)的購(gòu)買(mǎi)歷史中恢復(fù)。客戶(hù)應(yīng)完成交易。")
                queue.finishTransaction(transaction)
                break
            case .deferred://最終狀態(tài)未確定
                print("最終狀態(tài)未確定")
                removeSKPaymentQueue()
                break
            default:
                break
            }
        }
    }

說(shuō)道這里我們來(lái)解決第二個(gè)坑,天坑,解決了1天,我在支付回調(diào)的時(shí)候始終拿到的都是支付失敗,打印出來(lái)的錯(cuò)誤就是無(wú)法連接到 iTunes Store,網(wǎng)上也查詢(xún)很多資料,給我的結(jié)果就是更改Build


9187A6BF-FC9F-4B51-A8DE-E74BD4D6647C.png

我不知道是不是我更錯(cuò)了還是怎么,但是就是不行
然后還有博主說(shuō)的是重置手機(jī),我也重置了,還是不行,后面拿到一個(gè)手機(jī)上面可以翻墻的手機(jī)成功了,然后我的解決方案就是開(kāi)vpn果然解決了(如果有客官有更好的方法歡迎留言)
6)、支付完成,這個(gè)沒(méi)有什么好說(shuō)的,不管支付成功與否都會(huì)調(diào)用這個(gè)方法

func requestDidFinish(_ request: SKRequest) {
        print("支付流程完成")
    }

7)、支付失敗,也沒(méi)有什么好說(shuō)的

func request(_ request: SKRequest, didFailWithError error: Error) {
        print("支付失敗")
        if requestErrorBlock != nil{
            requestErrorBlock()
        }
    }

4、測(cè)試

第三個(gè)坑,我在寫(xiě)完這些之后就能正常的支付了,但是支付的回調(diào)成功的時(shí)候輸入AppID之后總是提示我該賬號(hào)沒(méi)有權(quán)限,后面百度才知道有沙盒賬號(hào)的測(cè)試,關(guān)鍵是不需要支付錢(qián)哦,想怎么買(mǎi)就怎么買(mǎi)
創(chuàng)建沙盒賬號(hào)的流程
App Store Connect->用戶(hù)和職能->沙盒技術(shù)測(cè)試員
最后一個(gè)坑:測(cè)試的時(shí)候需要退出自己的賬號(hào)用沙盒賬號(hào)
設(shè)置->iTunes Strore與App Store
App Store->個(gè)人信息

如果覺(jué)得對(duì)各人客官有用就希望點(diǎn)贊一下,下一篇文章支付寶H5支付無(wú)法返回APP坑和解決方案

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容