MerchantKit - A modern In-App Purchases management framework for iOS developers

Overview

MerchantKit

A modern In-App Purchases management framework for iOS developers.

MerchantKit dramatically simplifies the work indie developers have to do in order to add premium monetizable components to their applications. Track purchased products, offer auto-renewing subscriptions, restore transactions, and much more.

Designed for apps that have a finite set of purchasable products, MerchantKit is a great way to add an unlockable 'pro tier' to an application, as a one-time purchase or ongoing subscription.

Example Snippets

Find out if a product has been purchased:

let product = merchant.product(withIdentifier: "iap.productidentifier")
print("isPurchased: \(merchant.state(for: product).isPurchased))"

Buy a product:

let task = merchant.commitPurchaseTask(for: purchase)
task.onCompletion = { result in 
    switch result {
        case .succeeded(_):
            print("purchase completed")
        case .failed(let error):
            print("\(error)")
    }
}

task.start()

Get notified when a subscription expires:

public func merchant(_ merchant: Merchant, didChangeStatesFor products: Set) {
    if let subscriptionProduct = products.first(where: { $0.identifier == "subscription.protier" }) {
        let state = merchant.state(for: subscriptionProduct)
        
        switch state {
            case .isPurchased(let info):
                print("subscribed, expires \(info.expiryDate)")
            default:
                print("does not have active subscription")
        }
    }
}

Project Goals

  • Straightforward, concise, API to support non-consumable, consumable and subscription In-App Purchases.
  • Simplify the development of In-App Purchase interfaces in apps, including localized formatters to dynamically create strings like "£2.99 per month" or "Seven Day Free Trial".
  • No external dependencies beyond what Apple ships with iOS. The project links Foundation, StoreKit, SystemConfiguration and os for logging purposes.
  • Prioritise developer convenience and accessibility over security. MerchantKit users accept that some level of piracy is inevitable and not worth chasing.
  • Permissive open source license.
  • Compatibility with latest Swift version using idiomatic language constructs.

The codebase is in flux right now and the project does not guarantee API stability. MerchantKit is useful, it works, and will probably save you time. That being said, MerchantKit is by no means finished. The test suite is patchy.

Installation

CocoaPods

To integrate MerchantKit into your Xcode project using CocoaPods, specify it in your Podfile.

pod 'MerchantKit'

Carthage

To integrate MerchantKit into your Xcode project using Carthage, specify it in your Cartfile.

github "benjaminmayo/merchantkit"

Manually

Compile the MerchantKit framework and embed it in your application. You can download the source code from Github and embed the Xcode project into your app, although you'll have to upgrade to the latest releases manually.

Getting Started

  1. In your app delegate, import MerchantKit create a Merchant instance in application(_:, didFinishLaunchingWithOptions:). Supply a configuration (such as Merchant.Configuration.default) and a delegate.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    ...
    
    self.merchant = Merchant(configuration: .default, delegate: self)
    
    ...
}
  1. Register products as soon as possible (typically within application(_:, didFinishLaunchingWithOptions:)). You may want to load Product structures from a file, or simply declaring them as constants in code. These constants can then be referred to statically later.
let product = Product(identifier: "iap.productIdentifier", kind: .nonConsumable)
let otherProduct = Product(identifier: "iap.otherProductIdentifier", kind: .subscription(automaticallyRenews: true)) 
self.merchant.register([product, otherProduct])
  1. Call setup() on the merchant instance before escaping the application(_:, didFinishLaunchingWithOptions:) method. This tells the merchant to start observing the payment queue.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    ...
    
    self.merchant = Merchant(configuration: .default, delegate: self)    
    self.merchant.register(...)
    self.merchant.setup()
    
    ...
}
  1. Profit! Or something.

Merchant Configuration

Merchant is initialized with a configuration object; an instance of Merchant.Configuration. The configuration controls how Merchant validates receipts and persist product state to storage. Most applications can simply use Merchant.Configuration.default and get the result they expect. You can supply your own Merchant.Configuration if you want to do something more customized.

