GithubHelp home page GithubHelp logo

revenuecat / purchases-capacitor Goto Github PK

View Code? Open in Web Editor NEW
117.0 9.0 12.0 19.14 MB

Capacitor in-app purchases and subscriptions made easy.

License: MIT License

JavaScript 0.48% Java 0.08% Objective-C 3.02% TypeScript 48.39% Swift 18.38% Ruby 5.32% HTML 0.58% CSS 4.61% Kotlin 19.14%
capacitor capacitor-plugin ios android

purchases-capacitor's People

Contributors

aboedo avatar actions-user avatar dependabot[bot] avatar github-actions[bot] avatar mitcheljager avatar nachosoto avatar productdevbook avatar rcgitbot avatar renovate[bot] avatar riderx 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

purchases-capacitor's Issues

question: difference between `cycles` and `periodNumberOfUnits`

In the types the following two fields are returned on PurchasesIntroPrice: cycles and periodNumberOfUnits.

They seem very similar. From the docs:

cycles:

Number of subscription billing periods for which the user will be given the discount, such as 3.

periodNumberOfUnits

Number of units for the billing period of the discount.

Without any other information, these fields seem to be exactly the same. So what's the difference between the two, if any?

login() not implemented on ios

Hey there, i switched from https://github.com/RevenueCat/cordova-plugin-purchases to this plugin, but get the error `login() is not implemented on ios". Setup works however. But as far as the docs state, you should only call setup once and rather login() if you use a classical auth login/register schema.

Is this an oversight, should i just ignore it and call setup every time, although this might lead to multiple calls of setup() if the user logs out and logs in again?

Product Type For Consumable

I am using the 6.0 plugin and when I try to purchase nothing happened. When I pull the product I get the following:

"title":"BoosterPack","currencyCode":"USD","identifier":"BoosterPack","introPrice":null,"priceString":"$0.49","productCategory":"NON_SUBSCRIPTION","description":"test","price":0.49,"productType":"NON_CONSUMABLE","subscriptionPeriod":null,"discounts":[]}

However the product should be "CONSUMABLE" instead but there is no way for me to change it. I am wondering if this is a bug that causing the plugin not pulling up the ios purchase window?

Crash on iOS and a cancelled purchase

Thanks for a great plugin!

I'm using iPadOS 16.3.1 and now testing sad flows, like when a user decides not to subscribe. It seems like the Web view crashed:

2023-03-20 10:05:49.561019+0200 App[9756:440662] [Purchases] - WARN: ๐ŸŽโš ๏ธ StoreKit 2 purchase took longer than expected (31.04 seconds)
2023-03-20 10:05:49.564911+0200 App[9756:440662] [Purchases] - DEBUG: โ„น๏ธ Vending CustomerInfo from cache.
2023-03-20 10:05:49.569594+0200 App[9756:439523] [Purchases] - ERROR: ๐ŸŽโ€ผ๏ธ Purchase was cancelled.
ERROR MESSAGE:  {"errorMessage":"Restore failed","message":"Restore failed"}
โšก๏ธ  [error] - {"errorMessage":"Restore failed","message":"Restore failed"}
2023-03-20 10:05:49.579256+0200 App[9756:439523] [Process] 0x10b324880 - [PID=9762] WebProcessProxy::didClose: (web process 0 crash)
2023-03-20 10:05:49.579512+0200 App[9756:439523] [Process] 0x10b324880 - [PID=9762] WebProcessProxy::processDidTerminateOrFailedToLaunch: reason=Crash

CocoaPods could not find compatible versions for pod "PurchasesHybridCommon"

I migrated capgo plugin to purchases-capacitor plugin but getting errors in ios
i am using ionic capacitor with all the latest version packages.
Here is what i am getting in terminal after running npx cap sync ios:

[!] CocoaPods could not find compatible versions for pod "PurchasesHybridCommon":
        In Podfile:
        RevenuecatPurchasesCapacitor (from
        `../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@revenuecat/purchases-capacitor`)
        was resolved to 6.0.0, which depends on
        PurchasesHybridCommon (= 6.1.3)
        
        None of your spec sources contain a spec satisfying the dependency:
        `PurchasesHybridCommon (= 6.1.3)`.
        
        You have either:
        * out-of-date source repos which you can update with `pod repo update` or with `pod
        install --repo-update`.
        * mistyped the name or version.
        * not added the source repo that hosts the Podspec to your Podfile.

Please help

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): update capacitor monorepo to v5.2.3 (@capacitor/android, @capacitor/cli, @capacitor/core, @capacitor/ios)
  • chore(deps): update dependency @ionic/prettier-config to v3.1.0
  • chore(deps): update dependency eslint to v8.47.0
  • chore(deps): update dependency eslint-plugin-import to v2.28.0
  • chore(deps): update dependency prettier-plugin-java to v2.2.0
  • chore(deps): update dependency rollup to v3.28.0
  • chore(deps): update dependency typescript to v5.1.6
  • chore(deps): update typescript-eslint monorepo to v5.62.0 (@typescript-eslint/eslint-plugin, @typescript-eslint/parser)

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

