iOS開發內購詳細

一、最近公司很多的項目用到了內購,抽空整理下內購的詳細內容吧。

如對你有幫助,請不要吝惜打賞和喜歡,謝謝!

一....iOS開發內購全套圖文教程


======================第一部分協議===============


第一步.png

第二步.jpg

第三步.jpg

第四步.png

第五步.png

第六步.png

第七步.jpg

第八步.jpg

第九步.jpg

第十步.png

CNAPS CODE 查詢地址
https://e.czbank.com/CORPORBANK/query_unionBank_index.jsp


十一步.jpg

十二步.jpg

十三步.png

十四步.png

十五步.jpg

十七步.jpg

十八步.jpg

十九步.png

2016/11/18號更新


十九步(1).png

十九步(2).png

沒顯示的都是可以不填的,主要是打鉤 title 和最後面的Self


二十步.png

=============第二部分創建內購項目============


1.png

2.png

3.png

4.png

5.png

6.png

7.png

===========第三部分貼加內購項目測試賬號==========


創建測試賬號.png

沙盒測試員.png

賬號信息.png

=============第四部分主要實現代碼==========

首先導入StoreKit.framework

.h文件

#import <StoreKit/StoreKit.h>

enum{
IAP0p20=20,
IAP1p100,
IAP4p600,
IAP9p1000,
IAP24p6000,
}buyCoinsTag;

//代理
@interface RechargeVC : UIViewController <SKPaymentTransactionObserver,SKProductsRequestDelegate >

{
int buyType;
}

- (void) requestProUpgradeProductData;

-(void)RequestProductData;

-(void)buy:(int)type;

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

-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction;

- (void) completeTransaction: (SKPaymentTransaction *)transaction;

- (void) failedTransaction: (SKPaymentTransaction *)transaction;

-(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;

-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;

- (void) restoreTransaction: (SKPaymentTransaction *)transaction;

-(void)provideContent:(NSString *)product;

-(void)recordTransaction:(NSString *)product;

@end

.m文件

#import "RechargeVC.h"

//在內購項目中創的商品單號
#define ProductID_IAP0p20 @"Nada.JPYF01"//20
#define ProductID_IAP1p100 @"Nada.JPYF02" //100
#define ProductID_IAP4p600 @"Nada.JPYF03" //600
#define ProductID_IAP9p1000 @"Nada.JPYF04" //1000
#define ProductID_IAP24p6000 @"Nada.JPYF05" //6000

@interface RechargeVC ()

@end

@implementation RechargeVC

- (void)viewDidLoad {

    [super viewDidLoad];

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [self buy:IAP0p20];

}

-(void)buy:(int)type
{
    buyType = type;
    if ([SKPaymentQueue canMakePayments]) {
    [self RequestProductData];
    NSLog(@"允許程序內付費購買");
}
else
{
    NSLog(@"不允許程序內付費購買");
    UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@"提示"
    message:@"您的手機沒有打開程序內付費購買"
    delegate:nil cancelButtonTitle:NSLocalizedString(@"關閉",nil) otherButtonTitles:nil];

    [alerView show];

    }
}

-(void)RequestProductData
{
    NSLog(@"---------請求對應的產品信息------------");
    NSArray *product = nil;
    switch (buyType) {
        case IAP0p20:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP0p20,nil];
        break;
        case IAP1p100:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP1p100,nil];
        break;
        case IAP4p600:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP4p600,nil];
        break;
        case IAP9p1000:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP9p1000,nil];
        break;
        case IAP24p6000:
        product=[[NSArray alloc] initWithObjects:ProductID_IAP24p6000,nil];
        break;

        default:
        break;
}
    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
    request.delegate=self;
    [request start];

}

