版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.05.24 |
前言
大家都知道,ios虚拟商品如宝石、金币等都需要走内购,和苹果三七分成,如果这类商品不走内购那么上不去架或者上架以后被发现而被下架。最近有一个项目需要增加内购支付功能,所以最近又重新集成并整理了下,希望对大家有所帮助。感兴趣的可以参考上面几篇。
1. iOS内购IAP(一) —— 基础配置篇(一)
实现详情
这里ios开发平台上的证书和税务等基础配置我就不说了,不明白的可以参考为的另外一篇文章ios内购之基础配置篇。这一篇的重点就是说一下我在项目中的具体实现,将抽象进一步具体化。
一、增加内购项目
在开发者账号itunesConnect--我的app中增加内购项目,如下图所示。
细心的朋友可能发现,我这里状态中有的是已删除,有的是元数据丢失,这是怎么回事呢?这里我要和大家说一下,这里提示已删除的是因为我有的信息填错了,后来让我在这里删除了;而下面的元数据丢失是因为,在增加内购项目的时候,没有填写完全,比如screenshot我就没有填写,这里就显示了元数据丢失。这里还有一点需要提醒大家,产品ID是唯一的,假如你增加的内购项目删除了,那么这个产品ID就不能用了,你下边就是增加再多的内购项目也不能使用这个删除的产品ID了,所以填写要慎重。还要就是别忘记添加沙盒测试人员账号,不会的同样参考我上面的文章。还有就是这里的价格是根据内购的一个价格表定的,这里不支持自定义价格。
二、代码集成
下面我就只要说一下内购项目的代码及其逻辑。不废话,我就直接上代码了。
JJMoneyChargeVC.m文件
//增加头文件
#import "StoreKit/StoreKit.h"
//必要的几个属性
@property (nonatomic, strong) SKProductsRequest *productRequest;
@property (nonatomic, copy) NSString *productID;
@property (nonatomic, copy) NSString *chargeMoneyNumStr;
@property (nonatomic, copy) NSString *orderIDStr;
//开启内购
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"充值";
self.view.backgroundColor = [UIColor whiteColor];
[self setupUI];
//开启内购
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
//下面就是具体的方法实现了
//点击手势选择要充值的金额
- (void)tapDidTapped:(UITapGestureRecognizer *)tapGesture
{
switch (tapGesture.view.tag) {
case JJChargeVCChargeType100:
NSLog(@"我充值100金币");
self.chargeMoneyNumStr = @"1";
break;
case JJChargeVCChargeType600:
NSLog(@"我充值600金币");
self.chargeMoneyNumStr = @"6";
break;
case JJChargeVCChargeType1800:
NSLog(@"我充值1800金币");
self.chargeMoneyNumStr = @"18";
break;
case JJChargeVCChargeType3000:
NSLog(@"我充值3000金币");
self.chargeMoneyNumStr = @"30";
break;
case JJChargeVCChargeType9800:
NSLog(@"我充值9800金币");
self.chargeMoneyNumStr = @"98";
break;
case JJChargeVCChargeType19800:
NSLog(@"我充值19800金币");
self.chargeMoneyNumStr = @"198";
break;
default:
break;
}
//向服务器请求生成订单号
[self getOderNumbderRequest];
}
//请求服务器生成订单号
-(void)getOderNumbderRequest
{
//先检查网络
if (self.chargeMoneyNumStr.length == 0) {
return;
}
NSMutableDictionary *paramatersDictM = [NSMutableDictionary dictionary];
[paramatersDictM setObject:@"1" forKey:@"chargeType"];
[paramatersDictM setObject:self.chargeMoneyNumStr forKey:@"totalAmount"];
[[JJNetWorkManager manager] requestByPostNetworkWithPayUrl:kappleInnerPharchase parameters:paramatersDictM success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"responseObject---%@",responseObject);
if ([[responseObject objectForKey:@"code"] integerValue] == 0) {
NSDictionary *dataDict = [responseObject objectForKey:@"data"];
self.orderIDStr = [dataDict objectForKey:@"orderNo"];
if ([self.chargeMoneyNumStr isEqualToString:@"1"]) {
self.productID = @"这里是添加的内购项目产品ID";
}
else if([self.chargeMoneyNumStr isEqualToString:@"6"]){
self.productID = @"这里是添加的内购项目产品ID";
}
else if([self.chargeMoneyNumStr isEqualToString:@"18"]){
self.productID = @"这里是添加的内购项目产品ID";
}
else if([self.chargeMoneyNumStr isEqualToString:@"30"]){
self.productID = @"这里是添加的内购项目产品ID";
}
else if([self.chargeMoneyNumStr isEqualToString:@"98"]){
self.productID = @"这里是添加的内购项目产品ID";
}
else if([self.chargeMoneyNumStr isEqualToString:@"198"]){
self.productID = @"这里是添加的内购项目产品ID";
}
if (self.productID && self.chargeMoneyNumStr) {
//根据产品信息发起请求,去苹果服务器请求商品
[self beginRequestWithProductID:self.productID];
}
else {
NSLog(@"不允许程序内付费,必须走内购");
}
}
} error:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"error---%@",error);
}];
}
//根据产品信息发起请求,去苹果服务器请求商品
- (void)beginRequestWithProductID:(NSString *)productID
{
NSArray *productArr = [[NSArray alloc] initWithObjects:productID, nil];
NSSet *productSet = [NSSet setWithArray:productArr];
self.productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productSet];;
self.productRequest.delegate = self;
[self.productRequest start];
}
//下面就是走请求的代理方法
#pragma mark - SKProductsRequestDelegate
//当请求到可卖商品的结果会执行该方法
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray *productArr = response.products;
if (productArr.count == 0) {
NSLog(@"购买失败");
return;
}
SKProduct *productInfo;
for (SKProduct *product in productArr) {
NSLog(@"商品描述 %@", [product description]);
NSLog(@"商品标题 %@", [product localizedTitle]);
NSLog(@"商品本地化描述 %@", [product localizedDescription]);
NSLog(@"商品价格 %@", [product price]);
NSLog(@"商品ID %@", [product productIdentifier]);
if ([product.productIdentifier isEqualToString:self.productID]) {
productInfo = product;
}
}
//发送购买请求
if (productInfo) {
SKPayment *payment = [SKPayment paymentWithProduct:productInfo];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
//支付失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(@"%@---error",error);
}
//支付后的反馈信息
- (void)requestDidFinish:(SKRequest *)request
{
//这里可以取消提示框
}
//下面就是查询购买结果
#pragma mark - SKPaymentTransactionObserver
//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
NSLog(@"可以请求购买了");
[self completeTransactionWithTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing:
NSLog(@"商品正在购买中。。。");
break;
case SKPaymentTransactionStateRestored:
NSLog(@"已经购买过商品");
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"购买失败");
[self failedTransaction:transaction];
break;
default:
break;
}
}
}
//完成购买
- (void)completeTransactionWithTransaction:(SKPaymentTransaction *)transaction
{
[self getPhuechaseReceipt:transaction];
NSString *productIdentify = transaction.payment.productIdentifier;
if (productIdentify.length > 0) {
//向自己的服务器请求验证,增加金币
[self requestPurchaseViaServerWithReceipt:self.receiptStr];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
//服务器端验证金币,成功后服务器则给予用户虚拟物
- (void)requestPurchaseViaServerWithReceipt:(NSString *)storeReceipt
{
NSMutableDictionary *mutableDictM = [NSMutableDictionary dictionary];
[mutableDictM setObject:self.orderIDStr?:@"" forKey:@"orderNo"];
[mutableDictM setObject:storeReceipt?:@"" forKey:@"receipt"];
[[JJNetWorkManager manager] requestByPostNetworkWithPayUrl:kappleInnerPharchaseToMyServer parameters:mutableDictM success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"responseObject---%@",responseObject);
if ([[responseObject objectForKey:@"code"] integerValue] == 0) {
NSDictionary *dataDict = [responseObject objectForKey:@"data"];
self.accountCashNumLabel.text = [NSString stringWithFormat:@"%@",[dataDict objectForKey:@"userCoin"]];
}
} error:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"error--%@",error);
}];
}
//已经购买过改商品
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
NSString * productIdentifier = transaction.payment.productIdentifier;
if ([productIdentifier length] > 0) {
// 向自己的服务器验证购买凭证,成功后服务器则给予用户虚拟物
//post请求传给服务器
[self requestPurchaseViaServerWithReceipt:self.receiptStr];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
//购买失败
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
if(transaction.error.code != SKErrorPaymentCancelled) {
NSLog(@"购买失败");
[MBProgressHUD hideHUDForView:self.view animated:YES];
[self showNotice:@"购买失败"];
}
else {
NSLog(@"用户取消交易");
[MBProgressHUD hideHUDForView:self.view animated:YES];
[self showNotice:@"交易已取消"];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
//获取购买凭证
-(void)getPhuechaseReceipt:(SKPaymentTransaction *)transaction
{
//从沙盒中获取交易凭证并且拼接成请求体数据
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
self.receiptStr = [receiptData base64EncodedStringWithOptions:0];
}
三、实现效果
ios内购的实现效果如下图所示。
我这里使用的是沙盒进行的测试。
后记
内购就写这么多了,明后天有时间我再把支付宝支付的也加上。谢谢大家,晚安哦~~~