iOS 内购最新讲解

一.总说内购的内容

协议、税务和银行业务 信息填写

内购商品的添加

添加沙盒测试账号

内购代码的具体实现

内购的注意事项

二.协议、税务和银行业务 信息填写

2.1、协议、税务和银行业务 信息填写 的入口

协议、税务和银行业务 信息填写 的入口

2.2、选择申请合同类型

进入协议、税务和银行业务页面后,会有3种合同类型,如果你之前没有主动申请过去合同,那么一般你现在激活的合同只有iOS Free Application一种。

页面内容分为两块:

Request Contracts(申请合同)

Contracts In Effect(已生效合同)。

合同类型分为3种:

iOS Free Application(免费应用合同)

iOS Paid Application(付费应用合同)

iAd App NetNetwork(广告合同)

这里我们主要主要讲一下付费应用合同的申请流程。

付费应用合同的申请流程

2.3、申请iOS Paid Application合同(协议、税务和银行业务3个都要填写)

协议、税务和银行业务

2.4、Contact Info(填写联系方式)

填写联系方式

如果你没有添加过联系人,你需要通过Add New Contact按钮来添加一个新的联系人。然后指定联系人的职务,

职务如下:

Senior Management:高管

Financial:财务

Technical:技术支持

Legal:法务

Marketing:市场推广

如果你是独立开发者,可以全部填你自己一个人。

2.5、填写银行信息

填写银行信息

选择你的银行账户,如果你没有,点击旁边的Add Bank Account添加一个账户。下面是添加一个账户的流程。

2.5.1、选择银行所在的国家

选择银行所在的国家

2.5.2、填写银行标识CNAPS Code

如果你不知道CNAPS Code是多少,可以百度搜CNAPS Code来查询,查询时会根据3个关键信息来查询,如下:

Bank Name:银行的英文名称(不能是拼音)

City:银行所在的城市英文名称(中国的城市用拼音)

Postal Code:邮编

然后在下面就会出来备选的银行,选择正确的银行后,点击next,进入下一步。

百度搜CNAPS Code来查询

银行信息的填写

2.5.3、确认银行信息

确认银行信息

2.5.4、填写银行账号信息

Bank Account Number:银行账号

Confirm Bank Account Number:再次输入银行账号

Account Holder Name:持卡人姓名,中文名用拼写,名在前,姓在后

Bank Account Currency:货币类型,一般国内的开发者选择CNY

填写银行账号信息

2.5.5、确认所有信息

确认所有信息

2.6.填写税务信息(这个内容比较多)

2.6.1.税务信息这一块了解不是很多,不过因为是国内开发者,可以不用太费心,税务信息分3种:

U.S Tax Forms: 美国税务

Australia Tax Forms:澳大利亚税务

Canada Tax Forms: 加拿大税务

税务信息

2.6.2.一堆条约

我选择的是U.S Tax Forms,选择后会问你两个问题:

第1个问题如下:询问你是否是美国居民,有没有美国伙伴关系或者美国公司,如果没有直接选择No。

询问你是否是美国居民,有没有美国伙伴关系或者美国公司,如果没有直接选择No

接下来第二个问题如下:询问你有没有在美国的商业性活动,没有也直接选No

接下来第二个问题如下:询问你有没有在美国的商业性活动,没有也直接选No

2.6.3.然后填写你的税务信息,包括以下几点:

Individual or Organization Name:个人或者组织名称

Country of incorporation: 所在国家

Type of Beneficial Owner:受益方式,独立开发者选个人

Permanent Residence:居住地址

Mailing address:邮寄地址

Name of Person Making this Declaration:声明人

Title:头衔

填写你的税务信息

2.6.4.打钩

打钩

2.6.5.澳大利亚的不要管了

澳大利亚的不要管了

2.6.6.加拿大的也不用管了

加拿大的也不用管了

2.7.填写完成

填写完成

