走進(jìn)蘋果內(nèi)購IAP

屏幕快照 2017-01-23 15.19.12.png
馬上要過年了,而且還是本命年,為了慶祝下大雞年,放一張?zhí)O果官網(wǎng)的中國元素(不多說設(shè)計(jì)此圖的人NB).

1,了解蘋果內(nèi)購

當(dāng)我們?cè)贏ppStore里面下載下載軟件的時(shí)候,標(biāo)題下面會(huì)顯示提供App內(nèi)購買項(xiàng)目,通常我們下載的游戲也有購物的軟件,應(yīng)用里面采用了虛擬商品,例如:金幣,點(diǎn)券,奪寶幣,100顆寶石,,,,, 當(dāng)然像電商的軟件直接買實(shí)物就不是的, 蘋果公司就強(qiáng)制使用IAP內(nèi)購,原因很簡單,他要從中扣稅賺錢.蘋果2016賺了2000億主要來自這個(gè)地方.蘋果2016收入報(bào)表
65965B5B3055225F3E2FF2CFAA2C0776.png

2,熟悉內(nèi)購的流程;

  1. 程序向服務(wù)器發(fā)送請(qǐng)求右冻,獲得一份產(chǎn)品列表,以及訂單號(hào)(這里獲取商品的productID也可以放在本地)浑此。
  2. 服務(wù)器返回包含產(chǎn)品標(biāo)識(shí)符的列表秃嗜。
  3. 程序根據(jù)產(chǎn)品的productID向App Store發(fā)送請(qǐng)求惑申,得到產(chǎn)品的信息(包括價(jià)格,productID,,,,,)岩睁。
  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ù)器(也可以在本地驗(yàn)證但是不安全)。
  10. 服務(wù)器記錄交易信息碾局。
  11. 服務(wù)器將數(shù)據(jù)發(fā)給App Store來驗(yàn)證該交易荆残。
  12. App Store對(duì)收到的數(shù)據(jù)進(jìn)行解析奴艾,返回該數(shù)據(jù)和說明其是否有效的標(biāo)識(shí)净当。
  13. 服務(wù)器讀取返回的數(shù)據(jù),確定用戶購買的內(nèi)容蕴潦。
  14. 服務(wù)器將購買的內(nèi)容傳遞給程序像啼。(如果你是在app內(nèi)驗(yàn)證當(dāng)然是沒有10-14的)

3,完成內(nèi)購前的準(zhǔn)備工作;

<1>. 去蘋果開發(fā)者中心填寫appid,創(chuàng)建齒輪文件;
<2>. 去iTunes上填寫合同、稅務(wù)以及銀行信息(下面給的參考文獻(xiàn)有具體步驟,不多說),關(guān)于填寫W-8BEN-E可以參考這篇文章
iOS-Appstore-iTunes Connect最新協(xié)議潭苞、稅務(wù)和銀行業(yè)務(wù)填寫(W-8BEN)
<3>. 去iTunes創(chuàng)建對(duì)應(yīng)appid的項(xiàng)目;
<4> 添加App內(nèi)購買項(xiàng)目;
<5> 添加沙箱測(cè)試賬號(hào);(在真機(jī)測(cè)試自己的程序時(shí)需要退出當(dāng)前手機(jī)在Appstore登錄的賬號(hào))

5,開始擼內(nèi)購的代碼;

