cocos creator 发布IOS版本(六)内购

cocos creator 版本3.3

参考文档:

iOS 内购(In-App Purchase)总结 | 笑忘书店

iOS的应用内支付In-app purchase的开发 - 胡东东博客

App内购项目的App Store推广 - 胡东东博客

Unity调用iOS原生内购 - 围墙外的世界 - 博客园

以非消耗型为例:非消耗型和订阅类型,存在app升级或者重装后恢复内购的需求

1、配置产品ID

在对应项目中找到-》管理点击+

非消耗型可以调用恢复接口恢复: 

  • 消耗品(Consumable products):比如游戏内金币等。
  • 非消耗品(Non-consumable products):简单来说就是一次购买,终身可用(用户可随时从App Store restore)。
  • 自动更新订阅品(Auto-renewable subscriptions):和不可消耗品的不同点是有失效时间。比如一整年的付费周刊。在这种模式下,开发者定期投递内容,用户在订阅期内随时可以访问这些内容。订阅快要过期时,系统将自动更新订阅(如果用户同意)。
  • 非自动更新订阅品(Non-renewable subscriptions):一般使用场景是从用户从IAP购买后,购买信息存放在自己的开发者服务器上。失效日期/可用是由开发者服务器自行控制的,而非由App Store控制,这一点与自动更新订阅品有差异。
  • 免费订阅品(Free subscriptions):在Newsstand中放置免费订阅的一种方式。免费订阅永不过期。只能用于Newsstand-enabled apps。
扫描二维码关注公众号,回复: 14662106 查看本文章

 填写好相对于的所有信息,其中产品id,就是传递的接口

 正式上线完的状态是已批准,测试状态是:审核或者准备中,元数据丢失状态是内容没填全,可能会影响测试

2、Xcode代码调用(如何发布ios可参考前面文章)

a、添加内购的Lib库:StoreKit.framework

 b、Xcode接口,供cocos调用及回掉cocos

IAPInterface.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface IAPInterface : NSObject
+ (instancetype)sharedSingleton;

+ (void) InitIAPManager;
+ (bool) IsProductAvailable;
+ (void) RequstProductInfo :(NSString *)p;
+ (void) BuyProduct :(NSString *)p;
+ (void) RestoreBuyProduct :(NSString *)p;

- (void) BuyProcuctSucessCallBack:(NSString *)str;
- (void) BuyProcuctFailedCallBack:(NSString *)str;
- (void) ShowProductList:(NSString *)str;
- (void) RestoreBuyProductSucessCallBack:(NSString *)str;
- (void) test1;

@end

NS_ASSUME_NONNULL_END

IAPInterface.mm

#import "IAPInterface.h"
#import "IAPManager.h"
#import "cocos/bindings/jswrapper/SeApi.h"

@interface IAPInterface()

@property  IAPManager *iapManager;
@end

@implementation IAPInterface

+ (instancetype)sharedSingleton {
   static IAPInterface *_sharedSingleton = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
       //不能再使用alloc方法
       //因为已经重写了allocWithZone方法,所以这里要调用父类的分配空间的方法
       if (_sharedSingleton==nil) {
           _sharedSingleton = [[super allocWithZone:NULL] init];
       }
       //[_sharedSingleton initDelegate];
       //[_sharedSingleton checkTransaction];
   });
   return _sharedSingleton;
}

/**
 //初始化商品信息
 */
+ (void) InitIAPManager{
    NSLog(@"InitIAPManagerUser");
    [[IAPInterface sharedSingleton] InitIAPManagerUser];
    
}

- (void) InitIAPManagerUser{
   
    self.iapManager=[[IAPManager alloc] init];
    [self.iapManager attachObserver];
    
}

//判断用户是否可以付费
+ (bool) IsProductAvailable{
    return [[IAPInterface sharedSingleton] IsProductAvailableUser];
}
- (bool) IsProductAvailableUser{
   
    return [self.iapManager CanMakePayment];
}

//获取商品信息
+ (void) RequstProductInfo:(NSString *)p{
    NSLog(@"商品列表:%@",p);
    [[IAPInterface sharedSingleton] RequstProductInfoUser:p];
}

- (void) RequstProductInfoUser:(NSString *)p{
        [self.iapManager requestProductData:p];
}

//购买商品
+ (void) BuyProduct:(NSString *)p{
    NSLog(@"购买:%@",p);
    [[IAPInterface sharedSingleton] BuyProductUser:p];
    
    //[IAPInterface RestoreBuyProduct:p];
}

- (void) BuyProductUser:(NSString *)p{
    [self.iapManager buyRequest:p];
}