Tip: MerchantKit provides Merchant.Configuration.usefulForTestingAsPurchasedStateResetsOnApplicationLaunch as a built-in configuration. This can be used to test purchase flows during development as the configuration does not persist purchase states to permanent storage. You can repeatedly test 'buying' any Product, including non-consumables, simply by restarting the app. As indicated by its unwieldy name, you should not use this configuration in a released application.

Merchant Delegate

The delegate implements the MerchantDelegate protocol. This delegate provides an opportunity to respond to events at an app-wide level. The MerchantDelegate protocol declares a handful of methods, but only one is required to be implemented.

func merchant(_ merchant: Merchant, didChangeStatesFor products: Set) {
    // Called when the purchased state of a `Product` changes.
    
    for product in products {
        print("updated \(product)")
    }
}

The delegate optionally receives loading state change events, and a customization point for handling Promoted In-App Purchase flows that were initiated externally by the App Store. Sensible default implementations are provided for these two methods.

Product Interface Controller

The tasks vended by a Merchant give developers access to the core operations to fetch and purchase products with interfaces that reflect Swift idioms better than the current StoreKit offerings. Many apps will not need to directly instantiate tasks. ProductInterfaceController is the higher-level API offered by MerchantKit that covers the use case of many projects. In an iOS app, a view controller displaying an upgrade screen would be backed by a single ProductInterfaceController which encapsulated all necessary product and purchasing logic.

The ProductInterfaceController class encompasses common behaviours needed to present In-App Purchase for sale. However, it remains abstract enough not be tied down to one specific user interface appearance or layout.

Developers simply provide the list of products to display and tells the controller to fetch data. The delegate notifies the app when to update its custom UI. It handles loading data, intermittent network connectivity and in-flight changes to the availability and state of products.

See the Example project for a basic implementation of the ProductInterfaceController.

Formatters

MerchantKit includes several formatters to help developers display the cost of In-App Purchases to users.

PriceFormatter is the simplest. Just give it a Price and it returns formatted strings like '£3.99' or '$5.99' in accordance with the store's regional locale. You can specify a custom string if the price is free. SubscriptionPriceFormatter takes a Price and a SubscriptionDuration. Relevant Purchase objects exposes these values so you can simply pass them along the formatter. It generates strings like '$0.99 per month', '£9.99 every 2 weeks' and '$4.99 for 1 month' depending on the period and whether the subscription will automatically renew.

In addition to the renewal duration, subscriptions can include free trials and other introductory offers. You can use a SubscriptionPeriodFormatter to format a text label in your application. If you change the free trial offer in iTunes Connect, the label will dynamically update to reflect the changed terms without requiring a new App Store binary. For example:

func subscriptionDetailsForDisplay() -> String? {
    guard let terms = purchase.subscriptionTerms, let introductoryOffer = terms.introductoryOffer else { return nil }
    
    let formatter = SubscriptionPeriodFormatter()
    
    switch introductoryOffer {
        case .freeTrial(let period): return "\(formatter.string(from: period)) Free Trial" // something like '7 Day Free Trial'
        default: ...
    }
}

PriceFormatter works in every locale supported by the App Store. SubscriptionPriceFormatter and SubscriptionPeriodFormatter are currently offered in a small subset of languages. Voluntary translations are welcomed.

See the Example project for a demo where you can experiment with various configuration options for PriceFormatter and SubscriptionPriceFormatter.

Consumable Products

Merchant tracks the purchased state of non-consumable and subscription products. Consumable products are considered transitory purchases and not recorded beyond the initial time of purchase. Because of their special nature, they must be handled differently. Ensure you supply a consumableHandler when creating the Merchant. This can by any object that conforms to the MerchantConsumableProductHandler protocol. The protocol has a single required method:

func merchant(_ merchant: Merchant, consume product: Product, completion: @escaping () -> Void) {
    self.addCreditsToUserAccount(for: product, completion: completion) // application-specific handling 
}

The Merchant will always report a consumable product's state as PurchasedState.notPurchased. Forgetting to implement the delegate method will result in a runtime fatal error.

