iOS内购—— In-App Purchase(消耗型)

iOS应用如果涉及到支付功能,分为两类:第三方支付和苹果内购。那么什么情况下选择使用第三方支付,又在什么情况下选择苹果内购呢?让我们先来简单了解一下:

Understanding What You Can Sell Using In-App Purchase

You can use In-App Purchase to sell content, app functionality, and services.

App functionality.Unlock behavior and expand features you’ve already delivered. Examples include a free game that offers multiplayer mode as an in-app purchase and a free weather app that lets users make a one-time purchase to remove ads.

Services.Have users pay for one-time services such as voice transcription and for ongoing services such as access to a collection of data.

You can’t use In-App Purchase to sell real-world goods and services or to sell unsuitable content.

Real-world goods and services.You must deliver a digital good or service within your app when using In-App Purchase. Use a different payment mechanism to let your users buy real-world goods and services in your app, such as a credit card or payment service.

Unsuitable content.Don’t use In-App Purchase to sell content that the isn’t allowed by the App Review Guidelines—for example, pornography, hate speech, or defamation.

开发文档的这里:Understanding What You Can Sell Using In-App Purchase

开发者中心的这里:https://developer.apple.com/app-store/review/guidelines/#payments

```

购买的内容如果要在 app 内部使用,必须使用 IAP ,但是你要买的东西与 app 本身无关,就不能使用 IAP 。For Example:你用淘宝、京东的 app 买个鼠标,真实物品就不能使用IAP。但是要想在斗鱼app内买虚拟物品来送主播礼物,则必须使用 IAP ,不走内购就不行。

```


一、先到iTunes Connect上填写协议、税务和银行业务


如果你是外包公司,那么你可以让你的客户填写这一堆信息;如果你只是是产品公司的技术开发人员,那么你可以让项目负责人填写这一堆信息;如果没有如果,兄弟辛苦了,自己动手来吧。

第一步


第二步


第三步


第四步


第五步


先点击Contact Info 的Set Up

第六步


第七步


第八步


第九步


第十步


第十一步


第十二步

进行十二步的时候可能有些银行通过下面的Look up CNAPS Code方法查不到,就需要借助百度了,一定要准确查询,否则会有问题。推荐一个地址

https://e.czbank.com/CORPORBANK/query_unionBank_index.jsp

第十三步


这一步需要注意的是,货币类型可能有歧义,看你是想收美元还是人民币了,都说美元合适。不过,我做的时候为了避免事情,还是选择了CNY,支持国产。还有一点,银行账号如果是对公的账号,需要填写公司的英文名称,如果没有的话,上拼音!然后点击保存银行信息就算ok了,然后退回到最开始的页面

第十四步


第十五步


第十六步


第十七步


第十八步


第十九步


第二十步


第二十一步(完成)


二、为app添加内购产品

在iTunes Connect在你要添加内购的app中,进入到功能页面

添加内购项目


在你点击添加内购产品按钮后会有弹框,提示你选择类型,这个就要看你app的需求了

选择类型


名称和定价
本地化版本(可以“+”添加语言)
填写审核信息(现在的图)

填写完审核信息后,点击右上角的“存储”按钮,就添加了一个内购产品~


三、添加沙盒技术测试员

在iTunes Connect的用户和智能中选择“沙盒技术测试员”,填写信息保存以后就有一个测试员了

添加沙盒测试员


四、代码部分

首先是.h文件

#import <UIKit/UIKit.h>

#import <StoreKit/StoreKit.h>

#import "MBProgressHUD.h"


@interface GiftChartViewController :UIViewController<SKPaymentTransactionObserver,SKProductsRequestDelegate>

@end

然后是.m文件


//下面的字符串就是你在iTunes Connect上的内购项目的产品ID,

static const NSString *productCoin60 =@"随便写的60";

static const NSString *productCoin300 =@"随便写的300";

static const NSString *productCoin600 =@"随便写的600";

static const NSString *productCoin980 =@"随便写的980";

static const NSString *productCoin1280 =@"随便写的1280";

static const NSString *productCoin2580 =@"随便写的2580";