//恢复购买商品
+ (void) RestoreBuyProduct:(NSString *)p{
    NSLog(@"恢复购买:%@",p);
    [[IAPInterface sharedSingleton] RestoreBuyProductUser:p];
    
}

- (void) RestoreBuyProductUser:(NSString *)p{
    [self.iapManager Restore:p];
}


/// <summary>
/// 购买商品成功的回调
/// </summary>
/// <param name="str">String.</param>
- (void) BuyProcuctSucessCallBack:(NSString *)str
{
    NSLog(@"-----ObjectToJs----BuyProcuctSucessCallBack-------");
    
    NSString *bodyString = [NSString stringWithFormat:@"window.PlatformApi.BuyProcuctSucessCallBack(%@)", str];//拼接请求数据
    NSLog(bodyString);
    std::string param1=[bodyString UTF8String];
   //通过evalString执行上面的代码
   se::ScriptEngine::getInstance()->evalString(param1.c_str());
}

/// <summary>
/// 购买商品失败的回调
/// </summary>
/// <param name="str">String.</param>
- (void) BuyProcuctFailedCallBack:(NSString *)str
{
    NSLog(@"-----ObjectToJs----BuyProcuctFailedCallBack-------");
    
    NSString *bodyString = [NSString stringWithFormat:@"window.PlatformApi.BuyProcuctFailedCallBack(%@)", str];//拼接请求数据
    NSLog(bodyString);
    std::string param1=[bodyString UTF8String];
   //通过evalString执行上面的代码
   se::ScriptEngine::getInstance()->evalString(param1.c_str());
}

/// <summary>
/// 产品反馈信息回掉-
/// </summary>
/// <param name="str">String.</param>
- (void) ShowProductList:(NSString *)str
{
    NSLog(@"-----ObjectToJs----ShowProductList-------");
    
    NSString *bodyString = [NSString stringWithFormat:@"window.PlatformApi.ShowProductList(%@)", str];//拼接请求数据
    
    std::string param1=[bodyString UTF8String];
   //通过evalString执行上面的代码
   se::ScriptEngine::getInstance()->evalString(param1.c_str());
}

/// <summary>
/// 恢复购买的商品完成的回调
/// </summary>
/// <param name="str">String.</param>
- (void) RestoreBuyProductSucessCallBack:(NSString *)strId
{
    NSLog(@"-----ObjectToJs----RestoreBuyProductSucessCallBack-------");
    
    NSString *bodyString = [NSString stringWithFormat:@"window.PlatformApi.RestoreBuyProductSucessCallBack(%@)", strId];
    //NSLog(bodyString);
    std::string param1=[bodyString UTF8String];
   //通过evalString执行上面的代码
   se::ScriptEngine::getInstance()->evalString(param1.c_str());
}

- (void) test1
{
    NSLog(@"-----ObjectToJs----test1-------");
    
    NSString *bodyString = [NSString stringWithFormat:@"window.PlatformApi.showRewardVideoADCallback()"];//拼接请求数据
    
    std::string param1=[bodyString UTF8String];
   //通过evalString执行上面的代码
   se::ScriptEngine::getInstance()->evalString(param1.c_str());
}
@end

c、具体调用内购sdk方法

IAPManager.h

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

@interface IAPManager : NSObject<SKProductsRequestDelegate, SKPaymentTransactionObserver>{
    SKProduct *proUpgradeProduct;
    SKProductsRequest *productsRequest;
    NSString *productIndentify;
    
}

-(void)attachObserver;
-(BOOL)CanMakePayment;
-(void)requestProductData:(NSString *)productIdentifiers;
-(void)buyRequest:(NSString *)productIdentifier;//购买
-(void)Restore:(NSString *)productIdentifier;
@end

IAPManager.m

#import "IAPManager.h"
#import "IAPInterface.h"

@implementation IAPManager

//初始化
-(void) attachObserver{
    NSLog(@"AttachObserver");
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

//判断用户是否可以付费
-(BOOL) CanMakePayment{
    return [SKPaymentQueue canMakePayments];
}

//已内购的内容,恢复购买
-(void) Restore:(NSString *)productIdentifier{
    NSLog(@"Restore");
    [[SKPaymentQueue defaultQueue]  restoreCompletedTransactions];
}

//请求商品数据
-(void) requestProductData:(NSString *)productIdentifiers{
    NSArray *idArray = [productIdentifiers componentsSeparatedByString:@"\t"];
    NSSet *idSet = [NSSet setWithArray:idArray];
    [self sendRequest:idSet];
}

-(void)sendRequest:(NSSet *)idSet{
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:idSet];
    request.delegate = self;
    [request start];
}

