如何构建React Native免费与付费版本的统一仓库及工作流
Hey there! Great question—maintaining two separate React Native apps for free and paid versions is a total slog, so let’s break down a clean repo structure and workflow that keeps you from duplicating work while supporting both variants.
Forget separate repos—keep all your code in a single repository with a clear split between shared and version-specific code. Here’s a practical setup:
your-app/ ├── src/ │ ├── common/ # All shared code: UI components, core logic, API calls │ ├── free/ # Free-only features (ads, limited functionality prompts) │ ├── paid/ # Paid-only premium features │ ├── App.js # Entry point that loads variant-specific modules │ └── config/ # Variant configs (API keys, feature flags) ├── android/ │ ├── app/ │ │ ├── src/ │ │ │ ├── main/ # Shared Android setup │ │ │ ├── free/ # Free variant config (Play Store ID, ad SDK setup) │ │ │ └── paid/ # Paid variant config (no ads, premium entitlements) │ └── build.gradle # Configure Android product flavors ├── ios/ │ ├── YourApp/ │ │ ├── Common/ # Shared iOS code │ │ ├── Free/ # Free variant settings │ │ └── Paid/ # Paid variant settings │ └── YourApp.xcodeproj # Set up iOS targets for each variant └── .env # Environment variables to flag FREE/PAID builds
The key is to use environment variables and platform-specific build configurations to toggle features without messy code duplication.
React Native Code Checks
Use an environment variable to branch logic in your JS/TS code:const isPaidVersion = process.env.APP_VARIANT === 'PAID'; // Example component function PremiumDashboard() { if (!isPaidVersion) { return <UpgradeToProPrompt />; } return <ActualPremiumDashboard />; }For larger premium features, use dynamic imports to keep free app bundle size small:
let PremiumModule; if (isPaidVersion) { PremiumModule = require('../paid/PremiumModule').default; } else { PremiumModule = require('../free/UpgradeModule').default; }Android Product Flavors
Inandroid/app/build.gradle, define flavors to generate separate APKs with unique IDs and settings:android { flavorDimensions "version" productFlavors { free { dimension "version" applicationId "com.yourapp.free" resValue "string", "app_name", "Your App" } paid { dimension "version" applicationId "com.yourapp.paid" resValue "string", "app_name", "Your App Pro" } } }iOS Targets
Duplicate your main iOS target in Xcode, name itYourAppPaid, and update its Bundle ID, display name, and entitlements. Use preprocessor macros to branch native code:#ifdef PAID_VERSION // Paid-only native logic (e.g., remove ad SDK hooks) #else // Free-only native logic #endif
Manual builds for two variants are error-prone—automate the process to save time.
Package Scripts
Add these to yourpackage.jsonto trigger variant-specific builds:"scripts": { "build:free:android": "APP_VARIANT=FREE cd android && ./gradlew assembleFreeRelease", "build:paid:android": "APP_VARIANT=PAID cd android && ./gradlew assemblePaidRelease", "build:free:ios": "APP_VARIANT=FREE xcodebuild -workspace ios/YourApp.xcworkspace -scheme YourAppFree -configuration Release archive", "build:paid:ios": "APP_VARIANT=PAID xcodebuild -workspace ios/YourApp.xcworkspace -scheme YourAppPaid -configuration Release archive" }CI/CD Integration
Set up pipelines (GitHub Actions, GitLab CI, etc.) to automatically build both variants on every main branch push. Configure them to upload builds directly to Play Store/App Store Connect’s testing tracks for easy validation.Sync Version Numbers
Keep version codes and names in sync across variants. Manage the core version inpackage.json, then reference it in your Androidbuild.gradleand iOSInfo.plistto avoid mismatches.
- Keep Shared Code Pure: Avoid cluttering
commoncode with variant-specific conditionals. Encapsulate variant logic infree/paidmodules and expose consistent interfaces to shared code. - Test Both Variants: Use your test framework’s environment variable support (e.g., Jest’s
setupFiles) to run tests for both free and paid scenarios. - Link Apps in Stores: In Play Console, mark your free and paid apps as "related" so users can easily upgrade from the free version’s store listing.
内容的提问来源于stack exchange,提问作者Aswin Mohan