typedefNS_ENUM(NSInteger,coinType) {

coinType60,/** 60金币*/

coinType300,/** 300金币*/

coinType600,/** 600金币*/

coinType980,/** 980金币*/

coinType1280,/** 1280金币*/

coinType2580/** 2580金币*/

};


#pragma mark - lifecycle

- (void)viewDidLoad {

[super viewDidLoad];

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

//支付的点击事件

- (void)payAction:(id)sender{

NSLog(@"pay pay pay");

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

if([SKPaymentQueue canMakePayments]) {

[self requestProductData];

}else{

//做一些提示

}

}

- (void)requestProductData{

NSArray *product;

switch(_buyCoinType) {

case:coinType60:

product =@[productCoin60];

break;

case:coinType300:

product =@[productCoin300];

break;

case:coinType600:

product =@[productCoin600];

break;

case:coinType980:

product =@[productCoin980];

break;

case:coinType1280:

product =@[productCoin1280];

break;

case:coinType2580:

product =@[productCoin2580];

break;

default:

break;

}

NSLog(@"请求的产品%@",product);

NSSet *nsset = [NSSet setWithArray:product];

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

request.delegate =self;

[request start];

[MBProgressHUD showHUDAddedTo:self.view animated:YES];

}


#pragma mark - SKProductsRequestDelegate

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

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

NSArray *myProduct = response.products;

NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);

NSLog(@"产品付费数量: %d", (int)[myProduct count]);

// populate UI

for(SKProduct *productinmyProduct){

NSLog(@"product info");

NSLog(@"SKProduct描述信息%@", [product description]);

NSLog(@"产品标题%@", product.localizedTitle);

NSLog(@"产品描述信息: %@", product.localizedDescription);

NSLog(@"价格: %@", product.price);

NSLog(@"Product id: %@", product.productIdentifier);

[MBProgressHUD hideHUDForView:self.view animated:YES];

SKPayment *payment = [SKPayment paymentWithProduct:product];

[[SKPaymentQueue defaultQueue] addPayment:payment];

//addPayment 将支付信息添加进苹果的支付队列后,苹果会自动完成后续的购买请求,在用户购买成功或者点击取消购买的选项后回调

}

//payment = [SKPayment paymentWithProductIdentifier:coin60];这个方法不要使用了

//+ (id)paymentWithProductIdentifier:(NSString*)identifier NS_DEPRECATED_IOS(3_0,5_0,"Use +paymentWithProduct: after fetching the available products using SKProductsRequest");

};

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

NSLog(@"------------------错误-----------------:%@", error);

}

- (void)requestDidFinish:(SKRequest *)request{

NSLog(@"------------反馈信息结束-----------------");

}


//监听购买结果的回调

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

for(SKPaymentTransaction *tranintransaction){

switch(tran.transactionState) {

case:SKPaymentTransactionStatePurchased:{

NSLog(@"交易完成");

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

[self verifyTransactionResult];

break;

 }

case:SKPaymentTransactionStatePurchasing:

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

break;

case:SKPaymentTransactionStateRestored:

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

break;

case:SKPaymentTransactionStateFailed:{

NSLog(@"交易失败");

[MyTaShowMessageView showMessage:@"交易失败!"];

[[SKPaymentQueue defaultQueue] finishTransaction:tran];

break;

}

default:

break;

}

}

}

- (void)dealloc{

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

}


购买成功后我们iOS前端可以单独在客户端完成订单正确性的验证。但是因为有的项目后台要Android和iOS两端生成账单便于对账。所以我们请求后台接口,服务器处验证是否支付成功,依据后台返回结果做相应逻辑处理。

(PS:订单正确性的验证本来可以是:iOS客户端(购买成功)→ 前端到苹果服务器验证→处理苹果返回结果做相应逻辑处理; 现在:iOS客户端(购买成功)→ 后台→后台到苹果服务器验证→处理后台返回结果做相应逻辑处理)

服务器要做的是:

1.接收iOS前端发过来的购买凭证。

2.判断凭证是否已经存在或验证过,然后存储该凭证。

