title: ios-iap应用内购接入
categories: Ios
tags: [ios, iap, 内购, 苹果支付]
date: 2021-03-26 16:51:37
comments: false
mathjax: true
toc: true
ios-iap应用内购接入
前篇
- 官方
- App 内购买项目信息 - https://help.apple.com/app-store-connect/#/dev84b80958f
- 接入Apple Pay流程 - https://juejin.cn/post/6844904001897512967
- iOS内购(IAP)模块总结 - https://www.jianshu.com/p/bf7e42a3c73b
- iOS的应用内支付In-app purchase的开发 - http://blog.hudongdong.com/ios/868.html
- 2019最新iOS内购流程基本配置篇 - https://www.jianshu.com/p/94fa6793b197
- apple苹果IOS内购申请教程协议、税务和银行业务配置
前置条件
-
协议是 active 状态, https://appstoreconnect.apple.com/agreements/#/
-
产品 id 是 非 元数据丢失 状态
流程
-
先创建个沙盒测试人员, 测试时不会真实扣钱. https://appstoreconnect.apple.com/access/testers
-
内购代码
#import "IapHelper.h" #import "NetTool.h" #import "NSString+MyExt.h" #import <Foundation/Foundation.h> #import <StoreKit/StoreKit.h> #import <YYModel/YYModel.h> @interface IapHelper()<SKProductsRequestDelegate, SKPaymentTransactionObserver> @property (strong, nonatomic) CodeMsgFn _Nullable cb; @end @implementation IapHelper static IapHelper *_sharedIns = nil; +(instancetype) shareInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sharedIns = [[self alloc] init] ; [[SKPaymentQueue defaultQueue] addTransactionObserver:_sharedIns]; }) ; return _sharedIns ; } // 内扣接口 - (void)getById:(NSString *)prodId cb:(CodeMsgFn)cb { if (![SKPaymentQueue canMakePayments]) { cb(ECodeSupportError, @"--- cant pay"); return; } self.cb = cb; NSSet *set = [NSSet setWithObjects:prodId, nil]; SKProductsRequest * request = [[SKProductsRequest alloc] initWithProductIdentifiers:set]; request.delegate = self; [request start]; } // 客户端校验 receipt, 测试使用 -(void)verify:(NSString*)url cb:(CodeMsgFn)cb { NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSData *receipt = [NSData dataWithContentsOfURL:recepitURL]; NSDictionary *requestContents = @{@"receipt-data": [receipt base64EncodedStringWithOptions:0]}; [NetTool httpPostAsync:url json:[requestContents yy_modelToJSONString] callback:^(CHttpJsonRsp * _Nonnull rsp) { cb(ECodeOk, [rsp yy_modelToJSONString]); }]; } -(void)doCallback:(ECode)code msg:(NSString*)msg{ if (self.cb) { self.cb(code, msg); self.cb = nil; } } // ------------------------------- 实现 SKProductsRequestDelegate 的接口 - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { if (response.products.count == 0) { [self doCallback:ECodeTaskError msg:@"--- products count is 0"]; return; } SKProduct* product = response.products[0]; SKMutablePayment *payMent = [SKMutablePayment paymentWithProduct:product]; payMent.quantity = 1; payMent.applicationUsername = @"orderId_001"; // 透传参数 [[SKPaymentQueue defaultQueue] addPayment:payMent]; } // ------------------------------- 实现 SKPaymentTransactionObserver 的接口 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions { if (transactions.count == 0) { [self doCallback:ECodeLoginError msg:@"--- transactions count is 0"]; return; } SKPaymentTransaction* transaction = transactions[0]; switch (transaction.transactionState) { case SKPaymentTransactionStatePurchased: [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; [self doCallback:ECodeOk msg:@"--- pay success"]; break; case SKPaymentTransactionStateFailed: [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; [self doCallback:ECodeCancel msg:@"--- SKPaymentTransactionStateFailed"]; break; default: break; } } @end
验证 receipt
- 参考: https://developer.apple.com/cn/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store/
- 生产环境 url: https://buy.itunes.apple.com/verifyReceipt
- 沙盒环境 url: https://sandbox.itunes.apple.com/verifyReceipt
验证流程: 先使用生产环境 url 去验证, 如果返回的 status 为 0, 表示是生成环境产生的正式购买; 如果返回的 status 为 21007, 表示是 测试人员产生的测试购买, 弹窗会显示环境是 sandbox.
-
返回值
{ "receipt":{ "receipt_type":"ProductionSandbox", "adam_id":0, "app_item_id":0, "bundle_id":"aaa.bbb.com", "application_version":"1", "download_id":0, "version_external_identifier":0, "receipt_creation_date":"2021-03-29 09:46:49 Etc/GMT", "receipt_creation_date_ms":"1617011209000", "receipt_creation_date_pst":"2021-03-29 02:46:49 America/Los_Angeles", "request_date":"2021-03-29 09:46:54 Etc/GMT", "request_date_ms":"1617011214550", "request_date_pst":"2021-03-29 02:46:54 America/Los_Angeles", "original_purchase_date":"2013-08-01 07:00:00 Etc/GMT", "original_purchase_date_ms":"1375340400000", "original_purchase_date_pst":"2013-08-01 00:00:00 America/Los_Angeles", "original_application_version":"1.0", "in_app":[ { "quantity":"1", "product_id":"chips90", "transaction_id":"1000000123123123", "original_transaction_id":"1000000123123123", "purchase_date":"2021-03-29 09:46:48 Etc/GMT", "purchase_date_ms":"1617011208000", "purchase_date_pst":"2021-03-29 02:46:48 America/Los_Angeles", "original_purchase_date":"2021-03-29 09:46:48 Etc/GMT", "original_purchase_date_ms":"1617011208000", "original_purchase_date_pst":"2021-03-29 02:46:48 America/Los_Angeles", "is_trial_period":"false" } ] }, "environment":"Sandbox", "status":0 // 0 就是成功的标记 }
踩坑
产品状态 元数据丢失
需要填写 审核信息, 包裹 截图 和 备注, 状态就会修改为 准备提交
拉取 产品 id 为空
可以以下几个原因
-
产品状态是 元数据丢失, 不是 准备提交
-
付费 app 协议没有同意, 需要同意后才行 (需要账户持有人才能同意, 协作伙伴不行), 状态是 有效 状态才行.
https://appstoreconnect.apple.com/agreements/#/
付费 app 协议 地址错误
付费 app 协议 同意前可能遇到 地址错误要修正, 报错: The address entered appears to be invalid.
报这样的错只要提交三次就行了, 这是什么鬼操作.
第一填写比如: (第一行加个 # 号, 第三行不用填)
Address
# FLAT 501,MAPPLE CELESTIA,PLOT 49,
JAY ABHERI ENCLAVE,GACHIBOWLI,HYDERABAD,
参考: https://stackoverflow.com/questions/43922778/the-address-entered-appears-to-be-invalid-please-correct-your-address-and-resu