iOS開發之內購-AppStore


本文會給大家詳細介紹iOS內購,雖然之前網上也有內購的教程,但是還不夠詳細,我重新整理出一份教程,希望對大家有所幫助。

基於Xcode7.1.1版本,模擬器iphone6,9.1系統。
部分地方直接摘自網絡,省時省心省力。
多圖預警!!!
轉載請注明出處@yimouleng

一. 創建測試App

創建App-1

首先你需要登錄 App的ItunesConnection,你會看到如下界面

簡單的介紹一下這幾個選項

  • 1.我的App主要用於管理自己的App應用,例如編輯資料,上架,下架等。
  • 2.銷售和趨勢主要是來查看App在各個平台的下載量,收入等方面數據,里面有曲線圖等圖文結合的方式給我們參考。
  • 3.付款和財務報告顯示的是你的收入以及付款等相關信息。
  • 4.iAd主要是跟廣告有關,開發者可以登錄到Workbench,通過iAd對應用的廣告進行控制。
  • 5.用戶和職能用於生成相應賬號,例如蘋果沙河測試賬號。
  • 6.協議,稅務和銀行業務則是你銀行相關賬戶的信息設置。

在這里我們選擇第一個選項,我的App, 然后點擊左上角的加號,新建一個用來測試用的App。

我們會看到彈出的窗口

在這里有幾個需要填寫的地方,名稱自己取,平台IOS,語言選擇了簡體中文,套裝ID也就是你的Bundle Identifier,需要你在Certificates頁面 申請BundleID,在這里簡單的給大家介紹一下。

申請BundleID

打開Certificates頁面 ,在左側選擇 Identifiers,並點擊加號,申請一個新的Identifiers。

在這里Name可以隨意填寫,我填寫的是TestAppStroeTestDemo,而用來使用的BundleID,我們在這里必須選擇第一個選項唯一的,不用選擇通配。在下面的選項中, 我們只需要勾選一個 Apple Pay即可,其他選項看自己需求,我在這里只選擇了它。

之后一路Done即可。

創建App-2

之后我們回到創建App,選擇好自己剛創建的 BundleID ,填寫SKU, SKU是你App的專用ID,我在這里隨意填寫,直接復制了App名。點擊創建,我們的測試App則創建成功。

二.添加內購

App創建好之后,我們打開創建的App,在左上角選擇功能,會看到左側的App 內購買項目。我們點擊右下角的加號,為App添加內購項目。

之后我們會看到類型的選項,如下圖

官方的注釋寫的很清楚了,只在這里簡單的說下前兩種

消耗型項目 就像你玩游戲需要買金幣,買鑽石等,只要花錢就可以無限次的購買
非消耗型項目 就像你在App Store購買App,買了一次之后就不用再買第二次,你擁有永久使用權。

在這里為了方便測試,我們選擇第一種 消耗型項目 。來到內購項目填寫頁面,如下圖。

這里有幾個選項,需要填寫商品名稱,產品ID以及價格等級,簡單說明一下

1.商品名稱根據你的消費道具的實際意義來說明,比如“100顆寶石”,“100金幣”等。
2.產品ID是比較重要的,由項目自定義,只要唯一即可,因為測試,我在這里隨便填寫的123,在實際應用中,一定要認真填寫。
3.價格等級的話“查看價格表”中有對應的說明,可以對照着表中每個國家的貨幣價格與等級來選擇

接下來是語言選擇,和上傳快照如下圖

點擊添加語言,填寫名稱和描述,這里我們依然選擇簡體中文,如下

審核備注,根據實際情況填寫,可以不填。而下面的屏幕快照,則是商品圖片,以像素為單位,最低尺寸為321,390,尺寸需求如下圖,上傳即可。

到這里為止, 我們的內購項目則添加完成。接下來則是測試階段了。

三.申請沙盒測試賬號(用來測試購買項目)

這個賬號,是利用蘋果的沙盒測試環境來模擬AppStore的購買流程,你肯定不會想要用真實RMB去購買測試吧?
首先我們回到iTunes Connect中,在這里我們選擇用戶和職能

然后在上面的第三個選項沙箱技術測試員中點擊加號,添加測試員。

在信息填寫頁面只簡單說兩句。

所有信息都可以隨意填寫,不用管是否真實。
App Store地區選擇,一定要選對,它對應的是你創建的App的地區, 你App是中國的話, 在這里我們依然選擇中國。
此賬號只能用來測試,不要在正式的appstore上使用

填寫完畢,點擊保存后,我們則生成一個測試賬號,當然這個賬號是可以隨時刪除和添加的。

四.核心代碼

之后終於到了我們擼代碼的時候了,點開你的Xcode創建你的項目!

首先我們需要在項目工程中加入“storekit.framework”,加入頭文件#import 
在.h文件中加入“SKPaymentTransactionObserver,SKProductsRequestDelegate”監聽機制
代碼很簡單,直接在.m文件在中填寫,添加了二次驗證,防止越獄手機等內購。如下,

.m文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
//
// ViewController.m
// 內購
//
// Created by Ely on 15/12/15.
// Copyright © 2015年 Ely. All rights reserved.
//

#import "ViewController.h"
#import <StoreKit/StoreKit.h>
#import "SVProgressHUD.h"

@interface ViewController ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>
@property (nonatomic,strong) NSArray *profuctIdArr;
@property (nonatomic,copy) NSString *currentProId;

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

[self createPay];
}


- (void)createPay
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
self.profuctIdArr = @[@"123"];

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];
button.tag = 100;
[self.view addSubview:button];
}

- (void)btnClick:(UIButton *)button
{
NSString *product = self.profuctIdArr[button.tag-100];
_currentProId = product;
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

在這里需要注意幾點,

  • 代碼中的self.profuctIdArr所填寫的是你的購買項目的的ID,我這里是當時填寫的ID 123。
  • 在監聽購買結果后,一定要調用[[SKPaymentQueue defaultQueue] finishTransaction:tran];來允許你從支付隊列中移除交易。
  • 沙盒環境測試appStore內購流程的時候,請使用沒越獄的設備。
  • 請務必使用真機來測試,一切以真機為准。
  • 項目的Bundle identifier需要與您申請AppID時填寫的bundleID一致,不然會無法請求到商品信息。
  • 真機測試的時候,一定要退出原來的賬號,才能用沙盒測試賬號
  • 二次驗證,請注意區分宏, 測試用沙盒驗證

在這里附上截圖:

點擊購買按鈕

選擇使用現有Apple ID,填寫測試賬號

確認是否購買

購買成功

最后師打印輸出日志

到這里,我們的內購則全部完成了。
如還有不懂得請留言,或者 加群67784110聯系我。
本文所寫的Demo可在我的GITHUB下載,點此鏈接
內購時遇到的問題和解決辦法,我放在下一篇文章中,點此內購時遇到的問題和解決辦法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM