蘋果支付
一:綁定銀行卡visa卡 參考鏈接
二:創(chuàng)建內(nèi)購產(chǎn)品 :app里面的功能 參考鏈接
三:創(chuàng)建沙盒測試賬戶:Itunes里面用戶和職能。參考鏈接
四:購買代碼塊 參考鏈接
+(instancetype)share{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
applePay = [[AHApplePay alloc]init];
});
if (applePay.myProducts.count == 0) {
[applePay getPurchaseGoodsList];
}
return applePay;
}
//獲取商品列表
-(void)getPurchaseGoodsList{
if ([SKPaymentQueue canMakePayments]) {
//此處內(nèi)購商品編碼是虛構(gòu)的 ?????
NSString *productPath = [[NSBundle mainBundle] pathForResource:@"productIDS" ofType:@"plist"];
NSArray *products = [NSArray arrayWithContentsOfFile:productPath];
[self getProductInfo:products];
}else{
if (_cannotPurchaseBlock) {
_cannotPurchaseBlock(nil,@"失敗,用戶禁止應(yīng)用內(nèi)付費購買");
}
}
}
//購買商品
-(void)purchaseGoods:(id)goods{
[self purchaseGoodsWithApplePurchase:goods];
}
//蘋果支付
-(void)purchaseGoodsWithApplePurchase:(id)goods{
NSString *identify = (NSString*)goods;
SKProduct *paymentPay = nil;
for (SKProduct *payment in self.myProducts) {
if ([payment.productIdentifier isEqualToString:identify]) {
paymentPay = payment;
}
}
if (paymentPay == nil) {
return;
}
//1.發(fā)起一個購買操作
SKPayment *payment = [SKPayment paymentWithProduct:paymentPay];
if (payment == nil) {
return;
}
// 2.將票據(jù)加到到交易隊列中
[[SKPaymentQueue defaultQueue] addPayment:payment];
//3.觀察交易隊列中交易發(fā)生的改變
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
//購買 根據(jù)在plist文件位置
-(void)applePay:(NSInteger)idx{
NSString *productPath = [[NSBundle mainBundle] pathForResource:@"productIDS" ofType:@"plist"];
NSArray *products = [NSArray arrayWithContentsOfFile:productPath];
if (idx<products.count) {
NSString *identify = products[idx];
[self.myProducts enumerateObjectsUsingBlock:^(SKProduct *payment, NSUInteger idx, BOOL * _Nonnull stop) {
if ([payment.productIdentifier isEqualToString:identify]) {
//1.發(fā)起一個購買操作
SKPayment *paymentPro = [SKPayment paymentWithProduct:payment];
// 2.將票據(jù)加到到交易隊列中
[[SKPaymentQueue defaultQueue] addPayment:paymentPro];
//3.觀察交易隊列中交易發(fā)生的改變
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
}];
}
}
//通過該IAP的Product ID向App Store查詢,獲取SKPayment實例,接著通過SKPaymentQueue的addPayment方法發(fā)起一個購買的操作
//下面的ProductId應(yīng)該是事先在itunesConnect中添加好的,已存在的付費項目,否則會查詢失敗
-(void)getProductInfo:(NSArray *)productIds{
NSSet *set = [NSSet setWithArray:productIds];
_applePurchaseRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
_applePurchaseRequest.delegate = self;
[_applePurchaseRequest start];
}
#pragma mark - SKProductsRequestDelegate
//查詢的回調(diào)函數(shù) -----獲取可銷售的商品,并且排序
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
//獲取到的所有內(nèi)購商品
NSArray *myProducts = response.products;
//判斷個數(shù)
if (myProducts.count==0) {
if (_failureBlock) {
_failureBlock(nil,@"無法獲取產(chǎn)品信息,購買失敗。");
}
NSLog(@"無法獲取產(chǎn)品信息,購買失敗。");
return;
}else{
self.myProducts = myProducts;
}
//刷新、配置UI ???
#warning 發(fā)起一個購買操作
// //1.發(fā)起一個購買操作
// SKPayment *payment = [SKPayment paymentWithProduct:myProducts[self.purchaseGoodsNumber]];
// // 2.將票據(jù)加到到交易隊列中
// [[SKPaymentQueue defaultQueue] addPayment:payment];
// //3.觀察交易隊列中交易發(fā)生的改變
// [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
#pragma mark - SKPaymentTransactionObserver
//當(dāng)用戶購買的操作有結(jié)果時,就會觸發(fā)下面的回調(diào)函數(shù),相應(yīng)進行處理
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased: //交易完成
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed: //交易失敗
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored: //已經(jīng)購買過該商品
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing: //商品添加進列表
LOG(@"商品添加進列表");
break;
default:
break;
}
}
}
//交易完成后的操作
-(void)completeTransaction:(SKPaymentTransaction *)transaction{
NSString * productIdentifier = transaction.payment.productIdentifier;
// NSURL *url = [[NSBundle mainBundle] appStoreReceiptURL];
// NSData *transactionReceiptData = [NSData dataWithContentsOfURL:url];
// NSString *receipt = [transactionReceiptData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSData *data = transaction.transactionReceipt;
NSString * receipt = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
[[NSUserDefaults standardUserDefaults]setObject:receipt forKey:@"receipt"];
[[NSUserDefaults standardUserDefaults] synchronize];
if ([productIdentifier length]>0 && !TestStringIsBlank(receipt)) {
//向自己的服務(wù)器驗證購買憑證????
AHPersonInfoModel *infoModel = [AHPersonInfoManager share].infoModel;
NSDictionary *dic = @{@"uid":@(infoModel.uid),@"token":infoModel.token,@"orderid":receipt};
[AHRequestTool applepay:dic succussBlock:^(AHBaseModel *baseModel) {
LOG(@"%@",baseModel);
if (self.successfulBlock) {
self.successfulBlock(nil, nil);
self.successfulBlock = nil;
}
} failureBlock:^(NSString *errorStr) {
if (self.failureBlock) {
self.failureBlock(nil, nil);
self.failureBlock = nil;
}
}];
//創(chuàng)建描述請求的JSON對象
NSError *error;
NSDictionary * requestContents = @{@"receipt-data":receipt,@"password":@"7ad47dcb6de94b08aa3ac3b7dd0d55f8",@"exclude-old-transactions":@(YES)};
NSData * requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0 error:&error];
if(!requestData){
//錯誤處理
}
//創(chuàng)建帶有收據(jù)數(shù)據(jù)的POST請求。
NSURL * storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest * storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
//在后臺隊列上連接到iTunes Store。
NSOperationQueue * queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
completionHandler:^(NSURLResponse * response,NSData * data,NSError * connectionError){
if(connectionError){
//錯誤處理
} else {
NSError *error;
NSDictionary * jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if(jsonResponse){
//驗證
LOG(@"%@",jsonResponse);
}
}}];
}
//移除transaction購買操作
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
//交易失敗后的操作
-(void)failedTransaction:(SKPaymentTransaction *)transaction{
if (transaction.error.code != SKErrorPaymentCancelled) {
if (_failureBlock) {
_failureBlock(nil,@"購買失敗");
}
LOG(@"購買失敗");
}else{
if (_failureBlock) {
_failureBlock(nil,@"用戶取消交易");
}
LOG(@"用戶取消交易");
}
//移除transaction購買操作
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
//已經(jīng)購買過該商品
-(void)restoreTransaction:(SKPaymentTransaction *)transaction{
//對于已購買商品,處理恢復(fù)購買的邏輯
//移除transaction購買操作
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
五:蘋果支付驗證代碼塊,建議后臺驗證。
NSString *recept = [[NSUserDefaults standardUserDefaults]objectForKey:@"receipt"];
if (!recept) {
return;
}
//創(chuàng)建描述請求的JSON對象 只有訂閱型才有密碼設(shè)置。
NSError *error;
NSDictionary * requestContents = @{@"receipt-data":recept,@"password":@"7ad47dcb6de94b08aa3ac3b7dd0d55f8"};
NSData * requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0 error:&error];
if(!requestData){
//錯誤處理
}
//創(chuàng)建帶有收據(jù)數(shù)據(jù)的POST請求。
NSURL * storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest * storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
//在后臺隊列上連接到iTunes Store。
NSOperationQueue * queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
completionHandler:^(NSURLResponse * response,NSData * data,NSError * connectionError){
if(connectionError){
//錯誤處理
} else {
NSError *error;
NSDictionary * jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if(jsonResponse){
//驗證
LOG(@"%@",jsonResponse);
}
}}];
內(nèi)購沙盒測試續(xù)訂周期時間不一樣,且一天測試次數(shù)大概6次,且自動續(xù)費一般失敗。

