- 消耗型項目?
就像你玩游戲需要買金幣,買鉆石等,只要花錢就可以無限次的購買
- 非消耗型項目?
就像你在App Store購買App,買了一次之后就不用再買第二次,你擁有永久使用權。
充值會員選擇的是第一種,可以無限次購買。
需要填寫商品名稱,產品ID以及價格等級,簡單說明一下
1. 商品名稱根據你的消費道具的實際意義來說明,比如“100顆寶石”,“100金幣”等。
2. 產品ID是比較重要的,由項目自定義,只要唯一即可,在實際應用中,一定要認真填寫。
3. 價格等級的話“查看價格表”中有對應的說明,可以對照著表中每個國家的貨幣價格與等級來選擇
申請沙盒測試賬號(用來測試購買項目)
這個賬號,是利用蘋果的沙盒測試環境來模擬AppStore的購買流程
回到iTunes Connect中,在這里我們選擇用戶和職能。
然后在沙箱技術測試員中點擊加號,添加測試員。
所有信息都可以隨意填寫,不用管是否真實。
App Store地區選擇,一定要選對,它對應的是你創建的App的地區, 你App是中國的話, 在這里我們依然選擇中國。
此賬號只能用來測試,不要在正式的appstore上使用
填寫完畢,點擊保存后,我們則生成一個測試賬號,當然這個賬號是可以隨時刪除和添加的。
#import "ViewController.h"
#import <StoreKit/StoreKit.h>
#import "SVProgressHUD.h"
@interface ViewController ()
@property (nonatomic,copy) NSString *currentProId;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(100, 100, 100, 100);
button.backgroundColor = [UIColor greenColor];
[button setTitle:@"6元" forState:UIControlStateNormal];
[button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:button];
}
- (void)btnClick:(UIButton *)button
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
_currentProId = @"123";
if([SKPaymentQueue canMakePayments]){
[self requestProductData:product];
}else{
NSLog(@"不允許程序內付費");
}
}
//去蘋果服務器請求商品
- (void)requestProductData:(NSString *)type{
NSLog(@"-------------請求對應的產品信息----------------");
[SVProgressHUD showWithStatus:nil maskType:SVProgressHUDMaskTypeBlack];
NSArray *product = [[NSArray alloc] initWithObjects:type,nil];
NSSet *nsset = [NSSet setWithArray:product];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
request.delegate = self;
[request start];
}
//收到產品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
NSLog(@"--------------收到產品反饋消息---------------------");
NSArray *product = response.products;
if([product count] == 0){
[SVProgressHUD dismiss];
NSLog(@"--------------沒有商品------------------");
return;
}
NSLog(@"productID:%@", response.invalidProductIdentifiers);
NSLog(@"產品付費數量:%lu",(unsigned long)[product count]);
SKProduct *p = nil;
for (SKProduct *pro in product) {
NSLog(@"%@", [pro description]);
NSLog(@"%@", [pro localizedTitle]);
NSLog(@"%@", [pro localizedDescription]);
NSLog(@"%@", [pro price]);
NSLog(@"%@", [pro productIdentifier]);
if([pro.productIdentifier isEqualToString:_currentProId]){
p = pro;
}
}
SKPayment *payment = [SKPayment paymentWithProduct:p];
NSLog(@"發送購買請求");
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
//請求失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
[SVProgressHUD showErrorWithStatus:@"支付失敗"];
NSLog(@"------------------錯誤-----------------:%@", error);
}
- (void)requestDidFinish:(SKRequest *)request{
[SVProgressHUD dismiss];
NSLog(@"------------反饋信息結束-----------------");
}
//沙盒測試環境驗證
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式環境驗證
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
/**
* ?驗證購買,避免越獄軟件模擬蘋果請求達到非法購買問題
*
*/
-(void)verifyPurchaseWithPaymentTransaction{
//從沙盒中獲取交易憑證并且拼接成請求體數據
NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];
NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//轉化為base64字符串
NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接請求數據
NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
//創建請求到蘋果官方進行購買驗證
NSURL *url=[NSURL URLWithString:SANDBOX];
NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];
requestM.HTTPBody=bodyData;
requestM.HTTPMethod=@"POST";
//創建連接并發送同步請求
NSError *error=nil;
NSData *responseData=[NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error];
if (error) {
NSLog(@"驗證購買過程中發生錯誤,錯誤信息:%@",error.localizedDescription);
return;
}
NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
NSLog(@"%@",dic);
if([dic[@"status"] intValue]==0){
NSLog(@"購買成功!");
NSDictionary *dicReceipt= dic[@"receipt"];
NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject];
NSString *productIdentifier= dicInApp[@"product_id"];//讀取產品標識
//如果是消耗品則記錄購買數量,非消耗品則記錄是否購買過
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
if ([productIdentifier isEqualToString:@"123"]) {
int purchasedCount=[defaults integerForKey:productIdentifier];//已購買數量
[[NSUserDefaults standardUserDefaults] setInteger:(purchasedCount+1) forKey:productIdentifier];
}else{
[defaults setBool:YES forKey:productIdentifier];
}
//在此處對購買記錄進行存儲,可以存儲到開發商的服務器端
}else{
NSLog(@"購買失敗,未通過驗證!");
}
}
//監聽購買結果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
for(SKPaymentTransaction *tran in transaction){
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased:{
NSLog(@"交易完成");
// 發送到蘋果服務器驗證憑證
[self verifyPurchaseWithPaymentTransaction];
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
case SKPaymentTransactionStatePurchasing:
NSLog(@"商品添加進列表");
break;
case SKPaymentTransactionStateRestored:{
NSLog(@"已經購買過商品");
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
case SKPaymentTransactionStateFailed:{
NSLog(@"交易失敗");
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
[SVProgressHUD showErrorWithStatus:@"購買失敗"];
}
break;
default:
break;
}
}
}
//交易結束
- (void)completeTransaction:(SKPaymentTransaction *)transaction{
NSLog(@"交易結束");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
在這里需要注意幾點,
代碼中的_currentProId所填寫的是你的購買項目的的ID,這個和第二步創建的內購的productID要一致;本例中是 123。
在監聽購買結果后,一定要調用[[SKPaymentQueue defaultQueue] finishTransaction:tran];來允許你從支付隊列中移除交易。
沙盒環境測試appStore內購流程的時候,請使用沒越獄的設備。
請務必使用真機來測試,一切以真機為準。
項目的Bundle identifier需要與您申請AppID時填寫的bundleID一致,不然會無法請求到商品信息。
真機測試的時候,一定要退出原來的賬號,才能用沙盒測試賬號
二次驗證,請注意區分宏, 測試用沙盒驗證,App Store審核的時候也使用的是沙盒購買,所以驗證購買憑證的時候需要判斷返回Status Code決定是否去沙盒進行二次驗證,為了線上用戶的使用,驗證的順序肯定是先驗證正式環境,此時若返回值為21007,就需要去沙盒二次驗證,因為此購買的是在沙盒進行的。