iOS內(nèi)購丟單的解決方案

????iOS內(nèi)購這塊的開發(fā)一直比較麻煩,除了各種購買選項(xiàng)的問題,最惡心的問題就是丟單問題。
????丟單就是iOS內(nèi)購過程中付了錢,但是App沒有發(fā)貨的問題。要解決丟單問題,先要梳理一下整個(gè)購買的過程:

  1. 調(diào)用服務(wù)器接口創(chuàng)建訂單
  2. 調(diào)用內(nèi)購的api完成購買
  3. 獲取receipt、transactionIdentifier發(fā)送給服務(wù)器
  4. 本地服務(wù)器拿到receipt向蘋果發(fā)起驗(yàn)證,并回調(diào)結(jié)果給App

以上就是整個(gè)購買的過程,現(xiàn)在我們根據(jù)每一步分析下可能出問題的點(diǎn)


1. 調(diào)用服務(wù)器接口創(chuàng)建訂單

這一步的操作就是讓服務(wù)器創(chuàng)建當(dāng)前購買商品的訂單,返回結(jié)果失敗或者成功,這里基本不會(huì)出問題,成功就繼續(xù)接下來的流程,失敗的話,客戶端返回失敗的提醒就行。


2. 調(diào)用內(nèi)購的api完成購買

絕大多數(shù)的問題都出在這里,在這里說一下我遇見的坑

  1. 客戶在付完款之后,直接殺死了app。
  2. 在支付過程中,若當(dāng)前賬戶里的錢不夠,且沒有綁定銀行卡、微信或者支付寶,會(huì)觸發(fā)一個(gè)綁定機(jī)制,但是用戶在點(diǎn)擊去綁定時(shí)候,- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions,會(huì)返回一個(gè)失敗的transaction,當(dāng)用戶完成支付,又會(huì)返回一個(gè)成功的transaction。由于我們之前使用RMStore這個(gè)第三方插件,他在處理回調(diào)的時(shí)候有這樣一個(gè)機(jī)制,每次發(fā)起購買RMStore都會(huì)把回調(diào)的block存儲(chǔ)到RMAddPaymentParameters這個(gè)對(duì)象里面,當(dāng)?shù)谝淮五e(cuò)誤回調(diào)返回時(shí),會(huì)把RMAddPaymentParameters里面的block取出來并執(zhí)行,執(zhí)行之后,持有這個(gè)對(duì)象的數(shù)組會(huì)把這個(gè)對(duì)象移除,所以當(dāng)?shù)诙纬晒Φ幕卣{(diào)返回時(shí),再想去執(zhí)行block,但是持有這個(gè)block的對(duì)象已經(jīng)被移除了,導(dǎo)致了非常多的丟單。

對(duì)于第一個(gè)問題,內(nèi)購的api有一個(gè)監(jiān)聽機(jī)制,在每次app剛啟動(dòng)的時(shí)候調(diào)用[[SKPaymentQueue defaultQueue] addTransactionObserver:self];方法,- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions,會(huì)回調(diào)所有未執(zhí)行[[SKPaymentQueue defaultQueue] finishTransaction:tran];的transaction,這個(gè)時(shí)候再去和服務(wù)器進(jìn)行訂單的驗(yàn)證。這里還有一個(gè)很麻煩的問題,在上個(gè)流程中,調(diào)用服務(wù)器創(chuàng)建了訂單,會(huì)返回一個(gè)訂單號(hào),驗(yàn)證的時(shí)候一般都是把訂單號(hào),以及receipt,transactionid一起發(fā)送給服務(wù)器,但是這里是拿不到訂單號(hào)的。針對(duì)這個(gè)問題,網(wǎng)上有人用applicationUsername這個(gè)字段去存入訂單號(hào),但是也有一些人在使用這個(gè)字段的時(shí)候出現(xiàn)了Bug(App殺死后,獲取這個(gè)字段的值為空,參見下面的引用),為了保險(xiǎn),這里還是不用字段。我的解決方案是在用戶創(chuàng)建完訂單之后,存儲(chǔ)當(dāng)前的訂單信息,用戶token等等,當(dāng)購買完之后,再去取這個(gè)訂單信息,完成驗(yàn)證,刪除訂單,這個(gè)方案的核心是永遠(yuǎn)只存儲(chǔ)一個(gè)訂單,若在購買的時(shí)候有未完成的訂單,必須先驗(yàn)證之前的訂單,驗(yàn)證完之后,再去發(fā)起新的購買,這樣就能規(guī)避多個(gè)transaction不能匹配訂單號(hào)的問題;
????對(duì)于第二個(gè)問題,這個(gè)問題好解決,不用這個(gè)第三方就行,自己造個(gè)輪子,基本的購買邏輯很簡單,沒必要用這個(gè)插件。當(dāng)- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions返回的transaction的state為failure時(shí)候,finish這個(gè)transaction,state為purchsed的時(shí)候,去驗(yàn)證。
????這里還有一個(gè)問題,finishTransaction:的調(diào)用時(shí)機(jī),一定要在與服務(wù)器完成驗(yàn)證之后,再去調(diào)用這個(gè)方法,因?yàn)樵谂c服務(wù)器的驗(yàn)證的過程中,也是會(huì)出現(xiàn)錯(cuò)誤的,如果再購買成功回調(diào)之后就調(diào)用這個(gè)方法,驗(yàn)證錯(cuò)誤的訂單也被finish了,下次去取transaction的時(shí)候,就取不到了,這樣就造成了丟單問題。


