內(nèi)購(gòu)類型有四種:
消耗型商品,非消耗型商品,非續(xù)期訂閱,自動(dòng)續(xù)期訂閱. 其中最有難度的就是自動(dòng)續(xù)期訂閱的實(shí)現(xiàn),開(kāi)通自動(dòng)續(xù)期訂閱后,訂閱會(huì)員的處理將會(huì)遇到如下難點(diǎn)問(wèn)題:自動(dòng)訂閱的到期繼續(xù)自動(dòng)訂閱的處理,訂閱取消的處理,取消后又在App Store開(kāi)啟自動(dòng)訂閱的處理等一系列問(wèn)題
異常情況說(shuō)明提醒用戶:
當(dāng)用戶使用appleid下買(mǎi)了一個(gè)月的應(yīng)用會(huì)員,換個(gè)賬號(hào)登錄當(dāng)前app,appleid不變,購(gòu)買(mǎi)的時(shí)候提示我已經(jīng)訂閱過(guò)該項(xiàng)目,這種問(wèn)題怎么處理
客戶端開(kāi)發(fā)者方面匯總
APP專用共享秘鑰
App 專用共享密鑰是用于接收此 App 自動(dòng)續(xù)訂訂閱收據(jù)的唯一代碼。如果您要將此 App 轉(zhuǎn)讓給其他開(kāi)發(fā)者或不想公開(kāi)主共享密鑰,建議使用 App 專用共享密鑰。
注: 經(jīng)過(guò)驗(yàn)證:購(gòu)買(mǎi)過(guò)自動(dòng)續(xù)期訂閱后,驗(yàn)證內(nèi)購(gòu)時(shí)(即使是消耗型商品)必須帶上password字段,測(cè)試模式?jīng)]有提供用戶取消訂閱或者進(jìn)行退款的測(cè)試
訂閱群組
創(chuàng)建自動(dòng)續(xù)訂類型的時(shí)候,當(dāng)你創(chuàng)建一個(gè)訂閱產(chǎn)品時(shí)點(diǎn)擊創(chuàng)建后會(huì)自動(dòng)讓你創(chuàng)建一個(gè)訂閱群組,以向用戶提供一系列內(nèi)容供應(yīng)、服務(wù)等級(jí)或時(shí)限。名字自己隨便起,就是給自己看的,有代表意義就行,一個(gè)群組下可以有多個(gè)自動(dòng)續(xù)訂訂閱。如果你要搞促銷優(yōu)惠,那么每個(gè)顧客可以享受每個(gè)訂閱群組的一個(gè)推介促銷優(yōu)惠一次。
創(chuàng)建兩個(gè)訂閱組,一個(gè)開(kāi)發(fā)、測(cè)試,一個(gè)生產(chǎn)使用訂閱組可有效避免用戶同時(shí)訂閱多個(gè)項(xiàng)目
注意 一個(gè)訂閱群組中的訂閱是 互斥 的,這意味著用戶只能一次訂閱一個(gè)群組中的一個(gè)選項(xiàng)。如果你希望用戶能夠一次購(gòu)買(mǎi)多個(gè)訂閱,你可以將這些 App 內(nèi)購(gòu)買(mǎi)項(xiàng)目放在不同的訂閱群組中。
App Store 服務(wù)器通知網(wǎng)址
您服務(wù)器上的網(wǎng)址 (URL),可接收有關(guān) App 內(nèi)購(gòu)買(mǎi)項(xiàng)目的重要事件(例如訂閱狀態(tài)變更或 App 內(nèi)購(gòu)買(mǎi)項(xiàng)目退款)的相關(guān) App Store 通知。更多請(qǐng)看https://help.apple.com/app-store-connect/#/dev0067a330b
代碼配置
在APP啟動(dòng)時(shí)候要增加一下監(jiān)聽(tīng)方法以便查詢到訂單信息:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
訂閱訂單再次購(gòu)買(mǎi)與首次購(gòu)買(mǎi)所執(zhí)行的方法不一(如下圖):
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing: // 0
break;
case SKPaymentTransactionStatePurchased: // 1
//訂閱特殊處理
if(transaction.originalTransaction){
//如果是自動(dòng)續(xù)費(fèi)的訂單originalTransaction會(huì)有內(nèi)容
}else{
//普通購(gòu)買(mǎi),以及 第一次購(gòu)買(mǎi) 自動(dòng)訂閱
}
break;
case SKPaymentTransactionStateFailed: // 2
[self failTracker:transaction];
break;
case SKPaymentTransactionStateRestored: // 3
[self restoreTransaction:transaction];
break;
default:
break;
}
}
}
測(cè)試驗(yàn)證
自動(dòng)續(xù)費(fèi)測(cè)試時(shí)需注意:
一天最多測(cè)試6次自動(dòng)續(xù)費(fèi),如需更多測(cè)試驗(yàn)證需要多申請(qǐng)一些沙盒賬號(hào),用戶在訂閱期間同一個(gè)群組產(chǎn)品無(wú)法重復(fù)訂閱,如需允許多次訂閱請(qǐng)創(chuàng)建多個(gè)群組將產(chǎn)品歸納在不同的群組中,以便可以重復(fù)訂閱。
APP自動(dòng)續(xù)費(fèi)條款
自動(dòng)續(xù)訂訂閱,一定要在 app 中有詳細(xì)的使用條款相關(guān),類似下圖:
參考文案如下:
Once you confirm your purchase, you will be charged to your Apple ID account. If purchase the auto-renewing subscription, unless you cancel the order at least 24 hours before the end of the current billing cycle, the subscription will automatically renew, and your account will charge the renewal fee within 24 hours before the end of the current billing cycle. You can unsubscribe from account settings in the app store. \r\nPrivacy Policy & Terms of Use
確認(rèn)購(gòu)買(mǎi)后,將向您的Apple ID賬戶收款。購(gòu)買(mǎi)連續(xù)包年項(xiàng)目,除非您在當(dāng)前計(jì)費(fèi)周期結(jié)束前至少24小時(shí)取消訂單,否則項(xiàng)目會(huì)自動(dòng)續(xù)訂,您的賬戶將在當(dāng)前計(jì)費(fèi)周期結(jié)束前24小時(shí)內(nèi)收取續(xù)訂費(fèi)用。您可在App Store的賬戶設(shè)置中取消訂閱。\r\n隱私政策和使用條款
服務(wù)端方面匯總
- 自動(dòng)續(xù)費(fèi)產(chǎn)品進(jìn)行驗(yàn)證時(shí)需要憑證參數(shù)(receipt-data)和共享秘鑰(password),否則在驗(yàn)證返回"status": 21003(沙盒環(huán)境)或(21004 你提供的共享密鑰和賬戶的共享密鑰不一致),秘鑰獲取如圖所示:
** 再次溫馨提醒:購(gòu)買(mǎi)過(guò)自動(dòng)續(xù)期訂閱后,驗(yàn)證內(nèi)購(gòu)時(shí)(即使是消耗型商品)必須帶上password字段。
- 請(qǐng)求驗(yàn)證
獲取到票據(jù)以后我們通過(guò)App Store來(lái)驗(yàn)證票據(jù)是否真實(shí)
沙盒狀態(tài)下使用:https://sandbox.itunes.apple.com/verifyReceipt來(lái)驗(yàn)證
生產(chǎn)環(huán)境下使用:https://buy.itunes.apple.com/verifyReceipt
2:服務(wù)端驗(yàn)證
經(jīng)驗(yàn)實(shí)際驗(yàn)證得到以下結(jié)果:
in_app 與 latest_receipt_info
查看驗(yàn)證接口時(shí)發(fā)現(xiàn),這兩個(gè)字段的數(shù)值幾乎相同,不過(guò)有幾點(diǎn)需要注意:
1、自動(dòng)續(xù)訂訂閱類型,在到期后會(huì)再生成一條購(gòu)買(mǎi)記錄,這條記錄會(huì)出現(xiàn)在last_receipt_info里,但不會(huì)出現(xiàn)在in_app里
2、自動(dòng)續(xù)訂訂閱類型可以配置試用,試用記錄只有在latest_receipt_info里,is_trial_period字段才是true
3、消耗型購(gòu)買(mǎi)記錄未出現(xiàn)在latest_receipt_info,需要檢查in_app來(lái)確保校驗(yàn)正確
4、消耗型產(chǎn)品是無(wú)法查看到取消購(gòu)買(mǎi)或者退款狀態(tài)
5、當(dāng)訂單信息中有 Cancellation Date 字段說(shuō)明該訂單被取消,不管該訂閱的過(guò)期日期是什么,該訂單都可以設(shè)為無(wú)效訂單未進(jìn)行扣款成功或者發(fā)起了退款
6、因?yàn)樽詣?dòng)訂閱可能重視的就是到期時(shí)間,所以應(yīng)該關(guān)注的是“ expires_date”、“ expires_date_ms”、“ expires_date_pst”這三個(gè)字段,expires_date表示過(guò)期時(shí)間,expires_date_ms 表示過(guò)期時(shí)間毫秒數(shù)值,expires_date_pst表示的是太平洋時(shí)間
7、由于 expires_date 表示的是美國(guó)時(shí)間,所以一般都采用expires_date_ms數(shù)值來(lái)進(jìn)行驗(yàn)證有效期
8、判斷是否有自動(dòng)續(xù)費(fèi)產(chǎn)品,推薦循環(huán) latest_receipt_info訂單列表判斷是否有大于當(dāng)前時(shí)間日期,同時(shí)判斷是否有 Cancellation Date 字段;
9、transaction.originalTransaction是 一組自動(dòng)續(xù)訂類型,購(gòu)買(mǎi)過(guò),里面originalTransactionId會(huì)一樣。然后transaction.originalTransaction.transactionIdentifier這個(gè)會(huì)多單,每一單對(duì)應(yīng)的就是用戶的購(gòu)買(mǎi)記錄。周期到期,一般就expires_date時(shí)間到期,拿receipt去蘋(píng)果服務(wù)端驗(yàn)證,用戶是否續(xù)訂了。
客戶端上報(bào)
apple每期自動(dòng)扣款后, 會(huì)生成一筆新的receipt, 客戶端獲取后發(fā)送給server校驗(yàn), 成功后開(kāi)通下一期會(huì)員權(quán)益
狀態(tài)變更通知
用于自動(dòng)續(xù)訂訂閱的服務(wù)器到服務(wù)器通知服務(wù), 可以在蘋(píng)果后臺(tái)配置通知地址, 狀態(tài)變更時(shí), server會(huì)收到通知, 下面是摘自蘋(píng)果官方的狀態(tài)描述
說(shuō)明:
1.扣款失敗導(dǎo)致過(guò)期,不會(huì)有任何通知
2.正常扣款續(xù)訂,不會(huì)有任何通知
3.服務(wù)端最好處理CANCEL類型。因?yàn)镮AP存在黑產(chǎn):比如買(mǎi)了一年會(huì)員,然后打電話給蘋(píng)果客服退款,如果服務(wù)端不處理,這一年會(huì)員是生效的。(退款通知只有訂閱和非訂閱類型才有,消耗型無(wú)退款通知)
官方文檔 https://developer.apple.com/documentation/storekit/#//apple_ref/doc/uid/TP40008267-CH7-SW13
會(huì)員狀態(tài)輪詢
server輪詢 自動(dòng)續(xù)訂類型的收據(jù), 每一期的latest_receipt_info中都會(huì)記錄所有的交易(包含歷史和新增), 可以輪詢上一期(任意一期都可以)receipt, 通過(guò)latest_receipt_info 解析出用戶最新的訂閱狀態(tài).
關(guān)于用戶取消和用戶續(xù)訂:
cancellation_date_ms
此字段表示 Apple 客戶支持取消交易的時(shí)間和日期,或自動(dòng)續(xù)訂訂閱計(jì)劃升級(jí)的時(shí)間和日期,采用 UNIX 紀(jì)元時(shí)間格式,以毫秒為單位。此字段僅適用于 Apple 退還給用戶的購(gòu)買(mǎi)。使用此時(shí)間格式處理日期。
取消的應(yīng)用內(nèi)購(gòu)買(mǎi)無(wú)限期保留在收據(jù)中。僅當(dāng)退款用于非消耗性產(chǎn)品、自動(dòng)續(xù)訂訂閱或非續(xù)訂訂閱時(shí),才會(huì)出現(xiàn)此值。
此字段僅在生產(chǎn)中可用,不會(huì)出現(xiàn)在沙盒收據(jù)中。
您可以使用此值:
確定是否停止提供與購(gòu)買(mǎi)相關(guān)的內(nèi)容。
檢查任何最新的續(xù)訂交易,這可能表明用戶重新開(kāi)始或升級(jí)了他們的訂閱,以進(jìn)行自動(dòng)續(xù)訂訂閱購(gòu)買(mǎi)。
如用戶取消,這個(gè)憑證里面有 cancellation_date_ms 字段判斷。 檢索訂單如到期就不用管。 如果到期自動(dòng)續(xù)訂了,就要客戶端重新傳憑證給服務(wù)端,服務(wù)端去蘋(píng)果驗(yàn)證訂單。
因此,在判斷訂閱是否過(guò)期的時(shí)候,cancellation_date_ms 和 expires_date_ms 都需要判斷。
蘋(píng)果官方文檔https://developer.apple.com/documentation/appstorereceipts/cancellation_date_ms
蘋(píng)果驗(yàn)證結(jié)果說(shuō)明
下面是憑證驗(yàn)證返回的詳細(xì)結(jié)果:
當(dāng)訂閱產(chǎn)品驗(yàn)證后,新增返回了 latest_receipt_info 訂閱與非訂閱訂單信息列表
非訂閱和消耗品訂單如下圖:
in_app 返回結(jié)果
訂閱和非訂閱訂單數(shù)據(jù)內(nèi)容如下:
latest_receipt_info 返回結(jié)果
關(guān)于訂閱訂單參數(shù)做一個(gè)詳細(xì)說(shuō)明(參數(shù)后面有注釋):
{
"quantity": "1",
"product_id": "產(chǎn)品Id", /// 產(chǎn)品Id
"transaction_id": "1000000850764418",
"original_transaction_id": "1000000850764418", /// 此id值不變
"purchase_date": "2021-07-30 03:13:27 Etc/GMT", ///最新的購(gòu)買(mǎi)時(shí)間
"purchase_date_ms": "1627614807000", ///最新的購(gòu)買(mǎi)時(shí)間毫秒
"purchase_date_pst": "2021-07-29 20:13:27 America/Los_Angeles", ///最新的購(gòu)買(mǎi)時(shí)間(太平洋的時(shí)間)
"original_purchase_date": "2021-07-30 03:13:29 Etc/GMT", ///最初的購(gòu)買(mǎi)時(shí)間
"original_purchase_date_ms": "1627614809000", ///最初的購(gòu)買(mǎi)時(shí)間毫秒
"original_purchase_date_pst": "2021-07-29 20:13:29 America/Los_Angeles", /// 最初的購(gòu)買(mǎi)時(shí)間(太平洋的時(shí)間)
"expires_date": "2021-07-30 03:18:27 Etc/GMT", /// 時(shí)間到期
"expires_date_ms": "1627615107000", ///到期時(shí)間毫秒
"expires_date_pst": "2021-07-29 20:18:27 America/Los_Angeles", / //到期時(shí)間(太平洋的時(shí)間)
"web_order_line_item_id": "1000000064562233",
"is_trial_period": "false", /// 首次購(gòu)買(mǎi)
"is_in_intro_offer_period": "false", /// 是否是否是在試用期
"in_app_ownership_type": "PURCHASED",
"subscription_group_identifier": "20857364"
}