-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    NSLog(@"-----------收到产品反馈信息--------------");
    NSArray *products = response.products;
    NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);
    NSLog(@"产品付费数量: %d", (int)[products count]);
    // populate UI
    
    for (SKProduct *p in products) {
        NSLog(@"product info");
        NSLog(@"SKProduct 描述信息%@", [products description]);
        NSLog(@"产品标题 %@" , p.localizedTitle);
        NSLog(@"产品描述信息: %@" , p.localizedDescription);
        NSLog(@"价格: %@" , p.price);
        NSLog(@"Product id: %@" , p.productIdentifier);
        
        //UnitySendMessage("IOSIAPMgr", "ShowProductList", [[self productInfo:p] UTF8String]);
        NSString *pps= [self productInfo:p];
        [[IAPInterface sharedSingleton] ShowProductList:pps];
    }
    
    for(NSString *invalidProductId in response.invalidProductIdentifiers){
        NSLog(@"Invalid product id:%@",invalidProductId);
    }
    
    // [request autorelease];
}

//请求购买
-(void)buyRequest:(NSString *)productIdentifier{
    //  NSArray* transactions=[SKPaymentQueue defaultQueue].transactions;
    //  if(transactions.count>0)
    // {
    // for(SKPaymentTransaction *tran in transactions)
    // {
    //   NSLog(@"**************************************************************%@",tran.transactionState);
    //检查是否有完成的交易
    //   SKPaymentTransaction* transaction =[transactions firstObject];
    // if(tran.transactionState==SKPaymentTransactionStatePurchasing)
    //   {
    //   NSLog(@"----------------------%@",tran.transactionState);
    //   [[SKPaymentQueue defaultQueue] finishTransaction:tran];
    // return;
    //  }
    //}
    
    // }
    productIndentify=productIdentifier;
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

-(NSString *)productInfo:(SKProduct *)product{
    NSArray *info = [NSArray arrayWithObjects:product.localizedTitle,product.localizedDescription,product.price,product.productIdentifier, nil];
    
    return [info componentsJoinedByString:@"\t"];
}

-(NSString *)transactionInfo:(SKPaymentTransaction *)transaction{
    
    return [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];
    
    //return [[NSString alloc] initWithData:transaction.transactionReceipt encoding:NSASCIIStringEncoding];
}

-(NSString *)encode:(const uint8_t *)input length:(NSInteger) length{
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    
    NSMutableData *data = [NSMutableData dataWithLength:((length+2)/3)*4];
    uint8_t *output = (uint8_t *)data.mutableBytes;
    
    for(NSInteger i=0; i<length; i+=3){
        NSInteger value = 0;
        for (NSInteger j= i; j<(i+3); j++) {
            value<<=8;
            
            if(j<length){
                value |=(0xff & input[j]);
            }
        }
        
        NSInteger index = (i/3)*4;
        output[index + 0] = table[(value>>18) & 0x3f];
        output[index + 1] = table[(value>>12) & 0x3f];
        output[index + 2] = (i+1)<length ? table[(value>>6) & 0x3f] : '=';
        output[index + 3] = (i+2)<length ? table[(value>>0) & 0x3f] : '=';
    }
    
    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
//回执
-(void) provideContent:(SKPaymentTransaction *)transaction{
    //UnitySendMessage("IOSIAPMgr", "ProvideContent", [[self transactionInfo:transaction] UTF8String]);
}

//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
/**
 *  验证购买,避免越狱软件模拟苹果请求达到非法购买问题
 *
 */
-(void)verifyPurchaseWithPaymentTransaction{
    //从沙盒中获取交易凭证并且拼接成请求体数据
    NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];
    
    NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//转化为base64字符串
    
    NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接请求数据
    NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
    
    
    //测试的时候填写沙盒路径,上APPStore的时候填写正式环境路径
    NSURL *url=[NSURL URLWithString:SANDBOX];
    NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];
    requestM.HTTPBody=bodyData;
    requestM.HTTPMethod=@"POST";
    //创建连接并发送同步请求
    NSError *error=nil;
    NSData *responseData=[NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error];
    if (error) {
        NSLog(@"验证购买过程中发生错误,错误信息:%@",error.localizedDescription);
        return;
    }
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"%@",dic);
    if([dic[@"status"] intValue]==0){
        NSLog(@"购买成功!");
        NSDictionary *dicReceipt= dic[@"receipt"];
        
        NSLog(@"--------------%@",dicReceipt);
        
        //NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject];
        for(NSDictionary  *tmp in dicReceipt[@"in_app"])
        {
            
            
            // NSLog(@"+++++++++++%@",dicInApp);
            NSString *productIdentifier= tmp[@"product_id"];//读取产品标识
            NSLog(@"+++++++++++++++++++++++++++++++++++++%@",productIdentifier);
            NSLog(@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%@",productIndentify);
            //如果是消耗品则记录购买数量,非消耗品则记录是否购买过
            NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
            if ([productIdentifier isEqualToString:productIndentify]) {
                NSInteger purchasedCount=[defaults integerForKey:productIdentifier];//已购买数量
                [[NSUserDefaults standardUserDefaults] setInteger:(purchasedCount+1) forKey:productIdentifier];

                [[IAPInterface sharedSingleton] BuyProcuctSucessCallBack:productIdentifier];
                break;
            }else{
                [[NSUserDefaults standardUserDefaults] setBool:YES forKey:productIdentifier];
    
                [[IAPInterface sharedSingleton] BuyProcuctSucessCallBack:productIdentifier];
                break;
            }
            
        }
    }else{
        NSLog(@"购买失败,未通过验证!");
        [[IAPInterface sharedSingleton] BuyProcuctFailedCallBack:productIndentify];
    }
}

