https://blog.csdn.net/Kun__kun/article/details/115525030
恢復購買
內購有4種:消耗型項目,非消耗型,自動續期訂閱,非續期訂閱。 其中”非消耗型“和”自動續期訂閱“需要提供恢復購買的功能,例如創建一個恢復按鈕,不然審核很可能會被拒絕。
-
//調起蘋果內購恢復接口
-
[[ SKPaymentQueue defaultQueue] restoreCompletedTransactions];
“消耗型項目”和“非續期訂閱”蘋果不會提供恢復的接口,不要調用上述方法去恢復,否則有可能被拒。 “非續期訂閱”也是“跨設備同步”的,所以原則上來說也需要提供恢復購買的功能,但需要依靠app自建的賬戶體系恢復,不能用上述蘋果提供的接口。
恢復購買將為用戶完成的每個事務創建一個新事務,基本上是為事務隊列觀察者重新播放歷史記錄。
事務(Transaction)
內購事務的觀察者應盡早設置好,例如在程序啟動后馬上設置:
-
- ( BOOL)application:(UIApplication *)application
-
didFinishLaunchingWithOptions:( NSDictionary *)launchOptions
-
{
-
/* ... */
-
[[ SKPaymentQueue defaultQueue] addTransactionObserver:observer];
-
}
完成事務要調用:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
完成事務會告訴StoreKit你已經完成了購買所需的一切。未完成的事務將一直留在隊列中,直到它們完成為止,每次啟動應用程序時都會調用事務隊列觀察者,以便應用程序能夠繼續去完成未被完成的事務。你的應用需要完成每一筆交易,不管交易成功還是失敗。 需要注意:在你完成一個事務之后,不應該再對這次交易做任何操作,例如交付產品或者驗證交易是否有效等。如果還有工作要做,那證明你還沒有准備好完成這個事務。應在所有必要的工作完成后,再調用完成事務的方法。
購買后的記錄依據
對於iOS 7及以后的非消耗品和自動續期訂閱,使用app收據作為你的持久記錄。 對於iOS 7之前版本的非消耗品和自動續期訂閱,請使用用戶默認系統或iCloud保存持久記錄。 對於非續期的訂閱,請使用iCloud或你自己的服務器來保存持久記錄。 對於消耗品,應用程序更新其內部狀態以反映購買情況,但不需要保存持久記錄,因為消耗品不會跨設備恢復或同步。
驗證收據
應用程序收據包含用戶購買的記錄,由蘋果公司以密碼簽署。 對於消耗型項目,信息在付款時添加到收據中,並保留在收據中,直到你完成交易。在你完成交易之后,該信息將在下一次更新收據時被刪除——例如,下一次用戶進行購買時。 所有其他類型的購買信息在付款時被添加到收據中,並無限期地保留在收據中。
收據的驗證應該在服務端去做,這樣更加安全。 自動續期訂閱驗證收據時必須要帶上密鑰。
獲取receiptData:
-
// Load the receipt from the app bundle.
-
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
-
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
-
if (!receiptData) { /* No local receipt -- handle the error. */ }
-
/* ... Send the receipt data to your server ... */
測試環境url:https://sandbox.itunes.apple.com/verifyReceipt 正式環境url:https://buy.itunes.apple.com/verifyReceipt 獲取收據數據:
-
//先對receiptData用base64編碼
-
NSString *receiptBase64 = [receiptData base64EncodedStringWithOptions:0];
-
//請求參數包含兩個字段:“receipt-data”和”password“,其中”password“是自動續期訂閱的密鑰,其他類型的內購沒有這個密鑰就不會加這個參數。
-
NSDictionary *params = @{@"receipt-data":receiptBase64, @"password":secretKey};
-
//將params轉成jsonData
-
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
-
options: NSJSONWritingPrettyPrinted
-
error: nil];
-
//下面就是網絡請求,例如
-
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
-
[req setHTTPMethod: @"POST"];
-
[req setHTTPBody:jsonData];
-
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
-
...
解析收據: 請求成功后返回的數據類似這個格式:
-
{ "status": , //如果收據有效,則為0,其他值表示錯誤
-
"receipt": ,
-
"latest_receipt": ,
-
"latest_receipt_info": , //只返回包含自動更新訂閱的收據。這個鍵的值是一個包含所有應用程序內購買交易的數組。這排除了已經被你的應用標記為完成的消耗品的交易。
-
"latest_expired_receipt_info": ,
-
"pending_renewal_info": ,
-
"is-retryable": ,}
對於收據中每個字段的說明,參考蘋果官方文檔: https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1
這里說明一下自動續期訂閱的驗證問題: latest_receipt_info中包含所有訂閱的交易信息,這是一個數組,里面每個元素代表一次訂閱交易,元素中有expires_date_ms的字段表示訂閱的過期時間,purchase_date_ms表示訂閱的購買時間,product_id表示訂閱的產品id,is_trial_period表示是否是免費試用。 需要注意,latest_receipt_info中的元素沒有特定的排序,我們應該先將latest_receipt_info中的元素按expires_date_ms升序排序,然后獲取最后一個元素,這個元素就是最新的交易信息。 另外,收據的json解析有可能會出錯,要注意錯誤處理。
訂閱后聯系蘋果退款
訂閱在購買時全額支付。用戶只有聯系蘋果客服才能獲得退款。例如,如果用戶不小心購買了錯誤的產品,可以取消訂閱,並發出全額或部分退款。 要檢查購買是否已經被“Apple客戶支持”取消,請在收據中查找cancel Date字段。如果字段包含日期,無論訂閱的過期日期如何,購買都已取消。
自動續期訂閱的免費試用(促銷價)
假如訂閱設定了促銷價,例如免費試用,SKProduct對象的introductoryPrice屬性會有值,這個屬性包含了促銷價的信息,開發者應該根據這個屬性去顯示促銷的相關UI。
“非續期訂閱”不同於”自動續期訂閱“的地方
非續期訂閱與自動續期訂閱在幾個關鍵方面有所不同。這些差異使你的應用程序具有靈活性,可以根據你的需要實現正確的行為,對於“非續期訂閱”: 你的應用程序負責計算訂閱有效的時間段,並確定需要向用戶提供哪些內容。 你的應用程序負責檢測訂閱即將過期,並通過再次購買產品提示用戶更新訂閱。 你的應用程序負責在用戶的所有設備提供訂閱,並讓用戶恢復過去的購買。例如,大多數訂閱由服務器提供,你的服務器需要一些機制來識別用戶,並將訂閱購買與購買它們的用戶關聯起來。
測試
在沙盒環境中自動續期訂閱時限會縮短,便於測試:
實際時間 | 測試時間 |
---|---|
1周 | 3分鍾 |
1個月 | 5分鍾 |
3個月 | 15分鍾 |
1年 | 1小時 |
測試訂閱每天最多僅能自動續期 6 次。
審核
審核人員會用沙盒賬號測試內購,所以在審核的時候,收據驗證要用測試環境的url去驗證,不然會因為驗證失敗而被拒絕。 推薦的做法是,驗證收據時,如果status==21007,就用測試環境的url再次驗證,如果status==21008,就用正式環境的url再次驗證。
自動續期訂閱需要做一個自動續期會員說明,這個說明放在app的內購頁面中,並且在AppStoreConnect中的描述中也要寫一次,不然也會被拒絕,怎么寫,可以參考優酷,愛奇藝app的描述。
相關資料連接
https://help.apple.com/app-store-connect/#/devb57be10e7