iOS 苹果内购详细步骤

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/qq_22080737/article/details/79786500

一、设置协议等相关

1.点击协议、税务和银行业务。

2.点击 Request Contracts 下面的 Request,一直点击直到主协议界面。

主协议界面

Contact info :联系人信息

Bank info :银行信息

Tax info :税务信息

3.点击 Contact Info 下面的Set Up,设置联系人信息,然后点击 Add New Contract,添加新的联系信息。

4.填写完整并保存。

5.选择联系人,因为我是独立开发,所以填写的自己的,如果你是多人开发,你可以添加多个联系人。

Senior Management:高级管理人员

Financial :财务

Technical :技术支持

Legal :法务

Marketing :市场推广

添加完成之后,对应选择好就行。

6.点击 Bank Info 下的 Set Up,然后点击 Add Bank Account 添加银行账号。

点击 Select One,选择 China ,点击 next。

填写 CNAPS Code,点击 next。

CNAPS Code:中国现代化支付系统代码,又叫做联行号。可以从网上查询,也可以直接点击Look up CNAPS Code进行查询,再不济,也可以直接打电话咨询相应银行客服。

点击 next,核对一下,继续 next。

填写银行卡相关信息,点击 next。(持卡人姓名,如张三(Zhang San))

确认一下,点击 save 保存。

选择对应的银行卡,点击 save。

7.点击 Tax Info 下面的 Set Up,设置税务信息。

税务分三种:

U.S Tax Forms : 美国税务

Australia Tax Forms:澳大利亚税务

Canada Tax Forms : 加拿大税务

我们选择美国税务,点击 Done。

如果没有就选择 NO,点击 Submit。

如果没有就选择 NO。

填写完整,点击 Submit。

核对信息无误后提交,状态显示 Processing 表示成功。

二、创建项目的内购条目

1.进入 APP,点击功能。

根据情况选择,我选择的第一个。

填写内购项目信息,点击存储。

下面这些信息也要填完整,否则会提示元数据丢失(坑)。

注意:你 App 有几个内购级别就需要依次创建几个条目。

三、添加沙盒测试账号

1.点击用户和职能

2.点击沙盒技术测试员

3.点击 “+” 添加测试员,邮箱和密码用于支付的时候登陆 Apple ID。

四、代码集成

#import "ApplePayVC.h"

//导入

#import <StoreKit/StoreKit.h>

//遵循代理

@interface ApplePayVC ()

<

SKPaymentTransactionObserver,

SKProductsRequestDelegate

>

//支付按钮

@property (nonatomic, strong) UIButton *payBtn;

@end

@implementation ApplePayVC

- (void)viewDidLoad

{

    [super viewDidLoad];

    [self setupPayBtn];

    //设置支付服务

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

#pragma mark - UI

- (void)setupPayBtn

{

    _payBtn = [UIButton buttonWithType:UIButtonTypeCustom];

    _payBtn.frame = CGRectMake(100, 100, 100, 100);

    _payBtn.backgroundColor = [UIColor redColor];

    [_payBtn setTitle:@"支付" forState:UIControlStateNormal];

    [_payBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

    _payBtn.titleLabel.font = [UIFont systemFontOfSize:15.0];

    [_payBtn addTarget:self action:@selector(payBtnAction) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:_payBtn];

}

#pragma mark - BtnAction

- (void)payBtnAction

{

    //是否允许内购

    if ([SKPaymentQueue canMakePayments]) {

        NSLog(@"用户允许内购");

        //bundleid+xxx 就是你添加内购条目设置的产品ID

        NSArray *product = [[NSArray alloc] initWithObjects:@"bundleid+xxx",nil];

        NSSet *nsset = [NSSet setWithArray:product];

        //初始化请求

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

        request.delegate = self;

        //开始请求

        [request start];

    }else{

        NSLog(@"用户不允许内购");

    }

}

#pragma mark - SKProductsRequestDelegate

//接收到产品的返回信息,然后用返回的商品信息进行发起购买请求

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response NS_AVAILABLE_IOS(3_0)

{

    NSArray *product = response.products;

    //如果服务器没有产品

    if([product count] == 0){

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

        return;

    }

    SKProduct *requestProduct = nil;

    for (SKProduct *pro in product) {

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

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

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

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

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

        //如果后台消费条目的ID与我这里需要请求的一样(用于确保订单的正确性)

        if([pro.productIdentifier isEqualToString:@"bundleid+xxx"]){

            requestProduct = pro;

        }

    }

    //发送购买请求

    SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:requestProduct];

        payment.applicationUsername = userId;//可以是userId,也可以是订单id,跟你自己需要而定

    [[SKPaymentQueue defaultQueue] addPayment:payment];

}

#pragma mark - SKRequestDelegate

//请求失败

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error

{

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

}

//请求结束

- (void)requestDidFinish:(SKRequest *)request

{

    NSLog(@"请求结束");

}

#pragma mark - SKPaymentTransactionObserver

//监听购买结果

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

{

    for(SKPaymentTransaction *tran in transactions){

        switch (tran.transactionState) {

            case SKPaymentTransactionStatePurchased:

                NSLog(@"交易完成");

                [self completeTransaction:tran];

                break;

            case SKPaymentTransactionStatePurchasing:

                NSLog(@"商品添加进列表");

                break;

            case SKPaymentTransactionStateRestored:

                NSLog(@"已经购买过商品");

//                [[SKPaymentQueue defaultQueue] finishTransaction:tran]; 消耗型商品不用写

                break;

            case SKPaymentTransactionStateFailed:

                NSLog(@"交易失败");

                [[SKPaymentQueue defaultQueue] finishTransaction:tran];

                break;

            default:

                break;

        }

    }

}

//交易结束,当交易结束后还要去appstore上验证支付信息是否都正确,只有所有都正确后,我们就可以给用户方法我们的虚拟物品了。

- (void)completeTransaction:(SKPaymentTransaction *)transaction

{

    // 验证凭据,获取到苹果返回的交易凭据

    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址

    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];

    // 从沙盒中获取到购买凭据

    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];

    //发送POST请求,对购买凭据进行验证

    //测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt

    //正式验证地址:https://buy.itunes.apple.com/verifyReceipt

    NSURL *url = [NSURL URLWithString:AppStore_URL];

    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0f];

    urlRequest.HTTPMethod = @"POST";

    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

    _receipt = encodeStr;

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

    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];

    urlRequest.HTTPBody = payloadData;

    NSData *result = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];

    if (result == nil) {

        NSLog(@"验证失败");

        return;

    }

    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];

    NSLog(@"请求成功后的数据:%@",dic);

    //这里可以通过判断 state == 0 验证凭据成功,然后进入自己服务器二次验证,,也可以直接进行服务器逻辑的判断。

    //本地服务器验证成功之后别忘了 [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    NSString *productId = transaction.payment.productIdentifier;

    NSString *applicationUsername = transaction.payment.applicationUsername;

    NSLog(@"applicationUsername++++%@",applicationUsername);

    NSLog(@"payment.productIdentifier++++%@",productId);

    if (dic != nil) {

        userId = applicationUsername;

        //服务器二次验证

        [self vertifyApplePayRequestWith:transaction];

    }

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

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

注意:

1.内购必须用真机测试

2.测试时必须退出App Store自己的Apple ID,登录沙盒的测试Apple ID

————————————————

版权声明:本文为CSDN博主「Looking.」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_22080737/article/details/79786500

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容