1. 發(fā)蘋果服務(wù)器請(qǐng)求商品信息;
  //productID就是你在創(chuàng)建購買項(xiàng)目時(shí)所填寫的產(chǎn)品ID
   [self requestProductData: productID];
   [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

-(void)requestProductData:(NSString *)type{
    
    NSLog(@"-------------請(qǐng)求對(duì)應(yīng)的產(chǎn)品信息----------------");
    NSArray *product = [[NSArray alloc] initWithObjects:type, nil];
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;
    [request start];
    
}
2. 接收商品信息并發(fā)送購買請(qǐng)求;
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSLog(@"--------------收到產(chǎn)品反饋消息---------------------");
    NSArray *product = response.products;
    if([product count] == 0){
        NSLog(@"--------------沒有商品------------------");
        return;
    }
    
    SKProduct *p = nil;
    for (SKProduct *pro in product) {
        NSLog(@"pro info");
        NSLog(@"SKProduct 描述信息:%@", [pro description]);
        NSLog(@"localizedTitle 產(chǎn)品標(biāo)題:%@", [pro localizedTitle]);
        NSLog(@"localizedDescription 產(chǎn)品描述信息:%@", [pro localizedDescription]);
        NSLog(@"price 價(jià)格:%@", [pro price]);
        NSLog(@"productIdentifier Product id:%@", [pro productIdentifier]);
        
        if([pro.productIdentifier isEqualToString: productID]){
            p = pro;
            
        }else{
            NSLog(@"不相同");
        }
    }
    SKPayment *payment = [SKPayment paymentWithProduct:p];
    NSLog(@"發(fā)送購買請(qǐng)求");
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}
3. 監(jiān)聽購買請(qǐng)求結(jié)果;
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    
    NSLog(@" 監(jiān)聽購買結(jié)果 -----paymentQueue--------");
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:{
                NSLog(@"-----交易完成 --------");
                //交易完成
                [self commitSeversSucceeWithTransaction:transaction];

            }
                break;
            case SKPaymentTransactionStateFailed:{
                NSLog(@"-----交易失敗 --------");
                //交易失敗
                [self failedTransaction:transaction];
                
            }
                break;
            case SKPaymentTransactionStateRestored:{
                NSLog(@"-----已經(jīng)購買過該商品(重復(fù)支付) --------");
                //已經(jīng)購買過該商品
                [self restoreTransaction:transaction];
                [self commitSeversSucceeWithTransaction:transaction];
                
            }
            case SKPaymentTransactionStatePurchasing:  {
                //商品添加進(jìn)列表
                NSLog(@"-----商品添加進(jìn)列表 --------");
            }
                break;
            default:
                break;
        }
        
    }
    
}

5,得到receipt并向服務(wù)器驗(yàn)證;
    NSString * productIdentifier = transaction.payment.productIdentifier;
    NSLog(@"productIdentifier Product id:%@", productIdentifier);
    NSString *transactionReceiptString= nil;
    
    //系統(tǒng)IOS7.0以上獲取支付驗(yàn)證憑證的方式應(yīng)該改變忽冻,切驗(yàn)證返回的數(shù)據(jù)結(jié)構(gòu)也不一樣了。
    
    // 驗(yàn)證憑據(jù)此疹,獲取到蘋果返回的交易憑據(jù)
    // appStoreReceiptURL iOS7.0增加的僧诚,購買交易完成后遮婶,會(huì)將憑據(jù)存放在該地址
    NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
    NSData * receiptData = [NSData dataWithContentsOfURL:receiptUrl];
    
    transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    
    NSLog(@"transactionReceiptString == %@",transactionReceiptString);
    [[NSUserDefaults standardUserDefaults]setObject:transactionReceiptString forKey:@"receipt"];
    
    // 向自己的服務(wù)器驗(yàn)證購買憑證
    [SDKRequestManager requestPayReceipt:transactionReceiptString Succee:^(NSDictionary *dic) {
        NSLog(@"----yyy--%@",dic);

        
    } withFail:^(NSError *error) {
        
    }];
    

    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
6, 本地緩存receipt,,,,服務(wù)器驗(yàn)證成功刪除本地receipt,

代碼就不放到git上面了,內(nèi)購的代碼都差不多,自己問下度娘.

4,處理下工程中遇到的相關(guān)問題;

  1. 獲取不到商品信息(這是最痛苦的):
    <1>. 合同、稅務(wù)以及銀行信息沒有填對(duì),如果你是公司賬號(hào),那么W-8BEN-E必須填,而且不要填錯(cuò)額!個(gè)人賬號(hào)的話就不需要填了.
    <2>. 你的程序的AppID和iTunes上不一致;
    <3>. 齒輪文件和AppID不匹配;

  2. 蘋果驗(yàn)證后返回的結(jié)果;