2.8.待审核

你填写完所有资料后,合同状态就会变成Processing, 大概24小时内就会有结果。

三.内购商品的添加

3.1.创建内购商品

创建内购商品

3.2.选择内购类型

3.2.1.消耗型商品:类似游戏中的钻石,还有现在某些APP中的货币,比如斗鱼里的鱼丸、映客里的映票。会被消耗的,要选择消耗型商品

注意:大多数的消耗型商品都是需要登录的,因为需要在数据库存余额。

需要注意的是:在登录之前,你最好不要让用户看到商品,有可能会因为这个原因被拒(大家都说看运气)

3.2.2.非消耗型商品:无法被消耗的商品,比如上文提到的视频课程,一次购买,就应该永久可以观看

注意:当你使用非消耗型商品时,你需要添加一个恢复购买的按钮

这个常见于各种游戏中,其实知道这个规定以后还是挺好理解的,非消耗型商品是不可被消耗的,一次购买终身使用的,非消耗型的商品是跟appleId绑定的,就是你平时下载APP让你输入账号密码的内个。

你需要一个恢复购买的按钮,来让用户恢复他购买的内容

3.2.3.订阅类型商品:如果你的公司是外包公司,有订阅类型商品的APP一定要用客户的账号提交审核,因为当APP中有过订阅类型商品,注意是有过,创建过再删除也算,这个APP无法被转移账号

注意:使用或曾经使用过订阅型商品的APP无法转移

选择内购类型

具体内购类型

选择语言

FA40E42F-400E-4A85-949A-ED90C9B6B475.png

3.3.创建好的产品

创建好的产品

3.4.在上线的时候记得添加内购的商品

添加内购商品

选择内购产品之后的状态

四.添加沙盒测试账号

4.1.添加沙盒测试的入口

添加沙盒测试的入口

4.2.添加沙盒测试账号

添加沙盒测试账号

4.3.具体的测试账号信息填写

具体的测试账号信息填写

五.内购代码的具体实现(这才是大家所期望看到的)

5.1.我创建了一个购买金币的内购控制器ApplePayCIOViewController

在此,我仅仅向大家贴出.m的详细代码

5.2.内购的流程详细讲解

5.2.1. 用户先拿到购买产品的单子,

5.2.2.拿着单子去苹果那里交钱,交完钱让苹果在单子上盖个章

5.2.3.拿着盖了章的单子传给自己的服务器来验证是否真的支付成功

5.2.4.根据服务器返回的信息做具体的处理

内购的流程详细讲解

5.3.上代码

5.3.1.先导入StoreKit.framework库;

5.3.2.创建ApplePayCIOViewController,遵守协议

5.3.3.ApplePayCIOViewController.m代码

#import"ApplePayCIOViewController.h"

#import// 产品的ID

#define ProductID1 @"CIOCourses1"

@interfaceApplePayCIOViewController (){

NSString *selectProductID;

}

@end

@implementation ApplePayCIOViewController

-(void)viewWillAppear:(BOOL)animated{

[superviewWillAppear:animated];

// 添加观察者

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

-(void)viewWillDisappear:(BOOL)animated{

[superviewWillDisappear:animated];

// 移除观察者

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

}

- (void)viewDidLoad {

[superviewDidLoad];

self.title = @"内购";

self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"测试"style:UIBarButtonItemStylePlain target:self action:@selector(test)];

// 恢复购买的按钮

UIButton * revert = [[UIButton alloc]initWithFrame:CGRectMake(20,100,100,80)];

[revert setBackgroundColor:JKRandomColor];

[revert addTarget:self action:@selector(replyToBuy) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview: revert];

self.view.backgroundColor =[UIColor redColor];

}

#pragma mark 恢复购买(主要是针对非消耗产品)

-(void)replyToBuy{

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

}

#pragma mark 测试内购