To Be Completed (in no particular order)

  • Increase the number of localizations for SubscriptionPriceFormatter and SubscriptionPeriodFormatter.
  • Add extensive documentation with more examples in the Example project.
  • Support downloadable content In-App Purchases.
  • Probably a lot more stuff I haven't thought of yet.

Credits

Developed and managed by Benjamin Mayo, @bzamayo on Twitter.

Comments
  • suggestion for program flow?

    suggestion for program flow?

    While beta testing, these two situations occur, although not commonly, it's not 1/100, it's more like 1/20.

    Situation: Purchase screen appears and disappears rapidly

    1. The application starts
    2. The merchantkit instance is created and setup
    3. The state of a product is found to be "notPurchased"
    4. The purchase screen is displayed
    5. Started available purchases task for products
    6. Available purchases finds there is a new purchase and sets expiryDate to nil, which causes the purchase to be again valid
    7. Purchase screen disappears.
    8. Invoked receipt update for purchases, updates receipts

    I would like to avoid this purchase screen appearing and disappearing. Do you have any advice for the proper way to avoid this?

    Situation: Hung purchase

    1. Receipt is checked
    2. Product is notPurchased
    3. Purchase screen is displayed
    4. Purchased product
    5. Some large network lag occurs, receipt is not gotten
    6. Stays on purchase screen with product showing as "purchased"
    7. There is no call to func merchant(_ merchant: Merchant, didChangeStatesFor products: Set)

    I think I should just manually start a test during productInterfaceController didCommit and didRestore, but was wondering any opinion.

    opened by timprepscius 21
  • Rejected by Apple

    Rejected by Apple

    Hi! I recently got rejected by Apple with this weird reason:

    Guideline 2.1 - Performance - App Completeness

    We found that your in-app purchase products exhibited one or more bugs when reviewed on iPhone running iOS 13.3 on Wi-Fi.

    Next Steps

    When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead.

    Do you have any idea how to fix it?

    My current version MerchantKit 0.13.0

    opened by denandreychuk 13
  • unresolving state

    unresolving state

    Again, as with the previous post, I'm not sure if this is actually an issue or not.

    My app entered a state where the code:

        private func attemptFinishTaskFetchingLocalData(onFailure: () -> Void) {
            if let url = Bundle.main.appStoreReceiptURL, let isReachable = try? url.checkResourceIsReachable(), isReachable == true, let data = try? Data(contentsOf: url) {
                self.finish(with: .success(data))
            } else {
                onFailure()
            }
        }
    

    Would call onFailure, I think, because maybe I installed a Release version over a Debug version.. Not sure exactly- url.checkResourceIsReachable() would do an NSCocoaDomainError.

    But the receipt was in the KeyService. But it was expired.

    So, the end result was- I have an expired receipt, but isPurchased would be true. And it would never refresh it- removing from the keychain.

    To solve it I changed the code in MerchantKit:

    public func setup() {
        guard !self.hasSetup else { return }
        self.hasSetup = true
        
        self.storeInterface.setup(withDelegate: self)
        
        self.checkReceipt(updateProducts: .all, policy: .fetchElseRefresh, reason: .initialization)
    

    To have ".fetchElseRefresh"....

    But I really don't want to change your code at all..

    What should have I done?

    opened by timprepscius 12
  • MerchantKit debugging tips

    MerchantKit debugging tips

    Hi Ben, firstly many thanks for building this library it looks very good!

    I am trying to debug the purchase of a renewable subscription and I did not receive any callback from the:

         let task = merchant.commitPurchaseTask(for: purchase)
         task.onCompletion = { result in
             switch result {
             case .succeeded(_):
                 print("purchase completed")
             case .failed(let error):
                 print("\(error)")
             }
         }
    
         task.start()
    

    piece of code.

    What do you suggest as a to-do list if I want to debug this?

    opened by kutakmir 9
  • Fix crash when StoreKit returns nil original transaction

    Fix crash when StoreKit returns nil original transaction

    While testing restore functionality with a sandbox user I ran into a crash where the app would persistently crash due to StoreKit returning nil for transaction.original. The crash repeats infinitely since the unfinished transaction stays in the queue and replays at next app launch.

    Nit: do we really need original here at all? completeRestorePurchase only seems to need the product ID. Is it possible for the product ID to change for a transaction?

    opened by ekurutepe 8
  • Is there a way to check original app purchase?

    Is there a way to check original app purchase?

    I would like to move an app from fixed price to free with in app purchase. How can I check the original receipt of the app itself so I can unlock the in app purchase to all the users who paid for the app originally?

    opened by melvitax 8
  • Delegate methods

    Delegate methods

    Xcode 9.3 & Cocoapods 1.5.0

    After installing and creating a simple class to test the delegate methods I repeatadly get the following issue:

    error

    Do you have any ideas as to why this my be happening?

    opened by randomiser 7
  • Gets

    Gets "Cannot Connect to iTunes Store" after upgrading plan

    Hi! I faced with a problem related to subscription upgrading. Not sure exactly if it's related to MerchantKit, but I I get "Cannot Connect to iTunes Store" every time I upgrade plan for auto-renewable subscription.

    If I have already purchased, for example, "weekly" subscription and then tries to upgrade my plan to "monthly", I got "Cannot Connect to iTunes Store" after successfully complete transaction. The last part is weird. I got popup from Apple that everythings good, and that I was billed, and after that I receive error in didCommit delegate method of ProductInterfaceController.

    Please, let me know you have any idea what could be the problem.

    Best regard, Den

    opened by denandreychuk 6
  • Products not seen as purchased in TestFlight builds

    Products not seen as purchased in TestFlight builds

    I'm seeing the following behavior only in TestFlight builds. This is with configuration .default.

    1. Purchase a product
    2. Force quit the app and restart

    In the didChangeStatesFor: callback, the product purchased in step 1 doesn't seem to come back as .purchased. Note that it does get returned when calling restorePurchases().

    What's strange is that in dev builds, the product comes back as .purchased. Is this expected behavior because of the difference between sandbox and production iTunes accounts?

    opened by jzting 6
  • Localized Title on Purchase

    Localized Title on Purchase

    I have added a localizedTitle computed property on the Purchase struct, in order to get at the title of the IAP since it is tucked into the internal skProduct. I didn't see any other way to get at that name. Am I doing this right? If so, are you taking PR's on this repo?

    opened by BlueMilkApps 6
  • Draft: SPM Support

    Draft: SPM Support

    Hi,

    This wasn't meant to be a production-ready pull request but it's the changes I made to get it working w/ SPM for myself.

    I couldn't figure out how to get the header file to work w/ SPM - it complains that priceLocaleFromProductDiscount is undefined. Do get it compiling successfully I defined a placeholder in Source/Model/Purchase.swift.

    I did have to import Foundation in every swift file where a Foundation type was referenced.

    Hope this helps.

    opened by sgtsquiggs 5
  • error: Segmentation fault: 11 (in target 'MerchantKit' from project 'Pods')

    error: Segmentation fault: 11 (in target 'MerchantKit' from project 'Pods')

    I'm trying to build "Archive" an app using a M1 machine. I run into this error. When doing the same on an intel based mac it works like a charm 🤷‍♂️

    SwiftCodeGeneration normal arm64 (in target 'MerchantKit' from project 'Pods')
        cd /Users/bror/Developer/privat/mtbmap-native/Pods
        /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -c -primary-file /Users/bror/Library/Developer/Xcode/DerivedData/mtbmap-native-bllivwmndqinorfrabpowspkhymi/Build/Intermediates.noindex/ArchiveIntermediates/mtbmap-native/IntermediateBuildFilesPath/Pods.build/Release-iphoneos/MerchantKit.build/Objects-normal/arm64/Purchase.bc -embed-bitcode -target arm64-apple-ios11.0 -Xllvm -aarch64-use-tbi -O -disable-llvm-optzns -module-name MerchantKit -o /Users/bror/Library/Developer/Xcode/DerivedData/mtbmap-native-bllivwmndqinorfrabpowspkhymi/Build/Intermediates.noindex/ArchiveIntermediates/mtbmap-native/IntermediateBuildFilesPath/Pods.build/Release-iphoneos/MerchantKit.build/Objects-normal/arm64/Purchase.o
    
    Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
    Stack dump:
    0.	Program arguments: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -c -primary-file /Users/bror/Library/Developer/Xcode/DerivedData/mtbmap-native-bllivwmndqinorfrabpowspkhymi/Build/Intermediates.noindex/ArchiveIntermediates/mtbmap-native/IntermediateBuildFilesPath/Pods.build/Release-iphoneos/MerchantKit.build/Objects-normal/arm64/Purchase.bc -embed-bitcode -target arm64-apple-ios11.0 -Xllvm -aarch64-use-tbi -O -disable-llvm-optzns -module-name MerchantKit -o /Users/bror/Library/Developer/Xcode/DerivedData/mtbmap-native-bllivwmndqinorfrabpowspkhymi/Build/Intermediates.noindex/ArchiveIntermediates/mtbmap-native/IntermediateBuildFilesPath/Pods.build/Release-iphoneos/MerchantKit.build/Objects-normal/arm64/Purchase.o
    1.	Apple Swift version 5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)
    2.	Compiling with the current language version
    3.	Running pass 'Function Pass Manager' on module '/Users/bror/Library/Developer/Xcode/DerivedData/mtbmap-native-bllivwmndqinorfrabpowspkhymi/Build/Intermediates.noindex/ArchiveIntermediates/mtbmap-native/IntermediateBuildFilesPath/Pods.build/Release-iphoneos/MerchantKit.build/Objects-normal/arm64/Purchase.bc'.
    4.	Running pass 'ObjC ARC contraction' on function '@priceLocaleFromProductDiscount'
    Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
    0  swift-frontend           0x0000000106936f88 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
    1  swift-frontend           0x0000000106935f9c llvm::sys::RunSignalHandlers() + 112
    2  swift-frontend           0x0000000106937618 SignalHandler(int) + 344
    3  libsystem_platform.dylib 0x00000001a10854c4 _sigtramp + 56
    4  swift-frontend           0x00000001048b4e8c llvm::objcarc::BundledRetainClaimRVs::insertRVCallWithColors(llvm::Instruction*, llvm::CallBase*, llvm::DenseMap<llvm::BasicBlock*, llvm::TinyPtrVector<llvm::BasicBlock*>, llvm::DenseMapInfo<llvm::BasicBlock*>, llvm::detail::DenseMapPair<llvm::BasicBlock*, llvm::TinyPtrVector<llvm::BasicBlock*> > > const&) + 64
    5  swift-frontend           0x00000001048c5878 (anonymous namespace)::ObjCARCContract::run(llvm::Function&, llvm::AAResults*, llvm::DominatorTree*) + 1024
    6  swift-frontend           0x00000001066aae24 llvm::FPPassManager::runOnFunction(llvm::Function&) + 1292
    7  swift-frontend           0x00000001066b138c llvm::FPPassManager::runOnModule(llvm::Module&) + 60
    8  swift-frontend           0x00000001066ab5a8 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 1088
    9  swift-frontend           0x0000000102676ee8 swift::performLLVMOptimizations(swift::IRGenOptions const&, llvm::Module*, llvm::TargetMachine*) + 3376
    10 swift-frontend           0x0000000102677e28 swift::performLLVM(swift::IRGenOptions const&, swift::DiagnosticEngine&, llvm::sys::SmartMutex<false>*, llvm::GlobalVariable*, llvm::Module*, llvm::TargetMachine*, llvm::StringRef, swift::UnifiedStatsReporter*) + 2440
    11 swift-frontend           0x0000000102680364 swift::performLLVM(swift::IRGenOptions const&, swift::ASTContext&, llvm::Module*, llvm::StringRef) + 180
    12 swift-frontend           0x00000001021d8ea0 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 6976
    13 swift-frontend           0x00000001021a0130 swift::mainEntry(int, char const**) + 808
    14 dyld                     0x000000010919d088 start + 516
    error: Segmentation fault: 11 (in target 'MerchantKit' from project 'Pods')
    

    How to reproduce:

    • Create new project (with pods)
    • include merchantkit
    • archive build

    Note that builds and runs in simulator does work. This only happens when archiving.

    opened by brorhb 2
  • 'Product' is ambiguous for type lookup in this context

    'Product' is ambiguous for type lookup in this context

    I moved to XCode 13.2.1 and now suddenly, when I build my app I got that error: 'Product' is ambiguous for type lookup in this context The compiler says that it founds two candidates for the class "Product" but both candidates go to the same file "Product.swift" in the same pod (merchantkit)

    I don't know ho to fix that. Any help?

    opened by cyberneid 0
  • Question about example...

    Question about example...

    Hello,

    I wanted to try out merchant kit, but am unable to get the example to run. It tells me there was an error loading products.

    Can you tell me what I am doing wrong?

    Thank you.

    opened by LilMoke 1
  • WatchOS support?

    WatchOS support?

    Hello, I'd love to use MerchantKit on WatchOS as well, but WatchOS doesn't have SystemConfiguration (so the whole NetworkAvailabilityCenter class is unusable there).

    I tried at least building MerchantKit for WatchOS (apparently it needs either a new target, or somehow adding support for a WatchOS into existing tsrget), but I am not experienced enough to make it work.

    opened by tkafka 3
  • Add support for didRevokeEntitlementsForProductIdentifiers

    Add support for didRevokeEntitlementsForProductIdentifiers

    Thanks for an awesome library @benjaminmayo 🙌

    iOS 14 adds a new didRevokeEntitlementsForProductIdentifiers delegate method to SKPaymentTransactionObserver (docs here)

    From the docs:

    The system calls this delegate method whenever App Store revokes in-app purchases for the user. For example, it’s called when a user leaves a family sharing group that was sharing in-app purchases. By leaving the family group, the user is no longer entitled to the shared in-app purchases.

    The productIdentifiers parameter contains the revoked product IDs. Your app should check the receipt on the device, which the system automatically updates prior to calling this method, and provide the correct level of access for the in-app purchases — which may now be no access. If you use server-side receipt validation with the App Store, call your server to reprocess the receipt and update your purchase records.

    opened by ryanmeisters 5
