Cloudflare Provider

This guide walks you through setting up hot-updater with Cloudflare in a React Native project. You'll configure the environment, install required packages, and initialize Cloudflare for seamless updates.

Prerequisites

Before you begin, make sure the following are ready:

Step 1: Install Required Packages

Run the following command to install dependencies:

npm
pnpm
yarn
npm install hot-updater --save-dev

Step 2: Configure Cloudflare

Run the initialization script to start the interactive setup process. Use the following command with your preferred package manager:

npm
pnpm
yarn
npx hot-updater init
Interactive Setup Steps
  1. Select a Build Plugin: Choose a build plugin for your project (e.g., Metro for React Native).
  2. Select a Provider: Select Cloudflare as the provider for handling updates.

During the setup, you will be prompted to:

  1. Login to Cloudflare: Sign in to your Cloudflare account with wrangler
  2. Enter R2 & D1 API Token: Input your API token with R2 and D1 permissions
  3. Select R2 Bucket: Choose an existing R2 bucket or create a new one
  4. Select D1 Database: Choose an existing D1 database or create a new one
  5. Run D1 Migration: Execute database migrations for D1
  6. Deploy Worker: Deploy the Cloudflare Worker for update management

Once the setup is complete, a .env file will be generated containing the following keys:

HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID=your-account-id HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME=your-r2-bucket-name HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID=your-d1-database-id HOT_UPDATER_CLOUDFLARE_API_TOKEN=your-api-token
WARNING

If you’re not using the react-native-dotenv solution, the tokens from your .env file will not be included in your app bundle and are therefore not exposed to risks. However, if you’re still concerned,

please refer to the article below for more details: Security

Step 3: Generated Configurations

During the initialization process, the following file is automatically generated:

  • hot-updater.config.ts: This file contains the configuration settings for integrating Cloudflare with your project.
hot-updater.config.ts
import { metro } from "@hot-updater/metro";
import { d1Database, r2Storage } from "@hot-updater/cloudflare";
import { defineConfig } from "hot-updater";
import "dotenv/config";

export default defineConfig({
  build: metro({ enableHermes: true }),
  storage: r2Storage({
    bucketName: process.env.HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME!,
    accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
    cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
  }),
  database: d1Database({
    databaseId: process.env.HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID!,
    accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
    cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
  }),
});

Step 4: Add HotUpdater to Your Project

The HotUpdater component wraps your application, enabling seamless delivery of updates and fallback UI during updates. Follow these steps to integrate it into your App.tsx:

App.tsx
import { HotUpdater } from "@hot-updater/react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({ 
  source: "https://<your-worker-name>.<your-subdomain>.workers.dev/api/check-update", 
  requestHeaders: {
    // if you want to use the request headers, you can add them here
  },
  fallbackComponent: ({ progress, status }) => (
    <View
      style={{
        flex: 1,
        padding: 20,
        borderRadius: 10,
        justifyContent: "center",
        alignItems: "center",
        backgroundColor: "rgba(0, 0, 0, 0.5)",
      }}
    >
      {/* You can put a splash image here. */}

      <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
        {status === "UPDATING" ? "Updating..." : "Checking for Update..."}
      </Text>
      {progress > 0 ? (
        <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
          {Math.round(progress * 100)}%
        </Text>
      ) : null}
    </View>
  ),
})(App);

Step 5: Add Babel Plugin to Your Project

In this step, you will configure Babel to set the bundle ID at build time. This is necessary for integrating the hot-updater plugin into your project.

Add the following to your babel.config.js file:

babel.config.js
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    'hot-updater/babel-plugin', 
  ],
};

Step 6: Add Native Code

To complete the integration of hot-updater, you'll need to add native code modifications for both Android and iOS platforms. This step ensures the hot-updater can interact with your app's underlying framework to apply updates seamlessly.

Android

Kotlin
Java
android/app/src/main/java/com/<your-app-name>/MainApplication.kt
package com.hotupdaterexample

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import com.hotupdater.HotUpdater 

class MainApplication : Application(), ReactApplication {

  override val reactNativeHost: ReactNativeHost =
      object : DefaultReactNativeHost(this) {
        override fun getPackages(): List<ReactPackage> =
            PackageList(this).packages.apply {
              // Packages that cannot be autolinked yet can be added manually here, for example:
              // add(MyReactNativePackage())
            }

        override fun getJSMainModuleName(): String = "index"

        override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

        override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
        override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED

        override fun getJSBundleFile(): String? {  
          return HotUpdater.getJSBundleFile(applicationContext)  
        }  
      }

  override val reactHost: ReactHost
    get() = getDefaultReactHost(applicationContext, reactNativeHost)

  override fun onCreate() {
    super.onCreate()
    SoLoader.init(this, OpenSourceMergedSoMapping)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      load()
    }
  }
}

iOS

Objective-C
Swift
ios/<your-app-name>/AppDelegate.mm
#import "AppDelegate.h"
#import <HotUpdater/HotUpdater.h> 
#import <React/RCTBundleURLProvider.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.moduleName = @"HotUpdaterExample";
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};

  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
  return [self bundleURL];
}

- (NSURL *)bundleURL
{
#if DEBUG 
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 
#else 
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 
#endif 
  return [HotUpdater bundleURL]; 
}

@end

Verifying the Setup

  1. Check your Cloudflare dashboard for the newly created bucket, D1 database, and worker.
  2. Test the HotUpdater integration in your React Native app.

You're all set! 🎉 Start using hot-updater with Cloudflare for seamless updates in your React Native app.

This document simplifies the initialization process, making it easy for developers to get started with minimal friction.