{
    "receipt":
    {
        "original_purchase_date_pst":"2015-06-22 20:56:34 America/Los_Angeles", //購買時(shí)間,太平洋標(biāo)準(zhǔn)時(shí)間
        "purchase_date_ms":"1435031794826", //購買時(shí)間毫秒
        "unique_identifier":"5bcc5503dbcc886d10d09bef079dc9ab08ac11bb",//唯一標(biāo)識(shí)符
        "original_transaction_id":"xxxxxxxxx", //原始交易ID
        "bvrs":"1.0",//iPhone程序的版本號(hào)
        "transaction_id":"xxxxxxxxxx", //交易的標(biāo)識(shí)
        "quantity":"1", //購買商品的數(shù)量
        "unique_vendor_identifier":"AEEC55C0-FA41-426A-B9FC-324128342652", //開發(fā)商交易ID
        "item_id":"1008526677",//App Store用來標(biāo)識(shí)程序的字符串
        "product_id":"cosmosbox.strikehero.gems60",//商品的標(biāo)識(shí) 
        "purchase_date":"2015-06-23 03:56:34 Etc/GMT",//購買時(shí)間
        "original_purchase_date":"2015-06-23 03:56:34 Etc/GMT", //原始購買時(shí)間
        "purchase_date_pst":"2015-06-22 20:56:34 America/Los_Angeles",//太平洋標(biāo)準(zhǔn)時(shí)間
        "bid":"com.cosmosbox.StrikeHero",//iPhone程序的bundle標(biāo)識(shí)
        "original_purchase_date_ms":"1435031794826"http://毫秒
    },
    "status":0 //狀態(tài)碼,0為成功
}
這里的transaction_id和original_transaction_id是一樣的可以作為唯一標(biāo)示;;;
  1. "您已購買此App內(nèi)購買項(xiàng)目,此項(xiàng)目將免費(fèi)恢復(fù)"
    在收到購買監(jiān)聽,處理相關(guān)邏輯的時(shí)候需要加上:[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

5,參考文獻(xiàn)(都是些大神的文章值得借鑒,認(rèn)真看一般的問題能解決)

  1. iOS應(yīng)用內(nèi)購/內(nèi)付費(fèi)
  2. iOS應(yīng)用程序內(nèi)購/內(nèi)付費(fèi)
  3. 內(nèi)購
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末湖笨,一起剝皮案震驚了整個(gè)濱河市旗扑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌慈省,老刑警劉巖臀防,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異边败,居然都是意外死亡袱衷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門笑窜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來致燥,“玉大人,你說我怎么就攤上這事排截〈畚颍” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵匾寝,是天一觀的道長搬葬。 經(jīng)常有香客問我,道長艳悔,這世上最難降的妖魔是什么急凰? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮猜年,結(jié)果婚禮上抡锈,老公的妹妹穿的比我還像新娘。我一直安慰自己乔外,他們只是感情好床三,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杨幼,像睡著了一般撇簿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上差购,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天四瘫,我揣著相機(jī)與錄音,去河邊找鬼欲逃。 笑死找蜜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的稳析。 我是一名探鬼主播洗做,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼弓叛,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了诚纸?” 一聲冷哼從身側(cè)響起邪码,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咬清,沒想到半個(gè)月后闭专,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旧烧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年影钉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掘剪。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡平委,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夺谁,到底是詐尸還是另有隱情廉赔,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布匾鸥,位于F島的核電站蜡塌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏勿负。R本人自食惡果不足惜馏艾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奴愉。 院中可真熱鬧琅摩,春花似錦、人聲如沸锭硼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檀头。三九已至轰异,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鳖擒,已是汗流浹背溉浙。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蒋荚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓馆蠕,卻偏偏與公主長得像期升,于是被迫代替她去往敵國和親惊奇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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