//<SKProductsRequestDelegate> 請求協議
//收到的產品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{

    NSLog(@"-----------收到產品反饋信息--------------");
    NSArray *myProduct = response.products;
    NSLog(@"產品Product ID:%@",response.invalidProductIdentifiers);
    NSLog(@"產品付費數量: %d", (int)[myProduct count]);
    // populate UI
    for(SKProduct *product in myProduct){
    NSLog(@"product info");
    NSLog(@"SKProduct 描述信息%@", [product description]);
    NSLog(@"產品標題 %@" , product.localizedTitle);
    NSLog(@"產品描述信息: %@" , product.localizedDescription);
    NSLog(@"價格: %@" , product.price);
    NSLog(@"Product id: %@" , product.productIdentifier);
}
    SKPayment *payment = nil;
    switch (buyType) {
        case IAP0p20:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP0p20];    //支付25
        break;
        case IAP1p100:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP1p100];    //支付108
        break;
        case IAP4p600:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP4p600];    //支付618
        break;
        case IAP9p1000:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP9p1000];    //支付1048
        break;
        case IAP24p6000:
        payment  = [SKPayment paymentWithProductIdentifier:ProductID_IAP24p6000];    //支付5898
        break;
        default:
        break;
}
    NSLog(@"---------發送購買請求------------");
    [[SKPaymentQueue defaultQueue] addPayment:payment];

}
- (void)requestProUpgradeProductData
{
    NSLog(@"------請求升級數據---------");
    NSSet *productIdentifiers = [NSSet setWithObject:@"com.productid"];
    SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];

}
//彈出錯誤信息
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"-------彈出錯誤信息----------");
    UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]
    delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];
    [alerView show];

}

-(void) requestDidFinish:(SKRequest *)request
{
    NSLog(@"----------反饋信息結束--------------");

}

-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{
    NSLog(@"-----PurchasedTransaction----");
    NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
    [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
}

//<SKPaymentTransactionObserver> 千萬不要忘記綁定,代碼如下:
//----監聽購買結果
//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易結果
{
    NSLog(@"-----paymentQueue--------");
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:{//交易完成
            [self completeTransaction:transaction];
            NSLog(@"-----交易完成 --------");

            UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@""
            message:@"購買成功"
            delegate:nil cancelButtonTitle:NSLocalizedString(@"關閉",nil) otherButtonTitles:nil];

            [alerView show];

        } break;
        case SKPaymentTransactionStateFailed://交易失敗
            { [self failedTransaction:transaction];
            NSLog(@"-----交易失敗 --------");
            UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"提示"
            message:@"購買失敗,請重新嘗試購買"
            delegate:nil cancelButtonTitle:NSLocalizedString(@"關閉",nil) otherButtonTitles:nil];

            [alerView2 show];

        }break;
        case SKPaymentTransactionStateRestored://已經購買過該商品
            [self restoreTransaction:transaction];
            NSLog(@"-----已經購買過該商品 --------");
            case SKPaymentTransactionStatePurchasing:      //商品添加進列表
            NSLog(@"-----商品添加進列表 --------");
            break;
            default:
            break;
        }
    }
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction

{
    NSLog(@"-----completeTransaction--------");
    // Your application should implement these two methods.
    NSString *product = transaction.payment.productIdentifier;
    if ([product length] > 0) {

    NSArray *tt = [product componentsSeparatedByString:@"."];
    NSString *bookid = [tt lastObject];
    if ([bookid length] > 0) {
    [self recordTransaction:bookid];
    [self provideContent:bookid];
}
}

    // Remove the transaction from the payment queue.

    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

//記錄交易
-(void)recordTransaction:(NSString *)product{
    NSLog(@"-----記錄交易--------");
}

//處理下載內容
-(void)provideContent:(NSString *)product{
    NSLog(@"-----下載--------");
}

- (void) failedTransaction: (SKPaymentTransaction *)transaction{
    NSLog(@"失敗");
    if (transaction.error.code != SKErrorPaymentCancelled)
    {

    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}
-(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction{

}

- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
    NSLog(@" 交易恢復處理");

}

-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
    NSLog(@"-------paymentQueue----");
}

#pragma mark connection delegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSLog(@"%@",  [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{

}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    switch([(NSHTTPURLResponse *)response statusCode]) {
        case 200:
        case 206:
        break;
        case 304:
        break;
        case 400:
        break;
        case 404:
        break;
        case 416:
        break;
        case 403:
        break;
        case 401:
        case 500:
        break;
        default:
        break;
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"test");
}

-(void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除監聽

}

@end

二......iOS開發內購詳細版本說明

1、先從內購的iTunesConnect裏配置說起吧,我們先進入蘋果的iTunesConnect鏈接https://itunesconnect.apple.com,然後進入入下界面。



銀行信息填寫

填寫好銀行卡信息和公司地址等信息以後,第一步算完成了。

2、進入iTunesConnect選擇我的APP模塊,創建新的APP,綁定好你在蘋果開發者中心創建的apple IDS還有bundle id,那麼就創建成功了一個新的APP應用。如下圖:



創建APP

3、進入新創建的APP應用,點擊如圖所示功能按鈕:



我的APP“功能”

