通过应用内购买将现有的 iOS 付费应用程序转换为免费增值模式

发布于 2024-09-19 20:50:45 字数 556 浏览 9 评论 0原文

我目前在商店中有一个付费应用程序。苹果也不允许提交“精简”版本,所以我别无选择,只能将当前的付费版本更新为免费增值(带有应用程序内购买)模型。我遇到的问题是,第一次购买该应用程序的 v1 用户不会失去功能。

有什么方法可以确定应用程序是否已从以前安装的版本更新,以便我可以解锁应用程序的付费部分?

两个类似的问题(几个月前):

通过应用内购买将现有付费应用转换为免费版本

iPhone + 通过应用内购买将应用商店中现有的付费应用程序升级为免费应用程序 + 已经购买付费应用程序的客户怎么办

I currently have a paid app in the store. Apple have not allowed a 'lite' version to be submitted as well, so I have no choice but to update the current paid version to a freemium (with in app purchase) model. I have the problem of not loosing functionality for v1 users that have purchased the app the first time round.

Is there any way to determine if an application have been updated from a previously installed version so I can unlock the paid parts of the app?

Two similar questions (from a few months ago):

Transition an existing paid for app to free version with In App Purchase

iPhone + upgrade existing paid application on app store to free application with In App purchase + what about the customers who have already purchased the paid application

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

黑白记忆 2024-09-26 20:50:45

现在有一种 Apple 批准的方法可以在 iOS 和 macOS 上执行此操作。可以使用信息键原始购买版本从收据中获取应用程序的原始下载版本。然后,如果该版本早于切换到 IAP,您可以决定是否解锁功能。

例如,一旦您检索到收据信息:

NSArray *versionsSoldWithoutIAP = @[@"1.0", @"1.1", @"1.2", @"1.3"];
NSString *originalPurchasedVersion = [receiptInfoDict objectForKey:@"Original Purchased Version"];
for (NSString *version in versionsSoldWithoutIAP) {
    if ([version isEqualToString:originalPurchasedVersion]) {
        // user paid for the currently installed version
    }
}

有关详细信息,请参阅 WWDC 13 视频 使用保护您的数字销售的收据。 5:40 演示者评论道:“我认为今年收据中最令人兴奋的事情,特别是对于你们来说,如果您在商店中有付费应用程序,那就是我们在收据中包含了信息,让您能够从付费应用程序过渡到具有应用程序内购买功能的免费应用程序,而不会留下所有已经为您的应用程序付费的客户。”

There is now an Apple-approved way to do this on both iOS and macOS. The originally downloaded version of the app can be obtained from the receipt using the info key Original Purchased Version. You can then decide whether to unlock features if that version predates the switch to IAP.

For instance, once you have retrieved the receipt info:

NSArray *versionsSoldWithoutIAP = @[@"1.0", @"1.1", @"1.2", @"1.3"];
NSString *originalPurchasedVersion = [receiptInfoDict objectForKey:@"Original Purchased Version"];
for (NSString *version in versionsSoldWithoutIAP) {
    if ([version isEqualToString:originalPurchasedVersion]) {
        // user paid for the currently installed version
    }
}

For more info see the WWDC 13 video Using Receipts to Protect Your Digital Sales. At 5:40 the presenter comments: "I think the most exciting thing that's in the receipt this year, especially for you guys if you have a paid app in the store is that we've included information in the receipt that's going to let you do a transition from being a paid app to being a free app with in-app purchases without leaving behind all the customers that have already paid for your app."

莫言歌 2024-09-26 20:50:45

使用 iOS7,iOS 应用程序可以验证应用程序商店收据,其中包含应用程序下载日期。
通过使用此下载日期,您可以确定客户之前是否购买过

With iOS7, iOS app can verify app store receipt, which contains app download date.
By using this donwload date, you could determine if a customer is previously purchased or not

给我一枪 2024-09-26 20:50:45