-(void)test{

if([SKPaymentQueue canMakePayments]){

// productID就是你在创建购买项目时所填写的产品ID

selectProductID = [NSString stringWithFormat:@"%@",ProductID1];

[self requestProductID:selectProductID];

}else{

6

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

UIAlertView *alertError = [[UIAlertView alloc] initWithTitle:@"温馨提示"

message:@"请先开启应用内付费购买功能。"

delegate:nil

cancelButtonTitle:@"确定"

otherButtonTitles: nil];

[alertError show];

}

}

#pragma mark1.请求所有的商品ID

-(void)requestProductID:(NSString *)productID{

// 1.拿到所有可卖商品的ID数组

NSArray *productIDArray = [[NSArray alloc]initWithObjects:productID, nil];

NSSet *sets = [[NSSet alloc]initWithArray:productIDArray];

// 2.向苹果发送请求,请求所有可买的商品

// 2.1.创建请求对象

SKProductsRequest *sKProductsRequest = [[SKProductsRequest alloc]initWithProductIdentifiers:sets];

// 2.2.设置代理(在代理方法里面获取所有的可卖的商品)

sKProductsRequest.delegate = self;

// 2.3.开始请求

[sKProductsRequest start];

}

#pragma mark2.苹果那边的内购监听

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

NSLog(@"可卖商品的数量=%ld",response.products.count);

NSArray *product = response.products;

if([product count] ==0){

NSLog(@"没有商品");

return;

}

for(SKProduct *sKProductinproduct) {

NSLog(@"pro info");

NSLog(@"SKProduct 描述信息:%@", sKProduct.description);

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

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

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

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

if([sKProduct.productIdentifier isEqualToString: selectProductID]){

[self buyProduct:sKProduct];

break;

}else{

//NSLog(@"不不不相同");

}

}

}

#pragma mark 内购的代码调用

-(void)buyProduct:(SKProduct *)product{

// 1.创建票据

SKPayment *skpayment = [SKPayment paymentWithProduct:product];

// 2.将票据加入到交易队列

[[SKPaymentQueue defaultQueue] addPayment:skpayment];

// 3.添加观察者,监听用户是否付钱成功(不在此处添加观察者)

//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

#pragma mark4.实现观察者监听付钱的代理方法,只要交易发生变化就会走下面的方法

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

/*

SKPaymentTransactionStatePurchasing,    正在购买

SKPaymentTransactionStatePurchased,     已经购买

SKPaymentTransactionStateFailed,        购买失败

SKPaymentTransactionStateRestored,      回复购买中

SKPaymentTransactionStateDeferred       交易还在队列里面,但最终状态还没有决定

*/

for(SKPaymentTransaction *transactionintransactions) {

switch(transaction.transactionState) {

caseSKPaymentTransactionStatePurchasing:{

NSLog(@"正在购买");

}break;

caseSKPaymentTransactionStatePurchased:{

NSLog(@"购买成功");

// 购买后告诉交易队列,把这个成功的交易移除掉

[queue finishTransaction:transaction];

[self buyAppleStoreProductSucceedWithPaymentTransactionp:transaction];

}break;

caseSKPaymentTransactionStateFailed:{

NSLog(@"购买失败");

// 购买失败也要把这个交易移除掉

[queue finishTransaction:transaction];

}break;

caseSKPaymentTransactionStateRestored:{

NSLog(@"回复购买中,也叫做已经购买");

// 回复购买中也要把这个交易移除掉

[queue finishTransaction:transaction];

}break;

caseSKPaymentTransactionStateDeferred:{

NSLog(@"交易还在队列里面,但最终状态还没有决定");

}break;

default:

break;

}

}

}

// 苹果内购支付成功

