如何在 iOS 中检查产品是否已使用应用内购买进行购买?

2024-04-19

我有一个应用程序集成在其中的应用程序。在我的应用程序中,我有两个用于付费应用程序购买和订阅的按钮。当用户点击“购买”时,它会检查苹果验证并购买产品。

这可以正常工作,但是当购买产品时,我的购买按钮应该更改为“完成”,并且当应用程序下次运行时,该特定产品的购买按钮不应该可见。相反,应该显示“完成”按钮。我的问题是,购买产品时显示购买按钮而不是完成按钮。

这是我的代码:

-(void)checkPurchasedItems
{
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

//Then this delegate Function Will be fired
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"received restored transactions: %i", queue.transactions.count);
    for (SKPaymentTransaction *transaction in queue.transactions)
    {
        NSString *productID = transaction.payment.productIdentifier;
        NSLog(@"%@",productID);
    }

}

// called when a transaction has failed
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        // error!
        [self finishTransaction:transaction wasSuccessful:NO];
        if (transaction.error.code == SKErrorClientInvalid) {
            //[self showAlert:@"In-App Purchase" withMessage:INVALID_CLIENT];
        }
        else if (transaction.error.code == SKErrorPaymentInvalid) {
            //[self showAlert:@"In-App Purchase" withMessage:PAYMENT_INVALID];
        }
        else if (transaction.error.code == SKErrorPaymentNotAllowed) {
            //[self showAlert:@"In-App Purchase" withMessage:PAYMENT_NOT_ALLOWED];
        }
        else if (transaction.error.code == SKErrorPaymentCancelled) {
            // [self showAlert:@"In-App Purchase" withMessage:@"This device is not allowed to make the payment."];
            NSLog(@"User Cancellation.");
        }
        else {
            // SKErrorUnknown
            NSLog(@"Unknown Reason.");
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Transaction Status" message:@"Transaction Failed due to unknown reason" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];

        }
    }
    else {
        // this is fine, the user just cancelled, so don’t notify
        //        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Transaction Status" message:@"Transaction failed due to some reason" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        //        [alert show];
        //        return;
        //[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
}

- (void)provideContent:(NSString *)productId
{
    if ([productId isEqualToString:kMyFeatureIdentifier4])
    {
        // enable the pro features
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isStorePurchased"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
    else if([productId isEqualToString:kMyFeatureIdentifier3])
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isStoreSubscribed"];
        [[NSUserDefaults standardUserDefaults]synchronize];

    }
}



- (void)recordTransaction:(SKPaymentTransaction *)transaction
{

    NSData *receiptData = [NSData dataWithData:transaction.transactionReceipt];

    transactionreceipt = [Base64 encode:receiptData];
    NSLog(@"encoded String :%@",transactionreceipt);
    if ([transaction.payment.productIdentifier isEqualToString:kMyFeatureIdentifier4])
    {
        // save the transaction receipt to disk
        [[NSUserDefaults standardUserDefaults] setValue:transactionreceipt forKey:@"proUpgradeTransactionReceipt"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
    if ([transaction.payment.productIdentifier isEqualToString:kMyFeatureIdentifier3])
    {
        [[NSUserDefaults standardUserDefaults] setValue:transactionreceipt forKey:@"proUpgradeTransactionReceipt"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
    NSUserDefaults *userdefaults = [NSUserDefaults standardUserDefaults];
    transactionreceipt = [userdefaults valueForKey:@"proUpgradeTransactionReceipt"];
    NSLog(@"%@",transactionreceipt);
    // remove the transaction from the payment queue.
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];
    if (wasSuccessful)
    {
        // send out a notification that we’ve finished the transaction
        [self sendRequest];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"PurchaseSuccess" object:self userInfo:userInfo];

        [easytblView reloadData];
    }
    else
    {
        // send out a notification for the failed transaction
        // [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
    }
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"Purchasing...");
                break;
            default:
                break;
        }
    }
}

// called when a transaction has been restored and and successfully completed
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
    [self recordTransaction:transaction.originalTransaction];
    [self provideContent:transaction.originalTransaction.payment.productIdentifier];
    [self finishTransaction:transaction wasSuccessful:YES];
}


