從開(kāi)發(fā)iOS到現(xiàn)在,內(nèi)購(gòu)app也做過(guò)兩個(gè)了,現(xiàn)在好好記錄下這個(gè)流程。
首先需要在所屬的app下創(chuàng)建物品,這個(gè)流程網(wǎng)上很多也不難。這邊就詳細(xì)說(shuō)明了,可參考下面網(wǎng)址。
http://blog.csdn.net/shenjie12345678/article/details/40978977/
我們定義好一個(gè)或多個(gè)product 后 每個(gè)product id對(duì)應(yīng)著一個(gè)product。 我們拿到一個(gè)或多個(gè)product id,數(shù)據(jù)處理后對(duì)appstore 發(fā)起購(gòu)物請(qǐng)求,等待appstore處理后的響應(yīng)(之間很多操作,都是appStore和用戶之間,客戶端無(wú)法干預(yù)), 客戶端對(duì)購(gòu)物成功的回執(zhí)單進(jìn)行校驗(yàn)。

這個(gè)流程基本就是這樣,如上圖所示。
理清整個(gè)流程后,我們對(duì)內(nèi)購(gòu)就非常清晰了,要注意的就是細(xì)節(jié)了,對(duì)各種異常情況的處理。各種case 見(jiàn)下列枚舉,基本和app的sdk保持一致
typedef enum : NSUInteger {
EPaymentTransactionStateNoPaymentPermission, //沒(méi)有Payment權(quán)限
EPaymentTransactionStateAddPaymentFailed, //addPayment失敗
EPaymentTransactionStatePurchasing,//正在購(gòu)買(mǎi)
EPaymentTransactionStatePurchased,//購(gòu)買(mǎi)完成(銷(xiāo)毀交易)
EPaymentTransactionStateFailed, //購(gòu)買(mǎi)失敗(銷(xiāo)毀交易)
EPaymentTransactionStateCancel,//用戶取消
EPaymentTransactionStateRestored,//恢復(fù)購(gòu)買(mǎi)(銷(xiāo)毀交易)
EPaymentTransactionStateDeferred, //最終狀態(tài)未確定
} EPaymentTransactionState;
內(nèi)購(gòu)有個(gè)重要的協(xié)議 SKPaymentTransactionObserver
需要特殊特殊處理,不多說(shuō)廢話 直接附上代碼
#pragma mark - SKPaymentTransactionObserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
EPaymentTransactionState state;
switch (transaction.transactionState){
case SKPaymentTransactionStatePurchasing:
{
// 連接appStore
state = EPaymentTransactionStatePurchasing;
}
break;
case SKPaymentTransactionStatePurchased:
{
state = EPaymentTransactionStatePurchased;
//交易完成
if (isServiceVerify) {
[self completeTransaction:transaction];
}
else
{
//本地作校驗(yàn)
[self verifyPurchase:transaction];
}
}
break;
case SKPaymentTransactionStateFailed:
{
//交易失敗
if (transaction.error.code != SKErrorPaymentCancelled)
{
state = EPaymentTransactionStateFailed;
}else
{
state = EPaymentTransactionStateCancel;
}
[self finshTransaction:transaction];
}
break;
case SKPaymentTransactionStateRestored:
{
state = EPaymentTransactionStateRestored;
//已經(jīng)購(gòu)買(mǎi)過(guò)該商品
[self finshTransaction:transaction];
}
break;
case SKPaymentTransactionStateDeferred:
{
state = EPaymentTransactionStateDeferred;
}
break;
default:
break;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(updatedTransactions:)]) {
[self.delegate updatedTransactions:state];
}
}
}
補(bǔ)充一點(diǎn) :一旦啟動(dòng)了開(kāi)始購(gòu)買(mǎi)流程,必須要調(diào)用
//結(jié)束交易
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
來(lái)結(jié)束購(gòu)買(mǎi)流程,否者在下一次調(diào)用到 方法
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
還是會(huì)觸發(fā)繼續(xù)購(gòu)買(mǎi)流程,這個(gè)特性可以解決購(gòu)買(mǎi)過(guò)程中出現(xiàn)的各種異常場(chǎng)景,比如購(gòu)買(mǎi)完成app crash(沒(méi)網(wǎng)絡(luò)了),在下一次啟動(dòng)app時(shí)調(diào)用上面的方法可以回復(fù)購(gòu)買(mǎi)。
具體類(lèi) 放在gitHub下
https://github.com/weskhen/InAppPurchasing
貼上一段蘋(píng)果本地校驗(yàn)成功的json返回 估計(jì)服務(wù)器也是相同的
Printing description of jsonResponse:
{
environment = Sandbox; //購(gòu)買(mǎi)環(huán)境
receipt = {
"adam_id" = 0;
"app_item_id" = 0;
"application_version" = 30;
"bundle_id" = "com.wesk.PaoBa";
"download_id" = 0;
"in_app" = (
{
"is_trial_period" = false;
"original_purchase_date" = "2016-09-27 04:52:58 Etc/GMT";
"original_purchase_date_ms" = 1474951978000;
"original_purchase_date_pst" = "2016-09-26 21:52:58 America/Los_Angeles";
"original_transaction_id" = 1000000238538249;
"product_id" = “com.PaoBa.Product.001";
"purchase_date" = "2016-09-27 04:52:58 Etc/GMT";
"purchase_date_ms" = 1474951978000;
"purchase_date_pst" = "2016-09-26 21:52:58 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000238538249;
}
);
"original_application_version" = "1.0";
"original_purchase_date" = "2013-08-01 07:00:00 Etc/GMT";
"original_purchase_date_ms" = 1375340400000;
"original_purchase_date_pst" = "2013-08-01 00:00:00 America/Los_Angeles";
"receipt_creation_date" = "2016-09-27 07:42:18 Etc/GMT";
"receipt_creation_date_ms" = 1474962138000;
"receipt_creation_date_pst" = "2016-09-27 00:42:18 America/Los_Angeles";
"receipt_type" = ProductionSandbox;
"request_date" = "2016-09-27 07:43:44 Etc/GMT";
"request_date_ms" = 1474962224281;
"request_date_pst" = "2016-09-27 00:43:44 America/Los_Angeles";
"version_external_identifier" = 0;
};
status = 0;
}
蘋(píng)果反饋的狀態(tài)碼;
21000 App Store無(wú)法讀取你提供的JSON數(shù)據(jù)
21002 收據(jù)數(shù)據(jù)不符合格式 (踩過(guò)坑,越獄機(jī)會(huì)出現(xiàn))
21003 收據(jù)無(wú)法被驗(yàn)證
21004 你提供的共享密鑰和賬戶的共享密鑰不一致
21005 收據(jù)服務(wù)器當(dāng)前不可用
21006 收據(jù)是有效的,但訂閱服務(wù)已經(jīng)過(guò)期。當(dāng)收到這個(gè)信息時(shí),解碼后的收據(jù)信息也包含在返回內(nèi)容中
21007 收據(jù)信息是測(cè)試用(sandbox),但卻被發(fā)送到產(chǎn)品環(huán)境中驗(yàn)證
21008 收據(jù)信息是產(chǎn)品環(huán)境中使用,但卻被發(fā)送到測(cè)試環(huán)境中驗(yàn)證