3. 獲取receipt、transactionIdentifier發(fā)送給服務(wù)器

????這里的邏輯基本就是自己的了,跟蘋果內(nèi)購關(guān)系不大,把訂單、receipt等信息發(fā)給服務(wù)器就行,唯一需要注意的問題就是網(wǎng)絡(luò)錯(cuò)誤,這個(gè)時(shí)候我會(huì)做一個(gè)輪循,在發(fā)生錯(cuò)誤的時(shí)候,輪循幾次,超過這個(gè)次數(shù),認(rèn)為驗(yàn)證失敗,等到用戶購買下一個(gè)商品、或者app重新啟動(dòng),會(huì)重新驗(yàn)證這個(gè)訂單(當(dāng)然,這個(gè)情況是極少的!為了嚴(yán)謹(jǐn),做了以上處理)


4. 本地服務(wù)器拿到receipt向蘋果發(fā)起驗(yàn)證,并回調(diào)結(jié)果給App

????終于到最后一步了,這里有一個(gè)地方需要注意一下,就是本地服務(wù)器與蘋果服務(wù)器驗(yàn)證的方式,之前我們公司出了個(gè)問題,在調(diào)用/verifyReceip這個(gè)接口去驗(yàn)證,蘋果會(huì)返回一個(gè)數(shù)據(jù)status,它們認(rèn)為status等于0就是完成購買了,但是這個(gè)字段的含義并非如此

For iOS 7 style app receipts, the status code is reflects the status of the app receipt as a whole. For example, if you send a valid app receipt that contains an expired subscription, the response is 0 because the receipt as a whole is valid.

????它只是反映這個(gè)receipt是不是完整的,并不能證明這次購買完成。正確的做法應(yīng)該是服務(wù)器拿到此次的transaction和receipt之后,解析receipt,拿當(dāng)前的transaction和receipt里的transaction數(shù)組去比對(duì),若數(shù)組中有這個(gè)transaction對(duì)應(yīng)的transactionid,則認(rèn)為購買成功。
????蘋果服務(wù)器返回的錯(cuò)誤碼中,我們只需留意21005即可,它代表驗(yàn)證服務(wù)器當(dāng)前不可用(當(dāng)然這種情況是級(jí)級(jí)級(jí)小的!為了嚴(yán)謹(jǐn)),處理的方式和網(wǎng)絡(luò)錯(cuò)誤的處理方式是一樣的。


內(nèi)購流程圖.png

Receipt Validation Programming Guide

applicationUsername的坑

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 關(guān)于蘋果內(nèi)購(IAP)的一些問題以及那些坑: 最近在研究蘋果內(nèi)購功能,所以,在網(wǎng)上找了一些資料,進(jìn)行學(xué)習(xí)。但是,內(nèi)...
    魔芋Brace閱讀 7,625評(píng)論 0 5
  • 自己開發(fā)的視頻直播項(xiàng)目,牽涉到充值金幣,用到了蘋果公司的內(nèi)購,趴坑了兩天,這里總結(jié)下實(shí)現(xiàn)蘋果內(nèi)購。 一. 創(chuàng)建測試...
    Leo丶Dicaprio閱讀 3,504評(píng)論 8 7
  • iOS應(yīng)用如果涉及到支付功能,分為兩類:第三方支付和蘋果內(nèi)購。那么什么情況下選擇使用第三方支付,又在什么情況下選擇...
    ZfRee閱讀 39,236評(píng)論 36 66
  • 參考借鑒了一下幾篇文章(在這里很感謝各位作者大大做出的總結(jié)和方案): http://blog.csdn.net/a...
    輝546閱讀 14,281評(píng)論 3 12
  • 城老已經(jīng)幾度秋,昔時(shí)常事又曾留? 方山依故結(jié)清友,深巷無人藏忘憂。 清友:茶 忘憂:酒 唐代姚合品茶詩云:“竹里延...
    無是也閱讀 503評(píng)論 2 0

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