IOS内购开发(Objc和Swift)及漏单处理
2020-06-10 本文已影响0人
Hahn_z
Demo
demo是使用FMDB保存到本地(也可以使用归档等方法保存)
支付测试必须要使用真机
注意:在调用支付的过程比较慢,需要加入动画提示,不然可能被拒。
内购申请
进入https://appstoreconnect.apple.com
1.png这个是填写银行卡等信息的(这里我已经填写了)、具体就不展示了
2.png
添加上面的信息了、需要等待苹果审核(最晚一天、如果一天还没有通过。请检查个人信息)
进入我的App添加内购项目
3.png
这里我选择消耗型的项目作为Demo
4.png
进入用户和访问、添加沙盒测试员
5.png
沙盒测试
5.jpeg
内购流程
内购流程根据上图可以知道苹果内购结果回调是APP告诉应用服务器的。不是苹果服务器直接告诉应用服务器。这样可能出现漏单的情况。
比如说
网络不好的说话、没有告诉应用服务器结果
还没有应用服务器结果、用户关闭了APP等等情况。
处理方法
1.当支付成功的时候、把订单数据保存到本地。重新进入App的时候请求支付回调
//实现第一部的时候可以处理大部分漏单情况、但是还是没有办法避免漏单(用户删除了APP没有本地数据的情况等)
2.在创建预订单的时候保存下单时间等数据、可以让客服查询
Objc
#import "ViewController.h"
#import "SqlManager.h"
#import "ApplePayModel.h"
#import <StoreKit/StoreKit.h>
@interface ViewController ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>
@property (nonatomic, strong) SKProductsRequest * request;
@end
@implementation ViewController
- (void)dealloc {
NSLog(@"释放充值");
if (self.request)
{
[self.request cancel];
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *array = [[SqlManager sharedManager] getAllApplePayModel];
NSLog(@"数据库里面的数据 = %@",array);
if (array.count > 0) {
for (ApplePayModel *model in array) {
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:0];
[dict setObject:model.payData forKey:@"receiptData"];
/**
* 内购校验的Api(你的应用的api)
*/
}
}
}
# pragma mark 购买
- (IBAction)buyBtn:(id)sender {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
if([SKPaymentQueue canMakePayments]){
// 你的itunesConnect的商品ID
[self getProductInfowithprotectId:@""];
}else{
NSLog(@"不允许程序内付费");
}
}
#pragma mark -- 苹果内购服务,下面的ProductId应该是事先在itunesConnect中添加好的,已存在的付费项目。否则查询会失败。
- (void)getProductInfowithprotectId:(NSString *)proId
{
NSMutableArray *proArr = [NSMutableArray new];
[proArr addObject:proId];
NSSet * set = [NSSet setWithArray:proArr];
self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
self.request.delegate = self;
[self.request start];
NSLog(@"%@",set);
NSLog(@"请求开始请等待...");
}
//收到产品返回信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
NSLog(@"--------------收到产品反馈消息---------------------");
NSArray *product = response.products;
NSLog(@"productID:%@", response.invalidProductIdentifiers);
if(product.count==0){
NSLog(@"查找不到商品信息");
return;
}
SKProduct *p = nil;
for(SKProduct *pro in product) {
NSLog(@"%@", [pro description]);
NSLog(@"%@", [pro localizedTitle]);
NSLog(@"%@", [pro localizedDescription]);
NSLog(@"%@", [pro price]);
NSLog(@"%@", [pro productIdentifier]);
if([pro.productIdentifier isEqualToString: [pro productIdentifier]]){
p = pro;
}
}
SKPayment *payment = [SKPayment paymentWithProduct:p];
NSLog(@"发送购买请求");
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
NSLog(@"支付失败");
}
- (void)requestDidFinish:(SKRequest *)request{
NSLog(@"支付调用完成");
}
//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
for(SKPaymentTransaction *tran in transaction){
switch(tran.transactionState) {
case SKPaymentTransactionStatePurchased:{ // 购买成功,此时要提供给用户相应的内容
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
NSLog(@"购买成功 = %@", tran);
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
NSString *receiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
// 保存订单信息到数据库
ApplePayModel *model = [ApplePayModel new];
// 这里把订单ID写死了
model.orderId = @"12345";
model.payData = receiptString;
[[SqlManager sharedManager] saveApplePayModel:model];
/**
* 请求校验API 请求完成删除数据库对应数据
*/
// [[SqlManager sharedManager] removeMotionModel:model];
}
break;
case SKPaymentTransactionStatePurchasing: // 购买中,此时可更新UI来展现购买的过程
break;
case SKPaymentTransactionStateRestored:{ //恢复已购产品,此时需要将已经购买的商品恢复给用户
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
}
break;
case SKPaymentTransactionStateFailed:{ // 购买错误,此时要根据错误的代码给用户相应的提示
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
NSLog(@"购买失败");
}
break;
default:
break;
}
}
}
@end
Swift
import UIKit
import StoreKit
class ViewController: UIViewController {
var request:SKProductsRequest! = nil
override func viewDidLoad() {
super.viewDidLoad()
let array = SqlManager.shared().getAllApplePayModel()
if array.count > 0 {
for model in array {
let mo:ApplePayModel = model as! ApplePayModel
print(mo.orderId as Any)
/**
* 内购校验的Api(你的应用的api)
*/
}
}
}
deinit {
print("释放充值")
if (self.request != nil) {
self.request.cancel()
}
NotificationCenter.default.removeObserver(self)
SKPaymentQueue.default().remove(self)
}
// MARK:-购买
@IBAction func buyBtn(_ sender: Any) {
SKPaymentQueue.default().add(self)
if SKPaymentQueue.canMakePayments() {
// 你的itunesConnect的商品ID
self.getProductInfow(proId: "")
}else{
print("不允许程序内付费")
}
}
}
extension ViewController: SKProductsRequestDelegate, SKPaymentTransactionObserver{
// 苹果内购服务,下面的ProductId应该是事先在itunesConnect中添加好的,已存在的付费项目。否则查询会失败。
func getProductInfow(proId:String){
let proArr = NSMutableArray()
proArr.add(proId)
let set = NSSet(array: proArr as! [Any])
self.request = SKProductsRequest(productIdentifiers: set as! Set<String>)
self.request.delegate = self
self.request.start()
print("set")
print("请求开始请等待...")
}
// 收到产品返回信息
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("--------------收到产品反馈消息---------------------")
let product = response.products;
print("productID:\(response.invalidProductIdentifiers)")
if product.count == 0 {
print("查找不到商品信息")
return
}
var p = SKProduct()
for pro in product {
print(pro.description)
print(pro.localizedTitle)
print(pro.localizedDescription)
print(pro.price)
print(pro.productIdentifier)
if pro.productIdentifier == pro.productIdentifier {
p = pro
}
let payment = SKPayment(product: p)
print("发送购买请求")
SKPaymentQueue.default().add(payment)
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("请求失败")
}
func requestDidFinish(_ request: SKRequest) {
print("支付调用完成")
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for tran in transactions {
switch tran.transactionState {
case .purchased: // 购买成功,此时要提供给用户相应的内容
SKPaymentQueue.default().finishTransaction(tran)
let model = ApplePayModel()
model.orderId = "1234"
model.payData = "1234"
SqlManager.shared().saveApplePayModel(model: model)
/**
* 请求校验API 请求完成删除数据库对应数据
*/
// SqlManager.shared().removeMotionModel(model: model)
break
case .purchasing: // 购买中,此时可更新UI来展现购买的过程
break
case .restored: // 恢复已购产品,此时需要将已经购买的商品恢复给用户
SKPaymentQueue.default().finishTransaction(tran)
break
case .failed: // 购买错误,此时要根据错误的代码给用户相应的提示
SKPaymentQueue.default().finishTransaction(tran)
print("购买失败")
break
default:
break
}
}
}
}
Demo
demo是使用FMDB保存到本地(也可以使用归档等方法保存)