• Stars
    star
    1,509
  • Rank 31,076 (Top 0.7 %)
  • Language
    Objective-C
  • License
    MIT License
  • Created almost 9 years ago
  • Updated over 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A library to manage dynamic updates to React Native apps. Available as an NPM Package for iOS and Android.

Update:

Thanks everyone for using, supporting and contributing to react-native-auto-updater. In the last couple of months, we have not had time/resources to maintain this repo as we diverted our focus on our new product, Amium. As a result of that, I will not be able to resolve issues or review pull requests on this repo. Bottomline, we have stopped maintaining this repo. As for an alternative, we recommend using CodePush.

react-native-auto-updater

License Platform

React-Native Auto-Updater

About

At AeroFS, we're close to shipping our first React Native app. Once the app is out, we would want to send updates over the air to bypass the sluggish AppStore review process, and speed up release cycles. We've built react-native-auto-updater to do just that. It was built as a part of our 2015 Thanksgiving Hackathon.

Does Apple permit this?

Yes! Section 3.3.2 of the iOS Developer Program allows it "provided that such scripts and code do not change the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application."

Does Google permit this?

Of course!

React Native jsbundle can be easily over a couple of megabytes. On cellular connections, downloading them more often than what is needed is not a good idea. To tackle that problem, we need to decide if the bundle needs to be downloaded at all.

We solve this by shipping the app with an initial version of the jsbundle, this reduces the latency during the initial startup. Then we start querying for available update, and download the updated jsbundle. All subsequent runs of the app uses this updated bundle.

In order to decide whether to download the jsbundle or not, we need to know some meta-information about the bundle. For react-native-auto-updater, we store this meta-information as a form of a JSON file somewhere on the internet. The format of the JSON is as follows

{
	"version": "1.1.0",
	"minContainerVersion": "1.0",
	"url": {
      "url": "/s/3klfuwm74sfnj0w/main.jsbundle?raw=1",
      "isRelative": true
    }
}

Here's what the fields in the JSON mean:

  • version — this is the version of the bundle file (in major.minor.patch format)
  • minContainerVersion — this is the minimum version of the container (native) app that is allowed to download this bundle (this is needed because adding a new React Native component to your app might result into changed native app, hence, going through the AppStore review process)
  • url.url — this is where ReactNativeAutoUpdater will download the JS bundle from
  • url.isRelative — this tells if the provided URL is a relative URL (when set to true, you need to set the hostname by using the method (void)setHostnameForRelativeDownloadURLs:(NSString*)hostname;)

react-native-auto-updater needs know the location of this JSON file upon initialization.

Screenshots

Here's a GIF'ed screencast of react-native-auto-updater in action.

rn-auto-updater rn-auto-updater-android

Installation

NOTE — ReactNativeAutoUpdater requires a minimum version of 0.18 of React Native.

iOS

  1. npm install react-native-auto-updater --save
  2. In the Xcode's "Project navigator", right click on your project's Libraries folder ➜ Add Files to "Your Project Name"
  3. Go to node_modules ➜ react-native-auto-updater ➜ iOS ➜ select ReactNativeAutoUpdater.xcodeproj
  4. In the Xcode Project Navigator, click the root project, and in General tab, look for Linked Frameworks and Libraries. Click on the + button at the bottom and add libReactNativeAutoUpdater.a from the list.
  5. Go to Build Settings tab and search for Header Search Paths. In the list, add $(SRCROOT)/../node_modules/react-native-auto-updater and select recursive.

Add Files to Project

File Location

Link Frameworks and Libraries

Header Search Paths

Android

  1. In android/settings.gradle, add this

    // more stuff
    include ':ReactNativeAutoUpdater', ':app'
    project(':ReactNativeAutoUpdater').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-auto-updater/android')
  2. In android/app/build.gradle, add this

     // more stuff
     dependencies {
       // more dependencies
       compile project(':ReactNativeAutoUpdater')
     }
  3. In android/app/build.gradle, add this

android {
  // more stuff
  // add this
  packagingOptions {
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/NOTICE.txt'
  }
}

Usage

iOS

