iOS内购相关封装

将内购相关d功能封装成单例类,直接上代码

.h相关代码如下:

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
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>

@protocol YYAInAppPurchaseToolDelegate <NSObject>

/**
* TODO: System error.
*/
- (void)IAPToolSysWrong;

/**
* 已刷新可购买商品
*
* @param products 商品数组
*/
- (void)IAPToolGotProducts:(NSMutableArray *)products;

/**
* 购买成功
*
* @param productID 购买成功的商品ID
*/
- (void)IAPToolBoughtProductSuccessedWithProductID:(NSString *)productID
andInfo:(NSDictionary *)infoDic;;

/**
* 取消购买
*
* @param productID 商品ID
*/
- (void)IAPToolCanceldWithProductID:(NSString *)productID;

/**
* 购买成功,开始验证购买
*
* @param productID 商品ID
*/
- (void)IAPToolBeginCheckingdWithProductID:(NSString *)productID;

/**
* 重复验证
*
* @param productID 商品ID
*/
- (void)IAPToolCheckRedundantWithProductID:(NSString *)productID;

/**
* 验证失败
*
* @param productID 商品ID
*/
- (void)IAPToolCheckFailedWithProductID:(NSString *)productID
andInfo:(NSData *)infoData;

/**
* 恢复了已购买的商品(永久性商品)
*
* @param productID 商品ID
*/
- (void)IAPToolRestoredProductID:(NSString *)productID;

@end

NS_ASSUME_NONNULL_BEGIN

@interface YYAInAppPurchaseTool : NSObject

typedef void(^BoolBlock)(BOOL successed,BOOL result);

typedef void(^DicBlock)(BOOL successed,NSDictionary *result);

/**
* 代理
*/
@property(nonatomic,weak) id <YYAInAppPurchaseToolDelegate> delegate;

/**
* 购买完后是否在iOS端向服务器验证一次,默认为YES
*/
@property(nonatomic)BOOL CheckAfterPay;

/**
* 单例
*
* @return YQInAppPurchaseTool
*/
+(YYAInAppPurchaseTool *)defaultTool;

/**
* 询问苹果的服务器能够销售哪些商品
*
* @param products 商品ID的数组
*/
- (void)requestProductsWithProductArray:(NSArray *)products;

/**
* 用户决定购买商品
*
* @param productID 商品ID
*/
- (void)buyProduct:(NSString *)productID;


/**
* 恢复商品(仅限永久有效商品)
*/
- (void)restorePurchase;


@end

NS_ASSUME_NONNULL_END

.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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#import "YYAInAppPurchaseTool.h"

#ifdef DEBUG
#define checkURL @"https://sandbox.itunes.apple.com/verifyReceipt"
#else
#define checkURL @"https://buy.itunes.apple.com/verifyReceipt"
#endif

@interface YYAInAppPurchaseTool ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>

/**
* 商品字典
*/
@property(nonatomic,strong)NSMutableDictionary *productDict;

@end

@implementation YYAInAppPurchaseTool

static YYAInAppPurchaseTool *storeTool;

/// 单例
+ (YYAInAppPurchaseTool *)defaultTool {
if(!storeTool){
storeTool = [YYAInAppPurchaseTool new];
[storeTool setup];
}
return storeTool;
}

#pragma mark 初始化

- (void)setup {

self.CheckAfterPay = YES;

// 设置购买队列的监听器
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

/// 询问苹果的服务器能够销售哪些商品
- (void)requestProductsWithProductArray:(NSArray *)products {
NSLog(@"开始请求可销售商品");

// 能够销售的商品
NSSet *set = [[NSSet alloc] initWithArray:products];

// "异步"询问苹果能否销售
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];

request.delegate = self;

// 启动请求
[request start];
}

#pragma mark 获取询问结果,成功采取操作把商品加入可售商品字典里
/**
* 获取询问结果,成功采取操作把商品加入可售商品字典里
*
* @param request 请求内容
* @param response 返回的结果
*/
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
if (self.productDict == nil) {
self.productDict = [NSMutableDictionary dictionaryWithCapacity:response.products.count];
}

NSMutableArray *productArray = [NSMutableArray array];

