JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 12
  • Score
    100M100P100Q53170F
  • License MIT

A modern CodePush implementation for React Native applications

Package Exports

  • react-native-flix-codepush
  • react-native-flix-codepush/package.json

Readme

React Native Flix CodePush

A modern CodePush implementation for React Native applications that provides over-the-air updates for your React Native apps. This SDK is compatible with the latest React Native versions, including support for Hermes Engine and the New Architecture (Fabric).

Features

  • ๐Ÿš€ Compatible with the latest React Native versions (0.71.0 - 0.81.1+)
  • ๐Ÿ”„ Backward compatibility with older React Native versions
  • โšก๏ธ Full support for Hermes Engine
  • ๐Ÿงฉ Support for New Architecture (Fabric)
  • ๐Ÿ”Œ Auto-linking package
  • ๐Ÿ› ๏ธ Modern hooks-based API with configurable methods
  • ๐Ÿ“ฑ Full native implementations for both iOS and Android
  • ๐Ÿงช Production-ready code with robust error handling
  • ๐Ÿ—๏ธ Modular architecture (ApiClient, UpdateManager, PackageManager)
  • ๐ŸŽฃ React hooks for a first-class developer experience
  • ๐Ÿงฉ Pre-built UI components for update experience
  • ๐ŸŒ“ Dark mode support
  • ๐Ÿ”„ Download progress tracking
  • ๐Ÿ”” Update notifications

Installation

npm install react-native-flix-codepush --save
# or
yarn add react-native-flix-codepush

Basic Setup

iOS

Add the following to your Info.plist:

<key>CodePushDeploymentKey</key>
<string>YOUR_DEPLOYMENT_KEY</string>
<key>CodePushServerUrl</key>
<string>YOUR_SERVER_URL</string>

Android

Add the following to your strings.xml:

<string name="codepush_deployment_key">YOUR_DEPLOYMENT_KEY</string>
<string name="codepush_server_url">YOUR_SERVER_URL</string>

Usage

import React, { useEffect } from 'react';
import { View, Text, Button, SafeAreaView } from 'react-native';
import { useCodePush } from 'react-native-flix-codepush';

const App = () => {
  const {
    checkForUpdate,
    sync,
    restartApp,
    syncStatus,
    currentPackage,
    isCheckingForUpdate,
    downloadProgress
  } = useCodePush({
    deploymentKey: 'YOUR_DEPLOYMENT_KEY',
    updateDialog: true,
    installMode: 'ON_NEXT_RESTART'
  });

  useEffect(() => {
    // Check for updates when the app starts
    checkForUpdate();
  }, []);

  return (
    <SafeAreaView>
      <Text>Current Version: {currentPackage?.label || 'No package installed'}</Text>
      
      <Text>
        Download Progress: 
        {isDownloading ? 
          `${Math.round((downloadProgress.receivedBytes / downloadProgress.totalBytes) * 100)}%` : 
          'Not downloading'
        }
      </Text>
      
      <Button
        title="Check for Updates"
        onPress={() => checkForUpdate()}
        disabled={isCheckingForUpdate}
      />
      
      <Button
        title="Sync Updates"
        onPress={() => sync({ updateDialog: true })}
      />
      
      <Button
        title="Restart App"
        onPress={() => restartApp()}
      />
    </SafeAreaView>
  );
};

export default App;

Component Wrapper (Simple)

import React from 'react';
import { View, Text } from 'react-native';
import { CodePushHandler } from 'react-native-flix-codepush';

const App = () => {
  return (
    <View>
      <Text>My App Content</Text>
    </View>
  );
};

// Wrap your app with CodePushHandler
export default () => (
  <CodePushHandler
    deploymentKey="YOUR_DEPLOYMENT_KEY"
    checkOnStart={true}
    checkOnResume={true}
    updateDialog={true}
    installMode="ON_NEXT_RESTART"
    mandatoryInstallMode="IMMEDIATE"
  >
    <App />
  </CodePushHandler>
);

Configuration Method

import React from 'react';
import { configureCodePush } from 'react-native-flix-codepush';

// Configure CodePush
const { CodePushHandler, useCodePush } = configureCodePush({
  deploymentKey: 'YOUR_DEPLOYMENT_KEY',
  serverUrl: 'YOUR_SERVER_URL',
  checkFrequency: 1, // ON_APP_START
  installMode: 'ON_NEXT_RESTART',
  mandatoryInstallMode: 'IMMEDIATE'
});

// Create a custom hook with your configuration
const useMyCodePush = () => useCodePush();

// Wrap your app with CodePushHandler
const App = () => {
  return (
    <CodePushHandler>
      <YourApp />
    </CodePushHandler>
  );
};