// called when the transaction was successful
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    [self recordTransaction:transaction];
    [self provideContent:transaction.payment.productIdentifier];
    [self finishTransaction:transaction wasSuccessful:YES];
}
    -(void)buyProduct
    {
        if (arrPurchaseProducts.count>0)
        {
            SKProduct *selectedProduct = [arrPurchaseProducts objectAtIndex:0];
            SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
            [[SKPaymentQueue defaultQueue] addPayment:payment];
            //selectedProduct = nil;
            // payment = nil;
        }

    }

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSLog(@"IN-APP:productsRequest");
    arrPurchaseProducts = [[NSArray alloc]initWithArray:response.products];
    if ([arrPurchaseProducts count] == 1)
    {
        SKProduct *selectedProduct = [arrPurchaseProducts objectAtIndex:0];
        SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
        //responseStatus = 1;
        //        if ([purchaseButton.title isEqualToString:@"   "])
        //        {
        NSLog(@"Purchase had been attempted already.");

        // }
    }

    if ([arrPurchaseProducts count]>0)
    {
        product = [arrPurchaseProducts objectAtIndex:0];
        NSLog(@"Price: %.2f",product.price.floatValue);
        NSLog(@"Price Locale: %@",product.priceLocale.localeIdentifier);
        NSLog(@"Product Identifier: %@",product.productIdentifier);
        NSLog(@"IN-APP:array count: %i", [arrPurchaseProducts count]);
        [request autorelease];
        NSLog(@"IN-APP:productsRequest END");
    }
    //[arrPurchaseProducts release];
    // arrPurchaseProducts = nil;
}

- (void)requestProductData
{

    NSLog(@"IN-APP:requestProductData");
    SKProductsRequest *request;
    if (isSubscribe==YES)
    {
        request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kMyFeatureIdentifier3]];
    }
    else{
        request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kMyFeatureIdentifier3]];
    }
    request.delegate = self;
    [request start];
    NSLog(@"IN-APP:requestProductData END");
}

-(IBAction)buynow:(id)sender
{
    isSubscribe=NO;
    isviewloadedforfirsttime=NO;
        if([SKPaymentQueue canMakePayments])
        {
//            if (![[NSUserDefaults standardUserDefaults] valueForKey:@"isStorePurchased"])
//            {
                [self requestProductData];

            //}
            NSLog(@"IN-APP:can make payments");
        }
        else {
            NSLog(@"IN-APP:can't make payments");
    }

       [self performSelector:@selector(buyProduct) withObject:nil afterDelay:2.0];


}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"Purchasing...");
                break;
            default:
                break;
        }
    }
}

