蘋果支付有哪些坑,為什么蘋果支付比支付寶和微信容易丟單?
當前位置:點晴教程→知識管理交流
→『 技術文檔交流 』
前言接觸公司的充值業務很久了,在處理蘋果充值的時候也踩了很多的坑,這里就花時間來總結下。 蘋果內購IAP 全稱: 為什么這里著重來介紹 IAP 呢,因為 IAP 和微信支付和支付寶支付的實現邏輯不太一樣,因為 IAP 支付依賴 IOS 客戶端調用異步支付回調接口,進行用戶和訂單的綁定,會有丟單的情況產生,這里 聊下,目前 IAP 中充值我們遇到的問題點 1、丟單; 2、訂單充值到錯誤的賬號; 3、在蘋果設置中直接點擊充值,導致不到賬。 蘋果支付的難點關于蘋果充值的難點,這邊總結下來就是下面兩點: 1、如何處理訂單回執和用戶賬號的綁定關系; 2、APP 中復雜的網絡環境,如何保證訂單能夠成功回調; 方案設計下面來介紹下蘋果支付中需要特別關注的點。 1、商品設計蘋果對應的充值商品 id 需要進行申請,命名規則沒有強制性的要求,需要根據自己的商品類型來進行映射。通常的做法,服務端會定義自己系統的內部的商品,服務端會提供一個提供一個商品列表的接口,會把自己系統內部的商品信息,映射到蘋果系統中的商品id。 如何合理的設計蘋果 iap 的商品ID呢?一般有兩種做法? 1、每個系統內部的商品都對應一個蘋果 iap 的商品id; 這種就是需要申請的商品id比較多,同時如果商品信息發生更改,就需要重新申請,當然,如果自己系統內部的商品,比較單一,并且基本上能夠保持不變,那這種方式可以商品設計的選擇之一。 2、每種類型的商品,一個價格對應一個蘋果 iap 的商品id; 蘋果的 iap 的商品id和價格做綁定了,如果商品信息有變化,只要價格不變,就不用重新申請對應的 iap 商品id 了。 具體使用哪種可以根據自己系統中的商品特點來進行選擇。 2、用戶和回執的綁定蘋果支付中,蘋果回調中的是沒有第三方訂單信息的,所以,蘋果訂單回執信息和用戶的綁定需要在 APP 中完成。 蘋果充值成功,給到 IOS 客戶端充值的回調信息,然后客戶端需要把當前的回執信息和當前的用戶做好綁定,上報數據到自己的服務端,進行訂單校驗和充值道具的下發。 處理充值的時候,每一筆訂單都會生成唯一的訂單號。用戶和回執信息的綁定,也就是,訂單號和用戶回執信息的綁定,因為訂單對應數據,里面會關聯用戶信息。 這樣用戶和回執的綁定也就回歸到用戶訂單和蘋果回執的綁定,那么訂單號在何時生成,如何和蘋果回執做綁定呢?有兩種方案,下面來一一探討下。 1、生成訂單 -> 發起 iap 充值 -> 客戶端 綁定訂單id和 iap 充值的回執信息,向服務端發起回調 -> 服務端接收到回調信息,校驗訂單回執,給用戶增加道具; 2、發起 iap 充值 -> 接收到回調信息 -> 客戶端將商品信息,用戶信息,iap 的回執信息,一起回調給服務端 -> 服務端接收到回調信息,校驗回執信息,生成對應的訂單,同時給用戶增加道具; 這兩種最主要的差別就是訂單的生成時機不同,第一中訂單號對客戶端是可見的,第二種訂單號對客戶端是不可見的。 1、訂單提前生成
訂單提前生成,比較符合我們處理的訂單的邏輯,如果自己的充值系統中也同時集成了微信和支付寶的支付,那么選用這種方式,訂單的處理就相對統一。 缺點: 1、每次點擊充值就會有一個訂單的生成,即使用戶后面沒有實際的充值,會有無效訂單數據的產生; 2、因為訂單號和蘋果回執信息的綁定是需要在客戶端中進行綁定操作的,那么這個就會存在綁定錯亂的情況,用戶可能點擊充值了多個商品,這時候處理綁定的時候, A 商品的訂單號,綁定到了 B 商品的回執信息上了。結果就是用戶訂單異常。 2、回調的時候生成訂單號
訂單是后面生成的,所以可以控制只有回執信息驗證通過的時候才生成訂單號,避免了無用訂單的生成。 不過這兩種處理方式個人感覺差別不大,設計的時候考慮下如果有其它的支付方式同時存在,如何做好兼容就行了。 我們用的第一種,提前生成訂單,因為我們系統中同時存在了,微信,支付寶和蘋果充值,所以各個充值方式的兼容也是我們考慮的一個重要的點。 不過也根據第一種方式做了細微的調整,因為蘋果充值存在充值成功但是回調是失敗的情況,接收到失敗的訂單回調,本地記錄的訂單號就會被清理了,這時候有成功的回調過來,本地就沒有對應的訂單號了,同時對于訂閱商品,下一個扣款日重新發我續訂,app 接收到回調通知,本地也是沒有存儲對應的訂單號。沒有訂單號,也就意味著蘋果的充值回執信息,和用戶關聯不上了。這種情況,我們的處理方式就是,app 接收到成功的回調,本地沒有訂單號,就重新調用服務端接口重新生成一個。保證用戶和蘋果的回執信息一定能關聯上。 3、回調的重試因為蘋果訂單的綁定依賴于客戶端,當網絡環境不好,接收到回調信息,之后向自己的服務端進行回執信息的驗證,出現接口請求不通的情況,這時候就需要執行回調回執的重試。 當然重試分成兩部分 1、客戶端回調回執信息的重試; 2、服務端驗證回執信息的重試。 一般服務端在設計充值的時候,都會使用到分布式事務,消息隊列等來保證事務的最終一致性。同時對于一些第三方的請求,也會有對應的重試機制: 1、數據標記法:接收到請求,先落數據庫,如果驗證成功將數據標記成功,如果一直沒有驗證處理成功,就定時從數據庫將此數據取出來,繼續重試驗證的邏輯; 2、消息隊列的重試機制:一般消息隊列都有對應的重試機制,消息驗證成功,就將消息從隊列中移除,否則重新丟到隊列中,借助隊列的重試機制,知道本消息處理成功。 客戶端部分的重試步驟: 1、接收到蘋果的回調,拼接訂單和用戶信息,向自己的服務端發起回調; 2、如果自己服務端的回調接口,返回成功,在一定時間內定時查詢該訂單的狀態,如果訂單返回成功,更新用戶的賬戶信息; 3、如果回調自己的服務端失敗,這時候就需要進行重試操作,1分鐘內重試5次,直到該回調接口返回成功的狀態; 4、如果1分鐘內重試了5次還是失敗,記錄該回執信息,用戶打開app,或者切換到充值頁面的時候繼續重試。 因為對于回調的處理,服務端只要接收到請求,就會記錄該回調信息,然后接口返回成功,所以只要客戶端的網絡正常,這種失敗的情況是不會出現的,多次的重試操作一定能規避這種情況。 充值沖遇到的問題點1、丟單丟單是蘋果充值經常遇到的問題,因為是 app 接收到的蘋果的服務回調,相比于服務端的 如何處理呢? 原則上就是客戶端接收到蘋果的回調通知,盡可能的拼接用戶信息和回執信息發送給自己的服務單進行數據的驗證,服務在驗證數據的時候做好訂單的唯一性處理,避免商品超發的情況。 總結了可能有下面幾種情況: 1、接收到異常的回調:充值成功了,但是客戶端先接收到的是一個充值失敗的回調,然后草草結束掉本次訂單,導致后面收到了充值成功的訂單,但是訂單已經結束就不處理了,最終結果就是丟單了; 2、網絡不穩定:充值成功了,客戶端成功接收到了蘋果的回調,但是給自己服務端回調的時候,因為網絡原因導致回調失敗了,結果就是用戶丟單了; 3、用戶頻繁切換賬戶:充值成功了,用戶在充值過程中發生了賬號的切換,因為使用的蘋果賬號是同一個,但是登陸 app 的賬號可以是多個,切換賬號的過程中,充值到其中一個賬號中了,但是給到用戶的體驗就是當前賬號沒到賬,就認為是丟單了; 4、自己服務端校驗票據異常:充值成功了,客戶端接收到了回調,但是回調回執信息給自己服務端的時候,服務端在驗證票據的時候出現了異常,導致該訂單驗證失敗,用戶的體驗就是該訂單丟單了; 下面來分析下上面的幾種情況: 對于情況場景 1 和場景 2,客戶端盡可能的做好重試,只要接收到蘋果 iap 中的回調,就拼接信息回掉給自己的服務端,如果當前的回調接口沒有返回成功的標識,就要繼續重試。 對于場景 3 ,可以在交互上優化,用戶充值之后返回 app ,可以加一個充值中的 loading 頁面,避免用戶在這個過程中出現切換賬號的操作。 對于場景 3 ,一般服務端在設計充值這種業務的時候都會用到分布式事務,所以這種情況是能夠避免的。 2、充值成功,下發的物品不對因為充值商品,訂單號和 ipa 充值回執信息的綁定是在 app 中操作的。如果用戶在充值的時候有頻繁點擊充值的行為,那么在綁定充值回執的數據的時候,就有可能出現綁定錯亂的情況。 原來商品的 a 的回執信息,綁定時候,被綁定到了 商品 b 上面。 這時候服務端就需要做好數據的檢驗,如果通過回執信息請求蘋果的訂單接口是能拿到,充值訂單對應的 iap 商品,通過這個商品就能判斷回到數據綁定的數據是否正確,如果不正確修改當前訂單信息的數據即可。 3、處理退款根據蘋果的策略,用戶在購買IAP后90天內,能以各種原因申請退款(扣款后購買失敗、買錯了、不喜歡等等)。 用戶成功申請退款了,系統中對應的道具也要清除掉,不然就是充值漏洞了,里面的商品就會被用戶白嫖了。 蘋果在 退款流程: 1、用戶購買內購商品; 2、用戶申請退款; 3、蘋果發起退款; 4、Apple Store Server 發送退款通知; 5、用戶收到退款成功的通知; 6、開發者收到退款訂單通知。 最后來看下普通充值的訂單的具體信息 { "environment": "Production", // 當前的環境,Production表示生產環境,Sandbox表示的是沙盒環境 "receipt": { "receipt_type": "Production", "adam_id": 6666666, "app_item_id": 8888888, "bundle_id": "test.888888", "application_version": "4.79.0.1", "download_id": 999999999, "version_external_identifier": 862386348, "receipt_creation_date": "2024-01-07 04:33:30 Etc/GMT", "receipt_creation_date_ms": "1704602010000", "receipt_creation_date_pst": "2024-01-06 20:33:30 America/Los_Angeles", "request_date": "2024-01-10 01:39:43 Etc/GMT", "request_date_ms": "1704850783803", "request_date_pst": "2024-01-09 17:39:43 America/Los_Angeles", "original_purchase_date": "2023-12-30 23:42:26 Etc/GMT", "original_purchase_date_ms": "1703979746000", "original_purchase_date_pst": "2023-12-30 15:42:26 America/Los_Angeles", "original_application_version": "4.79.0.1", "in_app": [{ "quantity": "1", // 商品的數量 "product_id": "1111101_2_2_12.00", // iap 的商品id "transaction_id": "381201227775036", // 交易號 "original_transaction_id": "381201227775036", // 原始交易號 "purchase_date": "2024-01-07 04:33:29 Etc/GMT", // 最新的購買時間 "purchase_date_ms": "1704602009000", // 最新的購買時間毫秒 "purchase_date_pst": "2024-01-06 20:33:29 America/Los_Angeles", // 最新的購買時間,太平洋時間 "original_purchase_date": "2024-01-07 04:33:29 Etc/GMT", // 最初的購買時間 "original_purchase_date_ms": "1704602009000", // 最初的購買時間,毫秒 "original_purchase_date_pst": "2024-01-06 20:33:29 America/Los_Angeles", // 最初的購買時間太平洋時間 "is_trial_period": "false", // 是否是試用期 "in_app_ownership_type": "PURCHASED" } ] }, "latest_receipt": "xxxxx", // 憑證信息 "status": 0 //} 蘋果訂閱上面簡單聊了下蘋果中普通商品的充值流程,下面來聊一下訂閱商品的充值。 自動訂閱根據名字能看出來相對于普通的商品,自動訂閱的商品到了扣款周期,蘋果會自動發起重新扣款。 先來看下訂閱的充值流程,訂閱的首次充值流程和普通的商品的首次充值流程一樣,充值成功之后,后面會涉及訂閱的下次扣費,所以后面多了原始交易號和回執信息的記錄,方便后面自動扣款的續訂操作。
蘋果訂閱商品在下個扣款周期扣費的時候,扣款的動作由蘋果自動發起,這和支付寶和微信的訂閱扣款邏輯不同。 因為是蘋果自動進行的扣款處理,所以會如果蘋果扣款的時候的通知不及時或者消息丟失,就很容易造成用戶的丟單情況。 處理思路: 1、配置服務端回調通知配置服務端回調通知,配置服務端通知的動作思可選的,不過建議開啟。開啟之后就能及時收到蘋果的訂單的狀態,處理用戶的訂單狀態。
服務端的通知類型,有下面幾種: CANCEL:表示蘋果支持已經取消了自動續期訂閱并且用戶在cancellation_date_ms時間收到了退款信息; 觸發時機: CANCEL事件通過AppleCare支持取消訂閱并退還購買款項時觸發。 DID_CHANGE_RENEWAL_PREF:表示客戶對其訂閱計劃進行了更改,該更改會在下一次續訂時生效。當前活動的計劃不受影響; 觸發時機: 當用戶在同一訂閱分組中,從一個訂閱商品切換到另一個訂閱商品時,會觸發 DID_CHANGE_RENEWAL_PREF 事件; DID_CHANGE_RENEWAL_STATUS:表示訂閱續訂狀態發生變化; 觸發時機: 用戶關閉了訂閱,或者非訂閱狀態重新續訂。 通過判斷 auto_renew_status 判斷當前的訂閱狀態,auto_renew_status == 0 表示訂閱狀態已經關閉, auto_renew_status == 1 表示訂閱處于開啟狀態。 DID_FAIL_TO_RENEW:表示由于計費問題而無法續訂的訂閱,栗如,用戶當前卡上沒錢了; DID_RECOVER:表示成功自動續訂一個過去續訂失敗的過期訂閱。檢查expires_date以確定下一次續費的日期和時間; DID_RENEW:表示用戶當前的訂閱周期已經重新續訂了; INITIAL_BUY:用戶在首次發生訂閱時觸發; INTERACTIVE_RENEWAL:表示客戶通過使用應用程序界面或在 App Store 帳戶的訂閱設置中以交互方式續訂訂閱; 觸發時機: 用戶取消了訂閱,一段時間后用戶通過 AppStore 交互頁面重新訂閱產品,會觸發 INTERACTIVE_RENEWAL 事件。 REFUND:表示 App Store 已成功對消耗性應用內購買、非消耗性應用內購買或非續訂訂閱的交易進行退款,不同于取消(CANCEL)通知類型,取消通知類型針對的是自動續期訂閱類型商品,用戶通過 AppleCare 支持取消訂閱并退還購買款項時觸發; 蘋果服務端的返回狀態 DID_RENEW 就表示蘋果當前的訂閱的扣款已經成功了,接收到這個狀態的通知,處理用戶的訂單即可。 2、客戶端通知;蘋果每次訂閱的扣款也會下發通知到客戶端,客戶端接收到的扣款成功的通知,回調該信息到自己的服務端,服務端接收到該回調通知,判斷當前訂閱的道具有沒有下發,沒有下發,修改本次訂閱的狀態,下發對應的充值道具給到當前的用戶,并記錄本次訂閱已經完成。 3、服務端定時輪詢;服務端定時輪詢快到期的訂閱,向蘋果發起請求查詢當前訂閱的狀態,判斷訂閱當前的扣款狀態,如果扣款了,就修改訂閱扣款到下個周期,下發充值道具給到用戶,否則就繼續輪詢,直到用戶取消訂閱,或者用戶訂閱扣款成功。 StoreKit 1 對比 2
1、蘋果后臺不能查看到退款的訂單詳情。只能蘋果處理退款后發通知給我們的服務器,告知發生了一筆退款; 2、消耗性、非消耗性、非續期訂閱、自動續訂能不能在沙盒環境測試退款,系統沒提供這種測試方式; 3、不能夠將用戶反饋的蘋果付費收據里的 orderID 與具體的業務訂單進行關聯; 4、研發過程中,無法直接關聯蘋果交易號 transactionId 與 業務訂單號 orderID 之間聯系,、在開發過程中,無法直接關聯 transaction 與 orderID 之間聯系,雖然有一個 applicationUserName 字段,可以存儲一個信息。但是這個字段是不是 100%靠譜,在某些情況下會丟失存儲的數據;
2021 年 WWDC,在 iOS 15 系統上推出了一個新的 StoreKit 2 庫采用 Swift 5.5 版本最新特性重寫,只支持 Swift、iOS 15+,提供了一些新的 API 接口,導致新的支付流程會發生一些變化。 1、提供了獲取交易歷史記錄、可購買的商品列表(自動續期訂閱以及非消耗品)信息; 2、提供了獲取訂閱狀態、管理訂閱狀態接口; 3、支持在 App 內發起退款。 新的 api1、新的商品接口新增了一些商品類型,訂閱信息,這些字段信息在 StoreKit 1 里是沒有的。 方便利用的字段: 1、通過新增的 product type 我們可以輕易的知道當前的商品是消耗品還是訂閱商品; 2、針對于自動連續訂閱的第一次購買優惠,我們可以直接感知到當前的商品是不是用戶的 Apple ID 下的第一次購買; 2、新的購買接口提供了新的購買商品接口。其中購買商品時增加了一些可選參數 PurchaseOption 結構體,該結構體里有新增的特別重要的字段 appAccountToken, 類似 SKPayment.applicationUsername 字段,但是 appAccountToken 信息會永久保存在 Transaction 信息內。 appAccountToken 字段是由開發者創建的;關聯到 App 里的用戶賬號;使用 UUID 格式;永久存儲在 Transaction 信息里。這里的存儲的信息,不會像 v1 版本,存在數據丟失的情況。 這里的 appAccountToken 字段蘋果的意思是用來存儲用戶賬號信息的,但是應該也可以用來存儲 orderID 相關的信息,需要將 orderID 轉成 UUID 格式塞到 Transaction 信息內,方便處理補單、退款等操作。 處理驗證 Transaction。系統會驗證是否是一個合法的 Transaction,此時系統不再提供 base64 的 receip string 信息,只需要上傳 transaction.id 和 transaction.originalID,服務器端根據需要選擇合適的 ID 進行驗證。 3、交易歷史查詢接口提供了三個新的交易(Transcation)相關的 API: 1、All transactions:全部的購買交易訂單,在 transaction 里面獲取; 2、Latest transactions:最新的購買交易訂單; 3、Current entitlements:所有當前訂閱的交易,以及所有購買(且未退還)的非消耗品。 4、訂閱類型項目的狀態訂閱類型項目的狀態,比如主動獲取最新的交易、獲取更新訂閱的狀態,獲取更新訂閱的信息等。其中獲取更新訂閱的信息,可以獲取更新的狀態、品項 id、如果過期的話,可以知道過期的原因。(比如用戶取消、扣費失敗、訂閱正常過期等。)獲取的所有數據都是 JWS 格式驗證。 5、管理訂閱頁面可以直接喚起 App Store 里的管理訂閱頁面。 6、退款api提供了新的發起退款 API,允許用戶在開發者的 App 中直接進行退款申請。用戶進行申請退款后,App 可以收到通知、另外蘋果服務器也會通知開發者服務器。
對于后端來說, 總結上面主要總結了蘋果支付的主要邏輯。 1、蘋果支付對比微信和支付寶的最大的不同就是,IAP 支付依賴 IOS 客戶端調用異步支付回調接口,進行用戶和訂單的綁定; 2、蘋果支付最大的難點就是用戶和回執的綁定;
3、重試,因為依賴于 app 的回調,所有當網絡環境不好,接收到回調信息,之后向自己的服務端進行回執信息的驗證,出現接口請求不通的情況,這時候就需要執行回調回執的重試;
4、退款的處理,根據蘋果的策略,用戶在購買IAP后90天內,能以各種原因申請退款(扣款后購買失敗、買錯了、不喜歡等等);
5、蘋果訂閱:因為訂閱是蘋果直接發起的,所以我們要合理的處理訂閱扣款之后的回調;
參考【AppStore內購】https://liushoukai.github.io/2020/04/04/appstore-in-app-purchase/ 作者:ZhanLi 轉自博客園 https://www.cnblogs.com/ricklz/p/17993800 該文章在 2024/2/1 16:53:29 編輯過 |
關鍵字查詢
相關文章
正在查詢... |