export default App;

Using HOC (Legacy Approach)

import React, { Component } from 'react';
import { View, Text, Button } from 'react-native';
import { codePush } from 'react-native-flix-codepush';

class App extends Component {
  checkForUpdates = () => {
    codePush.checkForUpdate()
      .then((update) => {
        if (update) {
          console.log('Update available');
        } else {
          console.log('No update available');
        }
      });
  };

  sync = () => {
    codePush.sync({
      updateDialog: true,
      installMode: codePush.InstallMode.IMMEDIATE,
    });
  };

  render() {
    return (
      <View>
        <Text>CodePush Example</Text>
        <Button title="Check for Updates" onPress={this.checkForUpdates} />
        <Button title="Sync" onPress={this.sync} />
      </View>
    );
  }
}

export default codePush({
  checkFrequency: codePush.CheckFrequency.ON_APP_START,
  installMode: codePush.InstallMode.ON_NEXT_RESTART,
})(App);

API Reference

useCodePush(options)

React hook for using CodePush in functional components.

function useCodePush(options?: CodePushSyncOptions): UseCodePushResult;

interface UseCodePushResult {
  checkForUpdate: (deploymentKey?: string) => Promise<CodePushRemotePackage | null>;
  sync: (options?: CodePushSyncOptions) => Promise<CodePushSyncStatus>;
  getCurrentPackage: () => Promise<CodePushLocalPackage | null>;
  restartApp: () => Promise<void>;
  clearUpdates: () => Promise<void>;
  getUpdateMetadata: () => Promise<CodePushLocalPackage | null>;
  downloadUpdate: (remotePackage: CodePushRemotePackage) => Promise<CodePushLocalPackage>;
  installUpdate: (packageHash: string, installMode?: CodePushInstallMode) => Promise<void>;
  cancelSync: () => void;
  syncStatus: CodePushSyncStatus;
  currentPackage: CodePushLocalPackage | null;
  pendingUpdate: CodePushRemotePackage | null;
  isCheckingForUpdate: boolean;
  isDownloading: boolean;
  isInstalling: boolean;
  downloadProgress: { receivedBytes: number; totalBytes: number };
}

configureCodePush(config)

Configures the CodePush SDK with the provided options.

function configureCodePush(config: {
  deploymentKey: string;
  serverUrl: string;
  checkFrequency?: number;
  installMode?: string;
  mandatoryInstallMode?: string;
  minimumBackgroundDuration?: number;
}): {
  useCodePush: UseCodePushHook;
  CodePushHandler: React.ComponentType<CodePushHandlerProps>;
  UpdateDialog: React.ComponentType<UpdateDialogProps>;
  DownloadProgressView: React.ComponentType<DownloadProgressViewProps>;
  codePush: CodePushHOC;
  // Legacy methods
  checkForUpdate: (deploymentKey?: string) => Promise<CodePushRemotePackage | null>;
  getCurrentPackage: () => Promise<CodePushLocalPackage | null>;
  sync: (options?: CodePushSyncOptions) => Promise<CodePushSyncStatus>;
  restartApp: (onlyIfUpdateIsPending?: boolean) => Promise<void>;
};

createCodePushHook(options)

Creates a custom hook with pre-configured options.

function createCodePushHook(options: {
  deploymentKey: string;
  installMode?: string;
  mandatoryInstallMode?: string;
  minimumBackgroundDuration?: number;
}): () => UseCodePushResult;

CodePushHandler

Component for handling CodePush updates.

interface CodePushHandlerProps {
  children: React.ReactNode;
  checkOnStart?: boolean;
  checkOnResume?: boolean;
  deploymentKey?: string;
  serverUrl?: string;
  installMode?: CodePushInstallMode;
  mandatoryInstallMode?: CodePushInstallMode;
  minimumBackgroundDuration?: number;
  updateDialog?: UpdateDialogOptions | boolean;
  ignoreFailedUpdates?: boolean;
  onSyncStatusChanged?: (status: CodePushSyncStatus) => void;
  onDownloadProgress?: (progress: { receivedBytes: number; totalBytes: number }) => void;
  onBinaryVersionMismatch?: (update: CodePushRemotePackage) => boolean;
}

codePush(options)(Component)

Higher-order component for class components.

function codePush(options?: CodePushSyncOptions): (WrappedComponent: React.ComponentType<any>) => React.ComponentType<any>;

Components

UpdateDialog

A customizable dialog for prompting users to install updates.