首先,我只想说我个人认为免费增值模式很棒。对于许多开发人员来说,它的效果非常非常好。人们喜欢下载免费应用程序,并且会随心所欲地下载,但在花费 0.99 美元之前会更加关注应用程序(这是由于免费的影响 - 有关这方面的更多信息,请查看 Dan Ariely 的书 可预见的不合理

有关免费增值的更多信息,请谷歌搜索 - 已经写了很多文章关于它的成功。


好吧,回到实际的问题:

有几种方法可以处理这样的情况,尽管不幸的是,这些方法都不是万无一失的。

  • 最好的解决方案可能是让您的用户拥有帐户。在不了解您的应用程序的具体情况的情况下,我无法判断用户帐户是否适合您的应用程序。存储在服务器上的用户帐户有许多额外的好处,包括用户管理和跟踪用户的购买情况。这将允许用户删除该应用程序,然后重新安装该应用程序或获取新设备,以保留其购买的内容。此外,每当您使用应用内购买时,您应该在您自己的服务器(或Apple)上验证购买,基于服务器的用户管理系统都可以做到这一点。 如果您完全无法创建自己的用户管理服务器,请查看 Parse。创建一个令人惊叹的后端服务器(基本上免费)非常简单
  • iCloud Key/Value 类型的系统。我不太熟悉这是如何工作的 - 所以我会继续。
  • 另一个不太安全的解决方案(但更快/更容易实现)是使用 NSUserDefaults。您可以在用户购买时或用户安装您的应用程序的日期存储对象。然后,如果您发布更新,则将您的应用程序转换为免费增值。然后在新的更新中,检查用户进行了哪些购买或安装日期,并做出相应的反应。有关如何使用 NSUserDefaults 执行此操作的信息,请查看我对有关实现该操作的另一个问题的回答:NSUserDefaults 和应用版本
    但这个解决方案确实存在以下缺陷:

  • 如果用户删除您的应用,NSUserDefaults 将永远丢失

  • 如果用户没有安装设置 NSUserDefault 系统的更新,但随后使用新的免费增值模式安装了更新,则应用程序会将他们视为未购买内容。

在夏天,这是一个困难的问题,没有很多简单/完美的选择。

无论如何,

希望有帮助!

First, I just want to say I personally think the freemium model is great. It has worked out very well for many developers. People love to download free apps, and will do it on a whim, but pay much more attention to an app before spending $0.99 (Which is due to the effect of free - for more info on that, check out Dan Ariely's book Predictably Irrational)

For more info on freemium, google it - There have been tons of articles written about the success of it.


Ok, back to the actual question:

Theres a couple ways you can handle a situtation like this, although the unfortunate matter here is none of them are fool proof.

  • The best solution would probably be for your users to have accounts. Without knowing the specifics of your app, I can't say whether or not user accounts are appropiate for your app. User accounts stored on your server have many additional benefits, including user management, and tracking what purchases a user has made. This will allow users who delete the app, and then re-install it, or get a new device, to maintain their purchased content. Furher, whenever you use in-app purchase, you should validate the purchase on your own server (or with Apple), which a server based user manegment system can all do. If your totally in over your head with creating your own user management server, check out Parse. Its dead simple to create an amazing backend server (for basically free)
  • iCloud Key/Value type of system. I'm not very familiar with how this would work - so I'll move on.
  • Another, not nearly as fool proof solution (but much quicker/easier to implement) is to use NSUserDefaults. You can store an object when the user makes a purchase, or with the date a user installs your app. Then if you issue an update converting your app to freemium. Then in the new update, check which purchases the user has made or the date they installed it, and react accordingly. For info on how to do that with NSUserDefaults, check out my answer to another question on implementing that: NSUserDefaults and app versions.
    But this solution does present the following pitfalls:

  • If the user deletes your app, the NSUserDefaults are lost forever

  • If the user didn't install the update setting up the NSUserDefault system, but then installed the update with the new freemium model, the app would treat them as if they hadn't purchased the content.

In summery, this is a difficult question, with not a lot of easy/perfect options.

Anyway,

Hope that helped!

初雪 2024-09-26 20:50:45

我正在处理同样的事情,并提出了以下想法:使用新名称和应用程序 ID 创建免费增值版本。将现有的付费应用程序保留在应用程序商店中,但将价格提高到荒谬的程度,并在说明中明确说明该应用程序的存在是为了维持对现有用户的支持,并且新用户应该尝试免费增值版本。

现有付费用户不会失去对其现有应用程序的支持,并且可以随时删除和安装,而无需重新购买。

您也不必不断更新旧的付费应用程序。只需将其保存在应用程序商店中即可。

缺点是,现有的付费用户将无法顺利迁移到免费增值版本,以获取将来添加的任何额外功能,而无需重新支付他们已经拥有的功能。

仍在尝试决定这是否对我有用,但对其他人来说可能是一个不错的选择。评论赞赏。

I'm dealing with the same thing and came up with the following idea: Create the freemium version under a new name and app ID. Keep the existing paid app in the app store, but raise the price to something absurd and clearly state in the description that the app is there to maintain support for existing users and that new users should try the freemium version instead.

Existing paid users won't lose support for their existing app and can delete and install any time it without re-purchasing.

You won't have to keep updating the old paid app, either. Just keep it in the app store.

The downside is that existing paid users will not be able to migrate smoothly to the freemium version to get any extra features you add in the future without re-paying for what they already have.

Still trying to decide if this will work for me but it could be a good option for others. Comments appreciated.

逆光下的微笑 2024-09-26 20:50:45

我已经思考这个问题有一段时间了。我有大量客户为我的(在应用程序商店中)高价利基应用程序付费,我不想告诉他们重新购买,因为我计划迁移到应用程序内购买模式。

我提出的想法(我会询问苹果支持是否合法)是逐步淘汰当前的付费应用程序,但为其提供最后的更新,允许基于以下内容“解锁”新应用程序的应用内购买:应用内模型。我正在考虑一个挑战响应方案:

  • 用户在他的设备上安装了付费应用程序
  • 用户安装新的应用程序内应用程序并打开它。新应用程序检测付费版本并提供解锁应用程序内购买(当然仅在此设备上,并且只要应用程序未删除)
  • 新应用程序生成一个随机数,对其进行签名并用它调用旧应用程序通过 URL 方案
  • 旧应用程序解密随机数,向其添加 +1 并再次对其进行签名。通过 URL 方案回调新应用程序
  • 新应用程序验证随机数并解锁功能

该方案可以使用预共享密钥轻松实现。这当然是越狱设备上的一个弱点,但是每个存储应用内收据的应用程序都存在这些问题。

I've been thinking about this problem for some time now. I have a substantial amount of customers that paid for my (in App Store terms) high-price niche-App and I'd hate having to tell them to re-purchase as I plan to migrate to an In-App Purchase model.

The idea I came up with (and I'll ask Apple support whether it's legal) is to phase out the current paid App but ship a last update for it that allows "unlocking" the In-App purchases of the new App based on the In-App model. I was thinking about a challenge response scheme:

  • User has installed paid App on his device
  • User installs new In-App App and opens it. The new App detects the paid version and offers to unlock the In-App purchases (on this device only of course and as long as the App isn't deleted)
  • The new App generates a nonce, signs it and calls the old App with it via an URL Scheme
  • The old App decrypts the nonce, adds +1 one to it and signs it again. Calls back to the new App via URL scheme
  • The new App validates the nonce and unlocks the features

The scheme can be easily implemented using a pre-shared key. It's of course a weakness on jail-broken devices, but then every App storing In-App receipts has those problems.

久伴你 2024-09-26 20:50:45

您可以检查收据的“original_application_version”。所有从appStore下载的iOS应用程序都会有收据,即使它是免费应用程序。

TPInAppReceipt 是一个简单的快速库,可以帮助您完成此任务。

import TPInAppReceipt

do {
  /// Initialize receipt
  let receipt = try InAppReceipt.localReceipt() 

  let originalAppVersion = receipt.originalAppVersion
  let buildSoldWithoutIAP = 22

  let originalAppVersionInt = Int(originalAppVersion) ?? 23
  if originalAppVersionInt <= buildSoldWithoutIAP {
                
      // unlock all features
      UserDefaults.standard.set(true, forKey: "isPaid")
  }

} catch {
  print(error)
}

注意:返回的 receipt.originalAppVersion 是用户首次从 appSore 购买应用时的内部版本号。此外,除非您先购买或恢复 inAppPurchase,否则收据将无法在沙盒环境中使用。

You can check the 'original_application_version' of the receipt. All iOS downloaded from the appStore have a receipt even if it is a free app.

TPInAppReceipt is a simple swift library that can help you with this.

import TPInAppReceipt

do {
  /// Initialize receipt
  let receipt = try InAppReceipt.localReceipt() 

  let originalAppVersion = receipt.originalAppVersion
  let buildSoldWithoutIAP = 22

  let originalAppVersionInt = Int(originalAppVersion) ?? 23
  if originalAppVersionInt <= buildSoldWithoutIAP {
                
      // unlock all features
      UserDefaults.standard.set(true, forKey: "isPaid")
  }

} catch {
  print(error)
}

Note: The receipt.originalAppVersion returned is the build number as at the time the user first purchased the app from the appSore. Also, the receipt won't be available in the sandbox environment until you purchase or restore an inAppPurchase first.

菩提树下叶撕阳。 2024-09-26 20:50:45

对于 iOS 16ma​​cOS 13.0,您可以直接使用 StoreKit 执行此操作:

import StoreKit

do {
     // Get the appTransaction.
      let shared = try await AppTransaction.shared
        if case .verified(let appTransaction) = shared {
            // Hard-code the major version number in which the app's business model changed.
            #if os(macOS)
            let newBusinessModelVersion = "2" // CFBundleShortVersionString
            #else
            let newBusinessModelVersion = "42" // CFBundleVersion
            #endif
            
            // Get the major version number of the version the customer originally purchased.
            #if os(macOS)
            let versionComponents = appTransaction.originalAppVersion.split(separator: ".")
            let originalVersion = versionComponents[0]
            #else
            let originalVersion = appTransaction.originalAppVersion
            #endif

            NSLog("original purchased version: \(originalVersion)")

            if originalVersion < newBusinessModelVersion {
                // This customer purchased the app before the business model changed.
                // Deliver content that they're entitled to based on their app purchase.
            }
            else {
                // This customer purchased the app after the business model changed.
            }
        }
    }
catch {
    // Handle errors.
}

https://developer.apple.com/documentation/storekit/apptransaction/3954447-originalappversion

With iOS 16 and macOS 13.0 you can do this directly with StoreKit:

import StoreKit

do {
     // Get the appTransaction.
      let shared = try await AppTransaction.shared
        if case .verified(let appTransaction) = shared {
            // Hard-code the major version number in which the app's business model changed.
            #if os(macOS)
            let newBusinessModelVersion = "2" // CFBundleShortVersionString
            #else
            let newBusinessModelVersion = "42" // CFBundleVersion
            #endif
            
            // Get the major version number of the version the customer originally purchased.
            #if os(macOS)
            let versionComponents = appTransaction.originalAppVersion.split(separator: ".")
            let originalVersion = versionComponents[0]
            #else
            let originalVersion = appTransaction.originalAppVersion
            #endif

            NSLog("original purchased version: \(originalVersion)")

            if originalVersion < newBusinessModelVersion {
                // This customer purchased the app before the business model changed.
                // Deliver content that they're entitled to based on their app purchase.
            }
            else {
                // This customer purchased the app after the business model changed.
            }
        }
    }
catch {
    // Handle errors.
}

https://developer.apple.com/documentation/storekit/apptransaction/3954447-originalappversion

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文