你自己的代码里面有这样的情况SKPaymentTransactionStateRestored它告诉我们何时恢复产品。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 iOS 中检查产品是否已使用应用内购买进行购买? 的相关文章

  • 与 Objective-C 的 VPN 连接

    有没有办法在 iPhone 的 Objective C 中以编程方式建立 VPN 连接 有这方面的好教程吗 有人知道吗 多谢 我认为第三方应用程序无法访问这些 API
  • 使用 Interface Builder 创建的自定义视图在其他视图中调用时不会呈现

    我有一个用于主窗口的 xib 并通过以下步骤创建了一个自定义视图 创建一个新类 继承自NSView MyView h import
  • Objective C 中类别是如何实现的?

    作为一名程序员 我知道如何使用类别 但我很好奇它们是如何实现的 编译器是否将它们编译为对类替换方法 http developer apple com library mac documentation Cocoa Reference Obj
  • 如何编辑应用程序包中的文件?

    在我的应用程序中 我从存储在捆绑资源中的 CSV 文件加载数据 但是 我希望能够在用户点击 更新 按钮时以编程方式更新此文件 有没有办法以编程方式更改应用程序包中的资源 这是我用来访问该文件的代码 NSString path NSBundl
  • 使用 ZBarSDK 时 iPhone 相机失去自动对焦功能

    我正在开发一个应用程序 用户可以选择是否要扫描条形码或拍摄某物的照片 为了拍照 我正在使用UIImagePickerController照常 为了扫描条形码 我使用 ZbarSDK 1 2ZBarReaderViewController 拍
  • 如果我在 iTunes Connect 中点击“拒绝二进制文件”来提交更新的二进制文件,我会失去排队的位置吗?

    我已通过 iTunes Connect 向 App Store 提交了一个应用程序 状态为 审核中 我不知道这是否意味着他们真的开始关注它 我怀疑这只是意味着它已被放入审阅者队列中 在它发布之前我想添加一个调整 但是 如果这意味着点击 拒绝
  • 如何将自定义 C 代码放入 SwiftPM 包中?

    我正在尝试将 C 代码打包到 Swift 模块中 我们称之为CModule 一旦我将其放入项目的基本文件夹中 Swift模块 并配置了搜索路径 我可以在 Swift 文件中自动完成工作 并检测错误 警告 问题是 导入时它无法识别该模块 并且
  • 从plist文件中读取数据

    我正在尝试为我的 iPhone 应用程序实现保存状态 我有一个名为 SaveData plist 的 plist 文件 我可以通过以下方式读取它 NSString pListPath2 bundle pathForResource Save
  • 游戏中心邀请处理程序,它属于哪里?

    我已经搜索了该网站并发现了这个 GameCenter 邀请处理程序 https stackoverflow com questions 4639284 gamecenter invitation handler He says 正如文档中所
  • UiTextField 和 resignFirstResponder

    我有一个奇怪的设置 我有一个View called View1 and a ViewController call 视图控制器1 in IB View1是 的孩子视图控制器1 Inside View1 我使用代码创建UITextField并
  • 如何确定 NSTimeInterval 是否发生在任意 NSDate 期间?

    我有一个 NSTimeInterval 我想知道该时间戳是否位于日期的开始和结束之间 基本上我需要能够做类似的事情 NSDate today NSDate date NSTimeInterval myInterval someInterva
  • iPhone JPG 图像有非标准魔术字节 ff d8 ff e1?

    我的网络应用程序在接受上传的图像之前会根据文件扩展名检查前四个字节 一位同事向我展示了他 iPhone 上的图像 但这些图像被拒绝了 它们具有不同的第四个字节 e1 225 而不是预期的 e0 224 这对于 iPhone 来说是常见的吗
  • AVCaptureDevice 找不到任何设备

    这行代码是我今天遇到的问题 macOS 应用程序 NSArray devices AVCaptureDevice devicesWithMediaType AVMediaTypeVideo 我更新Xcode后 系统总是让我空着devices
  • 查找已用应用程序名称的捆绑包/开发人员

    我正在尝试将应用程序上传到应用程序商店并收到以下错误 很容易理解 The App Name you have entered has already been used 该应用程序不在 iTunes 上 有什么方法可以找出谁拥有该应用程序或
  • 在文本视图滚动之前无法看到 UITextView 中的文本

    我的应用程序中有一堆文本视图 由于某种原因 无论我以编程方式 来自互联网 还是通过界面生成器 硬编码 设置 UITextView 文本 无论我做什么 当我在测试时转到该文本视图时它都是空白的 但当我滚动它的那一刻 所有文本就突然出现了 只是
  • 应用程序打开时处理推送通知

    我正在运行推送通知 有用 我收到通知并使用 application didReceiveRemoteNotification 获取传入数据 然后将用户发送到必要的屏幕 问题是 如果您正在使用该应用程序并收到通知 它会跳转到目标屏幕 而不会发
  • NSCFData fastCharacterContents 崩溃? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我目前在控制台中收到此崩溃日志 20
  • iOS 视图控制器内存在被关闭后未释放

    当用户单击按钮时 它会显示一个带有两个视图控制器的新选项卡栏视图控制器 我是这样做的 ACLevelDownloadController dvc ACLevelDownloadController alloc initWithNibName
  • ios 导航 堆栈操作

    我在尝试从 iOS 应用程序操作导航堆栈时遇到问题 或者至少是由于这种操纵而产生的行为 我的情况 我有 3 个 ViewController 控制器a显示多个级别 控制器 b 是游戏视图 控制器 c 是某种分数 显然 我将在控制器 a 中选
  • 如何将相机中的图像保存到 iPhone 图库中的特定文件夹?

    嘿 我是 iPhone 新手 最近我一直在尝试制作一个应用程序 基本上 我想要做的是 如果用户将从相机捕获任何图像 那么它应该保存在设备库中 我知道如何将照片保存在图库中 它对我有用 但我无法将所有捕获的图像保存到设备图库中的特定文件夹 例

