purchases_flutter

repository·main·Indexed 20 days ago

https://github.com/revenuecat/purchases-flutter

An open-source Flutter client for the RevenueCat backend that simplifies in-app subscriptions. It provides a unified wrapper around StoreKit (iOS) and Google Play Billing (Android) to handle server-side receipt validation, subscription status tracking, webhooks, and analytics.

Tokens
17.2K
Snippets
50
Records
83
Agent score
69%

What's inside purchases_flutter

  1. Overview of purchases_flutter features

    main

    The purchases_flutter package is a client for the RevenueCat subscription and purchase tracking system. It wraps StoreKit and Google Play Billing to provide:

    • Server-side receipt validation: Ensures purchases are legitimate via the RevenueCat backend.
    • Subscription status tracking: Unified tracking of whether a user is subscribed across both iOS and Android.
    • Webhooks: Server-to-server communication for events like purchases, renewals, and cancellations.
    • Analytics: Automatic calculation of metrics such as conversion, MRR, and churn.
    • Integrations: Support for over a dozen third-party integrations to export purchase data.
  2. Understand the Maestro E2E Test App configuration

    main

    The E2E tests rely on a specific RevenueCat project configuration to validate functionality:

    • V2 Paywall: The tests assert that a "Paywall V2" is visible.
    • pro entitlement: The tests verify entitlement status following a successful purchase.
    • Test Store: The tests use the Test Store environment for purchase confirmations.

    Additionally, the app uses purchases_flutter and purchases_ui_flutter as local path: dependencies. This ensures that the E2E tests always exercise the code from the current branch rather than a version published to pub.dev.

  3. Apply specific offers during purchase in v5

    main

    In v4, calling purchase() on a Package or StoreProduct automatically applied eligible free trials. In v5, because a product can contain multiple offers, the SDK uses specific logic when you call purchase() on a Package or StoreProduct:

    1. Filters out offers with the rc-ignore-default-offer tag.
    2. Selects the SubscriptionOption with the longest free trial or cheapest first phase.
    3. Falls back to the base plan.

    To bypass this logic and purchase a specific offer, use the new explicit purchase methods instead of the generic purchase() method.

  4. Handle multiple offers with StoreProduct in v5

    main

    In v5, a StoreProduct can contain multiple free trials and introductory offers on Google Play.

    • defaultOption: A property on StoreProduct that automatically selects the offer with the longest free trial period or the cheapest introductory offer.
    • subscriptionOptions: A list of all available SubscriptionOptions on a StoreProduct. Use this if you need manual control over which specific offer (base plan, free trial, or intro offer) the user selects.

    Example of accessing options:

    final basePlan = storeProduct.subscriptionOptions?.firstWhere((option) => option.isBasePlan);
    final defaultOption = storeProduct.defaultOption;
    final freeOffer = storeProduct.subscriptionOptions?.firstWhere((option) => option.freePhase != null);
    final trialOffer = storeProduct.subscriptionOptions?.firstWhere((option) => option.introPhase != null);
    final basePlan = storeProduct.subscriptionOptions?.firstWhere((option) => option.isBasePlan);
    final defaultOption = storeProduct.defaultOption
    final freeOffer = storeProduct.subscriptionOptions?.firstWhere((option) => option.freePhase != null);
    final trialOffer = storeProduct.subscriptionOptions?.firstWhere((option) => option.introPhase != null);
  5. Prerequisites for RevenueCat Integration

    main

    Before implementing RevenueCat in your Flutter app, ensure you have completed the following:

    1. Developer Accounts: Have an active Apple Developer Account or Google Play Console Account.
    2. Product Setup: Set up at least one subscription in the App Store or Google Play Store.
    3. RevenueCat Dashboard Configuration:
      • Add the product (e.g., rc_3999_1y) to RevenueCat. The ID must match the store's product ID.
      • Attach the product to an entitlement (e.g., premium).
      • Attach the product to a package (e.g., Annual) inside an offering (e.g., default).
    4. API Keys: Obtain your Public API Key from the RevenueCat project settings.
  6. Configure local Android dependencies

    main

    There are three ways to use local native Android dependencies for development.

    Use the Gradle task provided in the sample apps to configure local paths.

    For purchases-hybrid-common:

    ./gradlew enableLocalBuild -PcommonPath="/path/to/purchases-hybrid-common/android"

    For purchases-android:

    ./gradlew enableLocalBuild -PandroidPath="/path/to/purchases-android"

    To disable: ./gradlew disableLocalBuild

    Option 2: Manual includeBuild setup

    Add the following to your sample app's android/settings.gradle:

    includeBuild('/path/to/purchases-hybrid-common/android') {
        dependencySubstitution {
            substitute module('com.revenuecat.purchases:purchases-hybrid-common') using project(':hybridcommon')
            substitute module('com.revenuecat.purchases:purchases-hybrid-common-ui') using project(':hybridcommon-ui')
        }
    }
    
    includeBuild('/path/to/purchases-android') {
        dependencySubstitution {
            substitute module('com.revenuecat.purchases:purchases') using project(':purchases')
            substitute module('com.revenuecat.purchases:purchases-ui') using project(':ui:revenuecatui')
        }
    }

    Option 3: Local Maven repository

    1. Publish the local version: cd /path/to/purchases-hybrid-common/android && ./gradlew publishToMavenLocal
    2. Add mavenLocal() to your sample app's android/build.gradle:
    allprojects {
        repositories {
            mavenLocal()
            google()
            mavenCentral()
        }
    }
    # Recommended: Enable local build for hybrid-common
    ./gradlew enableLocalBuild -PcommonPath="/path/to/purchases-hybrid-common/android"
  7. Setup the PurchaseTester sample app

    main

    The PurchaseTester is a comprehensive testing app covering all RevenueCat features. It defaults to using Swift Package Manager for iOS dependencies.

    App Identifiers:

    • iOS Bundle ID: com.revenuecat.sampleapp
    • Android Package Name: com.revenuecat.purchases_sample

    Steps:

    1. Navigate to the directory: cd revenuecat_examples/purchase_tester
    2. Choose dependency manager (optional):
      • For Swift Package Manager (default): flutter config --enable-swift-package-manager
      • For CocoaPods: flutter config --no-enable-swift-package-manager
    3. Install dependencies: flutter pub get
    4. Configure API keys in lib/src/constant.dart from your RevenueCat dashboard.
    5. (Optional) Update bundle ID/application ID to match your RevenueCat settings.
    6. Connect a physical device and run: flutter run

    Integration Tests: To run integration tests, replace the API key in the test file using sed: sed -i.bck s/api_key/$API_KEY/ integration_test/app_test.dart

    cd revenuecat_examples/purchase_tester
    flutter config --enable-swift-package-manager
    flutter pub get
    # Edit lib/src/constant.dart with your API keys
    flutter run
  8. Switch between Swift Package Manager and CocoaPods for iOS

    main

    The PurchaseTester sample supports both Swift Package Manager (SPM) and CocoaPods. You can switch between them using Flutter configuration.

    To enable Swift Package Manager (Default):

    flutter config --enable-swift-package-manager
    flutter clean
    flutter pub get

    To switch to CocoaPods (Legacy Support):

    flutter config --no-enable-swift-package-manager
    flutter clean
    flutter pub get
    cd ios && pod install
    # Switch to CocoaPods
    flutter config --no-enable-swift-package-manager
    flutter clean
    flutter pub get
    cd ios && pod install
  9. Configure local iOS dependencies with Swift Package Manager

    main

    To debug native iOS issues, you can point the plugin to local versions of RevenueCat's native SDKs by updating the Package.swift files. Xcode will automatically use these local paths during builds.

    1. For purchases-hybrid-common: Update ios/purchases_flutter/Package.swift (in the plugin) or ios/purchases_ui_flutter/Package.swift (in the UI plugin):

    dependencies: [
        .package(path: "/path/to/purchases-hybrid-common")
    ],

    2. For purchases-ios (Optional): If using a local purchases-ios repository, update purchases-hybrid-common's Package.swift to use the local SDK:

    dependencies: [
        .package(path: "/path/to/purchases-ios")
    ],
    targets: [
        .target(
            name: "PurchasesHybridCommon",
            dependencies: [
                .product(name: "RevenueCat", package: "purchases-ios")
            ]
        ),
        .target(
            name: "PurchasesHybridCommonUI", 
            dependencies: [
                .product(name: "RevenueCatUI", package: "purchases-ios")
            ]
        )
    ]

    Recommended Workflow:

    1. Make Flutter changes in your editor.
    2. Open ios/Runner.xcodeproj in Xcode.
    3. Build and run from Xcode.
    // Example: Updating purchases_flutter/ios/purchases_flutter/Package.swift
    dependencies: [
        .package(path: "/path/to/purchases-hybrid-common")
    ],