In your AppDelegate.m (make sure you complete step #5 from installation above, otherwise Xcode will not find the header file)

#import "ReactNativeAutoUpdater.h"

The code below essentially follows these steps.

  1. Get an instance of ReactNativeAutoUpdater
  2. Set self as a delegate
  3. Initialize with updateMetadataUrl , defaultJSCodeLocation and defaultMetadataFileLocation
  4. Make a call to checkUpdate, checkUpdateDaily or checkUpdateWeekly
  5. Don't forget to implement the delegate methods (optional)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // defaultJSCodeLocation is needed at least for the first startup
  NSURL* defaultJSCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

  ReactNativeAutoUpdater* updater = [ReactNativeAutoUpdater sharedInstance];
  [updater setDelegate:self];

  // We set the location of the metadata file that has information about the JS Code that is shipped with the app.
  // This metadata is used to compare the shipped code against the updates.

  NSURL* defaultMetadataFileLocation = [[NSBundle mainBundle] URLForResource:@"metadata" withExtension:@"json"];
  [updater initializeWithUpdateMetadataUrl:[NSURL URLWithString:JS_CODE_METADATA_URL]
                     defaultJSCodeLocation:defaultJSCodeLocation
               defaultMetadataFileLocation:defaultMetadataFileLocation ];
  [updater setHostnameForRelativeDownloadURLs:@"https://www.aerofs.com"];
  [updater checkUpdate];

  NSURL* latestJSCodeLocation = [updater latestJSCodeLocation];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  self.window.rootViewController = rootViewController;
  RCTBridge* bridge = [[RCTBridge alloc] initWithBundleURL:url moduleProvider:nil launchOptions:nil];
    RCTRootView* rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"ReactNativeAutoUpdater" initialProperties:nil];
    self.window.rootViewController.view = rootView;
  [self.window makeKeyAndVisible];
  return YES;
}

If you want, you can ask the user to apply the update, right after an update is downloaded. To do that, implement the delegate methods. Check the Example app to see a working sample.

react-native-auto-updater is highly configurable. Here are the options you can configure

ReactNativeAutoUpdater *updater = [ReactNativeAutoUpdater sharedInstance];
/* Show progress during the udpate 
 * default value - YES
 */
[updater showProgress: NO]; 

/* Allow use of cellular data to download the update 
 * default value - NO
 */
[updater allowCellularDataUse: YES];

/* Decide what type of updates to download
 * Available options - 
 *	ReactNativeAutoUpdaterMajorUpdate - will download only if major version number changes
 *	ReactNativeAutoUpdaterMinorUpdate - will download if major or minor version number changes
 *	ReactNativeAutoUpdaterPatchUpdate - will download for any version change
 * default value - ReactNativeAutoUpdaterMinorUpdate
 */
[updater downloadUpdatesForType: ReactNativeAutoUpdaterMajorUpdate];

/* Check update right now
*/
[updater checkUpdate];

/* Check update daily - Only check update once per day
*/
[updater checkUpdateDaily];

/* Check update weekly - Only check updates once per week
*/
[updater checkUpdatesWeekly];

/*  When the JSON file has a relative URL for downloading the JS Bundle,
 *  set the hostname for relative downloads
 */
[updater setHostnameForRelativeDownloadURLs:@"https://www.aerofs.com/"];

Android

