Code Monkey home page Code Monkey logo

purchases-ios's Introduction

๐Ÿ˜ป In-App Subscriptions Made Easy ๐Ÿ˜ป

License Version Carthage compatible SwiftPM compatible

RevenueCat is a powerful, reliable, and free to use in-app purchase server with cross-platform support. Our open-source framework provides a backend and a wrapper around StoreKit and Google Play Billing to make implementing in-app purchases and subscriptions easy.

Whether you are building a new app or already have millions of customers, you can use RevenueCat to:

  • Fetch products, make purchases, and check subscription status with our native SDKs.
  • Host and configure products remotely from our dashboard.
  • Analyze the most important metrics for your app business in one place.
  • See customer transaction histories, chart lifetime value, and grant promotional subscriptions.
  • Get notified of real-time events through webhooks.
  • Send enriched purchase events to analytics and attribution tools with our easy integrations.

Sign up to get started for free.

RevenueCat.framework

RevenueCat is the client for the RevenueCat subscription and purchase tracking system. It's 100% Swift and compatible with Objective-C.

Migrating from Purchases v3

RevenueCat SDK Features

RevenueCat
โœ… Server-side receipt validation
โžก๏ธ Webhooks - enhanced server-to-server communication with events for purchases, renewals, cancellations, and more
๐Ÿ–ฅ iOS, tvOS, macOS, watchOS, Mac Catalyst, and visionOS support
๐ŸŽฏ Subscription status tracking - know whether a user is subscribed whether they're on iOS, Android or web
๐Ÿ“Š Analytics - automatic calculation of metrics like conversion, mrr, and churn
๐Ÿ“ Online documentation and SDK Reference up to date
๐Ÿ”€ Integrations - over a dozen integrations to easily send purchase data where you need it
๐Ÿ’ฏ Well maintained - frequent releases
๐Ÿ“ฎ Great support - Contact us

Getting Started

For more detailed information, you can view our complete documentation at docs.revenuecat.com.

Please follow the Quickstart Guide for more information on how to install the SDK.

Note: When integrating SPM, it is recommended to add the SPM mirror repository for faster download/integration times: https://github.com/RevenueCat/purchases-ios-spm

Or view our iOS sample apps:

Requirements

  • Xcode 14.0+
Platform Minimum target
iOS 11.0+
tvOS 11.0+
macOS 10.13+
watchOS 6.2+
visionOS 1.0+

SDK Reference

Our full SDK reference can be found here.

Contributing

Contributions are always welcome! To learn how you can contribute, please see the Contributing Guide.

purchases-ios's People

Contributors

a2 avatar aboedo avatar alfondotnet avatar beylmk avatar codykerns avatar davedelong avatar dependabot[bot] avatar douglashill avatar dylanmaryk avatar ethervoid avatar fire-at-will avatar fotidim avatar jamesrb1 avatar jeiting avatar joshdholtz avatar juanpe avatar kevinquisquater avatar kitwtnb avatar markvillacampa avatar mshmoustafa avatar nachosoto avatar rcgitbot avatar revenuecat-ops avatar rkotzy avatar schayes04 avatar taquitos avatar tiinanguyen avatar timac avatar tonidero avatar vegaro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

purchases-ios's Issues

Add info about using for macOS + minimum requirements

I honestly thought this repo was just for iOS and then found out it supports macOS as well. This is great since I'm going to be using it for Mac apps.

I believe it would be helpful to mention this in the readme as well as the minimum version of macOS needed, which seems to be 10.12.

And thanks for supporting both iOS and macOS, it's a nice change to see!

Please leave old API in place, but mark it as unavailable or deprecated

I just updated my copy of Purchases to the latest version, and got hit with a bunch of compiler errors about missing methods or missing parameters.

Next time you add parameters, leave the old method in place but mark it as deprecated, and add the hint to use a different on instead.

Instead of removing methods, remove their implementations, and then mark the method in the header as deprecated, and point to the new method.

This helps make upgrading from release to release much easier for users.

Invalid Product Identifiers?

DEBUG: Requesting products with identifiers: {(
    "com.<myapp>.MONTH_SUB",
    "com.<myapp>.BASE_SUB"
)}
DEBUG: Products request finished
DEBUG: Valid Products:
DEBUG: Invalid Product Identifiers - (
    "com.<myapp>.BASE_SUB",
    "com.<myapp>.MONTH_SUB"
)
DEBUG: 1 completion handlers waiting on products
INFO: Could not find SKProduct for (
    "com.<myapp>.MONTH_SUB",
    "com.<myapp>.BASE_SUB"
)
INFO: Ensure your products are correctly configured in App Store Connect