- (void)buyAppleStoreProductSucceedWithPaymentTransactionp:(SKPaymentTransaction *)paymentTransactionp {

NSString * productIdentifier = paymentTransactionp.payment.productIdentifier;

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

NSString *transactionReceiptString= nil;

//系统IOS7.0以上获取支付验证凭证的方式应该改变,切验证返回的数据结构也不一样了。

NSString *version = [UIDevice currentDevice].systemVersion;

if([version intValue] >=7.0){

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

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

NSURLRequest * appstoreRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle]appStoreReceiptURL]];

NSError *error = nil;

NSData * receiptData = [NSURLConnection sendSynchronousRequest:appstoreRequest returningResponse:nil error:&error];

transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

}else{

NSData * receiptData = paymentTransactionp.transactionReceipt;

//  transactionReceiptString = [receiptData base64EncodedString];

transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

}

// 去验证是否真正的支付成功了

[self checkAppStorePayResultWithBase64String:transactionReceiptString];

}

- (void)checkAppStorePayResultWithBase64String:(NSString *)base64String {

/* 生成订单参数,注意沙盒测试账号与线上正式苹果账号的验证途径不一样,要给后台标明 */

/*

注意:

自己测试的时候使用的是沙盒购买(测试环境)

App Store审核的时候也使用的是沙盒购买(测试环境)

上线以后就不是用的沙盒购买了(正式环境)

所以此时应该先验证正式环境,在验证测试环境

正式环境验证成功,说明是线上用户在使用

正式环境验证不成功返回21007,说明是自己测试或者审核人员在测试

*/

/*

苹果AppStore线上的购买凭证地址是:https://buy.itunes.apple.com/verifyReceipt

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

*/

//    NSNumber *sandbox;

NSString *sandbox;

#if(defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX) && defined(DEBUG))

//sandbox = @(0);

sandbox = @"0";

#else

//sandbox = @(1);

sandbox = @"1";

#endif

NSMutableDictionary *prgam = [[NSMutableDictionary alloc] init];;

[prgam setValue:sandbox forKey:@"sandbox"];

[prgam setValue:base64String forKey:@"reciept"];

/*

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

0 代表沙盒  1代表 正式的内购

最后最验证后的

*/

/*

内购验证凭据返回结果状态码说明

21000 App Store无法读取你提供的JSON数据

21002 收据数据不符合格式

21003 收据无法被验证

21004 你提供的共享密钥和账户的共享密钥不一致

21005 收据服务器当前不可用

21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中

21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证

21008 收据信息是产品环境中使用,但却被发送到测试环境中验证

*/

NSLog(@"字典==%@",prgam);

}

#pragma mark 客户端验证购买凭据

- (void)verifyTransactionResult

{

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

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

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

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

NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];

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

/**

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

BASE64是可以编码和解码的

*/

NSDictionary *requestContents = @{

@"receipt-data": [receipt base64EncodedStringWithOptions:0]

};

NSError *error;

// 转换为 JSON 格式

NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents

options:0

error:&error];

// 不存在

if(!requestData) {/* ... Handle error ... */}

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

NSString *verifyUrlString;

#if(defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX) && defined(DEBUG))

verifyUrlString = @"https://sandbox.itunes.apple.com/verifyReceipt";

#else

verifyUrlString = @"https://buy.itunes.apple.com/verifyReceipt";

#endif

// 国内访问苹果服务器比较慢,timeoutInterval 需要长一点

NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:[[NSURL alloc] initWithString:verifyUrlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];

[storeRequest setHTTPMethod:@"POST"];

[storeRequest setHTTPBody:requestData];

// 在后台对列中提交验证请求,并获得官方的验证JSON结果

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue

completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

if(connectionError) {

NSLog(@"链接失败");

}else{

NSError *error;

NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0error:&error];

if(!jsonResponse) {

NSLog(@"验证失败");

}

// 比对 jsonResponse 中以下信息基本上可以保证数据安全

/*

bundle_id

application_version

product_id

transaction_id

*/

NSLog(@"验证成功");

}

}];

}

@end

六.内购的注意事项