Owner
Benjamin Mayo
Independent iOS developer and contractor. Email for work enquiries.
Benjamin Mayo
SwiftyStoreKit is a lightweight In App Purchases framework for iOS, tvOS, watchOS, macOS, and Mac Catalyst ⛺

SwiftyStoreKit is a lightweight In App Purchases framework for iOS, tvOS, watchOS, macOS, and Mac Catalyst. Features Super easy-to-use block-based API

Andrea Bizzotto 6.1k Jan 7, 2023
Apphud SDK is a lightweight open-source Swift library to manage auto-renewable subscriptions and other in-app purchases in your iOS app.

Apphud SDK Apphud SDK is a lightweight open-source Swift library to manage auto-renewable subscriptions and other in-app purchases in your iOS app. No

Apphud 143 Dec 16, 2022
Mercato is a lightweight In-App Purchases (StoreKit 2) library for iOS, tvOS, watchOS, macOS, and Mac Catalyst.

Mercato Mercato is a lightweight In-App Purchases (StoreKit 2) library for iOS, tvOS, watchOS, macOS, and Mac Catalyst. Installation Swift Package Man

Pavel T 49 Jan 4, 2023
🍎 An App to check whether a non-App Store app is in App Store.

AppStorify ?? An App to check whether a non-App Store app is in App Store. Benfits Use App Store's upgrade mechanism instead of app's. App Store apps