I have ensured my products are correctly configured in ASC. They are in the "Ready to Submit" state. I can use these same product identifiers to successfully pull products via SwiftyStoreKit and through Apple's API. This leads me to assume that the problem is with my configuration in RevenueCat. But I've gone through the documentation multiple times now over several days and I can't figure out where the problem is. @jeiting I know you diagnose these problems a lot and I've read your blogs. I'm out of things to check and just desperate for some suggestions. Thanks.

How to use the library in watch app?

Hi, I have the error with version 4.0 when running it with the latest Xcode beta.

Showing Recent Messages
/Users/majid/Library/Developer/Xcode/DerivedData/SleepBot-fcdzzaaaglxzwpcmtdyrkdzbxapm/SourcePackages/checkouts/purchases-ios/Purchases/Public/RCPurchases.m:27:9: 'RCDeviceCache.h' file not found

Unable to run example

Hi,

I am getting this error immediately after running pod install.

purchases-ios-2.3.0/Examples/SwiftExample/Target Support Files/Pods-SwiftExample/Pods-SwiftExample.debug.xcconfig: unable to open file (in target "SwiftExample" in project "SwiftExample") (in target 'SwiftExample')

podfile content is

platform :ios, '12.0'

use_frameworks!

target 'SwiftExample' do

 # Pods for SwiftExample
 pod 'Purchases', :path => '../../'

end

I changed platform version and added use_frameworks

I know it is pod framework related but i tried all solutions on stackoverflow and Cocoapods GitHub thread. Nothing worked.

what could be the issue?

Thanks
Ashish