//从App Store支付
- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product {
    NSLog(@"从App Store支付");
    //bool _is =  paySuccess;
    //根据product.productIdentifier去判断是否去直接弹出购买弹窗
    if ([product.productIdentifier isEqualToString:@"1000000000"]) {
        return true;
    }
    return false;
}

//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    for(SKPaymentTransaction *tran in transaction){
        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:{
                NSLog(@"交易完成");
                // 发送到苹果服务器验证凭证
                [self verifyPurchaseWithPaymentTransaction];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                
            }
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加进列表");
                
                break;
            case SKPaymentTransactionStateRestored:{
                NSLog(@"交易状态恢复");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                }
                break;
            case SKPaymentTransactionStateFailed:{
                NSLog(@"交易取消");
                UIAlertView *mBoxView = [[UIAlertView alloc]
                                         initWithTitle:@"Transaction reminder"
                                         message:@"Transaction failed"
                                         delegate:nil
                                         cancelButtonTitle:nil
                                         otherButtonTitles:@"OK", nil];
                [mBoxView show];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                [[IAPInterface sharedSingleton] BuyProcuctFailedCallBack:productIndentify];
                //[[IAPInterface sharedSingleton] test1];
                
            }
                break;
            default:
            {
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
        }
    }
}
-(void) completeTransaction:(SKPaymentTransaction *)transaction{
    NSLog(@"Comblete transaction : %@",transaction.transactionIdentifier);
    [self provideContent:transaction];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

-(void) failedTransaction:(SKPaymentTransaction *)transaction{
    NSLog(@"Failed transaction : %@",transaction.transactionIdentifier);
    
    if (transaction.error.code != SKErrorPaymentCancelled) {
        NSLog(@"!Cancelled");
    }
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

-(void) restoreTransaction:(SKPaymentTransaction *)transaction{
    NSLog(@"Restore transaction : %@",transaction.transactionIdentifier);
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

//已内购的内容,恢复购买时回掉
-(void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
    NSLog (@"received restored transactions: %i", queue.transactions.count);
    //没有购买过
    if (queue.transactions.count==0) {

    }
    //购买过
    for (SKPaymentTransaction *transaction in queue.transactions)
    {
        NSString *productID = transaction.payment.productIdentifier;
        NSLog(@"Restore transaction : %@",transaction.payment.productIdentifier);

        [[IAPInterface sharedSingleton] RestoreBuyProductSucessCallBack:productID];

    }


    UIAlertView *mBoxView = [[UIAlertView alloc]
                             initWithTitle:@"Transaction reminder"
                             message:@"Restore purchase completed"
                             delegate:nil
                             cancelButtonTitle:nil
                             otherButtonTitles:@"OK", nil];
    [mBoxView show];
}

@end

 d、初始化内购

e、cocos调用

PlatformApi.ts


import { _decorator, Component, sys, game, director } from 'cc';
import GameManager from './GameManager';
const { ccclass, property } = _decorator;

@ccclass('PlatformApi')
export class PlatformApi extends Component {


    private static _instance: PlatformApi | null = null;

    public static get Instance() {

        if (!PlatformApi._instance) {
            window["PlatformApi"] = new PlatformApi();
            PlatformApi._instance = new PlatformApi()
        }
        // return PlatformApi._instance || (PlatformApi._instance = new PlatformApi());
        return PlatformApi._instance;
    }

    //内购请求(目前测试:1000000000)
    public BuyProduct(eventId: string) {
        console.log("BuyProduct " + eventId);
        if (sys.platform == sys.Platform.ANDROID) {

        } else if (sys.platform == sys.Platform.IOS) {
            jsb.reflection.callStaticMethod("IAPInterface", "BuyProduct:", eventId);
        }

    }

    //内购商品信息请求
    public RequstProductInfo(eventId: string) {
        console.log("RequstProductInfo " + eventId);
        if (sys.platform == sys.Platform.ANDROID) {

        } else if (sys.platform == sys.Platform.IOS) {
            jsb.reflection.callStaticMethod("IAPInterface", "RequstProductInfo:", eventId);
        }
    }

    //app升级或者重装后,对已内购信息恢复请求
    public RestoreBuyProduct(eventId: string) {
        console.log("RestoreBuyProduct " + eventId);
        if (sys.platform == sys.Platform.ANDROID) {
 
        } else if (sys.platform == sys.Platform.IOS) {
            jsb.reflection.callStaticMethod("IAPInterface", "RestoreBuyProduct:", eventId);
        }
    }

    //内购成功xcode回掉
    public BuyProcuctSucessCallBack(eventId: string) {
        console.log("BuyProcuctSucessCallBack " + eventId);
       
    }

    //内购失败xcode回掉
    public BuyProcuctFailedCallBack(eventId: string) {
        console.log("BuyProcuctFailedCallBack " + eventId);
        
    }

    //商品信息xcode回掉
    public ShowProductList(eventId: string) {
        console.log("ShowProductList " + eventId);

    }

    //对已购买的商品进行恢复xcode回掉
    public RestoreBuyProductSucessCallBack(eventId: string) {
        console.log("RestoreBuyProductSucessCallBack " + eventId);
        if (eventId=="1000000000") {
            //恢复已购买的商品
        }

    }

}

 F:有两个接口需要特别注意

1、非消耗品,需要恢复接口,不然可能会拒审核,单机项目,app升级或者重装,对已购买的商品,进行恢复

参考:

ios内购——因缺少“恢复购买”功能被拒解决方案_专治各种审核难题的博客-CSDN博客_恢复购买

//已内购的内容,恢复购买
-(void) Restore:(NSString *)productIdentifier{
    NSLog(@"Restore");
    [[SKPaymentQueue defaultQueue]  restoreCompletedTransactions];
}
//已内购的内容,恢复购买时回掉
-(void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
    NSLog (@"received restored transactions: %i", queue.transactions.count);
    //没有购买过
    if (queue.transactions.count==0) {

    }
    //购买过
    for (SKPaymentTransaction *transaction in queue.transactions)
    {
        NSString *productID = transaction.payment.productIdentifier;
        NSLog(@"Restore transaction : %@",transaction.payment.productIdentifier);

        [[IAPInterface sharedSingleton] RestoreBuyProductSucessCallBack:productID];

    }


    UIAlertView *mBoxView = [[UIAlertView alloc]
                             initWithTitle:@"Transaction reminder"
                             message:@"Restore purchase completed"
                             delegate:nil
                             cancelButtonTitle:nil
                             otherButtonTitles:@"OK", nil];
    [mBoxView show];
}

 2、appstore推广时,需要重载的接口,否则无法推广

参考:App内购项目的App Store推广 - 胡东东博客

//从App Store支付
- (BOOL)paymentQueue:(SKPaymentQueue *)queue shouldAddStorePayment:(SKPayment *)payment forProduct:(SKProduct *)product {
    NSLog(@"从App Store支付");
    //bool _is =  paySuccess;
    //推广的id对比
    //根据product.productIdentifier去判断是否去直接弹出购买弹窗,
    if ([product.productIdentifier isEqualToString:@"1000000000"]) {
        return true;
    }
    return false;
}

 3、测试

内购测试

内购也是需要测试的,但是内购涉及到钱,所以苹果为内购测试提供了 沙箱测试账号 的功能,Apple Pay 推出之后 沙箱测试账号 也可以用于 Apple Pay 支付的测试,沙箱测试账号 简单理解就是:只能用于内购和 Apple Pay 测试功能的 Apple ID,它并不是真实的 Apple ID,下面看如何创建 配置沙箱测试账号

 测试结果类似下面截图:

 App store推广测试

修改下面的链接地址,然后在手机safari浏览器打开,就可以测试从App Store发起购买了,进程序就会自动打开购买流程,其中链接中的bundleId修改为你自己应用的bundleId,比如com.hudongdong.blog,productId修改为你创建的商品的id

itms-services://?action=purchaseIntent&bundleId=bundleId&productIdentifier=productId

猜你喜欢

转载自blog.csdn.net/weixin_41843959/article/details/122317695