一、代碼邏輯
關於iOS 訂閱、自動訂閱 本身功能開發很簡單。跟正常的購買沒什么大的差異。唯一需要特殊處理(自動訂閱)的是,
在APP啟動時候要增加偵聽:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
因為自動訂閱,除了第一次購買行為是用戶主動觸發的。后續續費都是Apple自動完成的,一般在要過期的前24小時開始,蘋果會嘗試扣費,扣費成功的話 會在APP下次啟動的時候主動推送給APP。所以,APP啟動的時候一定要添加上面的那句話。
另外就是處理續費了:
- (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){ //如果是自動續費的訂單originalTransaction會有內容 }else{ //普通購買,以及 第一次購買 自動訂閱 } break; case SKPaymentTransactionStateFailed: // 2 [self failTracker:transaction]; break; case SKPaymentTransactionStateRestored: // 3 [self _restoreTransaction:transaction]; break; default: break; } } }
上述代碼片段對 transaction.originalTransaction 進行了判斷,如果有內容一定為訂閱類型的。為什么在這加個判斷處理,是因為續費 是發生在APP啟動的時候,這時候你登錄流程等可能還沒有走完,因為有的游戲在跟服務器進行 校驗的時候會傳一些userid等信息,或是加密的信息,視情況而定,是否要區分處理。
注意點:就是在沙箱環境測試時候,APP啟動可能得到5次的 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions ;訂單處理,算是要並發處理case SKPaymentTransactionStatePurchased: 這種case,這時候你得注意你得網絡請求隊列,不要最后一個訂單請求覆蓋了 前幾個。(可以用信號量處理下,比較簡單)
二、服務器驗證receipt
服務器在校驗receipt時候也就有一個坑:
1、那就是創建自動訂閱的時候需要新建一個共享秘鑰,就是一串字母。
2、服務器在向蘋果服務器校驗receipt時候,不僅需要傳receipt,還需要傳秘鑰。
{ “receipt-data” : “(actual receipt bytes here)” “password” : “(shared secret bytes here)” }
3、介紹下receipt結構
receipt通過base64解碼可得:
{ "signature" = "dfreree...."; //也是base64 "purchase-info" = "ewoJIm9x....."; //也是base64,這個里面存放詳細時間,流水號等 "environment" = "Sandbox"; "pod" = "100"; "signing-status" = "0"; }
"purchase-info"可以再次base64解碼可得:
{ "original-purchase-date-pst" = "2017-08-29 23:52:45 America/Los_Angeles"; "purchase-date-ms" = "1504144439749"; "unique-identifier" = "a063c2c321dd885642a5cddd9160e0ad8291d978"; "original-transaction-id" = "1000000328915948"; "expires-date" = "1504144739749"; "transaction-id" = "1000000329310742"; "original-purchase-date-ms" = "1504075965000"; "web-order-line-item-id" = "1000000036091900"; "bvrs" = "1"; "unique-vendor-identifier" = "B78549AC-58D4-4750-8E6F-F4CCE6138A5A"; "expires-date-formatted-pst" = "2017-08-30 18:58:59 America/Los_Angeles"; "item-id" = "1276511095"; "expires-date-formatted" = "2017-08-31 01:58:59 Etc/GMT"; "product-id" = "lcm.denachina.pickle.38.1month"; "purchase-date" = "2017-08-31 01:53:59 Etc/GMT"; "original-purchase-date" = "2017-08-30 06:52:45 Etc/GMT"; "bid" = "com.denachina.pickle"; "purchase-date-pst" = "2017-08-30 18:53:59 America/Los_Angeles"; "quantity" = "1"; }
你想要的東西,都可以獲取到。客戶端可以做這些事情,但是沒有多大必要,還是服務器處理得好。(對於無服務器APP只能客戶端處理了)
附上一個在線base64解碼的:http://base64.xpcha.com/
三、自動續費測試
重點都不是上面的,重點是測試,如何測試?尤其自動續費怎么測?
先看下Apple原文檔:
When testing auto-renewable subscriptions in the test environment, keep in mind that the duration times are compressed. Additionally, test subscriptions only auto-renew a maximum of six times. Table 3-1 lists the compressed duration times.
Actual duration |
Test duration |
---|---|
1 week |
3 minutes |
1 month |
5 minutes |
2 months |
10 minutes |
3 months |
15 minutes |
6 months |
30 minutes |
1 year |
1 hour |
意思就是,沙箱環境 自動續費時間縮短了,一周 對應 三分鍾,一月 對應 五分鍾。。。
購買完一個一周 類型訂閱,就不要在APP不退出的情況等待了,必須3分鍾 或是 10分鍾后重新登錄,Apple才會主動告知你結果,也就是第一點提到的。
測試中會遇到幾個問題:
1.沙箱環境自動續費是一定會自動續費的嗎?
答案:不一定的,有時候會,有時候不會。所以要多測測,多建幾個測試賬號。
2.是否需要實現restoreCompletedTransactions ?
答案:視需求吧。有少量文章說2014年起蘋果審核嚴格了,必須要有一個按鈕實現restoreCompletedTransactions。另外,我聽百度一位同學說,愛奇藝2015年因為這個被拒過。但是,目前來看很多使用了訂閱的應用或是游戲,並沒有這個功能。
我是感覺,看需求了。訂閱 是跟着 userid 唯一呢? 還是跟着apple id 呢?在國內,一般都是前者。
四、討論
1.自動訂閱歸屬的問題:
a. 蘋果設計自動訂閱的初衷是 ,訂閱一個服務, 這個服務需要跟着 Apple ID走。說白了,就是你A設備 用了Apple賬號100001購買了,你換了B設備 用Apple賬號100001登錄app store,你同樣能享受到服務。國外的一些音樂類型、雜志報刊等用的比較多,游戲類的少,蘋果自己的Apple music也有自動訂閱(首創)。
b. 目前國內的一些應用或是游戲,希望的是自動訂閱 關聯的是 APP的 user id ,而不是Apple ID。說白了,就是你購買了一個自動訂閱服務,我不管你哪個apple id 支付的, 但是只能我一個 APP的 唯一用戶可以享受服務。這時候就需要APP自身做處理了,就是記住首次購買的transaction-id,並且綁定某個用戶。以后自動續費的話,都會有original-transaction-id,這個id 是第一次購買的transaction-id,根據這個服務器可以聯系初始購買的服務。有點描述偏了,當transaction-id綁定了用戶,再次收到其它用戶transaction-id請求時候,視情況處理了。(你也可以根據unique-vendor-identifier處理)
2.同一個Apple ID購買完的自動訂閱,可以再次點擊購買嗎(有效期內)?
答案:不可以,蘋果自身會攔截,會出現這么個提示窗,如下圖:
但是,sandbox測試環境,在第三大點的對應表格對應時間內,apple會攔截的,過了這個時間蘋果是不會攔截的。
3.夠買了自動訂閱3個月的,可以換購 1年的 或是 1個月的嗎?
答案:可以,蘋果文檔有提到,視為升級訂閱套餐 或是 降級訂閱套餐。
4.關於掉單的問題
答案:一定要在服務器校驗完票據后,客戶端收到服務器的反饋結果后再:
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
5.關於普通消費商品,如何防止黑卡、掉單、外幣等?
我有時間會再寫一篇。
五、了解更多
https://stackoverflow.com/questions/8033673/ios-sandbox-environment-auto-renewal-subscription
http://www.jianshu.com/p/28fc3cc8c49f
http://www.cnblogs.com/zidong0822/p/4701839.html
http://blog.csdn.net/xiaoyuanzhiying/article/details/46708043
http://www.jianshu.com/p/e9e4dc3dc9ee
https://www.raywenderlich.com/154737/app-purchases-auto-renewable-subscriptions-tutorial
http://www.360doc.com/content/14/1118/16/12282510_426165722.shtml
關於驗證:
關於預防刷:
http://blog.csdn.net/skylin19840101/article/details/71757055