purchaserInfo.purchaseDate(forProductIdentifier returns a null purchase date for a purchased renewing product

Here is some sample client code that demonstrates the issue

    for purchasedProductIdentifier in purchaserInfo.allPurchasedProductIdentifiers {
        
        print ("ID: \(purchasedProductIdentifier)")
        print("Start Date:  \(String(describing: purchaserInfo.purchaseDate(forProductIdentifier: purchasedProductIdentifier)))")
        print("End Date:  \(String(describing: purchaserInfo.expirationDate(forProductIdentifier: purchasedProductIdentifier)))")
    }

For renewing products, the purchase date is always nil.

Fatal Exception in `RCPurchases.m`

We're seeing a Fatal Exception in our latest app version.

Details

  • iOS v13.3
  • App in foreground state
  • Crashlytics assumes device is jailbroken
  • SDK revenuecat/purchases-ios v3.2.2, installed through Carthage

Stack trace

Fatal Exception: NSInvalidArgumentException
*** -[__NSDictionaryM setObject:forKeyedSubscript:]: key cannot be nil

-[RCPurchases purchaseProduct:withPayment:withPresentedOfferingIdentifier:completion:]

0  CoreFoundation                 0x19b5a096c __exceptionPreprocess
1  libobjc.A.dylib                0x19b2b9028 objc_exception_throw
2  CoreFoundation                 0x19b5f9500 -[__NSCFString characterAtIndex:].cold.1
3  CoreFoundation                 0x19b6035a0 -[__NSDictionaryM setObject:forKeyedSubscript:].cold.2
4  CoreFoundation                 0x19b47b190 -[__NSDictionaryM setObject:forKeyedSubscript:]
5  Purchases                      0x1054aa4b0 -[RCPurchases purchaseProduct:withPayment:withPresentedOfferingIdentifier:completion:] + 558 (RCPurchases.m:558)
6  Purchases                      0x1054a9f08 -[RCPurchases purchasePackage:withCompletionBlock:] + 485 (RCPurchases.m:485)
7  AppName                        0x104f2d738 closure #1 in RCPurchases.purchase(_:) + 134 (PurchasesExtension.swift:134)
8  AppName                        0x105055ee8 partial apply for thunk for @escaping @callee_guaranteed (@guaranteed @escaping @callee_guaranteed (@guaranteed SingleEvent<RCOfferings>) -> ()) -> (@out Disposable)
9  RxSwift                        0x1061c99f4 partial apply for closure #1 in static PrimitiveSequenceType<>.create(subscribe:) + 39 (Single.swift:39)
10 RxSwift                        0x10619946c AnonymousObservable.run<A>(_:cancel:) + 60 (Create.swift:60)
11 RxSwift                        0x1061a6f64 Producer.subscribe<A>(_:) + 18 (Producer.swift:18)
...

Cannot upload Carthage build to App Store because it includes x86_64, i386

Hi,

I'm trying to upload a beta build of my app, which I just integrated with RevenueCat, to App Store Connect. I'm using Carthage to build the 3.0.0 version of RevenueCat.

I get this error on submission:

App Store Connect Operation Error
Unsupported Architectures. The executable for MyApp.app/Frameworks/Purchases.framework contains unsupported architectures '[x86_64, i386]'.

App Store Connect Operation Error
Invalid Segment Alignment. The app binary at 'MyApp.app/Frameworks/Purchases.framework/Purchases' does not have proper segment alignment. Try rebuilding the app with the latest Xcode version.

App Store Connect Operation Error
The binary is invalid. The encryption info in the LC_ENCRYPTION_INFO load command is either missing or invalid, or the binary is already encrypted. This binary does not seem to have been built with Apple's linker.

I'm using Xcode 11.2.1, and I believe my command-line build environment is set up properly:

$ xcode-select -p
/Applications/Xcode.app/Contents/Developer

I noticed that you recommend using the --no-use-binaries flag in Carthage, and I've tried both with and without that flag. I get the error either way.

carthage build --platform ios --configuration Release --no-use-binaries
carthage build --platform ios --configuration Release

I'm wondering whether the second and third error might be because of the first one. Do you know what I can do to prevent RevenueCat from building x86 targets when making iOS-only builds using Carthage?

Repeated syncs and calls to applicationDidBecomeActive with TV off

On an Apple TV 4K, running on the device (no simulator), everything works fine as long as the TV is on. As soon as I turn the TV off, I see:

12:21:59-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:01-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:01-0700 MyApp[] [Purchases] - DEBUG: applicationDidBecomeActive
12:22:05-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:07-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:07-0700 MyApp[] [Purchases] - DEBUG: applicationDidBecomeActive
12:22:12-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:13-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:13-0700 MyApp[] [Purchases] - DEBUG: applicationDidBecomeActive
12:22:14-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:19-0700 MyApp[] [Purchases] - INFO: Subscriber attributes synced successfully
12:22:19-0700 MyApp[] [Purchases] - DEBUG: applicationDidBecomeActive

(I've removed the date from the beginning of each line to shorten the length). It does this about every 5 seconds until the TV is turned back on whereupon it returns to normal.

-makePurchase:withDiscount:completionBlock: finishes with error for subscribed users

Hello,

Let's say a user has an active subscription to product X and redeems an offer for the same product. The operation is successful according to Apple, which is indicated by "You're all set" popup. However, we receive transaction with state .failed along with some generic error in -makePurchase:withDiscount:completionBlock: callback in this case. Also no changes in RevenueCat dashboard nor in decoded receipt are observed immediately after that.

Is it intended behaviour, a bug in RevenueCat or some glitch in Apple sandbox?

warning: nil passed to a callee that requires a non-null parameter

Steps to reproduce:

  • Open the Purchases.xcodeproj project in Xcode 11.4
  • Choose an iOS Simulator as target
  • Perform a static analysis with Product > Analyze

Result:
You see 3 warnings "nil passed to a callee that requires a non-null parameter":

  1. purchases-ios/Purchases/SubscriberAttributes/RCSubscriberAttributesManager.m:81:5: warning: nil passed to a callee that requires a non-null 2nd parameter
    [self storeAttributeLocallyIfNeededWithKey:key value:value appUserID:appUserID];

  2. purchases-ios/Purchases/Public/RCPurchases.m:177:26: warning: nil passed to a callee that requires a non-null 2nd parameter
    RCBackend *backend = [[RCBackend alloc] initWithAPIKey:APIKey platformFlavor:platformFlavor];

  3. purchases-ios/Purchases/Public/RCPurchases.m:874:9: warning: nil passed to a callee that requires a non-null 1st parameter
    [self markAttributesAsSyncedIfNeeded:subscriberAttributes appUserID:self.appUserID error:error];

It appears that the methods where nil is passed as parameter can perfectly handled the nil parameter. So I would assume that the keyword nullable is missing from the method prototype.

Unable to compile in Xcode 11.4 Beta 2

Hey!

I use purchases in an iPadOS app and ever since Xcode 11.4 Beta 1 (and persisting through to Beta 2), I haven't been able to compile my app.

Upon compiling, I get 7 errors
image

periodType = null in test environment.

The periodType in active entitlements is null. This is during sandbox testing with the latest version 3.2.2. If this is due to the sandbox, is there a way we can test to ensure it works in production?

offerings vs purchaserInfo

Hi !
How can I determine what exactly subscription is active now, if when I get all offers using Purchases.shared.offerings I get all identifiers like:

  • 0 : "$rc_monthly"
  • 1 : "$rc_annual"

and when I'm fetching purchaseInfo using Purchases.shared.purchaserInfo, the identifiers are the ones associated with my products, like:

  • 0 :com.product.subscription.month
  • 1 : com.product.subscription.year

thanks

Swift Package manager support

Xcode 11 comes with swift package manager, a lot easier than dealing with cocoapods or carthage, all of our other packages are on SPM, would love to see this one be there as well!

Non-renewing subscription rejection

Hello, I'm using the same PayWall in this repo as a payment screen. I have a non-renewing product. In my previous version, PayWall was directly presented to the user after launching the app. Now in this rejected version, I only moved the Paywall from the app start to the behind of 'download' button. Now the user transforms the image and performs the basic function of the app and then PayWall shown if the user wants to download the image.
What do you guys advise me to handle this rejection?

Guideline 3.1.1 - Business - Payments - In-App Purchase

We found that your app includes a feature to restore previously purchased in-app purchase products by entering the user's Apple ID and password. However, non-renewable subscriptions in-app purchases cannot be restored in this manner.

To resolve this issue, please revise your binary to implement your own restore mechanism, if you would like users to be able to restore non-renewable subscriptions in-app purchase products.

More information on in-app purchase product types is available in App Store Connect Help.

Guideline 3.1.2 - Business - Payments - Subscriptions

Your app offers a content subscription but does not have a mechanism in place to support the requirement that the subscription content be available to the user on all of their iOS devices.

Next Steps

To resolve this issue, please modify your app to include an optional user registration feature to deliver subscription content to all of the user's iOS devices. Such user registration must be made optional, not required. We also recommend indicating that registering is required to access the subscription content from their other iOS devices - and providing a way to register later, if users wish to have access to this content at a future time.

RCPurchases dealloc is not called

Hi,

I have when a problem when I need re-init Purchases class with a different userId during the same app session. Dealloc is not being called so all the listeners are still active for old user too(all calls are multiplied by number of pre-used users).
Workaround for now - manually set delegate to nil.

Crash when retrieving purchaser information from cache

I have a crash occurring here since appUserID is nil for some reason...

RCDeviceCache.m (Line 88)

  • (NSString *)purchaserInfoUserDefaultCacheKeyForAppUserID:(NSString *)appUserID {
    return [RCPurchaserInfoAppUserDefaultsKeyBase stringByAppendingString:appUserID];
    }

Should at least protect from nullable input like this.

  • (NSString *)purchaserInfoUserDefaultCacheKeyForAppUserID:(NSString *)appUserID {
    if(appUserID == nil) { return nil; }
    return [RCPurchaserInfoAppUserDefaultsKeyBase stringByAppendingString:appUserID];
    }

Or is there a reason why appUserID would be nil?

'Purchases' is not a member type of 'Purchases'

Hi, i recently updated my Purchases pod version 2.6 to 3.0.4. I also changed getting offerings method to this :

Purchases.shared.offerings { (offerings, error) in
            if let packages = offerings?.current?.availablePackages {
                // Display packages for sale
            }
}

but i couldn't be able to get current offerings.
i tried to delete derived data , deintegrating pods and installing again, deleting build folders, but no conclusion.
the error is :

Printing description of offering:
expression produced error: error: /var/folders/4g/w58ds9mx2l77zy4fzbd97jyw0000gn/T/expr11-5be3e6..swift:1:90: error: 'Purchases' is not a member type of 'Purchases'
Swift._DebuggerSupport.stringForPrintObject(Swift.UnsafePointer<Swift.Optional<Purchases.Purchases.Offerings>>(bitPattern: 0x1154b4450)!.pointee)
                                                                               ~~~~~~~~~ ^

Expose master appUserID to clients to support non-renewing products restoration across devices

Since RevenueCat does not fully support non-renewing subscriptions (restoration across devices, storing expiration dates, etc) I am working around this by storing the information in Firebase. However, I need to tie together purchases made in one device to another device of the same user for restoration.

Initially I tried to use RCPurchases.appUserID to do so but learned that they are unique to the device, not the appleID user, when using anonymous auth.

My app has no need for login/authorization beyond purchasing products and my users have spoken loudly they don't want a monthly subscription to the app. So non-renewing products are critical.

One solution I have is to expose the master user ID in the RevenueCat backend in RCPurchases or in RCPurchaserInfo. It is my understanding that this is the primary key for joining the list of device userAppIDs. This would give me a 1:1 relationship to the appleID I need to restore non-renewing transactions from Firebase. I think this would be a reasonable stopgap until RevenueCat fully supports non-renewing products.

I am open to other ideas to handle this too, this is simply the best one I thought of. In the end, solving the restoration and storing of supplemental information is the primary goal ahead of RevenueCat fully supporting non-renewing products. Ideally, if this could be exposed by Dec 15, 2018 that would align best with the 'season' picking up for my customers.

Explicitly triggering a network fetch

The following method is currently unused, although it would be handy if it was available through the public header. Without it, there is no way to explicitly trigger a network fetch which may be desirable, particularly from extensions where the applicationDidBecomeActive: handler does not get called (and adding NSExtensionHostDidBecomeActive would not be sufficient).

If made available, it should probably be renamed to updatePurchaserInfo or something else that clearly conveys a network fetch is going to happen (fetch?).

- (void)updatedPurchaserInfo

'SKProductDiscountPaymentMode' is only available on iOS 11.2 or newer

Annotate 'RCPaymentModeFromSKProductDiscountPaymentMode' with an availability attribute to silence this warning

iOS 12 issue.

RCBackend.h:33
RCPaymentMode RCPaymentModeFromSKProductDiscountPaymentMode(SKProductDiscountPaymentMode paymentMode);

should be

API_AVAILABLE(ios(11.2)) RCPaymentMode RCPaymentModeFromSKProductDiscountPaymentMode(SKProductDiscountPaymentMode paymentMode);

RCBackend.m
RCPaymentMode RCPaymentModeFromSKProductDiscountPaymentMode(SKProductDiscountPaymentMode paymentMode)

should be

API_AVAILABLE(ios(11.2)) RCPaymentMode RCPaymentModeFromSKProductDiscountPaymentMode(SKProductDiscountPaymentMode paymentMode)

Crash on logout call to Firebase auth with proceeding Purchases.shared.reset

Calling Auth.auth().signOut() crashes with the following stack trace if you have added an observer to

Auth.auth().addStateDidChangeListener

and call Purchases.shared.reset as per your guide

2019-12-25 12:52:16.687635+0100 Charged Production[95849:23984344] [Common] _BSMachError: port 12b03; (os/kern) invalid capability (0x14) "Unable to insert COPY_SEND"
2019-12-25 12:52:16.779726+0100 Charged Production[95849:23984344] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSCFConstantString stringByAppendingString:]: nil argument'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff23c7127e __exceptionPreprocess + 350
	1   libobjc.A.dylib                     0x00007fff513fbb20 objc_exception_throw + 48
	2   Foundation                          0x00007fff2577900e -[NSString stringByAppendingFormat:] + 0
	3   Purchases                           0x00000001065ac746 -[RCPurchases attributionDataUserDefaultCacheKeyForAppUserID:] + 70
	4   Purchases                           0x00000001065a505e -[RCPurchases resetWithCompletionBlock:] + 142
	5   Charged Production                  0x0000000102b27133 $s18Charged_Production23ApplicationConfiguratorC9configureyySo13UIApplicationCFZySo7FIRAuthC_So7FIRUserCSgtcfU_ + 499
	6   Charged Production                  0x0000000102b27a4f $sSo7FIRAuthCSo7FIRUserCSgIeggg_AbEIeyByy_TR + 95
	7   Charged Production                  0x0000000102e99b74 __41-[FIRAuth addAuthStateDidChangeListener:]_block_invoke + 532
	8   Charged Production                  0x0000000102e9a133 __39-[FIRAuth addIDTokenDidChangeListener:]_block_invoke + 163
	9   Foundation                          0x00007fff2574b44e -[__NSObserver _doit:] + 287
	10  CoreFoundation                      0x00007fff23b9b5bc __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12

I have enough bugs that I produce myself, so would be awesome to not have to deal with yours as well ;)