随机推荐

  • “不支持”在不指定 RuntimeIdentifier 的情况下构建或发布独立的应用程序

    使用最新的 Visual Studio 2019 我尝试发布 DotNetCore 3 1 WPF 应用程序的 Msix 安装程序 应用程序构建并正确运行 但是当我尝试发布应用程序时出现此错误 It is not supported to
  • 迭代 DFS 与递归 DFS 以及不同的元素顺序

    我编写了一个递归 DFS 算法来遍历图 void Graph
  • eclipse 烦恼:调试和启动工具栏不可用

    我正在运行 Windows XP 和 Eclipse 4 2 2 Build id M20130204 1200 并且我丢失了调试和启动工具栏 我尝试过 Windows gt 重置透视 原始值 和窗口 gt 自定义透视 工具栏可见性和命令组
  • JavaScript 中的错误:对象不是函数

    当我运行下面的代码时 它显示错误object is not a function在控制台中 这个错误就在这一行var todo new Todo contents in my script js文件 我怎样才能让它发挥作用 这是我的 tod
  • 监控网络连接带宽的最佳工具

    我正在寻找一个非常简单的工具来监控所有应用程序的带宽 不需要流量监视等额外功能 我只是对带宽感兴趣 我已经知道 Wireshark 这很棒 但我正在寻找更多类似 TcpView 来自 Sysinternals 的出色工具 以及当前带宽指示的
  • Rails、activerecord 求和然后排序

    我有一个属于用户的工作模型 并且用户有很多工作 我想创建一个 AR 查询来计算每个用户的总工作日数 然后按降序排列 到目前为止 我已经有了这个 但给了我一个错误 列 Job id 必须出现在 GROUP BY 子句中或在聚合函数中使用 wo
  • Phonegap - 在插件委托中从 Objective-c 向 Javascript 发送消息

    我有一个 Phonegap Cordova 插件 在此插件中 我收到来自 javascript 的点击事件 此点击触发使用我的客户端库的文件下载 此文件下载发送事件并调用我的插件中的方法 因为我已将其设置为委托 我无法使用 stringBy
  • java.lang.NoSuchFieldError:没有 Landroidx/compose/foundation/layout/BoxScope$Companion 类型的字段 Companion;

    我是第一次使用 Jetpack Compose 但收到此错误 我还没有弄清楚问题到底出在哪里 但我正在使用单活动架构 如果需要更多信息 请通知我 根据错误信息 问题似乎出在脚手架上 val scaffoldState rememberSca
  • 添加应用程序时 Firebase 数据库被删除

    好的 所以我正在构建一个将在 Play 商店上运行的应用程序 它具有将数据添加到 Firebase 的功能 它无法读取数据 第二个应用程序将保留在我身边 它不会出现在游戏商店中 它用于读取数据 现在我所做的是 假设第一个应用程序有包名称 c
  • 有目的地回到之前的活动

    我有两个活动 当我在第一个活动上按 Enter 时 它将打开第二个活动 它包含一个ListView当我从中选择一个项目时ListView 它将获得其值并返回到第一个活动 这就是我尝试过的 在第二项活动中 listPerasat setOnI
  • R:随机采样抛硬币组

    我正在使用 R 编程语言 Suppose 有一枚硬币 如果它正面朝上 那么下一次抛掷正面的概率是 0 6 如果是反面 那么下一次抛掷反面的概率也是 0 6 一个班有100名学生 每个学生随机抛掷硬币几次 Student n 的最后一次抛硬币
  • Iframe/CSS:强制 Iframe 适合屏幕

    我目前正在尝试让 iframe 适合我的屏幕尺寸 以及任何其他以不同分辨率使用它的用户 除非无论我尝试什么 最终都会导致 iframe 太小或高度太大导致双滚动条 iframe 和页面本身有滚动条 我的目标是让 iframe 仅适合页面宽度
  • CUDA程序导致nvidia驱动程序崩溃

    当我超过大约 500 次试验和 256 个完整块时 我的 monte carlo pi 计算 CUDA 程序导致我的 nvidia 驱动程序崩溃 这似乎发生在 monteCarlo 内核函数中 任何帮助都会受到赞赏 include
  • IMAP fetch() 返回命令错误:BAD [b' 命令参数错误。 12']

    我无法在网上找到示例 故障排除提示 并且不太确定我是否正确解释了文档 任何帮助将不胜感激 我正在连接到电子邮件服务器 并且想要阅读电子邮件主题和正文 我首先像这样建立连接 import imaplib c imaplib IMAP4 SSL
  • 如何在 Ruby 中使用模块重写静态类方法?

    module Imodule end class Some include Imodule def self imethod puts original end end Some imethod gt overrided 如何创建一个将覆盖
  • acts_as_taggable_on:如何优化查询?

    I use acts as taggable on在我当前的 Rails 项目中 在一个概述页面上 我显示了对象及其关联标签的索引 我使用以下代码 class Project lt ActiveRecord Base acts as tag
  • “Windows”键作为快捷键的一部分

    I very often open a console window while doing my development Usually Win R gt cmd gt enter However Windows also lets yo
  • 从 Android 中的“我的应用程序”发送彩信

    我想将彩信从我的应用程序发送到特定号码 我已经搜索并找到了这段代码 但我不知道这段代码是否是我需要的 我的问题是 任何人都可以向我解释这段代码 我是彩信初学者 另外 我认为这段代码是让用户从我的应用程序发送彩信 而不将其移动到本机消息收件箱
  • OpenCV GPU Farneback 光流在多线程中表现不佳

    我的应用程序使用 Opencv GPU 类gpu FarnebackOpticalFlow计算输入视频的一对连续帧之间的光流 为了加速该过程 我利用 OpenCV 的 TBB 支持在多线程中运行该方法 然而 多线程性能并不像单线程那样 为了
  • 如何在 iOS 中检查产品是否已使用应用内购买进行购买?

    我有一个应用程序集成在其中的应用程序 在我的应用程序中 我有两个用于付费应用程序购买和订阅的按钮 当用户点击 购买 时 它会检查苹果验证并购买产品 这可以正常工作 但是当购买产品时 我的购买按钮应该更改为 完成 并且当应用程序下次运行时 该