4、進入功能以後我們就可以創建我們想要的內購產品的ID了,一般都會存在如下幾個選擇項:



選擇類型

5、我們公司的項目由於都是直播類型的課程購買,所以用的是消耗型的項目,選擇好然後就進入創建界面裏去創建產品了。



需要填寫的幾項

6、填寫好這幾項,一個新的內購產品就創建成功了,我們需要記錄下每個產品的內購ID,也就是唯一ID,爲以後購買產品做準備。

7、我們需要在工程裏配置好證書,測試證書是必須的因爲我們內購需要連接到蘋果的App Store的,需要正式的測試證書才能測試,同時把下圖工程中的這一配置打開:



這是很重要的一步

二、講完上面基本的配置以後,我們進入我們最重要的部分,那就是我們的代碼部分。

1、要使用蘋果的內購功能,我們需要引入蘋果的頭件“#import<StoreKit/StoreKit.h>”,引入進來以後,我們就需要引入"SKProductsRequestDelegate,SKPaymentTransactionObserver"這兩個代理,我們需要在內購的那個頁面viewDidLoad方法裏直接調用方法,如下圖:



開啓內購檢測

然後接下來就是幾個最重要的代理方法了,如果正常的內購能夠走通,那麼這幾個代理方法就會很流暢的運行過去,並且返回你所購買的商品的信息。讓我們一步步來分析:



內購購買(1)



內購購買(2)



內購購買(3)



內購購買(4)



內購購買(5)



內購購買(6)



內購完成

1.必須用真機測試。
2.測試的時候必須退出自己的apple ID。彈出頁面後登陸沙盒的測試apple id。

#import "TestPayController.h"

// 1.首先導入支付包
#import <StoreKit/StoreKit.h>

// 2.設置代理服務
@interface TestPayController ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>

@end

@implementation TestPayController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];

    //3.創建測試按鈕
    UIButton *testBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    testBtn.backgroundColor = [UIColor redColor];
    [testBtn addTarget:self action:@selector(clickTestBtnAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:testBtn];

    // 4.設置支付服務
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];


}

//點擊測試按鈕
- (void)clickTestBtnAction
{

    // 5.點擊按鈕的時候判斷app是否允許apple支付

    //如果app允許applepay
    if ([SKPaymentQueue canMakePayments]) {
        NSLog(@"yes");

        // 6.請求蘋果後臺商品
        [self getRequestAppleProduct];
    }
    else
    {
        NSLog(@"not");
    }
}

//請求蘋果商品
- (void)getRequestAppleProduct
{
    // 7.這裏的com.czchat.CZChat01就對應着蘋果後臺的商品ID,他們是通過這個ID進行聯繫的。
    NSArray *product = [[NSArray alloc] initWithObjects:@"com.czchat.CZChat01",nil];

    NSSet *nsset = [NSSet setWithArray:product];

    // 8.初始化請求
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;

    // 9.開始請求
    [request start];
}

// 10.接收到產品的返回信息,然後用返回的商品信息進行發起購買請求
- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *product = response.products;

    //如果服務器沒有產品
    if([product count] == 0){
        NSLog(@"nothing");
        return;
    }

    SKProduct *requestProduct = nil;
    for (SKProduct *pro in product) {

        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);

        // 11.如果後臺消費條目的ID與我這裏需要請求的一樣(用於確保訂單的正確性)
        if([pro.productIdentifier isEqualToString:@"com.czchat.CZChat01"]){
            requestProduct = pro;
        }
    }

    // 12.發送購買請求
    SKPayment *payment = [SKPayment paymentWithProduct:requestProduct];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

//請求失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"error:%@", error);
}

//反饋請求的產品信息結束後
- (void)requestDidFinish:(SKRequest *)request{
    NSLog(@"信息反饋結束");
}

// 13.監聽購買結果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    for(SKPaymentTransaction *tran in transaction){

        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:
                NSLog(@"交易完成");

                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加進列表");

                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"已經購買過商品");

                break;
            case SKPaymentTransactionStateFailed:
                NSLog(@"交易失敗");

                break;
            default:
                break;
        }
    }
}

