iOS13 内购集成

简单记录。

1.协议填写
登录苹果商店中心直达链接选择协议条款填写信息。

step1

step2

进去填写资料即可,具体填写可参考[Lebus的文章]

2.创建商品
进入我的App-功能-App内购买项目-点击加号
添加内购商品

选择对应的商品
image.png

ps:作者项目用到的是会员功能,选择的是非续期订阅,多次购买会提示续订或延长订阅时间达到续费的目的
IMG_0823.PNG

具体创建商品设置
image.png

image.png

上传你购买商品的截图

以上配置工程基本完成

未完成部分
1.工程中开启内购功能

Xcode11中点击 +Capablility 添加

2.沙盒账号添加(用于付款)
image.png

国家选自己应用的地区!

ps:1.不用退出手机设置中的APPID,内购时系统检测到沙盒环境(个人猜测)自动弹出登录框登录并保存沙盒账号,输入沙盒账号密码即可
2.退出沙盒账号。设置-APPID-iTunes Store 与 App Store - 最底部就可以看到沙盒账户,点击对应账户就有退出登录选项
退出沙盒账户

实现APP内购买功能(代码部分)

头文件部分


#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>

NS_ASSUME_NONNULL_BEGIN

@class SuenAppStorePay;
@protocol SuenAppStrorePayDelegate <NSObject>
@optional

/// 内购支付成功回调
/// @param appStorePay 当前类
/// @param transaction 返回值
-(void)SuenAppStorePay:(SuenAppStorePay *)appStorePay responseAppStorePaySuccess:(SKPaymentTransaction *)transaction;


/// 内购支付结果回调提示
/// @param appStorePay 当前类
/// @param transaction 返回值
- (void)SuenAppStorePay:(SuenAppStorePay *)appStorePay responseAppStorePayStatusshow:(SKPaymentTransaction *)transaction;
@end

@interface SuenAppStorePay : NSObject<SKPaymentTransactionObserver,SKProductsRequestDelegate>
/**商品ID*/
@property (nonatomic,strong) NSString *goodsId;
@property (nonatomic,weak) id <SuenAppStrorePayDelegate> delegate;
+(instancetype)sharedInstance;

/// 购买商品
/// @param goodsID 商品ID
-(void)starBuyToAppStore:(NSString *)goodsID;

@end

NS_ASSUME_NONNULL_END

实现文件

#import "SuenAppStorePay.h"

@implementation SuenAppStorePay
+(instancetype)sharedInstance{
    static SuenAppStorePay *s;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        s = [[SuenAppStorePay alloc]init];
    });
    
    return s;
}
-(instancetype)init{
    
    self = [super init];
    if (self) {
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }
    return self;
}


#pragma mark -释放TransactionObserver
-(void)dealloc{
    [[SKPaymentQueue defaultQueue]removeTransactionObserver:self];
}
#pragma mark -购买商品
-(void)starBuyToAppStore:(NSString *)goodsID{
//    判断是否开启支付功能
    if ([SKPaymentQueue canMakePayments]) {
        [self getRequestAppleProduct:goodsID];
    }else{
//提示开启支付功能
        [FRObj showAlert:@"请开启支付功能" time:1];
    }
}
#pragma makr -private 购买方法
-(void)getRequestAppleProduct:(NSString *)goodsID{
    self.goodsId = goodsID;
    SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithObject:goodsID]];
    request.delegate = self;
    [request start];
}

#pragma mark -SKProductsRequestDelegate
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    SKProduct *product = nil;
    if (response.products.count > 0) {
        for (SKProduct *s in response.products) {
            if ([s.productIdentifier isEqualToString:self.goodsId]) {
                product = s;
            }
        }
        if (product) {
//            发送购买请求
            SKPayment *payment = [SKPayment paymentWithProduct:product];
            [[SKPaymentQueue defaultQueue] addPayment:payment];
        }
        
    }else{
//        结束加载视图
        NSLog(@"没有这个产品");
        return;
    }
}

-(void)request:(SKRequest *)request didFailWithError:(NSError *)error{
//    请求产品失败
    NSLog(@"请求产品失败");
}
-(void)requestDidFinish:(SKRequest *)request{
    //    请求产品结束
}

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
//    购买状态
    if (self.delegate && [self.delegate respondsToSelector:@selector(SuenAppStorePay:responseAppStorePayStatusshow:)]) {
        if (transactions.count != 0) {
            SKPaymentTransaction *transaction = transactions[0];
            [self.delegate SuenAppStorePay:self responseAppStorePayStatusshow:transaction];
        }
      
    }
    
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
//                交易完成
                break;
            case SKPaymentTransactionStateRestored:
