IAP內(nèi)購(gòu)

服務(wù)器模式:

使用這種方式,要提供另外的服務(wù)器將產(chǎn)品發(fā)送給程序。 服務(wù)器交付適用于訂閱、內(nèi)容類商品和服務(wù),因?yàn)樯唐房梢宰鳛閿?shù)據(jù)發(fā)送,而不需改動(dòng)程序束。

例如,一個(gè)游戲提供的新的內(nèi)容(關(guān)卡等)。 Store Kit不會(huì)對(duì)服務(wù)器端的設(shè)計(jì)和交互做出定義,這方面工作需要你來(lái)完成。 而且,Store

Kit不提供驗(yàn)證用戶身份的機(jī)制,你需要來(lái)設(shè)計(jì)。 如果你的程序需要以上功能,例如,紀(jì)錄特定用戶的訂閱計(jì)劃, 你需要自己來(lái)設(shè)計(jì)和實(shí)現(xiàn)。

服務(wù)器類型的購(gòu)買過(guò)程

1. 程序向服務(wù)器發(fā)送請(qǐng)求,獲得一份產(chǎn)品列表。

2. 服務(wù)器返回包含產(chǎn)品標(biāo)識(shí)符的列表。

3. 程序向App Store發(fā)送請(qǐng)求,得到產(chǎn)品的信息。

4. App Store返回產(chǎn)品信息。

5. 程序把返回的產(chǎn)品信息顯示給用戶(App的store界面)

6. 用戶選擇某個(gè)產(chǎn)品

7. 程序向App Store發(fā)送支付請(qǐng)求

8. App Store處理支付請(qǐng)求并返回交易完成信息。

9. 程序從信息中獲得數(shù)據(jù),并發(fā)送至服務(wù)器。

10. 服務(wù)器紀(jì)錄數(shù)據(jù),并進(jìn)行審(我們的)查。

11. 服務(wù)器將數(shù)據(jù)發(fā)給App Store來(lái)驗(yàn)證該交易的有效性。

12. App Store對(duì)收到的數(shù)據(jù)進(jìn)行解析,返回該數(shù)據(jù)和說(shuō)明其是否有效的標(biāo)識(shí)。

13. 服務(wù)器讀取返回的數(shù)據(jù),確定用戶購(gòu)買的內(nèi)容。

14. 服務(wù)器將購(gòu)買的內(nèi)容傳遞給程序。

Apple建議在服務(wù)器端存儲(chǔ)產(chǎn)品標(biāo)識(shí),而不要將其存儲(chǔ)在plist中。 這樣就可以在不升級(jí)程序的前提下添加新的產(chǎn)品。

在服務(wù)器模式下, 你的程序?qū)@得交易(transaction)相關(guān)的信息,并將它發(fā)送給服務(wù)器。服務(wù)器可以驗(yàn)證收到的數(shù)據(jù),并將其解碼以確定需要交付的內(nèi)容。 這個(gè)流程將在“驗(yàn)證store收據(jù)”一節(jié)討論。

對(duì)于服務(wù)器模式,我們有安全性和可靠性方面的顧慮。 你應(yīng)該測(cè)試整個(gè)環(huán)境來(lái)避免威脅。《Secure Coding Guide》文檔中有相關(guān)的提示說(shuō)明。

雖然非消耗性商品可以用內(nèi)置模式來(lái)恢復(fù),訂閱類商品必須通過(guò)服務(wù)器來(lái)恢復(fù)。你要負(fù)責(zé)紀(jì)錄訂閱信息、恢復(fù)數(shù)據(jù)。 消耗類商品也可以通過(guò)服務(wù)器方式來(lái)紀(jì)錄。例如,由服務(wù)器提供的一項(xiàng)服務(wù), 你可能需要用戶在多個(gè)設(shè)備上重新獲得結(jié)果。

蘋(píng)果服務(wù)端配置指南:

使用IAP內(nèi)購(gòu)的準(zhǔn)備工作。通常需要經(jīng)過(guò)以下幾個(gè)步驟(下面的準(zhǔn)備工作是針對(duì)真機(jī)的Provisioning Profile配置過(guò)程,模擬器無(wú)法測(cè)試IAP內(nèi)購(gòu)):

1.在蘋(píng)果開(kāi)發(fā)者中心創(chuàng)建支持IAP服務(wù)的App ID并指定具體的Bundle ID,假設(shè)是“com.tj.xxx”(注意這個(gè)Bundle ID就是日后要開(kāi)發(fā)的游戲的Bundle ID)。

2.基于“com.tj.xxx”創(chuàng)建開(kāi)發(fā)者配置文件(或描述文件)并導(dǎo)入對(duì)應(yīng)的設(shè)備(創(chuàng)建過(guò)程中選擇支持IAP內(nèi)購(gòu)服務(wù)的App ID,這樣iOS設(shè)備在運(yùn)行指定Boundle ID應(yīng)用程序就知道此應(yīng)用支持IAP內(nèi)購(gòu)服務(wù))。