interface UpdateDialogProps {
  update: CodePushRemotePackage;
  onIgnore: () => void;
  onAccept: () => Promise<void>;
  title?: string;
  descriptionPrefix?: string;
  mandatoryUpdateMessage?: string;
  optionalUpdateMessage?: string;
  mandatoryContinueButtonLabel?: string;
  optionalInstallButtonLabel?: string;
  optionalIgnoreButtonLabel?: string;
  appendReleaseDescription?: boolean;
}

DownloadProgressView

A component for displaying download progress.

interface DownloadProgressViewProps {
  progress: number;
  total: number;
  visible: boolean;
  title?: string;
  message?: string;
}

Types

CodePushInstallMode

enum CodePushInstallMode {
  IMMEDIATE = 'IMMEDIATE',
  ON_NEXT_RESTART = 'ON_NEXT_RESTART',
  ON_NEXT_RESUME = 'ON_NEXT_RESUME',
  ON_NEXT_SUSPEND = 'ON_NEXT_SUSPEND',
}

CodePushSyncStatus

enum CodePushSyncStatus {
  UP_TO_DATE = 0,
  UPDATE_INSTALLED = 1,
  UPDATE_IGNORED = 2,
  UNKNOWN_ERROR = 3,
  SYNC_IN_PROGRESS = 4,
  CHECKING_FOR_UPDATE = 5,
  AWAITING_USER_ACTION = 6,
  DOWNLOADING_PACKAGE = 7,
  INSTALLING_UPDATE = 8,
}

CodePushCheckFrequency

enum CodePushCheckFrequency {
  MANUAL = 0,
  ON_APP_START = 1,
  ON_APP_RESUME = 2,
}

Server API Endpoints

This SDK is designed to work with the following API endpoints:

1. Check for Update

GET /codepush/update/check

Query Parameters:

  • deployment_key: Your deployment key
  • app_version: The current app version
  • package_hash: The current package hash (optional)

2. Report Deployment Status

POST /codepush/report_status/{status}

Where {status} can be:

  • download
  • install
  • rollback

Body:

{
  "deploymentKey": "YOUR_DEPLOYMENT_KEY",
  "label": "v2",
  "appVersion": "1.0.0",
  "clientUniqueId": "a-unique-device-identifier",
  "previousLabelOrAppVersion": "v1"
}

3. Download CodePush Bundle

GET /codepush/download/{packageHash}

Advanced Features

Binary Version Mismatch Handling

const { useCodePush } = configureCodePush({
  deploymentKey: 'YOUR_DEPLOYMENT_KEY',
  serverUrl: 'YOUR_SERVER_URL',
});

const App = () => {
  const codePushOptions = {
    onBinaryVersionMismatch: (update) => {
      // Return true to install the update, false to ignore it
      return update.appVersion === '1.0.0';
    }
  };
  
  const { sync } = useCodePush(codePushOptions);
  
  // Rest of your component
};

Custom Update Dialog

const updateDialogOptions = {
  title: 'New Update Available',
  mandatoryUpdateMessage: 'An important update is available that you must install now.',
  optionalUpdateMessage: 'A new update is available. Would you like to install it?',
  mandatoryContinueButtonLabel: 'Install Now',
  optionalInstallButtonLabel: 'Install',
  optionalIgnoreButtonLabel: 'Later',
  appendReleaseDescription: true,
  descriptionPrefix: 'What\'s New:\n'
};

const { sync } = useCodePush();

// Use the custom dialog options
sync({ updateDialog: updateDialogOptions });

Monitoring Download Progress

const { downloadUpdate } = useCodePush();

const handleDownload = async (remotePackage) => {
  try {
    const localPackage = await downloadUpdate(
      remotePackage,
      (progress) => {
        console.log(`Downloaded ${progress.receivedBytes} of ${progress.totalBytes} bytes`);
        const percent = Math.round((progress.receivedBytes / progress.totalBytes) * 100);
        setDownloadProgress(percent);
      }
    );
    
    // Install the update
    await installUpdate(localPackage.packageHash);
  } catch (error) {
    console.error('Download failed:', error);
  }
};

Sync Status Monitoring

const { sync } = useCodePush();

const handleSync = async () => {
  try {
    await sync(
      { updateDialog: true },
      (status) => {
        switch (status) {
          case CodePushSyncStatus.CHECKING_FOR_UPDATE:
            console.log('Checking for update...');
            break;
          case CodePushSyncStatus.DOWNLOADING_PACKAGE:
            console.log('Downloading package...');
            break;
          case CodePushSyncStatus.INSTALLING_UPDATE:
            console.log('Installing update...');
            break;
          case CodePushSyncStatus.UPDATE_INSTALLED:
            console.log('Update installed!');
            break;
          // Handle other statuses
        }
      }
    );
  } catch (error) {
    console.error('Sync failed:', error);
  }
};

License

MIT