React Native < 0.29

  1. Import the needed classes

    import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdater;
    import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdater.ReactNativeAutoUpdaterUpdateType;
    import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdater.ReactNativeAutoUpdaterFrequency;
    import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdaterActivity;
    import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdaterPackage;
    
    import javax.annotation.Nullable;
  2. Extend your MainActivity.java from ReactNativeAutoUpdaterActivity instead of ReactActivity

    public class MainActivity extends ReactNativeAutoUpdaterActivity {
  3. Implement the required methods

     /**
      *  Name of the JS Bundle file shipped with the app.
      *  This file has to be added as an Android Asset.
      * */
     @Nullable
     @Override
     protected String getBundleAssetName() {
         return "main.android.jsbundle";
     }
    
     /**
      *  URL for the metadata of the update.
      * */
     @Override
     protected String getUpdateMetadataUrl() {
         return "https://www.aerofs.com/u/8691535/update.android.json";
     }
    
     /**
      * Name of the metadata file shipped with the app.
      * This metadata is used to compare the shipped JS code against the updates.
      * */
     @Override
     protected String getMetadataAssetName() {
         return "metadata.android.json";
     }
  4. (Optional) Implement the optional methods

     /**
      *  If your updates metadata JSON has a relative URL for downloading 
      *  the JS bundle, set this hostname.
      * */
     @Override
     protected String getHostnameForRelativeDownloadURLs() {
         return "https://www.aerofs.com";
     }
    
     /**
      *  Decide what type of updates to download.
      * Available options - 
      *  MAJOR - will download only if major version number changes
      *  MINOR - will download if major or minor version number changes
      *  PATCH - will download for any version change
      * default value - PATCH
      * */
     @Override
     protected ReactNativeAutoUpdaterUpdateType getAllowedUpdateType() {
         return ReactNativeAutoUpdater.ReactNativeAutoUpdaterUpdateType.MINOR;
     }
    
     /**
      *  Decide how frequently to check for updates.
      * Available options - 
      *  EACH_TIME - each time the app starts
      *  DAILY     - maximum once per day
      *  WEEKLY    - maximum once per week
      * default value - EACH_TIME
      * */
     @Override
     protected ReactNativeAutoUpdaterFrequency getUpdateFrequency() {
         return ReactNativeAutoUpdaterFrequency.EACH_TIME;
     }
    
     /**
      *  To show progress during the update process.
      * */
     @Override
     protected boolean getShowProgress() {
         return true;
     }
  5. (Optional) Register Module in MainActivity.java

    This is required if you want to get the currently installed JS code version in your JS code.

     /**
      * A list of packages used by the app. If the app uses additional views
      * or modules besides the default ones, add more packages here.
      */
     @Override
     protected List<ReactPackage> getPackages() {
         return Arrays.<ReactPackage>asList(
                 new ReactNativeAutoUpdaterPackage(), // Add the ReactNativeAutoUpdater Package
                 new MainReactPackage());
     }

React Native >= 0.29

In MainActivity.java:

// Add the imports
import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdater;
import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdater.ReactNativeAutoUpdaterUpdateType;
import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdater.ReactNativeAutoUpdaterFrequency;
import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdaterActivity;

// Extend ReactNativeAutoUpdaterActivity instead of ReactActivity
public class MainActivity extends ReactNativeAutoUpdaterActivity {

	// Add required methods
	/**
	*  URL for the metadata of the update.
	* */
	@Override
	protected String getUpdateMetadataUrl() {
	return "https://www.aerofs.com/u/8691535/update.android.json";
	}
	
	/**
	* Name of the metadata file shipped with the app.
	* This metadata is used to compare the shipped JS code against the updates.
	* */
	@Override
	protected String getMetadataAssetName() {
	return "metadata.android.json";
	}

OPTIONAL Add optional methods

	/**
	* 
	*  If your updates metadata JSON has a relative URL for downloading
	*  the JS bundle, set this hostname.
	* */
	@Override
	protected String getHostnameForRelativeDownloadURLs() {
	return "https://www.aerofs.com";
	}
	
	/**
	*  Decide what type of updates to download.
	* Available options -
	*  MAJOR - will download only if major version number changes
	*  MINOR - will download if major or minor version number changes
	*  PATCH - will download for any version change
	* default value - PATCH
	* */
	@Override
	protected ReactNativeAutoUpdaterUpdateType getAllowedUpdateType() {
	return ReactNativeAutoUpdater.ReactNativeAutoUpdaterUpdateType.MINOR;
	}
	
	/**
	*  Decide how frequently to check for updates.
	* Available options -
	*  EACH_TIME - each time the app starts
	*  DAILY     - maximum once per day
	*  WEEKLY    - maximum once per week
	* default value - EACH_TIME
	* */
	@Override
	protected ReactNativeAutoUpdaterFrequency getUpdateFrequency() {
	return ReactNativeAutoUpdaterFrequency.EACH_TIME;
	}
	
	/**
	*  To show progress during the update process.
	* */
	@Override
	protected boolean getShowProgress() {
	return false;
	}
}

In MainApplication.java:

// Add imports
import com.aerofs.reactnativeautoupdater.ReactNativeAutoUpdaterPackage;
import javax.annotation.Nullable;

public class MainApplication extends Application implements ReactApplication {
	private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
	    // Inside here!!
	    // add required method
	    /**
	     *  Name of the JS Bundle file shipped with the app.
	     *  This file has to be added as an Android Asset.
	     * */
	    @Nullable
	    @Override
	    protected String getBundleAssetName() {
	        return "main.android.jsbundle";
	    }
	
	    // add package to list here
	    @Override
	    protected List<ReactPackage> getPackages() {
	      return Arrays.<ReactPackage>asList(
	          new ReactNativeAutoUpdaterPackage(),
	          new MainReactPackage()
	      );
	    }
	}
}

JS (optional, common for iOS and Android)

var ReactNativeAutoUpdater = require('react-native-auto-updater');

ReactNativeAutoUpdater.jsCodeVersion() 
// will give you the JS code version that is currently in use