cocoapods
ios/Podfile
github-actions
.github/workflows/build.yml
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
  • actions/setup-java v3
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
  • JS-DevTools/npm-publish v2
  • JS-DevTools/npm-publish v2
.github/workflows/bump_version.yml
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
.github/workflows/test.yml
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
  • actions/setup-java v3
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
  • actions/checkout v3
  • pnpm/action-setup v2
  • actions/setup-node v3
gradle
android/gradle.properties
android/settings.gradle
android/build.gradle
  • com.android.tools.build:gradle 8.1.0
  • com.google.guava:guava 31.1-android
  • com.revenuecat.purchases:purchases 5.8.2
  • com.revenuecat.purchases:purchases-hybrid-common 4.18.0
gradle-wrapper
android/gradle/wrapper/gradle-wrapper.properties
  • gradle 8.2.1
npm
example/package.json
  • vite ^4.0.0
package.json
  • @capacitor/android ^5.0.3
  • @capacitor/cli ^5.0.3
  • @capacitor/core ^5.0.3
  • @capacitor/docgen ^0.2.1
  • @capacitor/ios ^5.0.3
  • @ionic/eslint-config ^0.3.0
  • @ionic/prettier-config ^3.0.0
  • @ionic/swiftlint-config ^1.1.2
  • @typescript-eslint/eslint-plugin ^5.59.7
  • @typescript-eslint/parser ^5.59.7
  • eslint ^8.41.0
  • eslint-plugin-import ^2.27.5
  • husky ^8.0.3
  • prettier ^2.8.8
  • prettier-plugin-java ^2.1.0
  • rimraf ^5.0.1
  • rollup ^3.23.0
  • swiftlint ^1.0.2
  • typescript ^5.0.4
  • @capacitor/core ^5.0.0

  • Check this box to trigger a request for Renovate to run again on this repository

Unable to serialize plugin response as JSON

Thanks for the great plugin!

I frequently get the below errors logged in XCode on Mac when running on an iOS device - the plugin call seems to succeed, and I'm not sure how serious it is.

Possibly it occurs when the plugin returns undefined?

[Capacitor Plugin Error] - CapacitorPurchases - addListener - Unable to serialize plugin response as JSON.Ensure that all data passed to success callback from module method is JSON serializable!
[Capacitor Plugin Error] - CapacitorPurchases - logIn - Unable to serialize plugin response as JSON.Ensure that all data passed to success callback from module method is JSON serializable!
[Capacitor Plugin Error] - CapacitorPurchases - logOut - Unable to serialize plugin response as JSON.Ensure that all data passed to success callback from module method is JSON serializable!

From calls like this:

  await CapacitorPurchases.setup({
      apiKey: REVENUECAT_PUBLIC_API_KEY,
  })

  CapacitorPurchases.addListener("purchasesUpdate", ({ purchases, purchaserInfo }) => {
      console.log("Got updated purchaserInfo!", purchaserInfo)
  })

Incidentally, the plugin says I should supply appUserID to setup(), but the docs say it's optional.

[Purchases] - DEBUG: โ„น๏ธ Configuring SDK using RevenueCat's UserDefaults suite.
[Purchases] - WARN: โš ๏ธ The appUserID is empty. This method should only be called with non-empty values.
[Purchases] - DEBUG: ๐Ÿ‘ค Identifying App User ID
[Purchases] - DEBUG: โ„น๏ธ Debug logging enabled
[Purchases] - DEBUG: โ„น๏ธ SDK Version - 4.16.0

โ”€ @capacitor/[email protected]
โ”œโ”€ @capacitor/[email protected]
โ”‚ โ”œโ”€ @ionic/cli-framework-output@^2.2.5
โ”‚ โ”œโ”€ @ionic/utils-fs@^3.1.6
โ”‚ โ”œโ”€ @ionic/utils-subprocess@^2.1.11
โ”‚ โ”œโ”€ @ionic/utils-terminal@^2.3.3
โ”‚ โ”œโ”€ commander@^9.3.0
โ”‚ โ”œโ”€ debug@^4.3.4
โ”‚ โ”œโ”€ env-paths@^2.2.0
โ”‚ โ”œโ”€ kleur@^4.1.4
โ”‚ โ”œโ”€ native-run@^1.6.0
โ”‚ โ”œโ”€ open@^8.4.0
โ”‚ โ”œโ”€ plist@^3.0.5
โ”‚ โ”œโ”€ prompts@^2.4.2
โ”‚ โ”œโ”€ rimraf@^3.0.2
โ”‚ โ”œโ”€ semver@^7.3.7
โ”‚ โ”œโ”€ [email protected]
โ”‚ โ”‚ โ””โ”€ lru-cache@^6.0.0
โ”‚ โ”œโ”€ tar@^6.1.11
โ”‚ โ”œโ”€ tslib@^2.4.0
โ”‚ โ””โ”€ xml2js@^0.4.23
โ”œโ”€ @capacitor/[email protected]
โ”‚ โ””โ”€ tslib@^2.1.0
โ”œโ”€ @capacitor/[email protected]
โ”œโ”€ @capacitor/[email protected]
โ”œโ”€ @capacitor/[email protected]
โ”œโ”€ @capacitor/[email protected]
โ”œโ”€ @capacitor/[email protected]
โ”œโ”€ @capgo/[email protected]