seedgou 58 Dec 7, 2022
InAppPurchase - A Simple and Lightweight framework for In App Purchase

InAppPurchase A Simple, Lightweight and Safe framework for In App Purchase Feature Simple and Light ?? Support Promoting In-App Purchases ?? No need t

Jin Sasaki 269 Dec 15, 2022
An easy way to access reviews for your app instead of writing repetitive and redundant codes for every app.

AppStoreReviewManager An easy way to access reviews for your app instead of writing repetitive and redundant codes for every app. Requirements iOS 9.0

Jinya 4 Dec 23, 2022
Appirater - A utility that reminds your iPhone app's users to review the app.

Introduction Appirater is a class that you can drop into any iPhone app (iOS 4.0 or later) that will help remind your users to review your app on the

Arash Payan 4.7k Jan 7, 2023
Harpy - Notify users when a new version of your app is available and prompt them to upgrade.

After 6 years of Harpy and 4 years of Siren, I have decided to deprecate Harpy in favor of Siren. Why? Siren is written in Swift and has a feature set

Arthur Ariel Sabintsev 2.6k Dec 29, 2022
Siren - Notify users when a new version of your app is available and prompt them to upgrade.

Siren ?? Notify users when a new version of your app is available and prompt them to upgrade. Table of Contents Meta About Features Screenshots Ports