Important

Don't forget to provide react-native-auto-updater with the metadata file for the JS code that is shipped with the app. Metadata in this file is used to compare the shipped JS code with updates. Thanks to @arbesfeld for pointing out this bug.

License

react-native-auto-updater is available under the MIT license. See the LICENSE file for more info.

More Repositories

1

teambox

This is the legacy version of Teambox - the award-winning collaboration solution, inspired by Basecamp, Yammer and Twitter.
Ruby
1,864
star
2

gockerize

Package golang service into minimal docker containers.
Shell
666
star
3

free-file-icons

Platform-agnostic icons for audio, image, programming and office files.
611
star
4

scrum-poker-cards

588
star
5

backbone-redux

Easy way to keep your backbone collections and redux store in sync.
JavaScript
191
star
6

viper-module-generator

Gem to generate VIPER modules to use them in your Objective-C/Swift projects.
Ruby
162
star
7

ssmp

Stupid-Simple Messaging Protocol.
122
star
8

lipwig

Golang implementation of the Stupid-Simple Messaging Protocol.
Go
98
star
9

departure

Percona's pt-online-schema-change runner for ActiveRecord migrations.
Ruby
86
star
10

SimplePagedView

A UIPageViewController replacement built to be as simple as possible
Swift
75
star
11

immortal

Make any ActiveRecord model paranoid by just including Immortal, and instead of being deleted from the database, the object will just marked as 'deleted' with a boolean field in the database.
Ruby
60
star
12

openjdk-trim

Tool to trim unneeded classes from an OpenJDK build.
Shell
47
star
13

react-native-quick-look

React Native Component for iOS QuickLook Framework.
Objective-C
37
star
14

aerofs-docker

Ready-to-use cloud-config file for the AeroFS appliance.
Shell
34
star
15

jssmp

Java implementation of the Stupid-Simple Messaging Protocol
Java
25
star
16

planning-time-android

Redbooth's planning poker app for Android.
Java
21
star
17

jnotify

Java bindings for native notification libraries.
C++
20
star
18

ssmperf

Load testing tool for SSMP servers.
Go
18
star
19

nps-surveys

Rails engine to add NPS surveys to your application.
Ruby
17
star
20

teambox-ruby-client

Ruby gem to access Teambox API
Ruby
16
star
21

npm-shrinkwrap-check

Util to check that package.json and npm-shrinkwrap.json are in sync.
JavaScript
14
star
22

fastqrcode

Fast and robust Python bindings for libqrencode.
C
11
star
23

redbooth-ruby

This is a Ruby wrapper for Redbooth's API.
Ruby
10
star
24

gerrit-slack-hooks

Make noise in Slack for Gerrit actions.
Shell
9
star
25

classy-immutable

Immutable instances of ES6 classes.
JavaScript
9
star
26

zendesk-elasticsearch

Index Zendesk tickets in Elasticsearch for easy searching.
Ruby
9
star
27

growl-java-bindings

Objective-C
8
star
28

rubocop-migrations

Ruby
5
star
29

aerofs-sdk-python

An AeroFS Private Cloud API SDK written in Python.
Python
4
star
30

SimpleNotificationBar

Swift
4
star
31

https-pushstate-server

A simple static file server that works with HTML5 Pushstate and HTTPS.
JavaScript
3
star
32

zendesk-help-center-backer

Back your Zendesk Help Center in git. Modify articles locally, and deploy directly to Zendesk.
Python
3
star
33

valkyrie

Golang implementation of the Zephyr relay protocol.
Go
3
star
34

aerofs-sdk-csharp

An AeroFS Private Cloud API SDK written in C#.
C#
2
star
35

retrace-server

Fast and simple TCP Server around Proguard's Retrace tool.
Java
2
star
36

fake-consul

Fakes a consul server. Usecase is for feature specs using Diplomat client
Ruby
2
star
37

api-docs

API v3 Documentation (depreciated).
CSS
2
star
38

aerofs-sdk-golang

An AeroFS Private Cloud API SDK written in Golang.
Go
1
star
39

aeroup

Secure AeroFS upload service. Send link, receive file.
JavaScript
1
star
40

switchboard

A service to perform real-time transcription and translation of audio streams.
Go
1
star
41

rbo-auth2-manager

AFOAuth2Manager in a Framework
Objective-C
1
star
42

freshdesk-help-center-backer

Back your Freshdesk Help Center in git. Modify articles locally, and deploy directly to Freshdesk.
Python
1
star