//                 购买过
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
//                  交易失败
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                break;
                
            default:
                break;
        }
    }
    
    
    
}
#pragma mark ------ 支付完成
- (void)completeTransaction:(SKPaymentTransaction *)transaction{
    
    
//    [transaction transactionIdentifier];
    if (self.delegate && [self.delegate respondsToSelector:@selector(SuenAppStorePay:responseAppStorePaySuccess:)]) {

        [self.delegate SuenAppStorePay:self responseAppStorePaySuccess:transaction];
     }
    
    
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

@end

使用方法

@interface YourViewController ()<SuenAppStrorePayDelegate>

//设置代理
  [SuenAppStorePay sharedInstance].delegate = self;
//出入商品ID
  [[SuenAppStorePay sharedInstance] starBuyToAppStore:goodsId];


#pragma mark -SuenAppStorePayDelegate
-(void)SuenAppStorePay:(SuenAppStorePay *)appStorePay responseAppStorePayStatusshow:(SKPaymentTransaction *)transaction{
//    状态回调
    switch (transaction.transactionState) {
        case SKPaymentTransactionStateFailed:
            NSLog(@"取消或失败");
            break;
        case SKPaymentTransactionStateRestored:
            NSLog(@"从用户的购买历史中恢复。客户应完成交易");
            break;
        default:
            break;
    }
}

-(void)SuenAppStorePay:(SuenAppStorePay *)appStorePay responseAppStorePaySuccess:(SKPaymentTransaction *)transaction {
    //支付完成,需要二次验证的在此操作(后台大佬不搞二次验证,苹果不建议APP内验证故没做)
 
}

Swift 简单版


import UIKit
import StoreKit
//Block模式
typealias SuenStorePayStatusBlock = (_ transaction :SKPaymentTransaction) ->(Void)
typealias SuenStorePaySuccessBlock = (_ transaction :SKPaymentTransaction) ->(Void)

//代理模式
protocol SuenIAPPayDelegate : NSObjectProtocol {
    func SuenAppStorePayStatus(iapPay: SuenIAPPay,transaction: SKPaymentTransaction)
    func SuenAppStorePaySuccess(iapPay: SuenIAPPay,transaction: SKPaymentTransaction)

}

class SuenIAPPay: NSObject,SKPaymentTransactionObserver,SKProductsRequestDelegate {
   
    
    /// 商品id
    var goodsId : String?
    
    /// 代理
    static weak var delegate : SuenIAPPayDelegate?

  //Block
    var statusBlock : SuenStorePayStatusBlock?
    var successBlock : SuenStorePaySuccessBlock?

    
    /// 单例
    static let su : SuenIAPPay = {
        let instance = SuenIAPPay()
        SKPaymentQueue.default().add(instance)
        return instance
    }()


  
    /// 实例购买方法
    /// - Parameter goodsId: 商品id
    func buyToAppStore(goodsId: String){
           if SKPaymentQueue.canMakePayments() {
               self.goodsId = goodsId
               let set = NSSet.init(object: goodsId)
               let productsRequest = SKProductsRequest.init(productIdentifiers: set as! Set<String>)
               productsRequest.delegate = self
               productsRequest.start()
               
           }else {
               print("请开启支付功能")
           }

       }
    
    
      /// 购买
      /// - Parameter goodsId: 商品id
    class func starBuyToAppStore(goodsId: String){
        if SKPaymentQueue.canMakePayments() {
            su.goodsId = goodsId
            let set = NSSet.init(object: goodsId)
            let productsRequest = SKProductsRequest.init(productIdentifiers: set as! Set<String>)
            productsRequest.delegate = su
            productsRequest.start()
            
        }else {
            print("请开启支付功能")
        }

    }
      
      
      /// 支付完成
      /// - Parameter transaction: 购买的产品
    func completeTransaction(transaction: SKPaymentTransaction){
        
        if (SuenIAPPay.delegate != nil) {
            SuenIAPPay.delegate?.SuenAppStorePaySuccess(iapPay: self, transaction: transaction)
        }
        SKPaymentQueue.default().finishTransaction(transaction)
    }
 
    ///SKPaymentTransactionObserver
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {

        if transactions.count > 0 {
            SuenIAPPay.delegate?.SuenAppStorePayStatus(iapPay: SuenIAPPay.su, transaction: transactions[0])
        }
        
        
        for transaction in transactions {
            switch transaction.transactionState {
            case .purchased:
//                交易完成
                self.completeTransaction(transaction: transaction)
                break;
            case .restored:
//                购买过
                SKPaymentQueue.default().finishTransaction(transaction)
                break
            case .failed:
//                失败
                SKPaymentQueue.default().finishTransaction(transaction)

                break
            default: break
                
            }
        }
        
        
    }
    ///SKProductsRequestDelegate
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        if response.products.count > 0 {
            var product : SKProduct?
            for s in response.products {
                if s.productIdentifier  == SuenIAPPay.su.goodsId  || s.productIdentifier  == self.goodsId{
                    product = s
                }
            }
            if (product != nil) {
                let payment = SKPayment.init(product: product!)
                SKPaymentQueue.default().add(payment)
            }
   
        }else{
            print("没有这个产品")
        }
    }
    
    func requestDidFinish(_ request: SKRequest) {
//        请求产品完成
    }
    func request(_ request: SKRequest, didFailWithError error: Error) {
//        请求失败
    }

}

使用


import UIKit
import StoreKit
class ViewController: UIViewController,SuenIAPPayDelegate {
    let suenIap = SuenIAPPay()

    override func viewDidLoad() {
        super.viewDidLoad()
/*
单例购买
        SuenIAPPay.delegate = self
        SuenIAPPay.starBuyToAppStore(goodsId: "goods123")
*/

//实例购买(Block)
     suenIap.buyToAppStore(goodsId: "bdymember01")
        suenIap.statusBlock = {(_ tr : SKPaymentTransaction) in
           print("状态回调")
        }
        suenIap.successBlock = {(_ tr : SKPaymentTransaction) in
          print("购买成功")
        }

        // Do any additional setup after loading the view.
    }

//    TODO:状态
    func SuenAppStorePayStatus(iapPay: SuenIAPPay, transaction: SKPaymentTransaction) {
    }
    
//    TODO:交易完成
    func SuenAppStorePaySuccess(iapPay: SuenIAPPay, transaction: SKPaymentTransaction) {
    }

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

推荐阅读更多精彩内容