iOS,苹果虚拟商品内付详解,从零到完成支付,2019-04-09

首先絮叨下为什么写这篇文章,每个人做每件事都有第一次,第一次做一件事总有一些弯路要走,我开始搞内付的时候 也是在网上翻了许多文章,但是没有找到一篇完整的, 苹果虚拟商品内付前期准备工作又是有许多牵连的,所以想要写这篇文章总结下  好了 下面开始讲如何实现内购,


因为实现的过程中有些截图没有保存,所以会有些图缺失,文章重在讲解流程和遇到的问题以及各个流程的关系

http://www.cnblogs.com/huanghaipo/p/7064383.html参考


文章结构:

1:银行税务,协议

2:证书

3:添加内购虚拟商品信息

4:xcode 配置

5:实现代码

6:内购实现过程中遇到的问题讲解

7:添加测试账号


1:协议,税务和银行业务

如果你的苹果账号是一个新的账号没有添加协议税务和银行业务信息,那么首先需要添加这些信息,上面参考链接里面有,

如果协议,税务和银行业务信息没有添加 那么后面就算实现了代码,app会返回给你的信息是搜索不到商品,

协议,税务和银行业务填写的信息是需要审核的,所以这个有必要先完成,

下图是我下午填写的信息第二天看到的状态都是有效,这样就可以搜索到商品信息了,



2:证书


一般我们用到的上传App Store和调试证书 applepay 是没有亮点的,但是内购支付证书需要这个,

当然 你可以在创建appid的时候 选择applepay 也可以在创建之后 点击下面的edit 更改



点击edit进入下图

如上图选择applepay 点击edit


上图如果点击进来没有merchant ID 那么需要在1出创建

参考 https://blog.csdn.net/shenguanhua/article/details/50772186

完成之后 会有一个这样的证书


安装到项目里面是这样的


证书只是讲解了与普通测试上架证书的不同,没有很详细的步骤讲解,

3:添加内购虚拟商品

这个问题 网上文章最多,参考 https://www.cnblogs.com/fengmin/p/8126079.html


如上图所示,是添加完商品之后的样子,



上面图箭头指向的审核信息一定也要填写,


上图 箭头指向的产品ID,是在程序里面搜索此商品的标识,只要是唯一就可以,程序里面就是通过这个id搜索到这个商品的,



如上图 我的审核信息没有填写,点击保存,会出现元数据丢失


4:xcode配置



如果 打开Apple Pay,如果是新的xocde 没有添加账号 1 和2 的箭头指向 会有错误,此时 点击 3箭头指向的加号或者刷新会有错误提示 ,需要xcode添加账号



如上图 点击xocde->preferences 



点击 箭头指向加号添加账号 ,完成之后 点击 3处的刷新 就好了

1处的 merchant ID是签名创建了才会有,这里如果没有 merchant ID 那么证书是有问题的 ,签名见了如何创建merchant ID


4 :代码

上面一些配置信息比较复杂,下面就是简单的代码了,代码我整个粘贴的.m里面的所有代码 如果网站编码没有问题 复制粘贴就可以运行,

#import "ViewController.h"

#import

@interface ViewController ()

@property (nonatomic,copy) NSString *currentProId;

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];


    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom];

    button2.frame=CGRectMake(300,100,100,100);

    button2.backgroundColor = [UIColor greenColor];

    [button2setTitle:@"6元" forState:UIControlStateNormal];

    [button2addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:button2];


}

- (void)btnClick:(UIButton*)button

{

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    _currentProId = @"201904081503";//产品id

    if([SKPaymentQueue canMakePayments]){

        [self requestProductData:_currentProId];

    }else{

        NSLog(@"不允许程序内付费");

    }

}

//去苹果服务器请求商品

- (void)requestProductData:(NSString*)type{

    NSLog(@"-------------请求对应的产品信息----------------");


//    [SVProgressHUD showWithStatus:nil maskType:SVProgressHUDMaskTypeBlack];





    NSArray*product = [[NSArrayalloc]initWithObjects:type,nil];


    NSSet*nsset = [NSSetsetWithArray:product];

    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];

    request.delegate=self;

    [requeststart];


}

//收到产品返回信息

- (void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse*)response{


    NSLog(@"--------------收到产品反馈消息---------------------");

    NSArray*product = response.products;

    if([productcount] ==0){

//        [SVProgressHUD dismiss];

        NSLog(@"--------------没有商品------------------");

        return;

    }


    NSLog(@"productID:%@", response.invalidProductIdentifiers);

    NSLog(@"产品付费数量:%lu",(unsignedlong)[product count]);


    SKProduct*p =nil;

    for(SKProduct*proinproduct) {

        NSLog(@"%@", [prodescription]);

        NSLog(@"%@", [pro localizedTitle]);

        NSLog(@"%@", [pro localizedDescription]);

        NSLog(@"%@", [proprice]);

        NSLog(@"%@", [pro productIdentifier]);


        if([pro.productIdentifierisEqualToString:_currentProId]){

            p = pro;

        }

    }


    SKPayment*payment = [SKPaymentpaymentWithProduct: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=[NSDatadataWithContentsOfURL:receiptUrl];


    NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//转化为base64字符串


    NSString*bodyString = [NSStringstringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接请求数据

    NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];



    //创建请求到苹果官方进行购买验证

    NSURL*url=[NSURLURLWithString: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([productIdentifierisEqualToString:@"123"]) {

            intpurchasedCount=[defaultsintegerForKey:productIdentifier];//已购买数量

            [[NSUserDefaultsstandardUserDefaults]setInteger:(purchasedCount+1)forKey:productIdentifier];

        }else{

            [defaultssetBool:YESforKey:productIdentifier];

        }

        //在此处对购买记录进行存储,可以存储到开发商的服务器端

    }else{

        NSLog(@"购买失败,未通过验证!");

    }

}

//监听购买结果

- (void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray*)transaction{

    for(SKPaymentTransaction*tranintransaction){

        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];

}

@end




6:  实现过程中遇到的问题,

在查找网上资料的时候,没有找到一篇很完整的文章,所以在开发的过程中,会出现许多问题,我在上面讲解的过程中也 有提到 ,

1:银行税务,协议

2:证书

3:添加内购虚拟商品信息

4:xcode 配置

5:实现代码

上面5个人步骤 在实现内购的过程中都是必要的,我在网站找资料的时候 没有遇到一个很完整的文章所以遇到了一些问题,如果上面5个步骤都完成了,应该不会有什么问题



7:添加测试账号


在用户和访问里面 沙箱技术,测试员添加测试账号 ,我的账号是我自己的appleid ,添加测试员不能添加当前账户的邮箱id,,我在购买的过程中,没有使用沙箱技术里面测试员的账户购买了 结果购买失败,于是用朋友的appleid 添加了 测试员 ,再次用测试员的账户购买 成功了

你可能感兴趣的:(iOS,苹果虚拟商品内付详解,从零到完成支付,2019-04-09)