Arthur Ariel Sabintsev 4.1k Dec 27, 2022
AppVersion - Keep users on the up-to date version of your App.

?? App Version Don't let you users to get stuck on outdated version of your app. Automatic update tracking using Semantic Versioning Buil-in UI alerts

Ameba Labs 31 Sep 30, 2022
An App where you can find product and see its detail.

MeliProductos Project ???? > An App where you can find product and see its detail. ???? > Una App donde puedes encontrar tus productos y ver su detall

Joaquin Segovia 3 May 6, 2022
A modern In-App Purchases management framework for iOS.

MerchantKit A modern In-App Purchases management framework for iOS developers. MerchantKit dramatically simplifies the work indie developers have to d

Benjamin Mayo 1.1k Dec 17, 2022
Apple's Framework to support in-app purchases and interaction with the App Store

Apple's Framework to support in-app purchases and interaction with the App Store.

paigeshin 0 Dec 5, 2021
SwiftyStoreKit is a lightweight In App Purchases framework for iOS, tvOS, watchOS, macOS, and Mac Catalyst ⛺

SwiftyStoreKit is a lightweight In App Purchases framework for iOS, tvOS, watchOS, macOS, and Mac Catalyst. Features Super easy-to-use block-based API

Andrea Bizzotto 6.1k Jan 7, 2023
Lightweight In App Purchases Swift framework for iOS 8.0+, tvOS 9.0+ and macOS 10.10+ ⛺