3.将该凭证发送到对应环境下的苹果服务器验证,并将验证结果返回给客户端。

4.根据需求,是否修改用户相应信息。

官方文档应该也是支持的这么做的→In-App Purchase Programming Guide

- (void)verifyTransactionResult{

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

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

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

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

NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];

//传输的是BASE64编码的字符串

/**

BASE64常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性,BASE64是可以编码和解码的。

*/

NSDictionary *requestDict =@{@"receipt-data": [receipt base64EncodedStringWithOptions:0],@"sandbox":@"1"};

/**

请求后台接口,服务器处验证是否支付成功,依据返回结果做相应逻辑处理

与后台协调好,让后台根据你的“sandbox”字段的1,0来区分请求是正式环境还是测试环境

(当然“sandbox”这个字段也可以替换为你想要的,但是“receipt-data”不能替换,要注意!)

详情点这里→苹果官方文档

*/

//请求成功的response自己输出看一下吧,status是0就成功了,这里就不贴出来了,因为有一些敏感数据,比如你的bundleID,product_id之类的

}

下面是两种环境下的苹果服务器验证地址

// Create a POST request with the receipt data.

//In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt

//In the real environment, use https://buy.itunes.apple.com/verifyReceipt

到这里最基本的内购流程就可以跑通了~

五、要注意的事项!

1.bundleID要与iTunes Connect上你App的相同,不然是请求不到产品信息的

2.在沙盒环境进行测试内购的时候,要使用没有越狱的苹果手机。

3.在沙盒环境下真机测试内购时,请去app store中注销你的apple ID,不然发起支付购买请求后会直接case:SKPaymentTransactionStateFailed。使用沙盒测试员的账号时不需要真正花钱的。

4.如果只添加了一个沙盒测试员账号,当一个真机已经使用了这个账号,另一个真机再使用这个账号支付也是会发生错误的。那就去多建几个沙盒测试员账号使用不同的,反正也是免费的,填写也很快。

5.监听购买结果,当失败和成功时代码中要调用:

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

该方法通知苹果支付队列该交易已完成,不然就会已发起相同 ID 的商品购买就会有此项目将免费恢复的提示。


六、请在本地做一下凭证存储!

现在订单正确性的验证是:iOS客户端(购买成功)→ 后台→后台到苹果服务器验证→处理后台返回结果做相应逻辑处理。

头疼的情况

针对图上的情况:当我们前端购买成功后,凭证本地保留一份,当与后台验证成功后,再将本地保留的凭证删除。否者一直使用本地已经保留的凭证与后台交互。


七、最后

在第一节 :先到iTunes Connect上填写协议、税务和银行业务中,因为我自己的开发者账号已经填写过一遍这个信息了,步骤无法复现。所以在征得简书作者:睡不着的叶-《iOS开发 内购流程 手把手教你还不学?》的同意后,转用了部分图片,在此表示感谢。


写的第一篇文章,写的不好的地方,大家多多包涵,在作为iOS开发者的路上我们一起奔跑~

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

推荐阅读更多精彩内容

  • iOS应用内付费(IAP)开发步骤 1.苹果iTunes Connect内购产品信息录入。 1)创建app内购买项...
    MillerWang阅读 10,468评论 0 7
  • iOS支付 iOS支付分为两类,第三方支付和应用内支付(内购)。 第三方支付包括:支付宝支付、微信支付、银联支付、...
    请输入账号名阅读 6,081评论 3 22
  • 在我们应用开发中我们经常在自己的项目中使用到支付,下面我们来谈谈iOS这块的支付;iOS支付主要分为两类,第三方支...
    Hither阅读 8,105评论 9 42
  • 是运气也好,天道酬勤也罢,前天下午,中国队在中国杯上打破了国家队552分钟的进球荒,同时在点球大战中依仗门...
    十三猫叔阅读 384评论 0 3
  • 上一篇介绍“网游动作设计师”的推文一推出,后台就有不少“小鲜肉”给我留言了:“张官,我们倒是想把游戏当成职业,...
    张官礼待阅读 654评论 0 1