時間對應(yīng)關(guān)系
六 :上線注意事項(這里是以訂購為例)

購買協(xié)議連接或彈框一定要有

購買協(xié)議具體內(nèi)容
購買協(xié)議具體內(nèi)容:
一定要有:自動續(xù)費,可隨時取消。提前24續(xù)費,下個周期第一天可取消。app設(shè)置里面可取消訂購。協(xié)議里最好加上自己的公司。
NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:13],NSForegroundColorAttributeName:[UIColor blackColor]};
NSString *contentStr = @"* The cost of subscription for Super Powers is 2.99 USD for 7 days, 7.99 USD for 1 month, 19.99 USD for 3 months, and 49.99 USD for 1 year.\n\n* If you choose to purchase Super Powers, the payment will be charged to your iTunes account at confirmation of purchase.\n\n* Your subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period.\n\n* Account will be charged for renewal within 24-hours prior to the end of the current period, and the cost of the renewal would be the same as your first payment.\n\n* You can manage your auto-renewal and auto-renewal may be turned off by going to your Account Settings after purchase.\n\n* No cancellation of the current subscription is allowed during the active subscription period.\n\n* If you don't want to purchase Super Powers, you can simply continue using Dittor for free.\n\n* Any unused portion of a free trial period, if offered, will be forfeited when you purchase a subscription to that publication.\n\nhttp://godittor.com/terms.html\n\nhttp://godittor.com/privacy.html";
NSMutableAttributedString *contentAttr = [[NSMutableAttributedString alloc]initWithString:contentStr attributes:dic];
NSRange range = [contentStr rangeOfString:@"http://godittor.com/terms.html\n\nhttp://godittor.com/privacy.html"];
NSString *lin1 = @"http://godittor.com/terms.html";
NSString *lin2 = @"http://godittor.com/privacy.html";
NSRange range1 = [contentStr rangeOfString:lin1];
NSRange range2 = [contentStr rangeOfString:lin2];
self.range1 = range1;
self.range2 = range2;
[contentAttr addAttributes:@{NSForegroundColorAttributeName:[UIColor blueColor]} range:range];
[contentAttr addAttributes:@{NSLinkAttributeName:lin1}
range:range1];
[contentAttr addAttributes:@{NSLinkAttributeName:lin2}
range:range2];
self.textView.attributedText = contentAttr;
self.textView.delegate =self;
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
if (characterRange.location == self.range1.location && characterRange.length == self.range1.length) {
[self bt_pushTrermAction:nil];
}else if(characterRange.location == self.range2.location && characterRange.length == self.range2.length){
[self bt_privacyAction:nil];
}
return NO;
}
app上線app描述包含商品名字,價格,最好加購買協(xié)議。

app上線的時候要在app描述里面加入內(nèi)購信息
可參考愛奇藝,等有內(nèi)購功能app在appstore上的描述。

愛奇藝
七 :深坑記錄。
- 第一次加內(nèi)購或者有新商品,發(fā)布成功后,服務(wù)器并沒有立刻同步,必須要等上一段時間(12小時左右)才能拉取到產(chǎn)品列表。
- 點擊發(fā)布后等待時間較久,大概12小時才能在appstore上搜索到。(官方說24之內(nèi)可以看到)
- 元數(shù)據(jù)需要,綁定銀行卡,設(shè)置報稅表,設(shè)置內(nèi)購項目(完整的需要截圖和描述),添加沙盒測試賬號(沙盒賬號不一定需要驗證,沙盒賬號iOS13在個人資料里有專門登陸的地方,iOS12在支付的時候會彈出登陸框登陸即可)。
-
綁定銀行卡的時候需要設(shè)置報稅表,一般選美國就好,后面選擇NO,然后同意條款,輸入生日,簽名就好。如下圖。
image.png