question: Does this plugin have integration with the web?

I have never used Revenuecat but from what I have seen it offers integration with stripe for the web.
I am looking for a solution that covers all platforms, web, ios and android.
Could I make subscriptions on the web with this plugin?
Thank you, and sorry for asking in this section

allowedCommonJsDependencies necessity?

Good morning,

When compiling I'm getting:

"Warning: c:\.....\node_modules\@revenuecat\purchases-capacitor\dist\esm\definitions.js depends on '@revenuecat/purchases-typescript-internal'. CommonJS or AMD dependencies can cause optimization bailouts."

I can resolve this message by suppressing it in angular.json by adding it to the allowedCommonJsDependencies array, but that's not ideal.

I was wondering if the new beta version would address this, or if it will remain like this.

iOS 15.5 Example purchase-tester App Stuck in Blank Screen

Hello there! Our team is currently facing an issue while attempting to migrate to the new version of the 'purchases-capacitor' plugin. While our Android app seamlessly integrates with the new version, our iOS app encounters problems running on iOS 15.5 and iOS 15.7. We decided to investigate further by checking if the same issue arises in the example app, and indeed, we found the same problem there as well.

Expected Behavior

We expect the example app to run smoothly on iOS 15.5 without any issues.

Current Behavior

However, when we try to run the example app on an iOS device, the build process succeeds, but the app gets stuck on a blank screen with error appearing in the output.

Steps to Reproduce

  1. Install the latest version of the purchases plugin
  2. Run the app on device/simulator with an iOS 15.5 version

Context (Environment)

Installed Dependencies:

  @capacitor/cli: 5.2.3
  @capacitor/core: 5.2.3
  @capacitor/android: 5.2.3
  @capacitor/ios: 5.2.3
System:

   NodeJS : v16.20.1
   npm    : 8.19.4
   OS     : macOS Unknown
Devices:

iOS: 15.5
iOS: 15.7

Detailed Description

There was no issue while running the both example app and our app with android devices and devices with iOS 16. However after the build succeeds on iOS 15.5, the Xcode output of the example app displays the following message:

2023-09-05 16:13:15.331114+0300 App[860:50726] [ViewportSizing] minimumViewportInset cannot be larger than frame

Migration guide: @awesome-cordova-plugins to @revenuecat/capacitor-purchases [docs]

Hi, how do I solve an error message that says "Missing identifier parameter in {}"?

Here is how I'm initializing purchases in a hook:

export function usePurchases() {
  const [isPurchasesInitialized, setIsInitialized] = useState(false)

  useEffect(() => {
    (async () => {
      const { Purchases, LOG_LEVEL } = (await import('@revenuecat/purchases-capacitor'))

      if (!isPurchasesInitialized) {
        const userUuid = await getUserUuid()
        Purchases.setLogLevel({ level: LOG_LEVEL.DEBUG });
        const apiKey = Capacitor.getPlatform() === 'android' ?
          process.env.REVENUECAT_API_KEY_ANDROID :
          process.env.REVENUECAT_API_KEY_IOS

        Purchases.configure({
          apiKey,
          appUserID: userUuid
        });
        myPurchases = Purchases

        setIsInitialized(true)
      }
    })()
  }, [isPurchasesInitialized]);

  return { isPurchasesInitialized, Purchases: myPurchases };
}

This is how I get and set the purchases' offerings and customer Info:

          const offerings = await Purchases.getOfferings();
          setOfferings(offerings)
          const customerInfo = process.env.APP_ENVIRONMENT === 'development' && SUBSCRIBE_DEV_USERS ?
            DEV_CUSTOMER_INFO :
            await Purchases.getCustomerInfo()

Here is the code that runs when the "Purchase Package" button is clicked:

console.log(offeringPackage)
await Purchases.purchasePackage(offeringPackage);

Here is what the offeringPackage log in the above code prints:

{
    "identifier": "$rc_monthly",
    "packageType": "MONTHLY",
    "product": {
        "identifier": "xxxxxx",
        "description": "Gives access to pro features of the RapBot app.",
        "title": "Pro (RapWriter)",
        "price": 0.99,
        "priceString": "$0.99",
        "currencyCode": "USD",
        "introPrice": null,
        "discounts": null,
        "productCategory": "SUBSCRIPTION",
        "productType": "AUTO_RENEWABLE_SUBSCRIPTION",
        "subscriptionPeriod": "P1M",
        "defaultOption": {
            "id": "xxxxx",
            "storeProductId": "xxxxx:xxxxx",
            "productId": "xxxxx",
            "pricingPhases": [
                {
                    "billingPeriod": {
                        "unit": "MONTH",
                        "value": 1,
                        "iso8601": "P1M"
                    },
                    "recurrenceMode": 1,
                    "billingCycleCount": 0,
                    "price": {
                        "formatted": "$0.99",
                        "amountMicros": 990000,
                        "currencyCode": "USD"
                    },
                    "offerPaymentMode": null
                }
            ],
            "tags": [],
            "isBasePlan": true,
            "billingPeriod": {
                "unit": "MONTH",
                "value": 1,
                "iso8601": "P1M"
            },
            "isPrepaid": false,
            "fullPricePhase": {
                "billingPeriod": {
                    "unit": "MONTH",
                    "value": 1,
                    "iso8601": "P1M"
                },
                "recurrenceMode": 1,
                "billingCycleCount": 0,
                "price": {
                    "formatted": "$0.99",
                    "amountMicros": 990000,
                    "currencyCode": "USD"
                },
                "offerPaymentMode": null
            },
            "freePhase": null,
            "introPhase": null,
            "presentedOfferingIdentifier": "xxxxxx"
        },
        "subscriptionOptions": [
            {
                "id": "xxxxx",
                "storeProductId": "xxxx:xxxx",
                "productId": "xxxx",
                "pricingPhases": [
                    {
                        "billingPeriod": {
                            "unit": "MONTH",
                            "value": 1,
                            "iso8601": "P1M"
                        },
                        "recurrenceMode": 1,
                        "billingCycleCount": 0,
                        "price": {
                            "formatted": "$0.99",
                            "amountMicros": 990000,
                            "currencyCode": "USD"
                        },
                        "offerPaymentMode": null
                    }
                ],
                "tags": [],
                "isBasePlan": true,
                "billingPeriod": {
                    "unit": "MONTH",
                    "value": 1,
                    "iso8601": "P1M"
                },
                "isPrepaid": false,
                "fullPricePhase": {
                    "billingPeriod": {
                        "unit": "MONTH",
                        "value": 1,
                        "iso8601": "P1M"
                    },
                    "recurrenceMode": 1,
                    "billingCycleCount": 0,
                    "price": {
                        "formatted": "$0.99",
                        "amountMicros": 990000,
                        "currencyCode": "USD"
                    },
                    "offerPaymentMode": null
                },
                "freePhase": null,
                "introPhase": null,
                "presentedOfferingIdentifier": "xxxx"
            }
        ],
        "presentedOfferingIdentifier": "xxxx"
    },
    "offeringIdentifier": "xxxx"
}

What am I doing wrong?

Thanks for the plugin!

Nothing happens with purchaseStoreProduct on iOS

Hi ! First of all, thank you for making this โค๏ธ

I'm able to display products correctly from the App Store, but the method purchaseStoreProduct never returns or logs anything. I'm using @capacitor/core 5.2.3 with a Nuxt 3.6.5 app.

The iOS payment popin never appears (it was working when I used cordova-plugin-purchase). I tested this on the simulator and my physical Iphone X.

Here's my code:

export const products: Ref<PurchasesStoreProduct[]> = ref([])

export const initIAP = async () => {  
  if (!Capacitor.isNativePlatform()) return 

  try {
    Purchases.configure({
      apiKey: 'XXX',
      observerMode: false
    })

    const { products: fetchedProducts } = await Purchases.getProducts({
      productIdentifiers: ['supporter_v2_one_month']
    })

    products.value = fetchedProducts
  } catch (e) {
    console.error(e)
  }
}

export const purchaseProduct = async (product: PurchasesStoreProduct) => {
  try {
    console.log('purchase')
    console.log(product)

    const response = await Purchases.purchaseStoreProduct({
      product
    })

    console.log(response) // never goes there
  } catch (e) {
    console.error(e) // or there
  }

  return true
}
โšก๏ธ  [log] - purchase
โšก๏ธ  [log] - {"description":"Aide Vibes LGBTQ ร  accueillir plus de monde !","price":4.99,"identifier":"supporter_v2_one_month","introPrice":null,"subscriptionPeriod":"P1M","discounts":[],"productType":"NON_CONSUMABLE","productCategory":"SUBSCRIPTION","priceString":"4,99ย โ‚ฌ","currencyCode":"EUR","title":"Abonnement Supporter (1 mois)"}

Thank you

compile against version 32 or later of the

https://github.com/riderx/capacitor-purchases/blob/c09243ff909dc8942c76709f9385e5339b5cc8c6/android/build.gradle#L61


  1.  Dependency 'androidx.core:core:1.9.0-alpha05' requires libraries and applications that
      depend on it to compile against version 32 or later of the
      Android APIs.

      :app is currently compiled against android-31.

      Recommended action: Update this project to use a newer compileSdkVersion
      of at least 32, for example 32.

ionic used 1.7.0

image

i think you need to sync this to user's config file

(IOS) Offer Code Advice - Discussion

There isn't a discussion thread on this repo, so I just wanted to open something to have a running dialogue on Offer/Promo Codes with this package. I migrated my existing app from the CapGo plugin to this one and am now onto the phase of implementing promo codes for our application. On Android, it seems straightforward; set up promo codes in Google Play and have Google handle the rest natively with no code or UI changes, so to speak.

On the other hand IOS seems like a different beast. From the docs it seems like there are two ways to approach building a sign up flow UI that involves a promo code:

1.)Add UI that is along the lines of "Have a promo code" that is clickable
2.) Attach a listener for addCustomerInfoUpdateListener(...)
3.) Present the user with the redeemSheet using presentCodeRedemptionSheet()
4.) Listen for changes on CustomerInfo to see if the promo has been applied which would exist on the entitlements property

Other option:

1.) Add UI that is along the lines of "Have a promo code" that is clickable
2.) Collect the Promo code in the JS layer and dynamically build the appStore URL
3.) Attach a listener for Browser.addListener('browserFinished', () =>)
4.) Redirect the user to the appStore link using Browser.open
5.) On browser finish event call syncPurchase then look at the customerInfo to see if an active entitlement exists

Both of these seem like okay options, but I wanted to get opinions on best practices, as it seems that presentCodeRedemptionSheet is unstable at the Apple level. Another issue I am running into is that promo codes are not testable in a sandbox environment, so I would be looking for the best options to not only build the UI but test it to ensure it's stable before releasing to users.

`CapacitorPurchases.setup` never resolves on Android devices

Hi Cap-go!

The plugin is cool! Comparing to the old Cordova one it has lightweight interface and after a bit of struggling with RevCat (and the issue below) everything works just like a breeze!

However I noticed an issue with the CapacitorPurchases.setup method, which in fact never resolves when run on Android devices.

Actual workaround is simply not to await the method call... and IAPs work well. So it looks like there's a bug on the Android implementation side and some internal callbacks are not handled correctly, maybe?

It would be awesome, especially for newcomers, to have the function working well!

getOfferings() response empty?

First off, thanks for forking and creating this capacitor plugin! It came at the perfect time in our app development.

I can't seem to get the offerings call to return anything though, despite having offerings and entitlements set up in Revenue Cat. Not sure if this is a bug in this plugin, something I'm doing wrong, or something I need to contact RevenueCat support about?

Am I using this correctly?

import { CapacitorPurchases } from 'capacitor-purchases';

CapacitorPurchases.setDebugLogsEnabled({ enabled: true });
await CapacitorPurchases.setup({ apiKey: API_KEY });
let { offerings } = await CapacitorPurchases.getOfferings();
console.log(offerings) // => {}

Unable to make a purchase or get any output

Thanks for this package.

I followed the tutorial and absolutely nothing happens when attempting to make a purchase. Not sure if I'm implementing it incorrectly (instructions unclear to me), or the package doesn't support my versions...

Ionic 7
Capacitor 5
Angular 16

I have a button on my Settings page to make a one-time purchase. When clicking the button I attempt to make a purchase, which for now is just trying to output something to the logs to see what's happening...

settings.page.ts

import { Package } from '@capgo/capacitor-purchases';

makePurchase() {
    console.log('making a purchase'); // this prints to the log
    const purchase = async (p: Package): Promise<PurchaserInfo | null> => {
        try {
            console.log('inside try block'); // this never prints to the log
        } catch (e) {
            console.error('error', e); // this doesn't print either
        }
    }
}

app.module.ts

import { IonicModule, IonicRouteStrategy, Platform } from '@ionic/angular';
import { CapacitorPurchases } from '@capgo/capacitor-purchases';

export class AppModule {
    constructor(private platform: Platform) {
        CapacitorPurchases.setDebugLogsEnabled({ enabled: true }).then();
        if (this.platform.is('ios')) {
            CapacitorPurchases.setup({ apiKey: 'appl_********' }).then(res => { // <-- I use my real API key
                const offerings = CapacitorPurchases.getOfferings();
            });
        } else if (this.platform.is('android')) {
            CapacitorPurchases.setup({ apiKey: 'goog_******' }).then();
        }
    }
}

I should note that the code inapp.module.ts was initially in the settings.page.ts constructor, and I could print the products to the log, so the plugin is installed.. it just never printed anything to the logs after setting const purchase so I moved it thinking I'd installed it correctly..

What am I doing wrong?

setAttributes - some attributes randomly being ignored...

I'm having a real head scratching issue with the setAttributes functionality, where randomly some attributes seem to be ignored.

They are all set to strings before being passed into setAttributes and are also stripped of any special characters.

It seems to be completely random, no consistency as to what causes an attribute to be ignored, which is leading me to believe there may be some kind of race condition somewhere, although having looked through the code I can't see anything obvious.

This may be a core iOS SDK issue and I'll post over there too.

As my logs below show, there are 9 attributes passed in, but only 4 get used:

2023-09-08 12:22:47.439156+0100 App[1670:452821] [attribution] DEBUG: โ„น๏ธ setting values for attributes: ["accessId", "iapName", "currencyCode", "interval", "teamId", "tmId", "teamName", "userId", "cost"]
2023-09-08 12:22:47.439710+0100 App[1670:452821] [attribution] DEBUG: โ„น๏ธ Attribute set locally: [SubscriberAttribute] key: accessId value: 2 setTime: 2023-09-08 11:22:47 +0000. It will be synced to the backend when the app backgrounds/foregrounds or when a purchase is made.
2023-09-08 12:22:47.441869+0100 App[1670:452821] [attribution] DEBUG: โ„น๏ธ Attribute set locally: [SubscriberAttribute] key: iapName value: MY_IAP_NAME_HERE setTime: 2023-09-08 11:22:47 +0000. It will be synced to the backend when the app backgrounds/foregrounds or when a purchase is made.
2023-09-08 12:22:47.443554+0100 App[1670:452821] [attribution] DEBUG: โ„น๏ธ Attribute set locally: [SubscriberAttribute] key: interval value: month setTime: 2023-09-08 11:22:47 +0000. It will be synced to the backend when the app backgrounds/foregrounds or when a purchase is made.
2023-09-08 12:22:47.445877+0100 App[1670:452821] [attribution] DEBUG: โ„น๏ธ Attribute set locally: [SubscriberAttribute] key: cost value: 5 setTime: 2023-09-08 11:22:47 +0000. It will be synced to the backend when the app backgrounds/foregrounds or when a purchase is made.
โšก๏ธ  TO JS undefined
2023-09-08 12:22:47.447725+0100 App[1670:452821] [offering] DEBUG: โ„น๏ธ Skipping products request for these products because they were already cached: ["MY_IAP_NAME_HERE"]
2023-09-08 12:22:47.448534+0100 App[1670:452496] [purchases] INFO: ๐Ÿ’ฐ Purchasing Product 'MY_IAP_NAME_HERE'
2023-09-08 12:22:47.449512+0100 App[1670:452496] [purchases] DEBUG: โ„น๏ธ Adding payment for product 'MY_IAP_NAME_HERE'. 0 transactions already in the queue.
2023-09-08 12:22:47.451671+0100 App[1670:452821] [purchases] DEBUG: โ„น๏ธ StoreKit1Wrapper (0x0000000283cfd020) updatedTransaction: MY_IAP_NAME_HERE 0
2023-09-08 12:22:47.458134+0100 App[1670:452821] [purchases] VERBOSE: The SKPaymentTransaction has a nil value for transaction date - this is a bug in StoreKit.
Unix Epoch will be used instead for the transaction within the app.
Transactions in the backend and in webhooks are unaffected and will have the correct timestamps.
Transaction state: SKPaymentTransactionState(rawValue: 0)
2023-09-08 12:22:47.458191+0100 App[1670:452821] [purchases] VERBOSE: The SKPaymentTransaction has a nil value for transaction identifier - this is a bug in StoreKit.
Transactions in the backend and in webhooks are unaffected and will have the correct identifier.
2023-09-08 12:23:03.238008+0100 App[1670:452883] [tcp] tcp_input [C1.1.1:3] flags=[R] seq=141240056, ack=0, win=0 state=LAST_ACK rcv_nxt=141240057, snd_una=757303259
2023-09-08 12:23:03.239182+0100 App[1670:452883] [tcp] tcp_input [C1.1.1:3] flags=[R] seq=141240056, ack=0, win=0 state=LAST_ACK rcv_nxt=141240057, snd_una=757303259
2023-09-08 12:23:03.240012+0100 App[1670:452883] [tcp] tcp_input [C1.1.1:3] flags=[R] seq=141240057, ack=0, win=0 state=LAST_ACK rcv_nxt=141240057, snd_una=757303259
2023-09-08 12:23:03.240854+0100 App[1670:452883] [tcp] tcp_input [C1.1.1:3] flags=[R] seq=141240057, ack=0, win=0 state=CLOSED rcv_nxt=141240057, snd_una=757303259

After backgrounding and then foregrounding the app, these are the logs:

2023-09-08 12:26:29.392922+0100 App[1670:453927] [attribution] INFO: โ„น๏ธ Marking attributes as synced for App User ID: $RCAnonymousID:5dc4892b7dbd48dabb6a1b393c86941b:
 attributes: ["cost": [SubscriberAttribute] key: cost value: 5 setTime: 2023-09-08 11:22:47 +0000, "interval": [SubscriberAttribute] key: interval value: month setTime: 2023-09-08 11:22:47 +0000, "accessId": [SubscriberAttribute] key: accessId value: 2 setTime: 2023-09-08 11:22:47 +0000, "iapName": [SubscriberAttribute] key: iapName value: MY_IAP_NAME_HERE setTime: 2023-09-08 11:22:47 +0000]
2023-09-08 12:26:29.397407+0100 App[1670:453927] [attribution] DEBUG: โ„น๏ธ Found 4 unsynced attributes for App User ID: $RCAnonymousID:5dc4892b7dbd48dabb6a1b393c86941b
2023-09-08 12:26:29.397847+0100 App[1670:453927] [attribution] DEBUG: โ„น๏ธ Unsynced attributes: ["interval": [SubscriberAttribute] key: interval value: month setTime: 2023-09-08 11:22:47 +0000, "accessId": [SubscriberAttribute] key: accessId value: 2 setTime: 2023-09-08 11:22:47 +0000, "cost": [SubscriberAttribute] key: cost value: 5 setTime: 2023-09-08 11:22:47 +0000, "iapName": [SubscriberAttribute] key: iapName value: MY_IAP_NAME_HERE setTime: 2023-09-08 11:22:47 +0000]
2023-09-08 12:26:29.402380+0100 App[1670:453927] [attribution] DEBUG: ๐Ÿ˜ป Subscriber attributes synced successfully for App User ID: $RCAnonymousID:5dc4892b7dbd48dabb6a1b393c86941b
2023-09-08 12:26:29.402594+0100 App[1670:453927] [network] DEBUG: โ„น๏ธ PostSubscriberAttributesOperation: Finished
2023-09-08 12:26:29.403023+0100 App[1670:453927] [network] DEBUG: โ„น๏ธ Serial request done: POST /v1/subscribers/$RCAnonymousID%3A5dc4892b7dbd48dabb6a1b393c86941b/attributes, 0 requests left in the queue