SwiftyStoreKit is a lightweight In App Purchases framework for iOS, tvOS, watchOS, macOS, and Mac Catalyst. Features Super easy-to-use block-based API

Andrea Bizzotto 6.1k Jan 7, 2023
A New, Modern Reactive State Management Library for Swift and SwiftUI (The iOS implementation of Recoil)

RecoilSwift RecoilSwift is a lightweight & reactive swift state management library. RecoilSwift is a SwiftUI implementation of recoil.js which powered

Holly Li 160 Dec 25, 2022
🪶 Feather is a modern Swift-based content management system powered by Vapor 4.

Feather CMS ?? ?? Feather is a modern Swift-based content management system powered by Vapor 4. ?? Click to join the chat on Discord. Requirements To

Phu Huynh 0 Oct 20, 2021
A modern download manager based on NSURLSession to deal with asynchronous downloading, management and persistence of multiple files.

TWRDownloadManager TWRDownloadManager A modern download manager for iOS (Objective C) based on NSURLSession to deal with asynchronous downloading, man

Michelangelo Chasseur 407 Nov 19, 2022
Apphud SDK is a lightweight open-source Swift library to manage auto-renewable subscriptions and other in-app purchases in your iOS app.

Apphud SDK Apphud SDK is a lightweight open-source Swift library to manage auto-renewable subscriptions and other in-app purchases in your iOS app. No

Apphud 143 Dec 16, 2022
Modern-collection-view - Modern collection view for swift

Modern collection view Sample application demonstrating the use of collection vi

Nitanta Adhikari 1 Jan 24, 2022