for (SKProduct *product in response.products) {
//NSLog(@"%@", product.productIdentifier);

// 填充商品字典
[self.productDict setObject:product forKey:product.productIdentifier];

[productArray addObject:product];
}
//通知代理
[self.delegate IAPToolGotProducts:productArray];
}

#pragma mark - 用户决定购买商品
/**
* 用户决定购买商品
*
* @param productID 商品ID
*/
- (void)buyProduct:(NSString *)productID {
SKProduct *product = self.productDict[productID];

// 要购买产品(店员给用户开了个小票)
SKPayment *payment = [SKPayment paymentWithProduct:product];

// 去收银台排队,准备购买(异步网络)
[[SKPaymentQueue defaultQueue] addPayment:payment];
}

#pragma mark - SKPaymentTransaction Observer
#pragma mark 购买队列状态变化,,判断购买状态是否成功
/**
* 监测购买队列的变化
*
* @param queue 队列
* @param transactions 交易
*/
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
// 处理结果
for (SKPaymentTransaction *transaction in transactions) {
NSLog(@"队列状态变化 %@", transaction);
// 如果小票状态是购买完成
if (SKPaymentTransactionStatePurchased == transaction.transactionState) {
//NSLog(@"购买完成 %@", transaction.payment.productIdentifier);

if(self.CheckAfterPay){
//需要向苹果服务器验证一下
//通知代理
[self.delegate IAPToolBeginCheckingdWithProductID:transaction.payment.productIdentifier];
// 验证购买凭据
[self verifyPruchaseWithID:transaction.payment.productIdentifier];
}else{
//不需要向苹果服务器验证
//通知代理
[self.delegate IAPToolBoughtProductSuccessedWithProductID:transaction.payment.productIdentifier
andInfo:nil];
}
// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

} else if (SKPaymentTransactionStateRestored == transaction.transactionState) {
//NSLog(@"恢复成功 :%@", transaction.payment.productIdentifier);

// 通知代理
[self.delegate IAPToolRestoredProductID:transaction.payment.productIdentifier];

// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
} else if (SKPaymentTransactionStateFailed == transaction.transactionState){

// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//NSLog(@"交易失败");
[self.delegate IAPToolCanceldWithProductID:transaction.payment.productIdentifier];


}else if(SKPaymentTransactionStatePurchasing == transaction.transactionState){
NSLog(@"正在购买");
}else{
NSLog(@"state:%ld",(long)transaction.transactionState);
NSLog(@"已经购买");
// 将交易从交易队列中删除
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
}

#pragma mark - 恢复商品
/**
* 恢复商品
*/
- (void)restorePurchase {
// 恢复已经完成的所有交易.(仅限永久有效商品)
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

#pragma mark 验证购买凭据
/**
* 验证购买凭据
*
* @param ProductID 商品ID
*/
- (void)verifyPruchaseWithID:(NSString *)ProductID {
// 验证凭据,获取到苹果返回的交易凭据
// appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
// 从沙盒中获取到购买凭据
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];

// 发送网络POST请求,对购买凭据进行验证
//In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt
//In the real environment, use https://buy.itunes.apple.com/verifyReceipt
// Create a POST request with the receipt data.
NSURL *url = [NSURL URLWithString:checkURL];

NSLog(@"checkURL:%@",checkURL);

// 国内访问苹果服务器比较慢,timeoutInterval需要长一点
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];

request.HTTPMethod = @"POST";

// 在网络中传输数据,大多情况下是传输的字符串而不是二进制数据
// 传输的是BASE64编码的字符串
/**
BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性
BASE64是可以编码和解码的
*/
NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];

request.HTTPBody = payloadData;

// 提交验证请求,并获得官方的验证JSON结果


NSURLSession *session = [NSURLSession sharedSession];

// 4.根据会话对象,创建一个Task任务

NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

NSLog(@"从服务器获取到数据");

NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingMutableLeaves) error:nil];

if (dict != nil) {
// 验证成功,通知代理
// bundle_id&application_version&product_id&transaction_id
[self.delegate IAPToolBoughtProductSuccessedWithProductID:ProductID
andInfo:dict];
} else {

//验证失败,通知代理
[self.delegate IAPToolCheckFailedWithProductID:ProductID
andInfo:data];
}

}];

[sessionDataTask resume];
}

@end

------ 本文结束------
0%