Nil Entitlements

I am developing a Mac App and seem to be getting a return of nil entitlemnts after implementing an instance of RCPurchases setting the delegate and calling the completion handler purchases?.entitlements({ (entitlements) in . Am I missing something. Please can you help.

Carthage currently not working

Running Carthage update produces the below, but nothing is actually downloaded:

*** Downloading purchases-ios.framework binary at "1.0.4"

original_transaction_id (OTI)

Can you please add to your SDK original property from apple receipt validation original_transaction_id ?

It is really necessary, because having all users marked as anonymous, it seems to be the only persistent value witch can be used as userID

thanks

Manual integration?

It would be great if we could add this as a dependency just using git submodules if we are not using Carthage or Cocoapods.

Another IAP API - App Store Review

Hi Guys

I have been using revenue cat on my MacOS app Shepherd for a couple of weeks now. Things were up and running. After updating the app with a bug fix (not related to purchases), I received this message from app rejecting the app.

"Your app enables the purchase of content, services, or functionality by means other than the in-app purchase (IAP) API.

We noticed that your app or its metadata provides access to external mechanisms for purchases or subscriptions to be used in the app, which does not comply with the App Store Review Guidelines."

Is this related to revenue cat's version not been updated to the latest version in line with Apples IAP API?
Have you encountered this before?
Is this perhaps a classic app store review that is misunderstood?

Your help will be appreciated.

I am currently using revenue cat for MacOS Version 2.3.

Restore subscriptions cancel error.

I use Purchases (v 1.2.0) in my project. I can see the Purchases library sends the receipt data even if user cancels the subscription restore. In this case RevenueCat backend returns error:

("Error Domain=RCBackendErrorDomain Code=0 "The receipt is not valid." UserInfo= { NSLocalizedDescription=The receipt is not valid. }")

and sends this error to delegate method. How can I distinguish between the case when user cancels restore subscription and the "real" backend error happens? Thanks!

Please add ability to hook in a custom logger

Currently RCSetShowDebugLogs(YES) will cause logging to go to NSLog. We (and presumably a lot of other people) have our own logger, and we would prefer to have logging routed through it.

The MVP for this is something like RCSetLoggingFunction(void *fn);

activeProduct is nil

Hi,
I am just integrating RevenueCat for subscriptions and when I try to do a purhcase, activeProduct is nil. According to the documentation:

The active product, this will be null if the product is not available, usually because it has not been approved for sale

This is correct, my product in iTunesConnect is still not Ready for Sale, but how can I test this? I want to call self.purchases.makePurchase(product).

Am I missing anything? Did I understood it wrong?

I use Xcode 10.0 and an iPhone X with iOS 12.

Thank you

Network calls during configure process

As soon as configure function is called library is making 2 network calls. This is a new logic and wasn't there before. Is it a bug or there is reasoning behind this decision?

Indicate user cancelled in restoreTransactions API

When I call restoreTransactions I'm prompted for my app store password. If I tap cancel, I would expect an error or other indication of cancellation, but my completion is called with success.

I would like to know if the operation is cancelled so that I can know whether to show a "purchases restored" alert.

Simplify Purchasing Calls

I find myself copying and pasting the same generic wrapper around RevenueCat into every app I make.

The issue is the purchasing is all handled through the delegate methods so I have to have a class that stores the completion block like so:


//MARK:- My Purchase Code
    
    public fileprivate(set) var analyticsProMonthly: SKProduct?
    fileprivate var completion: ((Bool?, Error?) -> ())?
    
    public func purchaseAnalyticsProMonthly(_ completion: @escaping (Bool?, Error?) -> ()) {
        self.completion = completion
        
        if let analyticsProMonthly = self.analyticsProMonthly {
            self.purchases.makePurchase(analyticsProMonthly)
        } else {
            purchases.products(withIdentifiers: [analyticsProMonthly2Identifier]) { (products) in
                if let product =  products.first {
                    self.purchases.makePurchase(product)
                } else {
                    completion(false, "couldn't get products" as? Error)
                }
            }
        }
    }
    
    //MARK:- RCPurchasesDelegate
    
    public func restoreTransactions(_ completion: @escaping (Bool?, Error?) -> ()) {
        self.completion = completion
        
        purchases.restoreTransactionsForAppStoreAccount()
    }
    
    public func purchases(_ purchases: RCPurchases, restoredTransactionsWith purchaserInfo: RCPurchaserInfo) {
        if let latestExpirationDate = purchaserInfo.latestExpirationDate {
            self.latestExpirationDate = latestExpirationDate
        }
        
        completion?(true, nil)
        self.completion = nil
    }
    
    public func purchases(_ purchases: RCPurchases, failedToRestoreTransactionsWithError error: Error) {
        completion?(false, error)
        self.completion = nil
    }
    
    public func purchases(_ purchases: RCPurchases, receivedUpdatedPurchaserInfo purchaserInfo: RCPurchaserInfo) {
        if let latestExpirationDate = purchaserInfo.latestExpirationDate {
            self.latestExpirationDate = latestExpirationDate
            completion?(true, nil)
        }
        
        self.completion = nil
        self.activeSubscriptions = purchaserInfo.activeSubscriptions
    }
    
    
    public func purchases(_ purchases: RCPurchases, failedToUpdatePurchaserInfoWithError error: Error) {
        completion?(false, error)
        self.completion = nil
        
    }
    
    public func purchases(_ purchases: RCPurchases, failedTransaction transaction: SKPaymentTransaction, withReason failureReason: Error) {
        completion?(false, failureReason)
        self.completion = nil
    }
    
    public func purchases(_ purchases: RCPurchases, completedTransaction transaction: SKPaymentTransaction, withUpdatedInfo purchaserInfo: RCPurchaserInfo) {
        if let latestExpirationDate = purchaserInfo.latestExpirationDate {
            self.latestExpirationDate = latestExpirationDate
            completion?(true, nil)
        }
        
        self.completion = nil
        self.activeSubscriptions = purchaserInfo.activeSubscriptions
    }
}

I really wish that it looked liked this:

public func purchaseProduct(productID: String, completion: (Bool, Error?) -> ()) {

}

And then a simple way of checking if the user is susbcribed. I think most users only have 1 tier and don't event have to check for various different products. Just a simple question, is the user subscribed or not?

purchases.isSubcribed(productID: String? = nil) -> Bool 

It's gotten to the point where I'm writing a development cocoapod for wrapping Purchases

library not found for -lPurchases

Getting the following error when running the swift example app:

ld: warning: directory not found for option '-L/Users/Damian/Library/Developer/Xcode/DerivedData/SwiftExample-ezbgahlnwhanmghczzjmgcifqczs/Build/Products/Debug-iphoneos/Purchases'
ld: library not found for -lPurchases
clang: error: linker command failed with exit code 1 (use -v to see invocation)

'Purchases' is not a member type of 'Purchases'

Hi, super excited to have found this potential IAP solution! But straightaway I'm getting an error:

Purchases.shared.offerings { (offerings, error) in
            if let packages = offerings?.current?.availablePackages {
                // Display packages for sale
            }
        }

The error:

expression produced error: error: /var/folders/9m/qr_cnwq903n_f_xf0nbgcf140000gn/T/expr9-ab7010..swift:1:90: error: 'Purchases' is not a member type of 'Purchases'
Swift._DebuggerSupport.stringForPrintObject(Swift.UnsafePointer<Swift.Optional<Purchases.Purchases.Offerings>>(bitPattern: 0x10be7d6e0)!.pointee)

Edit: Seems I get this error upon any attempt at using the API:

Purchases.shared.purchaserInfo { (purchaserInfo, error) in
            // access latest purchaserInfo
        }

My own Package conflicts with RCPackage

Hi,

I'm trying to migrate to the new offerings system in a Swift project that has struct Package. It obviously conflicts with RCPackage, which is defined as Package for Swift. I installed RevenueCat via Cocoapods.

I tried to use Purchases.Package instead, but Xcode gives me the following error: 'Package' is not a member type of 'Purchases'.

I'm not sure if this is an issue of RevenueCat or Swift, however I wanted to give you a heads up. I created a sample project that demonstrates the issue.

Thanks.

ConflictingProject.zip

Purchaser info not returning correct "isActive" value for entitlement on WatchOS

I am running v3.2.2 on my iOS and WatchOS targets with the same appUserID value. After making a sandbox subscription purchase on iOS, the purchaserInfo on iOS returns the correct entitlement with "isActive" true. However on WatchOS, it returns that same entitlement with "isActive" false.

Oddly enough, WatchOS does list the expirationDate as a time in the future, indicating it is an active entitlement. Any suggestions for a work around on this? I'm thinking of using the expirationDate value for WatchOS purchase validation only.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.