3.在iTunes Connect中創(chuàng)建一個(gè)應(yīng)用(假設(shè)叫“IAPTest”,這是一款含有內(nèi)購(gòu)的游戲)并指定“套裝ID”為之前創(chuàng)建的“com.tj.xxx”,讓?xiě)?yīng)用和這個(gè)App關(guān)聯(lián)(注意這個(gè)應(yīng)用不需要提交)。

4.在iTunes Connect的“用戶和職能”中創(chuàng)建沙盒測(cè)試用戶。(測(cè)試階段用沙盒用戶可以進(jìn)行購(gòu)買,購(gòu)買任何東西不用擔(dān)心被扣錢)。

5.到iTuens Connect中設(shè)置“App 內(nèi)購(gòu)買項(xiàng)目”,這里仍然以上面的“IAPest”項(xiàng)目為例,假設(shè)這個(gè)游戲中有一種道具,為“能量瓶”(為玩家提供能量),@“能量瓶”屬于消耗品,用完一次必須再次購(gòu)買。

6.到iTunes Connect中找到“協(xié)議、稅務(wù)和銀行業(yè)務(wù)”增加“iOS Paid Applications”協(xié)議,并完成所有配置后等待審核通過(guò)(注意這一步如果不設(shè)置在應(yīng)用程序中無(wú)法獲得可購(gòu)買產(chǎn)品)。

在iOS“設(shè)置”中找到”iTunes Store與App Store“,在這里可以選擇使用沙盒用戶登錄或者處于注銷狀態(tài),但是一定注意不能使用真實(shí)用戶登錄,否則下面的購(gòu)買測(cè)試不會(huì)成功,因?yàn)榈侥壳盀橹刮覀兊膽?yīng)用并沒(méi)有真正通過(guò)蘋(píng)果官方審核,所以只能用沙盒測(cè)試用戶。

7.有了上面的設(shè)置之后保證應(yīng)用程序Bundle ID和iTunes Connect中的Bundle ID(或者說(shuō)App ID中配置的Bundle ID)一致即可準(zhǔn)備開(kāi)發(fā)。

ios客戶端

#import

@interface JarIAPManager ()

{

id _observer;

}

@end

@implementation JarIAPManager

+ (instancetype)defaultManager{

static JarIAPManager *defaultManager = nil;

static dispatch_once_t onceToken = 0;

dispatch_once(&onceToken, ^{

defaultManager = [[JarIAPManager alloc]? init];

});

return defaultManager;

}

- (instancetype)init{

self = [super init];

if (self) {

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

_observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:self queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {

for (SKPaymentTransaction * paymentTransaction in [SKPaymentQueue defaultQueue].transactions) {

[[SKPaymentQueue defaultQueue] finishTransaction:paymentTransaction];

}

}];

}

return self;

}

- (void)dealloc{

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

[[NSNotificationCenter defaultCenter] removeObserver:_observer];

_observer = nil;

}

-(BOOL)iapEnable{

return [SKPaymentQueue canMakePayments];

}

#pragma mark --purchase product

//根據(jù)產(chǎn)品標(biāo)識(shí)符去購(gòu)買產(chǎn)品--[購(gòu)買結(jié)果]

- (void)purchaseProductWithIdenfifier:(NSString *)productIdentifier Order:(NSString *)Order{

//該字符串標(biāo)識(shí)一個(gè)特定的產(chǎn)品和用戶原意購(gòu)買的數(shù)量

SKMutablePayment * payment = [[SKMutablePayment alloc] init];

payment.productIdentifier = productIdentifier;

NSData *datas = [Order dataUsingEncoding:NSUTF8StringEncoding];

payment.requestData =datas;

[[SKPaymentQueue defaultQueue] addPayment:payment];

}

//SKPaymentTransactionObserver協(xié)議---[更常用的做法還是等待支付隊(duì)列告知交易狀態(tài)的更新。]

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{

__weak typeof(self)weakSelf = self;

for (SKPaymentTransaction * paymentTransaction in transactions) {

//小票狀態(tài)--》支付交易的狀態(tài)

switch (paymentTransaction.transactionState) {

case SKPaymentTransactionStatePurchasing:

{

NSLog(@"JarIAPManager: Transaction is being added to the server queue.");

}

break;

case SKPaymentTransactionStatePurchased:

{

NSLog(@"JarIAPManager: Transaction is in queue, user has been charged.? Client should complete the transaction.");

[weakSelf purchaseSuccessForTransaction:paymentTransaction];

}

break;

case SKPaymentTransactionStateFailed:

{

NSLog(@"JarIAPManager: Transaction was cancelled or failed before being added to the server queue.");

[weakSelf purchaseFailedForTransaction:paymentTransaction];

}

break;

case SKPaymentTransactionStateRestored:

{

NSLog(@"JarIAPManager: Transaction was restored from user's purchase history.? Client should complete the transaction.");

[[SKPaymentQueue defaultQueue] finishTransaction:paymentTransaction];

}

default:

break;

}

}

}

