美文网首页iOS学习专题
IOS内购开发(Objc和Swift)及漏单处理

IOS内购开发(Objc和Swift)及漏单处理

作者: Hahn_z | 来源:发表于2020-06-10 15:16 被阅读0次

    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保存到本地(也可以使用归档等方法保存)

    相关文章

      网友评论

        本文标题:IOS内购开发(Objc和Swift)及漏单处理

        本文链接:https://www.haomeiwen.com/subject/uxjetktx.html