// 14.交易結束,當交易結束後還要去appstore上驗證支付信息是否都正確,只有所有都正確後,我們就可以給用戶方法我們的虛擬物品了。
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    NSString * str=[[NSString alloc]initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding];

    NSString *environment=[self environmentForReceipt:str];
    NSLog(@"----- 完成交易調用的方法completeTransaction 1--------%@",environment);


    // 驗證憑據,獲取到蘋果返回的交易憑據
    // appStoreReceiptURL iOS7.0增加的,購買交易完成後,會將憑據存放在該地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 從沙盒中獲取到購買憑據
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    /**
     20      BASE64 常用的編碼方案,通常用於數據傳輸,以及加密算法的基礎算法,傳輸過程中能夠保證數據傳輸的穩定性
     21      BASE64是可以編碼和解碼的
     22      */
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

    NSString *sendString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSLog(@"_____%@",sendString);
    NSURL *StoreURL=nil;
    if ([environment isEqualToString:@"environment=Sandbox"]) {

        StoreURL= [[NSURL alloc] initWithString: @"https://sandbox.itunes.apple.com/verifyReceipt"];
    }
    else{

        StoreURL= [[NSURL alloc] initWithString: @"https://buy.itunes.apple.com/verifyReceipt"];
    }
    //這個二進制數據由服務器進行驗證;zl
    NSData *postData = [NSData dataWithBytes:[sendString UTF8String] length:[sendString length]];

    NSLog(@"++++++%@",postData);
    NSMutableURLRequest *connectionRequest = [NSMutableURLRequest requestWithURL:StoreURL];

    [connectionRequest setHTTPMethod:@"POST"];
    [connectionRequest setTimeoutInterval:50.0];//120.0---50.0zl
    [connectionRequest setCachePolicy:NSURLRequestUseProtocolCachePolicy];
    [connectionRequest setHTTPBody:postData];

    //開始請求
    NSError *error=nil;
    NSData *responseData=[NSURLConnection sendSynchronousRequest:connectionRequest returningResponse:nil error:&error];
    if (error) {
        NSLog(@"驗證購買過程中發生錯誤,錯誤信息:%@",error.localizedDescription);
        return;
    }
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"請求成功後的數據:%@",dic);
//這裏可以等待上面請求的數據完成後並且state = 0 驗證憑據成功來判斷後進入自己服務器邏輯的判斷,也可以直接進行服務器邏輯的判斷,驗證憑據也就是一個安全的問題。樓主這裏沒有用state = 0 來判斷。
    //    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    NSString *product = transaction.payment.productIdentifier;

    NSLog(@"transaction.payment.productIdentifier++++%@",product);

    if ([product length] > 0)
    {
        NSArray *tt = [product componentsSeparatedByString:@"."];

        NSString *bookid = [tt lastObject];

        if([bookid length] > 0)
        {

            NSLog(@"打印bookid%@",bookid);
//這裏可以做操作吧用戶對應的虛擬物品通過自己服務器進行下發操作,或者在這裏通過判斷得到用戶將會得到多少虛擬物品,在後面([self getApplePayDataToServerRequsetWith:transaction];的地方)上傳上面自己的服務器。
        }
    }
//此方法爲將這一次操作上傳給我本地服務器,記得在上傳成功過後一定要記得銷燬本次操作。調用[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    [self getApplePayDataToServerRequsetWith:transaction];
}

//結束後一定要銷燬
- (void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

-(NSString * )environmentForReceipt:(NSString * )str
{
    str= [str stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\n" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\t" withString:@""];

    str=[str stringByReplacingOccurrencesOfString:@" " withString:@""];

    str=[str stringByReplacingOccurrencesOfString:@"\"" withString:@""];

    NSArray * arr=[str componentsSeparatedByString:@";"];

    //存儲收據環境的變量
    NSString * environment=arr[2];
    return environment;
}

@end


2、進過我這一堆的代碼組合,是否已經明白了內購的方式了呢,只要把我列舉的這幾個方法,統統的導入進你的工程,那麼就基本上可以了。

三、常見內購錯誤,自己做內購總結的幾個常見錯誤。

1、請求不到內購的產品信息。

解決辦法:(1)、先看看bundle id,和測試證書之類的東西配置的都對不對,然後看看產品的唯一ID和iTunesConnect裏的能不能對應上。如果都沒有問題,那麼看下面的。

                  (2)、去看看iTunesConnect裏的協議裏面的公司的地址信息和銀行卡信息是否填寫正確,只要沒有報錯,報紅就可以。基本上上面這幾點弄好了也就能請求到商品了。

2、手機提示無法連接到itunesStore

解決辦法:把手機的Apple ID先註銷掉,然後購買的時候重新填寫Apple ID。


發佈了95 篇原創文章 · 獲贊 20 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章