Apple IAP 二三事
一、概述
1、簡介
-
IAP (
In-App Purchase
)即應用內購買,是App內購買「虛擬數字產品」的支付方式;Android
和iOS
都有IAP
支付;判斷APP是否需要IAP的標準:使用者付費購買的商品/服務是否為「虛擬數字產品」; -
更通俗的解釋:看商品/服務的實際消費場景是在 App 內,還是 App外;如果在 App內即可完成消費的,蘋果要求使用 IAP,如電子書、充值類虛擬貨幣、遊戲/直播中道具等;在App外完成消費,可以使用第三方支付;典型如線下電影票、實物電商、打車、外賣等。
-
Apple對IAP態度嚴苛,很大一部分原因是:Apple可以從IAP支付流水中,抽成30%;很多App不願意使用IAP支付,通過欺騙稽核方式
2、IAP商品種類
-
消耗型專案:只可使用一次的產品,使用之後即失效,必須再次購買,如:遊戲幣、一次性虛擬道具等
-
非消耗型專案:只需購買一次,不會過期或隨著使用而減少的產品。如:電子書
-
自動續期訂閱:允許使用者在固定時間段內購買動態內容的產品。除非使用者選擇取消,否則此類訂閱會自動續期,如:Apple Music這類按月訂閱的商品
-
非續期訂閱:允許使用者購買有時限性服務的產品,此 App 內購買專案的內容可以是靜態的。此類訂閱不會自動續期
IAP商品交易成功後,Apple收取30%的手續費,如果商品是30元,你只能得到21元;不過自動續訂的商品第二年開始只成15%
3、Pre Develop
-
在
iTunes Connect
後臺中填寫銀行賬戶資訊、配置內購商品(包括產品ID、價格等) -
在
iTunes Connect
申請 "沙盒測試人員賬號",用於IAP測試使用; -
準備iPhone真機一臺,IAP只能用真機測試;
-
更多細節可參考iOS內購一條龍------賬戶資訊填寫、iOS內購一條龍------配置內購產品ID 和 iOS內購一條龍------內購測試賬號
沙盒(SandBox)測試人員賬號 用於testflight、adhoc包的 IAP 測試 (沙盒環境),沙盒環境IAP支付並不花費money
二、支付流程對比
1、微信/支付寶の支付流程
-
目前,微信/支付寶絕對是國內最主流的第三方支付,和IAP相比,他們都提供了非常好的技術支援;(
雖無緣於支付寶,但必須給支付寶點贊!
) -
App內,微信/支付寶的支付流程簡述如下:
- App內發起支付請求;(
調起微信/支付寶支付有兩種,SDK方式 和 schema方式,建議前者
) - App跳到支付寶/微信客戶端,引導使用者完成支付;
- 使用者完成支付的同時,微信/支付寶伺服器回撥App的伺服器,告知支付結果;App中也會收到
微信/支付寶SDK
中的支付回撥結果(業務上,一般不以SDK回撥結果做最終結果
); - App的伺服器收到回撥後,完成訂單驗證和發貨操作;
- 從微信/支付寶返回第三方App,App去自己的伺服器查詢商品支付結果;
- App內發起支付請求;(
-
在整個支付流程中,如果發生使用者支付成功,但是的Server回撥出錯了(可能是網路,也可能是App伺服器異常),到賬使用者沒有收到貨物,這會對支付體驗造成非常大的打擊;
-
但是,微信/支付寶的伺服器非常靠譜:檢測回撥失敗後會重試,能最大程度(
錯誤重試機制
)保證將結果同步給第三方App伺服器;
2、IAPの支付流程
-
App內,IAP的支付流程,簡述如下:
- App內,通過IAP API(
StoreKit
),發起支付請求; - 使用者在App內完成支付;(
獲取商品資訊->建立交易加入到交易佇列->使用者支付->支付完成
) - 使用者完成支付的同時,IAP 伺服器回撥APP,通知購買成功,並把票據(receipt)寫入到 APP 沙盒中;
- App需要將票據(receipt) 上傳給App伺服器;
- App伺服器再將票據(receipt) 發給Apple伺服器去驗證;只有驗證成功,App伺服器才能去發貨。
- App內,通過IAP API(
-
在整個支付流程中,使用者在端上扣款成功,只是開始;後續的支付驗證至少需要保證App上傳票據成功、App伺服器將票據交給Apple伺服器成功、App伺服器獲取訂單驗證結果成功;否則,掉單是必然出現的事情;簡單來說:使用者扣款成功後,IAP支付的嚴峻挑戰開始了;
-
Apple將每次IAP支付行為被抽象成一個事務(
SKPaymentTransaction
),只有事務被正常結束(finishTransaction:
),該次支付行為才算完成。即使支付中途被中斷,但是這次事務並沒有丟失。eg: 支付未完成,App Crash了,下次App重啟(需addTransactionObserver:
),之前被中斷的事務會接著進行。StoreKit框架主要提供三部分功能:In-App Purchase(IAP,應用程式內購買)、Recommendations and reviews(建議和評論) 和 Apple Music(蘋果音樂,國內幾乎不用);IAP的API在StoreKit框架。
3、總結
-
對比第三方支付和IAP支付流程發現:
- 微信/支付寶的扣款後,交易驗證工作是在伺服器之間通訊完成的;只要使用者產生了交易,他們的伺服器會回撥App伺服器,交易的可靠性由支付寶/微信服務保證的;
- 而IAP扣款後,交易驗證是App驅動App伺服器完成的;但是移動裝置所處的網路環境遠比服務端複雜;扣款成功後,後續的下發票據 和 App上傳票據都面臨嚴峻的考驗(
網路異常、App伺服器異常、Apple伺服器異常等
)。
-
簡單來說:Apple預期將支付流程中最重要的驗證環節交給了App開發者;和國內的微信/支付寶套路完全不同;
-
此外,雖然Apple為保障交易驗證完成,提供了事務機制,但是事務機制最大的問題是:如果某一個事務在當次App生命週期內未能正常結束,只能在下次App重啟後,中斷的事務才能恢復;這其實是對使用者傷害比較大:扣了款,可能很長時間收不到貨。
三、優化IAP驗證
1、思路
-
完善重試機制;儘可能多的重試,保證使用者扣款後能比較及時收到貨物;
-
建立業務訂單和IAP訂單對映機制;Apple只負責告訴一個交易事務成功or失敗,不關心是否對映到業務訂單好;
2、完善重試機制
-
不依賴蘋果事務機制重試;當Apple通知使用者交易成功(
SKPaymentTransactionStatePurchased
),立刻持久化交易資料到keychain,儲存成功後,finish掉交易。補充1:交易資料持久化到keychain好處有二:儲存到keychain的資料被加密,安全可靠;即使App被解除安裝,keychain中資料也不會被刪除;
補充2:扣款成功後,可能蘋果沒有告知交易成功,可能下次甚至下下下次啟動,才告知交易成功;因此,App啟動後,監聽交易事務佇列,當收到交易事務完成通知,立刻持久化交易資料;
-
建設交易驗證佇列;每筆交易資料持久化成功後,嘗試訂單驗證,驗證包含兩步:上傳票據 和 查詢訂單狀態;只有兩步都完成,才能算一個訂單驗證結束;
-
豐富交易驗證的時機;
- App冷啟動後x秒,
keyChain
中還有沒有處理完的交易,一個個去發起校驗; - 使用者發生新購買,扣款成功,交易資料持久化成功後,發起驗證操作;
- App從後臺切換到前臺x秒,無網切到有網,前臺停留x分鐘等情況下,如果
keyChain
中有未驗證完成的交易,發起驗證請求; - ...
- App冷啟動後x秒,
3、訂單對映
- 訂單對映指:業務訂單和IAP訂單的對映,本質是將業務訂單號
orderID
繫結到蘋果的交易訂單上; - 發起IAP支付後,我們給Apple的是一個
SKPayment
物件,最後監聽到的是SKPaymentTransaction
物件(有SKPayment
屬性物件);我們可以通過利用SKPayment
的applicationUsername
欄位實現訂單對映; - 建立交易物件時,將業務訂單號
orderID
賦值給SKPayment
的applicationUsername
;等支付成功後,通過SKPaymentTransactiond
物件的payment
獲取到業務訂單號orderID
,從而實現了業務訂單和IAP訂單對映繫結; -
重要說明:利用
applicationUsername
透傳業務訂單號orderID
有失敗的概率,一些情況下會導致applicationUsername
透傳的值丟失(訂單號丟失問題
);如果不處理的話,會發生掉單; - 總的來說,利用
applicationUsername
實現訂單繫結雖然有不足,但是從ROI上評估還是可行的;訂單號丟失問題可以交給伺服器處理:服務端只要驗證交易是正確的,且該使用者的確有交易記錄,自動生成訂單重新發貨 or 最近訂單(時間、金額)匹配;即便這麼做,依然有case被遺漏,但能保證大盤基本OK。
4、票據的問題
- iOS 7後(
App幾乎都是iOS 9起步
),從[[NSBundle mainBundle] appStoreReceiptURL]]
中獲得的receipt(票據)資料;App上傳票據資訊的話,將其中的資料一起上傳; - iOS 7後,
[[NSBundle mainBundle] appStoreReceiptURL]]
中的票據資訊是一個receipt list
(in_app
欄位),本身帶有“自動修復的特性”,如果使用者某次支付沒有正確完成,後續也沒有被成功恢復;當他產生下一次成功支付後,[[NSBundle mainBundle] appStoreReceiptURL]]
中會包含這幾次支付的receipt
。 - 獲取不到票據情況:如監聽到交易成功了,但是從
[[NSBundle mainBundle] appStoreReceiptURL]]
中獲得的資料是空,遇到此類問題,可以打標記後續重試; - 票據無效,驗證失敗的情況也可能遇到,這時候,讓使用者提供了支付資訊,走補償 or 退款吧;
5、to be continued
- 保障扣過款的IAP訂單儘快得到驗證,是IAP問題中首要解決的問題;本節中簡單介紹了相關一些思路;我相信,做好這些能hold住大多數問題;
- 雖然IAP總體體驗被微信/支付寶吊打,但是由於iOS使用者被教育了這麼多年,Apple在新iOS版本上也有些不為認知的優化;總體上來說,IAP支付還可以,沒有早年那麼糟糕;
- 做好以上這些事,不是終點;優化產品體驗,做好使用者教育工作,也能很好幫助實現總目標。
四、IAP周邊建設
1、完善監控埋點
- 支付環節中,對關鍵路徑埋點,包括但不限於:持久化交易資料操作、上傳票據操作、查詢操作,結束驗單操作等;
- 監控異常的情況,包括但不限於:持久化交易資料失敗、上傳失敗,
applicationUsername
獲取訂單號為空、查詢失敗等; - 開發階段,儘可能多展示除錯日誌資訊;
2、響應使用者反饋
- 再好的方案,也無法hold所有的IAP問題,建立使用者反饋響應機制,及時響應使用者反饋;關注使用者關注的;
- 例1:部分使用者反饋無法支付,排查發現,是網路原因導致獲取SKProduct失敗;因此,嘗試提前拉取SKProduct;
- 例2:部分使用者反饋,iOS 13上必選Crash,排查得知:iOS13把
SKProductRequst
的回撥放到了子執行緒;如果在這個回撥中有UI操作,必然Crash。 - 將典型的,數量比較多的使用者反饋集中集中起來,針對問題,嘗試優化方案;同時,注意安撫使用者的情緒;
3、其他
-
要加強沉澱,包括但不限於:IAP優化方案、問題排查和解決記錄,使用者反饋和處理記錄等;
-
雖然,Apple提供了Testflight包,使用者可以IAP沙盒支付;針對沙盒支付,Server要做好驗證,這些非真實金錢交易,要特殊處理。