執(zhí)行

- (void)purchaseFailedForTransaction:(SKPaymentTransaction *)transaction{

NSLog(@"失敗流水--》%@",transaction.transactionIdentifier);

if (transaction != nil) {

[[Toast makeText:@"交易取消。" duration:3000] show:NO];

}

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

- (void)purchaseSuccessForTransaction:(SKPaymentTransaction *)transaction{

__weak typeof(self)weakSelf = self;

// 驗(yàn)證憑證,獲取蘋(píng)果返回的交易憑證

// appStoreReceiptURL iOS7.0增加的,購(gòu)買交易完成后,會(huì)將憑證存儲(chǔ)在該地址

NSURL * receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];

// 從沙盒中獲取到購(gòu)買憑證

NSData * receiptData = [NSData dataWithContentsOfURL:receiptURL];

//base64加密

NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

//打包成字典

NSMutableDictionary * parDic = [NSMutableDictionary dictionaryWithCapacity:3];

NSString *Order = [[NSString alloc] initWithData:transaction.payment.requestData encoding:NSUTF8StringEncoding];

DICT_SET_STRING(Order,TAG_ORDER, parDic);

DICT_SET_STRING(encodeStr, TAG_RECEIPT_DATA, parDic);

NSLog(@"下單成功的Order--》%@",Order);

if (Order !=NULL) {

//提前緩存

[[JarIAPSqliteService sharedInstance] insertTestListTransactionWithDic:parDic];

//??????? //檢測(cè)是否已經(jīng)存儲(chǔ)過(guò)了

//??????? NSMutableArray *getTestDatas = [[NSMutableArray alloc] init];

//??????? getTestDatas = [[JarIAPSqliteService sharedInstance] getTestList];

//??????? NSLog(@"存儲(chǔ)后的Order個(gè)數(shù)-->%ld",(unsigned long)getTestDatas.count);

//??????? if (getTestDatas.count != 0) {

//??????????? for (NSMutableDictionary * dic in getTestDatas) {

//??????????????? NSLog(@"存儲(chǔ)后的Order---》%@",dic[TAG_ORDER]);

//??????????? }

//??????? }else{

//??????????? NSLog(@"存儲(chǔ)為0.");

//??????? }

//發(fā)送到SDK服務(wù)器

[[LoginDataSource sharedInstance] verifyThePurchaseWithDictData:parDic completion:^(NSDictionary *resultData, NSError *error) {

if ([resultData[TAG_RESULT] intValue] == 0 || Order.length != 0) {

[weakSelf actionWithResult:resultData OrderStr:eOrder];//執(zhí)行刪除

}

}];

}

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

參考鏈接:

http://mobile.51cto.com/iphone-410162.htm? 比較全的文檔介紹

http://www.cocoachina.com/ios/20150129/11068.html demo

http://www.2cto.com/kf/201504/389224.html 有訂閱

http://blog.csdn.net/xingchen1106/article/details/45477433

http://blog.jobbole.com/38032/ 唐巧介紹安全

http://blog.csdn.net/fly_fish456/article/details/8955871

http://www.tairan.com/archives/2215/

【后期要理解的安全性,以及沙盒和正式環(huán)境】

http://www.360doc.com/content/14/1113/15/12282510_424834793.shtml

http://www.cocoachina.com/special/iap.html

http://www.2cto.com/kf/201504/389224.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 首先,用戶在購(gòu)買產(chǎn)品時(shí),應(yīng)用程序從應(yīng)用商店獲取該產(chǎn)品的信息,把商店 界面提供給用戶,然后讓用戶選擇產(chǎn)品,如下圖中第...
    Dosun閱讀 8,089評(píng)論 0 3
  • 購(gòu)買過(guò)程的最后一部分是應(yīng)用程序等待應(yīng)用商店處理支付請(qǐng)求,存儲(chǔ)本次購(gòu)買的信息以便將來(lái)啟動(dòng),下載購(gòu)買的內(nèi)容,然后標(biāo)記交...
    Dosun閱讀 1,149評(píng)論 0 1
  • 1 、在iTunes Connect中,每個(gè)應(yīng)用程序可以創(chuàng)建多少格內(nèi)置購(gòu)買產(chǎn)品 ID ? 閱讀 In-App Pu...
    Dosun閱讀 3,944評(píng)論 0 0
  • 在我們應(yīng)用開(kāi)發(fā)中我們經(jīng)常在自己的項(xiàng)目中使用到支付,下面我們來(lái)談?wù)刬OS這塊的支付;iOS支付主要分為兩類,第三方支...
    Hither閱讀 8,328評(píng)論 9 42
  • 介紹 分享下自己做內(nèi)購(gòu)遇到問(wèn)題,總結(jié)出來(lái)的經(jīng)驗(yàn)。 接入 使用RMStore。 1、使用RMStore的接入步驟 2...
    落影l(fā)oyinglin閱讀 6,216評(píng)論 31 21