6.1.一般发生于首次提交app或添加新商品,当你的app通过审核以后,你发现在生产环境下获取不到商品,这是因为app虽然过审核了,但是内购商品还没有正式添加到苹果的服务器里,耐心等待一段时间就可以啦~

6.2. 代码中的_currentProId所填写的是你的购买项目的的ID,这个和第二步创建的内购的productID要一致;本例中是 123。

6.3. 在监听购买结果后,一定要调用[[SKPaymentQueue defaultQueue] finishTransaction:tran];来允许你从支付队列中移除交易。

6.4. 沙盒环境测试appStore内购流程的时候,请使用没越狱的设备。

6.5. 请务必使用真机来测试,一切以真机为准。

6.6. 项目Bundle identifier需要与您申请AppID时填写的bundleID一致,不然会无法请求到商品信息。

6.7. 真机测试的时候,一定要退出原来的账号,才能用沙盒测试账号

6.8. 二次验证,请注意区分宏, 测试用沙盒验证,App Store审核的时候也使用的是沙盒购买,所以验证购买凭证的时候需要判断返回Status Code决定是否去沙盒进行二次验证,为了线上用户的使用,验证的顺序肯定是先验证正式环境,此时若返回值为21007,就需要去沙盒二次验证,因为此购买的是在沙盒进行的。

6.9.您的应用是否处于等待开发者发布(Pending Developer Release)状态?等待发布状态的IAP是无法测试的。

6.10.您的内购项目是否是最近才新建的,或者进行了更改?内购项目需要一段时间才能反应到所有服务器上,这个过程一般是一两小时,也可能再长一些达到若干小时。

6.11.您在iTC中Contracts, Tax, and Banking Information项目中是否有还没有设置或者过期了的项目?不完整的财务信息无法进行内购测试。

6.12.您是在越狱设备上进行内购测试么?越狱设备不能用于正常内购,您需要重装或者寻找一台没有越狱的设备。

6.13.您的应用是否是被拒状态(Rejected)或自己拒绝(Developer Rejected)了?被拒绝状态的应用的话对应还未通过的内购项目也会一起被拒,因此您需要重新将IAP项目设为Cleared for Sale。

6.14.您使用的测试账号是否是美国区账号?虽然不是一定需要,但是鉴于其他地区的测试账号经常抽风,加上美国区账号一直很稳定,因此强烈建议使用美国区账号。正常情况下IAP不需要进行信用卡绑定和其他信息填写,如果你遇到了这种情况,可以试试删除这个测试账号再新建一个其他地区的。

6.15.您是否将设备上原来的app删除了,并重新进行了安装?记得在安装前做一下Clean和Clean Build Folder。

6.16.您的plist中的Bundle identifier的内容是否和您的AppID一致?

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

推荐阅读更多精彩内容

  • 公司项目中有虚拟产品,所以要使用苹果内购.自此记录一下苹果内购的流程.前提是已有开发者账号 协议,税务和银行业务 ...
    better栋阅读 1,963评论 0 7
  • 自己开发的视频直播项目,牵涉到充值金币,用到了苹果公司的内购,趴坑了两天,这里总结下实现苹果内购。 一. 创建测试...
    Leo丶Dicaprio阅读 3,247评论 8 7
  • iOS应用如果涉及到支付功能,分为两类:第三方支付和苹果内购。那么什么情况下选择使用第三方支付,又在什么情况下选择...
    ZfRee阅读 38,316评论 36 66
  • 刚刚看完<心理追凶>,还没有缓过来,新浪微博上就有江歌刘鑫事件,觉得世界上真有这么自私的人,还不要脸,交朋友真...
    芸飘燃阅读 310评论 0 0
  • 我的梦想是成为一棵树。我的人生,便要是从一粒种子到一根树苗,到一棵小树,再到一棵大树的过程。 「树」,是关于我如何...
    心智学徒H阅读 1,447评论 2 7