I also noticed the typing of this function seems to be incorrect, it does not appear to return a promise.

Update Android SDK to 6+

Google recently adds new subscription api and it's useful for multiple base plans.
Please update SDK as RevenueCat gives this api in newer versions.

Now when I've added new products and checked "SDK Support in Offering Setup" in Android app settings to v6+, I have an error: "Backend Code: 7728 - This SDK version is not supported for this app.".

Google Play Billing deprecation

I installed and configured the plugin and it seems to work.

The issue is that I can't release the app for testing. I get this error:

We've detected that one or more of the app bundles included in this release are using the following Play Billing Library versions
4.1.0
These are unsupported versions of Google Play Billing. Upgrade to a supported version to publish this app.

Reminder

  1. Starting on August 2, 2023, all new apps must use Billing Library version 5 or newer. By November 1, 2023, all updates to existing apps must use Billing Library version 5 or newer. Learn more.
  2. If your app is targeting Android 14 or higher, you must update to PBL 5.2.1 or PBL 6.0.1 or higher.

Is there a way to update this library? It seems unusable unless Play Billing is bumped to a newer version.

Android customerInfo key changed

When implementing this plugin for Android 10+ using version 2.8.0 and Capacitor 5 the addListener('purchasesUpdate', ...) function returns an object with an odd key for the customerInfo. For me the current response returns:

{ purchasecustomerInforInfo: {...} purchases: {...} }

whereas the result is documented as:

{ customerInfo: {...} purchases: {...} }

The documented version is correct for iOS and works fine, I've only seen this issue on Android. For now I've just worked around it by checking the platform and using the relevant key, but it would be good to see this made consistent again in future.

RevenueCat official transfer

I've seen it mentioned in a few issues, but is there any news about this being officially rolled into the RevenueCat org?

You've done a great job getting this far, but I'm just weighing up longevity of the project. For example in this issue you mentioned you're a bit busy, which is 100% understandable, but considering RevenueCat is a paid/premium product having this repo officially backed/supported would be preferred from a business perspective.

Do you have a contact at RevenueCat who is looking after the connection with this repo?

Thanks for the library

Rename this repo to "capacitor-revenue-cat" or something indicating the affiliation

To me, it's overbearing and misleading to call this plugin "capacitor-purchases" when it's only usable with a 3rd party service that costs money. It's fine that you offer it but be clear about it.

Your strategy seems to be to lure people in by making it seem like a universal plugin, when it is definitely not. Non-developer stakeholders suggest this as "of course there is a capacitor plugin for in app purchases" when it's really not. It's not even clear wether the service hosted in the USA is GDPR compliant, so not an option for a lot of projects.

CocoaPods could not find compatible versions for pod "RevenueCat"

โœ– update ios - failed!
[error] Ignoring debug-1.7.1 because its extensions are not built. Try: gem pristine debug --version 1.7.1
        Ignoring rbs-2.8.2 because its extensions are not built. Try: gem pristine rbs --version 2.8.2
        Analyzing dependencies
        [!] CocoaPods could not find compatible versions for pod "RevenueCat":
        In Podfile:
        CapgoCapacitorPurchases (from
        `../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capgo/capacitor-purchases`)
        was resolved to 2.0.24, which depends on
        RevenueCat (>= 4.16.0)
        
        None of your spec sources contain a spec satisfying the dependency: `RevenueCat (>= 4.16.0)`.
        
        You have either:
        * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
        * mistyped the name or version.
        * not added the source repo that hosts the Podspec to your Podfile.

Cannot find symbol method getProducts

Getting this error in Android Studio:

node_modules\purchases-capacitor\android\src\main\java\ee\forgr\plugin\capacitor_purchases\CapacitorPurchasesPlugin.java:120: error: cannot find symbol
CommonKt.getProducts(
^
symbol: method getProducts(AppCompatActivity,List,OnResult)
location: class CommonKt

Capacitor vs. Cordova Version

Hello,

thank you for creating this awesome plugin! What are the advantages of using this Plugin instead of using the cordova version?

Kind Regards,
Marius

Capacitor 5 Support

I would like to request support for Capacitor 5.

As you may be aware, Capacitor 5 has been released with significant updates and improvements. It would be highly beneficial if this plugin could be updated to support Capacitor 5 and its features.

If you require any further information or assistance, please let me know. I would be happy to provide any additional details or collaborate in any way that can facilitate the update process.

Thank you for your attention to this matter. I look forward to your response and the possibility of seeing Capacitor 5 support.

Plugin is not implemented on android or app crashes

I am using this code on a NextJS project:
import { Purchases } from "@revenuecat/purchases-capacitor"

await Purchases.configure({
apiKey,
appUserID: uid
})

But getting this error:
Error: "CapacitorPurchases" plugin is not implemented on android

Does anyone maybe have any idea why it is not using Purchases instead of CapacitorPurchases?

When using:
import { CapacitorPurchases } from '@capgo/capacitor-purchases';

CapacitorPurchases.setDebugLogsEnabled({ enabled: true }).then()

The app crashes instrantly, what would be a correct and functioning code solution at this moment?

addListener purchasesUpdate in Vite/Vue3

Hey I'm having issues getting the addListener working.

I have a PurchaseService.js file with some classes including one for initiating the app stores etc.

Everything is working from setup through to purchase but I can't seem to get the listeners working.

I've tried a few different approaches all to no luck.

      CapacitorPurchases.addListener("purchasesUpdate", (data) => {
        console.log("โฑ PURCHASE UPDATE TRIGGERED");
        console.log(data);
      });
     addListener("purchasesUpdate", (data) => {
        console.log("โฑ PURCHASE UPDATE TRIGGERED");
        console.log(data);
      });

I also tried;

    window.addEventListener("purchasesUpdate", (data) => {
      console.log("โฑ purchasesUpdate TRIGGERED");
      console.log(data);
    });

No matter what I do I see the below and no console logs of course.

2022-08-19 14:34:14.702 18340-18340/app.meditimer.www V/Capacitor/CapacitorPurchasesPlugin: Notifying listeners for event purchasesUpdate
2022-08-19 14:34:14.702 18340-18340/app.meditimer.www D/Capacitor/CapacitorPurchasesPlugin: No listeners found for event purchasesUpdate

I'm hoping I'm just being silly and it's something little that somebody in the community can help me with :)

Regards,

Chris

Create quickstart guide or tutorial for newcomers

Hey guys! Thank for your product; I'm newbie in dealing with RevenueCat and ios InAppPurchases; It would be very helpful, if you give an example of a quickstart of your app;
Thank you in advance

Having troubles making NON_SUBSCRIPTION/NON_CONSUMABLE purchases on iOS

I'm trying to switch over from the https://github.com/revenuecat/cordova-plugin-purchases plugin but I'm running into issues with purchasing NON_SUBSCRIPTION/NON_CONSUMABLE products. I haven't had any issues with purchasing recurring SUBSCRIPTION type products.

Here is an example of one of the packages:

{
  "product": {
    "price": 6.99,
    "discounts": [],
    "introPrice": null,
    "priceString": "$6.99",
    "identifier": "[redacted]",
    "description": "Unlocks all content, features and removes ads",
    "productCategory": "NON_SUBSCRIPTION",
    "productType": "NON_CONSUMABLE",
    "title": "Full Unlock",
    "subscriptionPeriod": null,
    "currencyCode": "USD"
  },
  "offeringIdentifier": "full_unlock",
  "identifier": "$rc_lifetime",
  "packageType": "LIFETIME"
}

I've tried both purchasePackage and purchaseStoreProduct. An error isn't thrown and the promise never completes. The purchase popup on iOS is never shown. Here is what I've tried:

await Purchases.purchasePackage({ aPackage: this.package })
await Purchases.purchaseStoreProduct({ product: this.package.product })

In the Cordova plugin I had to specifically set PURCHASE_TYPE.INAPP when purchasing these kinds of non-consumable products but this seems to no longer be an option.

// https://revenuecat.github.io/cordova-plugin-purchases-docs/4.7.1/classes/default.html#purchaseProduct
await Purchases.purchaseProduct(this.package.product.identifier, null, PURCHASE_TYPE.INAPP)

Other Notes

I noticed this debug warning in the logs but I'm not sure if it's related to this issue or not.

2023-09-08 17:12:55.031426-0400 App[920:161684] [store_kit] DEBUG: โ„น๏ธ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.

Build issue: unexpected token 'export'

I installed the package in my NextJS project. And when running "next build", this error appeared.

node_modules@revenuecat\purchases-typescript-internal-esm\dist\index.js:1
export * from './errors';
^^^^^^

SyntaxError: Unexpected token 'export'

Could someone help resolve the issue, please?

Development setup

I'm having a hard time implementing in-app purchases with capacitor, what is the best setup for developing a capacitor app with in-app purchases?

The problem is I can't get real data (for example the list of my app offerings) because RevenueCat mocks data in web version. That means that every time I need to test real data I have to build e run on my phone and it takes too much.

My setup is:

  • Nuxt 3
  • Vite
  • Capacitor

I normally run

npm run dev

so I have hot reloads but as I said, this way I can't test in app purchases. Is there a way we can have hot reload + in app purchases without mocked data?

android return problem `CapacitorPurchases.purchasePackage`

export const purchase = async (p: Package): Promise<PurchaserInfo | null> => {
  try {
    const data = await CapacitorPurchases.purchasePackage({
      identifier: p.identifier,
      offeringIdentifier: p.offeringIdentifier
    })
    console.log('Purchases purchase', data)

    const purchaserInfo = data.purchaserInfo
    if (purchaserInfo.activeSubscriptions.includes(p.identifier)) {
      // setPaidPlan(p.identifier)
    }
    return purchaserInfo
  } catch (e) {
    console.log('Purchases purchase error', e)
    return null
  }
}

this same code used capacitor ?
ios working but android problem Purchases purchase error TypeError: Cannot read properties of undefined (reading 'activeSubscriptions')

console.log('Purchases purchase', data)
image

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.