From 9026dbd5cb3c22b72c876d0529e6d6aefd80e683 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 19 May 2016 15:05:55 -0700 Subject: [PATCH 01/60] Remove "More than one CodePush instance" message --- .../main/java/com/microsoft/codepush/react/CodePush.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java index 7bbd414..2c68754 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java @@ -104,10 +104,6 @@ public class CodePush implements ReactPackage { throw new CodePushUnknownException("Unable to get package info for " + applicationContext.getPackageName(), e); } - if (currentInstance != null) { - CodePushUtils.log("More than one CodePush instance has been initialized. Please use the instance method codePush.getBundleUrlInternal() to get the correct bundleURL for a particular instance."); - } - currentInstance = this; clearDebugCacheIfNeeded(); @@ -780,4 +776,4 @@ public class CodePush implements ReactPackage { public List createViewManagers(ReactApplicationContext reactApplicationContext) { return new ArrayList<>(); } -} \ No newline at end of file +} From 66a36071e537cf8b3b6c0c8ec5c275c952fc2370 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Thu, 19 May 2016 15:28:41 -0700 Subject: [PATCH 02/60] fix rollback status report --- .../codepush/react/CodePushTelemetryManager.java | 12 +++++++----- ios/CodePush/CodePushTelemetryManager.m | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java index 0c70a9a..c851316 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java @@ -113,11 +113,13 @@ public class CodePushTelemetryManager { } public void recordStatusReported(ReadableMap statusReport) { - if (statusReport.hasKey(APP_VERSION_KEY)) { - saveStatusReportedForIdentifier(statusReport.getString(APP_VERSION_KEY)); - } else if (statusReport.hasKey(PACKAGE_KEY)) { - String packageIdentifier = getPackageStatusReportIdentifier(statusReport.getMap(PACKAGE_KEY)); - saveStatusReportedForIdentifier(packageIdentifier); + if (statusReport.hasKey(STATUS_KEY) && DEPLOYMENT_SUCCEEDED_STATUS.equals(statusReport.getString(STATUS_KEY))) { + if (statusReport.hasKey(APP_VERSION_KEY)) { + saveStatusReportedForIdentifier(statusReport.getString(APP_VERSION_KEY)); + } else if (statusReport.hasKey(PACKAGE_KEY)) { + String packageIdentifier = getPackageStatusReportIdentifier(statusReport.getMap(PACKAGE_KEY)); + saveStatusReportedForIdentifier(packageIdentifier); + } } } diff --git a/ios/CodePush/CodePushTelemetryManager.m b/ios/CodePush/CodePushTelemetryManager.m index 21988fa..aec9309 100644 --- a/ios/CodePush/CodePushTelemetryManager.m +++ b/ios/CodePush/CodePushTelemetryManager.m @@ -101,11 +101,13 @@ static NSString *const StatusKey = @"status"; + (void)recordStatusReported:(NSDictionary *)statusReport { - if (statusReport[AppVersionKey]) { - [self saveStatusReportedForIdentifier:statusReport[AppVersionKey]]; - } else if (statusReport[PackageKey]) { - NSString *packageIdentifier = [self getPackageStatusReportIdentifier:statusReport[PackageKey]]; - [self saveStatusReportedForIdentifier:packageIdentifier]; + if ([DeploymentSucceeded isEqualToString:statusReport[StatusKey]]) { + if (statusReport[AppVersionKey]) { + [self saveStatusReportedForIdentifier:statusReport[AppVersionKey]]; + } else if (statusReport[PackageKey]) { + NSString *packageIdentifier = [self getPackageStatusReportIdentifier:statusReport[PackageKey]]; + [self saveStatusReportedForIdentifier:packageIdentifier]; + } } } From f3d45a850fd173f9f066a89f7dc8a1a9c4a1cb34 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 20 May 2016 09:32:21 -0700 Subject: [PATCH 03/60] Adding note about CI --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 51d4a61..3b4c53a 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,9 @@ This plugin provides client-side integration for the [CodePush service](http://c * [JavaScript API](#javascript-api-reference) * [Objective-C API Reference (iOS)](#objective-c-api-reference-ios) * [Java API Reference (Android)](#java-api-reference-android) -* [Example Apps](#example-apps) * [Debugging / Troubleshooting](#debugging--troubleshooting) +* [Example Apps](#example-apps) +* [Continuous Integration / Delivery](#continuous-integration---delivery) ## How does it work? @@ -894,3 +895,10 @@ Now you'll be able to see CodePush logs in either debug or release mode, on both | Update not being displayed after restart | If you're not calling `sync` on app start (e.g. within `componentDidMount` of your root component), then you need to explicitly call `notifyApplicationReady` on app start, otherwise, the plugin will think your update failed and roll it back. | | Images dissappear after installing CodePush update | If your app is using the React Native assets system to load images (i.e. the `require(./foo.png)` syntax), then you **MUST** release your assets along with your JS bundle to CodePush. Follow [these instructions](#releasing-updates-javascript--images) to see how to do this. | | No JS bundle is being found when running your app against the iOS simulator | By default, React Native doesn't generate your JS bundle when running against the simulator. Therefore, if you're using `[CodePush bundleURL]`, and targetting the iOS simulator, you may be getting a `nil` result. This issue will be fixed in RN 0.22.0, but only for release builds. You can unblock this scenario right now by making [this change](https://github.com/facebook/react-native/commit/9ae3714f4bebdd2bcab4d7fdbf23acebdc5ed2ba) locally. + +## Continuous Integration / Delivery + +In addition to using the CodePush CLI to "manually" release updates, we want to help support a continuous delivery solution that allows you and your teams automatically release updates to the CodePush server whenever you push a change to your repo (or whenever your personal needs demands). To help simplify the process of adding a CodePuhs-based CD solition to your existing CI setup, refer to the following OSS products which provide integration with various CI servers: + +* [Visual Studio Team Services](https://marketplace.visualstudio.com/items?itemName=ms-vsclient.code-push) +* [Travis CI](https://github.com/mondora/code-push-travis-cli) From 0037147fbcf24ba6351b7b5cd0d9693c5e916555 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 20 May 2016 09:33:07 -0700 Subject: [PATCH 04/60] Fixing typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b4c53a..1c5ebdc 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This plugin provides client-side integration for the [CodePush service](http://c * [Java API Reference (Android)](#java-api-reference-android) * [Debugging / Troubleshooting](#debugging--troubleshooting) * [Example Apps](#example-apps) -* [Continuous Integration / Delivery](#continuous-integration---delivery) +* [Continuous Integration / Delivery](#continuous-integration--delivery) ## How does it work? From 01ba39edae910af85bbdc92db03ac54fafe69605 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 20 May 2016 10:50:19 -0700 Subject: [PATCH 05/60] Fixing wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c5ebdc..4780af7 100644 --- a/README.md +++ b/README.md @@ -898,7 +898,7 @@ Now you'll be able to see CodePush logs in either debug or release mode, on both ## Continuous Integration / Delivery -In addition to using the CodePush CLI to "manually" release updates, we want to help support a continuous delivery solution that allows you and your teams automatically release updates to the CodePush server whenever you push a change to your repo (or whenever your personal needs demands). To help simplify the process of adding a CodePuhs-based CD solition to your existing CI setup, refer to the following OSS products which provide integration with various CI servers: +In addition to being able to use the CodePush CLI to "manually" release updates, we believe that it's important to create a repeatable and sustainable solution for contiously delivering updates to your app. That way, it's simple enough for you and/or your team to create and maintain the rhythm of performing agile deployments. In order to assist with seting up a CodePush-based CD pipeline, refer to the following integrations with various CI servers: * [Visual Studio Team Services](https://marketplace.visualstudio.com/items?itemName=ms-vsclient.code-push) * [Travis CI](https://github.com/mondora/code-push-travis-cli) From c2b895f38d21073f8da3527e6e846bcf140e48c4 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 20 May 2016 17:29:49 -0700 Subject: [PATCH 06/60] Add note about Redux Saga --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4780af7..1da7ec1 100644 --- a/README.md +++ b/README.md @@ -383,7 +383,9 @@ AppState.addEventListener("change", (newState) => { newState === "active" && codePush.sync(); }); ``` - + +*NOTE: If you are using [Redux](http://redux.js.org) and [Redux Saga](http://yelouafi.github.io/redux-saga/), you can alternatively use the [react-native-code-push-saga](http://github.com/lostintangent/react-native-code-push-saga) module, which allows you to customize when `sync` is called in simpler/more idiomatic way.* + Additionally, if you would like to display an update confirmation dialog (an "active install"), configure when an available update is installed (e.g. force an immediate restart) or customize the update experience in any way, refer to the `sync` method's [API reference](#codepushsync) for information on how to tweak this default behavior. *NOTE: While [Apple's developer agreement](https://developer.apple.com/programs/ios/information/iOS_Program_Information_4_3_15.pdf) fully allows performing over-the-air updates of JavaScript and assets (which is what enables CodePush!), it is against their policy for an app to display an update prompt. Because of this, we recommend that App Store-distributed apps don't enable the `updateDialog` option when calling `sync`, whereas Google Play and internally distributed apps (e.g. Enterprise, Fabric, HockeyApp) can choose to enable/customize it.* From f5589c072b4d17707ee211d08c8048fd0d662cc5 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 20 May 2016 18:14:44 -0700 Subject: [PATCH 07/60] Adding note about HockeyApp/Google Play extensions in VSTS --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1da7ec1..2507ab0 100644 --- a/README.md +++ b/README.md @@ -902,5 +902,5 @@ Now you'll be able to see CodePush logs in either debug or release mode, on both In addition to being able to use the CodePush CLI to "manually" release updates, we believe that it's important to create a repeatable and sustainable solution for contiously delivering updates to your app. That way, it's simple enough for you and/or your team to create and maintain the rhythm of performing agile deployments. In order to assist with seting up a CodePush-based CD pipeline, refer to the following integrations with various CI servers: -* [Visual Studio Team Services](https://marketplace.visualstudio.com/items?itemName=ms-vsclient.code-push) +* [Visual Studio Team Services](https://marketplace.visualstudio.com/items?itemName=ms-vsclient.code-push) - *NOTE: VSTS also has extensions for publishing to [HockeyApp](https://marketplace.visualstudio.com/items?itemName=ms.hockeyapp) and the [Google Play](https://github.com/Microsoft/google-play-vsts-extension) store, so it provides a pretty great mobile CD solution in general.* * [Travis CI](https://github.com/mondora/code-push-travis-cli) From e5e09db8a9878d58247a43b38b779b8a793f39ba Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sat, 21 May 2016 22:08:01 +0200 Subject: [PATCH 08/60] add constants --- .../src/main/java/com/microsoft/codepush/react/CodePush.java | 1 + .../java/com/microsoft/codepush/react/CodePushInstallMode.java | 3 ++- ios/CodePush/CodePush.h | 1 + ios/CodePush/CodePush.m | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java index 2c68754..81eee0b 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java @@ -375,6 +375,7 @@ public class CodePush implements ReactPackage { constants.put("codePushInstallModeImmediate", CodePushInstallMode.IMMEDIATE.getValue()); constants.put("codePushInstallModeOnNextRestart", CodePushInstallMode.ON_NEXT_RESTART.getValue()); constants.put("codePushInstallModeOnNextResume", CodePushInstallMode.ON_NEXT_RESUME.getValue()); + constants.put("codePushInstallModeOnNextRestartOpportunity", CodePushInstallMode.ON_NEXT_RESTART_OPPORTUNITY.getValue()); constants.put("codePushUpdateStateRunning", CodePushUpdateState.RUNNING.getValue()); constants.put("codePushUpdateStatePending", CodePushUpdateState.PENDING.getValue()); diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java index 9afe0f5..097219d 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java @@ -3,7 +3,8 @@ package com.microsoft.codepush.react; public enum CodePushInstallMode { IMMEDIATE(0), ON_NEXT_RESTART(1), - ON_NEXT_RESUME(2); + ON_NEXT_RESUME(2), + ON_NEXT_RESTART_OPPORTUNITY(3); private final int value; CodePushInstallMode(int value) { diff --git a/ios/CodePush/CodePush.h b/ios/CodePush/CodePush.h index 782b5b9..7ba7537 100644 --- a/ios/CodePush/CodePush.h +++ b/ios/CodePush/CodePush.h @@ -146,6 +146,7 @@ failCallback:(void (^)(NSError *err))failCallback; typedef NS_ENUM(NSInteger, CodePushInstallMode) { CodePushInstallModeImmediate, CodePushInstallModeOnNextRestart, + CodePushInstallModeOnNextRestartOpportunity, CodePushInstallModeOnNextResume }; diff --git a/ios/CodePush/CodePush.m b/ios/CodePush/CodePush.m index 25c4aa3..7d8955b 100644 --- a/ios/CodePush/CodePush.m +++ b/ios/CodePush/CodePush.m @@ -216,6 +216,7 @@ static NSString *bundleResourceName = @"main"; @"codePushInstallModeOnNextRestart":@(CodePushInstallModeOnNextRestart), @"codePushInstallModeImmediate": @(CodePushInstallModeImmediate), @"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume), + @"codePushInstallModeOnNextRestartOpportunity": @(CodePushInstallModeOnNextRestartOpportunity), @"codePushUpdateStateRunning": @(CodePushUpdateStateRunning), @"codePushUpdateStatePending": @(CodePushUpdateStatePending), From 41c51018209019e4b64e9fc111968d192eeda6fa Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 10:10:47 +0200 Subject: [PATCH 09/60] add constant to c# code --- windows/CodePushNativeModule.cs | 1 + windows/InstallMode.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/windows/CodePushNativeModule.cs b/windows/CodePushNativeModule.cs index abdd0d0..4ca6b23 100644 --- a/windows/CodePushNativeModule.cs +++ b/windows/CodePushNativeModule.cs @@ -40,6 +40,7 @@ namespace CodePush.ReactNative { "codePushInstallModeImmediate", InstallMode.Immediate }, { "codePushInstallModeOnNextResume", InstallMode.OnNextResume }, { "codePushInstallModeOnNextRestart", InstallMode.OnNextRestart }, + { "codePushInstallModeOnNextRestartOpportunity", InstallMode.OnNextRestartOpportunity }, { "codePushUpdateStateRunning", UpdateState.Running }, { "codePushUpdateStatePending", UpdateState.Pending }, { "codePushUpdateStateLatest", UpdateState.Lastest }, diff --git a/windows/InstallMode.cs b/windows/InstallMode.cs index c407127..11e2fb8 100644 --- a/windows/InstallMode.cs +++ b/windows/InstallMode.cs @@ -4,6 +4,7 @@ { Immediate, OnNextRestart, - OnNextResume + OnNextResume, + OnNextRestartOpportunity } } \ No newline at end of file From dacbf48af4cb9d357737e288b894caa5f364cd5d Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 10:12:02 +0200 Subject: [PATCH 10/60] add constant to RCTConvert category --- ios/CodePush/RCTConvert+CodePushInstallMode.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ios/CodePush/RCTConvert+CodePushInstallMode.m b/ios/CodePush/RCTConvert+CodePushInstallMode.m index 6ef74a8..0f8f2ba 100644 --- a/ios/CodePush/RCTConvert+CodePushInstallMode.m +++ b/ios/CodePush/RCTConvert+CodePushInstallMode.m @@ -7,7 +7,8 @@ RCT_ENUM_CONVERTER(CodePushInstallMode, (@{ @"codePushInstallModeImmediate": @(CodePushInstallModeImmediate), @"codePushInstallModeOnNextRestart": @(CodePushInstallModeOnNextRestart), - @"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume) }), + @"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume), + @"codePushInstallModeOnNextRestartOpportunity": @(CodePushInstallModeOnNextRestartOpportunity) }), CodePushInstallModeImmediate, // Default enum value integerValue) From 088daeaf7dd0f2958258d8ea6aa1fdee8c220cc9 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 11:53:20 +0200 Subject: [PATCH 11/60] add code to delay automatic restarts --- CodePush.js | 7 ++++++- RestartManager.js | 39 +++++++++++++++++++++++++++++++++++++++ package-mixins.js | 4 ++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 RestartManager.js diff --git a/CodePush.js b/CodePush.js index ff52fce..ab987bd 100644 --- a/CodePush.js +++ b/CodePush.js @@ -2,6 +2,7 @@ import { AcquisitionManager as Sdk } from "code-push/script/acquisition-sdk"; import { Alert } from "./AlertAdapter"; import requestFetchAdapter from "./request-fetch-adapter"; import { AppState, Platform } from "react-native"; +import RestartManager from "./RestartManager"; let NativeCodePush = require("react-native").NativeModules.CodePush; const PackageMixins = require("./package-mixins")(NativeCodePush); @@ -412,10 +413,14 @@ if (NativeCodePush) { restartApp, setUpTestDependencies, sync, + disallowRestart: RestartManager.disallow, + allowRestart: RestartManager.allow, + restartAllowed: RestartManager.allowed, InstallMode: { IMMEDIATE: NativeCodePush.codePushInstallModeImmediate, // Restart the app immediately ON_NEXT_RESTART: NativeCodePush.codePushInstallModeOnNextRestart, // Don't artificially restart the app. Allow the update to be "picked up" on the next app restart - ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume // Restart the app the next time it is resumed from the background + ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume, // Restart the app the next time it is resumed from the background + ON_NEXT_RESTART_OPPORTUNITY: NativeCodePush.codePushInstallModeOnNextRestartOpportunity }, SyncStatus: { CHECKING_FOR_UPDATE: 0, diff --git a/RestartManager.js b/RestartManager.js new file mode 100644 index 0000000..0178f3e --- /dev/null +++ b/RestartManager.js @@ -0,0 +1,39 @@ +let NativeCodePush = require("react-native").NativeModules.CodePush; + +const RestartManager = (() => { + let _allowed = true; + let restartPending = false; + + function tryRestart() { + if (restartPending && _allowed == true) { + NativeCodePush.restartApp(true); + } + } + + function requestRestart() { + restartPending = true; + tryRestart(); + } + + function allow() { + _allowed = true; + tryRestart(); + } + + function allowed() { + return _allowed + } + + function disallow() { + _allowed = false; + } + + return { + allow, + disallow, + allowed, + requestRestart + }; +})(); + +module.exports = RestartManager; diff --git a/package-mixins.js b/package-mixins.js index 0357c41..9184da0 100644 --- a/package-mixins.js +++ b/package-mixins.js @@ -1,5 +1,6 @@ import { AcquisitionManager as Sdk } from "code-push/script/acquisition-sdk"; import { DeviceEventEmitter } from "react-native"; +import RestartManager from "./RestartManager"; // This function is used to augment remote and local // package objects with additional functionality/properties @@ -44,6 +45,9 @@ module.exports = (NativeCodePush) => { if (installMode == NativeCodePush.codePushInstallModeImmediate) { NativeCodePush.restartApp(false); } else { + if (installMode == NativeCodePush.codePushInstallModeOnNextRestartOpportunity) { + RestartManager.requestRestart(); + } localPackage.isPending = true; // Mark the package as pending since it hasn't been applied yet } }, From 4017fe3d75e72cf2a4cef1d88d3b28e5f43136e2 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 12:12:52 +0200 Subject: [PATCH 12/60] adjust example to test delaying restart --- Examples/CodePushDemoApp/crossplatformdemo.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Examples/CodePushDemoApp/crossplatformdemo.js b/Examples/CodePushDemoApp/crossplatformdemo.js index 7111d1c..d9cc352 100644 --- a/Examples/CodePushDemoApp/crossplatformdemo.js +++ b/Examples/CodePushDemoApp/crossplatformdemo.js @@ -19,8 +19,7 @@ let CodePushDemoApp = React.createClass({ try { return await CodePush.sync( { - updateDialog: true, - installMode: CodePush.InstallMode.ON_NEXT_RESUME + installMode: CodePush.InstallMode.ON_NEXT_RESTART_OPPORTUNITY, }, (syncStatus) => { switch(syncStatus) { @@ -89,6 +88,15 @@ let CodePushDemoApp = React.createClass({ return { }; }, + toggleAllowRestart() { + if (CodePush.restartAllowed()) { + CodePush.disallowRestart(); + } else { + CodePush.allowRestart(); + } + this.forceUpdate(); + }, + render() { let syncView, syncButton, progressView; @@ -119,6 +127,9 @@ let CodePushDemoApp = React.createClass({ {syncView} {progressView} + ); } From d09baadad14864e3156fe7849dcc9cc36c92b6cf Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 13:19:28 +0200 Subject: [PATCH 13/60] update typings --- typings/react-native-code-push.d.ts | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/typings/react-native-code-push.d.ts b/typings/react-native-code-push.d.ts index bce50a0..8d631c2 100644 --- a/typings/react-native-code-push.d.ts +++ b/typings/react-native-code-push.d.ts @@ -217,6 +217,24 @@ declare namespace CodePush { * Notifies the CodePush runtime that an installed update is considered successful. */ function notifyAppReady(): Promise; + + /** + * Allow CodePush to automatically restart the app if an update is installed with + * InstallMode.ON_NEXT_RESTART_OPPORTUNITY. + */ + function allowRestart(): void; + + /** + * Forbid CodePush to automatically restart the app if an update is installed with + * InstallMode.ON_NEXT_RESTART_OPPORTUNITY. + */ + function disallowRestart(): void; + + /** + * Check if CodePush is allowed to automatically restart the app if an update is installed + * with InstallMode.ON_NEXT_RESTART_OPPORTUNITY. + */ + function restartAllowed(): boolean; /** * Immediately restarts the app. @@ -252,7 +270,14 @@ declare namespace CodePush { * Indicates that you want to install the update, but don't want to restart the * app until the next time the end user resumes it from the background. */ - ON_NEXT_RESUME + ON_NEXT_RESUME, + + /** + * Indicates that you want to install the update, and restart the app as soon as possible. + * You can allow/forbid restarts with CodePush.allowRestart and CodePush.disallowRestart + * respectively. + */ + ON_NEXT_RESTART_OPPORTUNITY } /** From d8e6d302a19b6b0d02c994118a72740b5ce2c0fd Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 18:41:07 +0200 Subject: [PATCH 14/60] move restartApp to RestartManager --- CodePush.js | 7 +------ RestartManager.js | 16 +++++----------- package-mixins.js | 5 +---- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/CodePush.js b/CodePush.js index ab987bd..e70c37c 100644 --- a/CodePush.js +++ b/CodePush.js @@ -214,10 +214,6 @@ async function tryReportStatus(resumeListener) { } } -function restartApp(onlyIfUpdateIsPending = false) { - NativeCodePush.restartApp(onlyIfUpdateIsPending); -} - var testConfig; // This function is only used for tests. Replaces the default SDK, configuration and native bridge @@ -410,7 +406,7 @@ if (NativeCodePush) { log, notifyAppReady: notifyApplicationReady, notifyApplicationReady, - restartApp, + restartApp: RestartManager.restartApp, setUpTestDependencies, sync, disallowRestart: RestartManager.disallow, @@ -420,7 +416,6 @@ if (NativeCodePush) { IMMEDIATE: NativeCodePush.codePushInstallModeImmediate, // Restart the app immediately ON_NEXT_RESTART: NativeCodePush.codePushInstallModeOnNextRestart, // Don't artificially restart the app. Allow the update to be "picked up" on the next app restart ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume, // Restart the app the next time it is resumed from the background - ON_NEXT_RESTART_OPPORTUNITY: NativeCodePush.codePushInstallModeOnNextRestartOpportunity }, SyncStatus: { CHECKING_FOR_UPDATE: 0, diff --git a/RestartManager.js b/RestartManager.js index 0178f3e..83a9cfc 100644 --- a/RestartManager.js +++ b/RestartManager.js @@ -2,22 +2,16 @@ let NativeCodePush = require("react-native").NativeModules.CodePush; const RestartManager = (() => { let _allowed = true; - let restartPending = false; - function tryRestart() { - if (restartPending && _allowed == true) { - NativeCodePush.restartApp(true); + function restartApp(onlyIfUpdateIsPending = false) { + if (_allowed) { + NativeCodePush.restartApp(onlyIfUpdateIsPending); } } - function requestRestart() { - restartPending = true; - tryRestart(); - } - function allow() { _allowed = true; - tryRestart(); + restartApp(true); } function allowed() { @@ -32,7 +26,7 @@ const RestartManager = (() => { allow, disallow, allowed, - requestRestart + restartApp, }; })(); diff --git a/package-mixins.js b/package-mixins.js index 9184da0..89c52e6 100644 --- a/package-mixins.js +++ b/package-mixins.js @@ -43,11 +43,8 @@ module.exports = (NativeCodePush) => { await NativeCodePush.installUpdate(this, installMode, minimumBackgroundDuration); updateInstalledCallback && updateInstalledCallback(); if (installMode == NativeCodePush.codePushInstallModeImmediate) { - NativeCodePush.restartApp(false); + RestartManager.restartApp(false); } else { - if (installMode == NativeCodePush.codePushInstallModeOnNextRestartOpportunity) { - RestartManager.requestRestart(); - } localPackage.isPending = true; // Mark the package as pending since it hasn't been applied yet } }, From 0745fe407ea3219e32a9939bca0a2c3e641ca224 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 18:42:06 +0200 Subject: [PATCH 15/60] remove InstallMode ON_NEXT_RESTART_OPPORTUNITY --- .../microsoft/codepush/react/CodePushInstallMode.java | 3 +-- ios/CodePush/RCTConvert+CodePushInstallMode.m | 3 +-- typings/react-native-code-push.d.ts | 9 +-------- windows/InstallMode.cs | 3 +-- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java index 097219d..9afe0f5 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java @@ -3,8 +3,7 @@ package com.microsoft.codepush.react; public enum CodePushInstallMode { IMMEDIATE(0), ON_NEXT_RESTART(1), - ON_NEXT_RESUME(2), - ON_NEXT_RESTART_OPPORTUNITY(3); + ON_NEXT_RESUME(2); private final int value; CodePushInstallMode(int value) { diff --git a/ios/CodePush/RCTConvert+CodePushInstallMode.m b/ios/CodePush/RCTConvert+CodePushInstallMode.m index 0f8f2ba..6ef74a8 100644 --- a/ios/CodePush/RCTConvert+CodePushInstallMode.m +++ b/ios/CodePush/RCTConvert+CodePushInstallMode.m @@ -7,8 +7,7 @@ RCT_ENUM_CONVERTER(CodePushInstallMode, (@{ @"codePushInstallModeImmediate": @(CodePushInstallModeImmediate), @"codePushInstallModeOnNextRestart": @(CodePushInstallModeOnNextRestart), - @"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume), - @"codePushInstallModeOnNextRestartOpportunity": @(CodePushInstallModeOnNextRestartOpportunity) }), + @"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume) }), CodePushInstallModeImmediate, // Default enum value integerValue) diff --git a/typings/react-native-code-push.d.ts b/typings/react-native-code-push.d.ts index 8d631c2..32ee1c2 100644 --- a/typings/react-native-code-push.d.ts +++ b/typings/react-native-code-push.d.ts @@ -270,14 +270,7 @@ declare namespace CodePush { * Indicates that you want to install the update, but don't want to restart the * app until the next time the end user resumes it from the background. */ - ON_NEXT_RESUME, - - /** - * Indicates that you want to install the update, and restart the app as soon as possible. - * You can allow/forbid restarts with CodePush.allowRestart and CodePush.disallowRestart - * respectively. - */ - ON_NEXT_RESTART_OPPORTUNITY + ON_NEXT_RESUME } /** diff --git a/windows/InstallMode.cs b/windows/InstallMode.cs index 11e2fb8..c407127 100644 --- a/windows/InstallMode.cs +++ b/windows/InstallMode.cs @@ -4,7 +4,6 @@ { Immediate, OnNextRestart, - OnNextResume, - OnNextRestartOpportunity + OnNextResume } } \ No newline at end of file From be3a74f3b001fdc26c8a42f3175f680b2033f1f5 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Sun, 22 May 2016 19:26:20 +0200 Subject: [PATCH 16/60] remove constant ON_NEXT_RESTART_OPPORTUNITY --- Examples/CodePushDemoApp/crossplatformdemo.js | 2 +- .../main/java/com/microsoft/codepush/react/CodePush.java | 1 - ios/CodePush/CodePush.h | 1 - ios/CodePush/CodePush.m | 1 - typings/react-native-code-push.d.ts | 9 +++------ windows/CodePushNativeModule.cs | 1 - 6 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Examples/CodePushDemoApp/crossplatformdemo.js b/Examples/CodePushDemoApp/crossplatformdemo.js index d9cc352..ef950b9 100644 --- a/Examples/CodePushDemoApp/crossplatformdemo.js +++ b/Examples/CodePushDemoApp/crossplatformdemo.js @@ -19,7 +19,7 @@ let CodePushDemoApp = React.createClass({ try { return await CodePush.sync( { - installMode: CodePush.InstallMode.ON_NEXT_RESTART_OPPORTUNITY, + installMode: CodePush.InstallMode.IMMEDIATE, }, (syncStatus) => { switch(syncStatus) { diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java index 81eee0b..2c68754 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java @@ -375,7 +375,6 @@ public class CodePush implements ReactPackage { constants.put("codePushInstallModeImmediate", CodePushInstallMode.IMMEDIATE.getValue()); constants.put("codePushInstallModeOnNextRestart", CodePushInstallMode.ON_NEXT_RESTART.getValue()); constants.put("codePushInstallModeOnNextResume", CodePushInstallMode.ON_NEXT_RESUME.getValue()); - constants.put("codePushInstallModeOnNextRestartOpportunity", CodePushInstallMode.ON_NEXT_RESTART_OPPORTUNITY.getValue()); constants.put("codePushUpdateStateRunning", CodePushUpdateState.RUNNING.getValue()); constants.put("codePushUpdateStatePending", CodePushUpdateState.PENDING.getValue()); diff --git a/ios/CodePush/CodePush.h b/ios/CodePush/CodePush.h index 7ba7537..782b5b9 100644 --- a/ios/CodePush/CodePush.h +++ b/ios/CodePush/CodePush.h @@ -146,7 +146,6 @@ failCallback:(void (^)(NSError *err))failCallback; typedef NS_ENUM(NSInteger, CodePushInstallMode) { CodePushInstallModeImmediate, CodePushInstallModeOnNextRestart, - CodePushInstallModeOnNextRestartOpportunity, CodePushInstallModeOnNextResume }; diff --git a/ios/CodePush/CodePush.m b/ios/CodePush/CodePush.m index 7d8955b..25c4aa3 100644 --- a/ios/CodePush/CodePush.m +++ b/ios/CodePush/CodePush.m @@ -216,7 +216,6 @@ static NSString *bundleResourceName = @"main"; @"codePushInstallModeOnNextRestart":@(CodePushInstallModeOnNextRestart), @"codePushInstallModeImmediate": @(CodePushInstallModeImmediate), @"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume), - @"codePushInstallModeOnNextRestartOpportunity": @(CodePushInstallModeOnNextRestartOpportunity), @"codePushUpdateStateRunning": @(CodePushUpdateStateRunning), @"codePushUpdateStatePending": @(CodePushUpdateStatePending), diff --git a/typings/react-native-code-push.d.ts b/typings/react-native-code-push.d.ts index 32ee1c2..b59b3b1 100644 --- a/typings/react-native-code-push.d.ts +++ b/typings/react-native-code-push.d.ts @@ -219,20 +219,17 @@ declare namespace CodePush { function notifyAppReady(): Promise; /** - * Allow CodePush to automatically restart the app if an update is installed with - * InstallMode.ON_NEXT_RESTART_OPPORTUNITY. + * Allow CodePush to restart the app. */ function allowRestart(): void; /** - * Forbid CodePush to automatically restart the app if an update is installed with - * InstallMode.ON_NEXT_RESTART_OPPORTUNITY. + * Forbid CodePush to restart the app. */ function disallowRestart(): void; /** - * Check if CodePush is allowed to automatically restart the app if an update is installed - * with InstallMode.ON_NEXT_RESTART_OPPORTUNITY. + * Check if CodePush is allowed to restart the app. */ function restartAllowed(): boolean; diff --git a/windows/CodePushNativeModule.cs b/windows/CodePushNativeModule.cs index 4ca6b23..abdd0d0 100644 --- a/windows/CodePushNativeModule.cs +++ b/windows/CodePushNativeModule.cs @@ -40,7 +40,6 @@ namespace CodePush.ReactNative { "codePushInstallModeImmediate", InstallMode.Immediate }, { "codePushInstallModeOnNextResume", InstallMode.OnNextResume }, { "codePushInstallModeOnNextRestart", InstallMode.OnNextRestart }, - { "codePushInstallModeOnNextRestartOpportunity", InstallMode.OnNextRestartOpportunity }, { "codePushUpdateStateRunning", UpdateState.Running }, { "codePushUpdateStatePending", UpdateState.Pending }, { "codePushUpdateStateLatest", UpdateState.Lastest }, From 889af2d77d38c23f40ece54e1cddbf2fed6e2d10 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 23 May 2016 10:25:22 -0700 Subject: [PATCH 17/60] Updating RN support matrix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2507ab0..1df7996 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ We try our best to maintain backwards compatability of our plugin with previous | <0.14.0 | **Unsupported** | | v0.14.0 | v1.3.0 *(introduced Android support)* | | v0.15.0-v0.18.0 | v1.4.0-v1.6.0 *(introduced iOS asset support)* | -| v0.19.0-v0.26.0 | v1.7.0+ *(introduced Android asset support)* | -| v0.27.0+ | TBD :) We work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our "official" support is. +| v0.19.0-v0.27.0 | v1.7.0+ *(introduced Android asset support)* | +| v0.28.0+ | TBD :) We work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our "official" support is. ## Supported Components From 3ffa9866700bf6eb91219d432890154681c07c45 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Mon, 23 May 2016 21:10:29 +0200 Subject: [PATCH 18/60] remove comma --- CodePush.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodePush.js b/CodePush.js index e70c37c..d38970b 100644 --- a/CodePush.js +++ b/CodePush.js @@ -415,7 +415,7 @@ if (NativeCodePush) { InstallMode: { IMMEDIATE: NativeCodePush.codePushInstallModeImmediate, // Restart the app immediately ON_NEXT_RESTART: NativeCodePush.codePushInstallModeOnNextRestart, // Don't artificially restart the app. Allow the update to be "picked up" on the next app restart - ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume, // Restart the app the next time it is resumed from the background + ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume // Restart the app the next time it is resumed from the background }, SyncStatus: { CHECKING_FOR_UPDATE: 0, From 1a49e760cb0ca9272bc074d30b96fa04d0125096 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Mon, 23 May 2016 21:59:44 +0200 Subject: [PATCH 19/60] work on issues from comments -remove restartAllowed -add logging to RestartManager -keep track of pending restarts --- CodePush.js | 7 +------ Examples/CodePushDemoApp/crossplatformdemo.js | 8 ++++---- RestartManager.js | 17 +++++++++++------ logging.js | 6 ++++++ 4 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 logging.js diff --git a/CodePush.js b/CodePush.js index d38970b..4804063 100644 --- a/CodePush.js +++ b/CodePush.js @@ -3,6 +3,7 @@ import { Alert } from "./AlertAdapter"; import requestFetchAdapter from "./request-fetch-adapter"; import { AppState, Platform } from "react-native"; import RestartManager from "./RestartManager"; +import log from './logging'; let NativeCodePush = require("react-native").NativeModules.CodePush; const PackageMixins = require("./package-mixins")(NativeCodePush); @@ -155,11 +156,6 @@ function getPromisifiedSdk(requestFetchAdapter, config) { return sdk; } -/* Logs messages to console with the [CodePush] prefix */ -function log(message) { - console.log(`[CodePush] ${message}`) -} - // This ensures that notifyApplicationReadyInternal is only called once // in the lifetime of this module instance. const notifyApplicationReady = (() => { @@ -411,7 +407,6 @@ if (NativeCodePush) { sync, disallowRestart: RestartManager.disallow, allowRestart: RestartManager.allow, - restartAllowed: RestartManager.allowed, InstallMode: { IMMEDIATE: NativeCodePush.codePushInstallModeImmediate, // Restart the app immediately ON_NEXT_RESTART: NativeCodePush.codePushInstallModeOnNextRestart, // Don't artificially restart the app. Allow the update to be "picked up" on the next app restart diff --git a/Examples/CodePushDemoApp/crossplatformdemo.js b/Examples/CodePushDemoApp/crossplatformdemo.js index ef950b9..ff7de19 100644 --- a/Examples/CodePushDemoApp/crossplatformdemo.js +++ b/Examples/CodePushDemoApp/crossplatformdemo.js @@ -85,16 +85,16 @@ let CodePushDemoApp = React.createClass({ }, getInitialState() { - return { }; + return { restartAllowed: true }; }, toggleAllowRestart() { - if (CodePush.restartAllowed()) { + if (this.state.restartAllowed) { CodePush.disallowRestart(); } else { CodePush.allowRestart(); } - this.forceUpdate(); + this.setState({restartAllowed: !this.state.restartAllowed}); }, render() { @@ -128,7 +128,7 @@ let CodePushDemoApp = React.createClass({ {progressView} ); diff --git a/RestartManager.js b/RestartManager.js index 83a9cfc..60ca20e 100644 --- a/RestartManager.js +++ b/RestartManager.js @@ -1,31 +1,36 @@ +let log = require('./logging'); let NativeCodePush = require("react-native").NativeModules.CodePush; const RestartManager = (() => { let _allowed = true; + let _restartPending = false; function restartApp(onlyIfUpdateIsPending = false) { if (_allowed) { NativeCodePush.restartApp(onlyIfUpdateIsPending); + } else { + log("restart not allowed"); + _restartPending = true; } } function allow() { + log("allow restart"); _allowed = true; - restartApp(true); - } - - function allowed() { - return _allowed + if (_restartPending) { + log("executing pending restart"); + restartApp(true); + } } function disallow() { + log("disallow restart"); _allowed = false; } return { allow, disallow, - allowed, restartApp, }; })(); diff --git a/logging.js b/logging.js new file mode 100644 index 0000000..7523589 --- /dev/null +++ b/logging.js @@ -0,0 +1,6 @@ +/* Logs messages to console with the [CodePush] prefix */ +function log(message) { + console.log(`[CodePush] ${message}`); +} + +module.exports = log; From 02633ef52999df6f969479e435034bccbfff1b66 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Mon, 23 May 2016 22:01:16 +0200 Subject: [PATCH 20/60] remove restartAllowed from typings --- typings/react-native-code-push.d.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/typings/react-native-code-push.d.ts b/typings/react-native-code-push.d.ts index b59b3b1..c6f9cc5 100644 --- a/typings/react-native-code-push.d.ts +++ b/typings/react-native-code-push.d.ts @@ -228,11 +228,6 @@ declare namespace CodePush { */ function disallowRestart(): void; - /** - * Check if CodePush is allowed to restart the app. - */ - function restartAllowed(): boolean; - /** * Immediately restarts the app. * From 4a0938f7a4dd98698a696538003fc95a14ce6e06 Mon Sep 17 00:00:00 2001 From: danielbasedow Date: Mon, 23 May 2016 22:18:19 +0200 Subject: [PATCH 21/60] add clearPendingRestart and return bool from restartApp indicating if restart has been initiated --- RestartManager.js | 7 +++++++ package-mixins.js | 1 + 2 files changed, 8 insertions(+) diff --git a/RestartManager.js b/RestartManager.js index 60ca20e..0b33c7e 100644 --- a/RestartManager.js +++ b/RestartManager.js @@ -8,9 +8,11 @@ const RestartManager = (() => { function restartApp(onlyIfUpdateIsPending = false) { if (_allowed) { NativeCodePush.restartApp(onlyIfUpdateIsPending); + log('restaes'); } else { log("restart not allowed"); _restartPending = true; + return true; } } @@ -28,10 +30,15 @@ const RestartManager = (() => { _allowed = false; } + function clearPendingRestart() { + _restartPending = false; + } + return { allow, disallow, restartApp, + clearPendingRestart }; })(); diff --git a/package-mixins.js b/package-mixins.js index 89c52e6..78127cf 100644 --- a/package-mixins.js +++ b/package-mixins.js @@ -45,6 +45,7 @@ module.exports = (NativeCodePush) => { if (installMode == NativeCodePush.codePushInstallModeImmediate) { RestartManager.restartApp(false); } else { + RestartManager.clearPendingRestart(); localPackage.isPending = true; // Mark the package as pending since it hasn't been applied yet } }, From c0c32babc7b5ef74a5bf1cf49718b226acc586e3 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 23 May 2016 15:06:17 -0700 Subject: [PATCH 22/60] Metrics fix --- .../codepush/react/CodePushTelemetryManager.java | 16 +++++++++------- ios/CodePush/CodePushTelemetryManager.m | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java index c851316..a8ec6f1 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java @@ -113,13 +113,15 @@ public class CodePushTelemetryManager { } public void recordStatusReported(ReadableMap statusReport) { - if (statusReport.hasKey(STATUS_KEY) && DEPLOYMENT_SUCCEEDED_STATUS.equals(statusReport.getString(STATUS_KEY))) { - if (statusReport.hasKey(APP_VERSION_KEY)) { - saveStatusReportedForIdentifier(statusReport.getString(APP_VERSION_KEY)); - } else if (statusReport.hasKey(PACKAGE_KEY)) { - String packageIdentifier = getPackageStatusReportIdentifier(statusReport.getMap(PACKAGE_KEY)); - saveStatusReportedForIdentifier(packageIdentifier); - } + // We don't need to record rollback reports, so exit early if that's what was specified. + if (statusReport.hasKey(STATUS_KEY) && DEPLOYMENT_FAILED_STATUS.equals(statusReport.getString(STATUS_KEY))) + return; + + if (statusReport.hasKey(APP_VERSION_KEY)) { + saveStatusReportedForIdentifier(statusReport.getString(APP_VERSION_KEY)); + } else if (statusReport.hasKey(PACKAGE_KEY)) { + String packageIdentifier = getPackageStatusReportIdentifier(statusReport.getMap(PACKAGE_KEY)); + saveStatusReportedForIdentifier(packageIdentifier); } } diff --git a/ios/CodePush/CodePushTelemetryManager.m b/ios/CodePush/CodePushTelemetryManager.m index aec9309..d652334 100644 --- a/ios/CodePush/CodePushTelemetryManager.m +++ b/ios/CodePush/CodePushTelemetryManager.m @@ -101,13 +101,15 @@ static NSString *const StatusKey = @"status"; + (void)recordStatusReported:(NSDictionary *)statusReport { - if ([DeploymentSucceeded isEqualToString:statusReport[StatusKey]]) { - if (statusReport[AppVersionKey]) { - [self saveStatusReportedForIdentifier:statusReport[AppVersionKey]]; - } else if (statusReport[PackageKey]) { - NSString *packageIdentifier = [self getPackageStatusReportIdentifier:statusReport[PackageKey]]; - [self saveStatusReportedForIdentifier:packageIdentifier]; - } + // We don't need to record rollback reports, so exit early if that's what was specified. + if ([DeploymentFailed isEqualToString:statusReport[StatusKey]]) + return; + + if (statusReport[AppVersionKey]) { + [self saveStatusReportedForIdentifier:statusReport[AppVersionKey]]; + } else if (statusReport[PackageKey]) { + NSString *packageIdentifier = [self getPackageStatusReportIdentifier:statusReport[PackageKey]]; + [self saveStatusReportedForIdentifier:packageIdentifier]; } } From f10eb7ef677b66a8046ef4be1095bcffcd171d17 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 23 May 2016 15:26:51 -0700 Subject: [PATCH 23/60] Adding braces --- .../com/microsoft/codepush/react/CodePushTelemetryManager.java | 3 ++- ios/CodePush/CodePushTelemetryManager.m | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java index a8ec6f1..3227907 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java @@ -114,8 +114,9 @@ public class CodePushTelemetryManager { public void recordStatusReported(ReadableMap statusReport) { // We don't need to record rollback reports, so exit early if that's what was specified. - if (statusReport.hasKey(STATUS_KEY) && DEPLOYMENT_FAILED_STATUS.equals(statusReport.getString(STATUS_KEY))) + if (statusReport.hasKey(STATUS_KEY) && DEPLOYMENT_FAILED_STATUS.equals(statusReport.getString(STATUS_KEY))) { return; + } if (statusReport.hasKey(APP_VERSION_KEY)) { saveStatusReportedForIdentifier(statusReport.getString(APP_VERSION_KEY)); diff --git a/ios/CodePush/CodePushTelemetryManager.m b/ios/CodePush/CodePushTelemetryManager.m index d652334..04c8d46 100644 --- a/ios/CodePush/CodePushTelemetryManager.m +++ b/ios/CodePush/CodePushTelemetryManager.m @@ -102,8 +102,9 @@ static NSString *const StatusKey = @"status"; + (void)recordStatusReported:(NSDictionary *)statusReport { // We don't need to record rollback reports, so exit early if that's what was specified. - if ([DeploymentFailed isEqualToString:statusReport[StatusKey]]) + if ([DeploymentFailed isEqualToString:statusReport[StatusKey]]) { return; + } if (statusReport[AppVersionKey]) { [self saveStatusReportedForIdentifier:statusReport[AppVersionKey]]; From 1306c4b635d7d91fb65a6856aff0a65915ee4740 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 23 May 2016 17:30:52 -0700 Subject: [PATCH 24/60] Tweaking log messages --- CodePush.js | 12 +++++++++-- RestartManager.js | 51 ++++++++++++++++++++++++----------------------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/CodePush.js b/CodePush.js index 4804063..253e1c9 100644 --- a/CodePush.js +++ b/CodePush.js @@ -182,15 +182,23 @@ async function tryReportStatus(resumeListener) { const previousDeploymentKey = statusReport.previousDeploymentKey || config.deploymentKey; try { if (statusReport.appVersion) { + log(`Reporting binary update (${statusReport.appVersion})`); + const sdk = getPromisifiedSdk(requestFetchAdapter, config); await sdk.reportStatusDeploy(/* deployedPackage */ null, /* status */ null, previousLabelOrAppVersion, previousDeploymentKey); } else { + const label = statusReport.package.label; + if (statusReport.status === "DeploymentSucceeded") { + log(`Reporting CodePush update success (${label})`); + } else { + log(`Reporting CodePush update rollback (${label})`); + } + config.deploymentKey = statusReport.package.deploymentKey; const sdk = getPromisifiedSdk(requestFetchAdapter, config); await sdk.reportStatusDeploy(statusReport.package, statusReport.status, previousLabelOrAppVersion, previousDeploymentKey); } - - log(`Reported status: ${JSON.stringify(statusReport)}`); + NativeCodePush.recordStatusReported(statusReport); resumeListener && AppState.removeEventListener("change", resumeListener); } catch (e) { diff --git a/RestartManager.js b/RestartManager.js index 0b33c7e..a34fffe 100644 --- a/RestartManager.js +++ b/RestartManager.js @@ -1,45 +1,46 @@ -let log = require('./logging'); -let NativeCodePush = require("react-native").NativeModules.CodePush; +const log = require("./logging"); +const NativeCodePush = require("react-native").NativeModules.CodePush; const RestartManager = (() => { let _allowed = true; let _restartPending = false; + function allow() { + log("Re-allowing restarts"); + _allowed = true; + + if (_restartPending) { + log("Executing pending restart"); + restartApp(true); + } + } + + function clearPendingRestart() { + _restartPending = false; + } + + function disallow() { + log("Disallowing restarts"); + _allowed = false; + } + function restartApp(onlyIfUpdateIsPending = false) { if (_allowed) { NativeCodePush.restartApp(onlyIfUpdateIsPending); - log('restaes'); + log("Restarting app"); } else { - log("restart not allowed"); + log("Restart request queued until restarts are re-allowed"); _restartPending = true; return true; } } - function allow() { - log("allow restart"); - _allowed = true; - if (_restartPending) { - log("executing pending restart"); - restartApp(true); - } - } - - function disallow() { - log("disallow restart"); - _allowed = false; - } - - function clearPendingRestart() { - _restartPending = false; - } - return { allow, + clearPendingRestart, disallow, - restartApp, - clearPendingRestart + restartApp }; })(); -module.exports = RestartManager; +module.exports = RestartManager; \ No newline at end of file From 58f0bfc336fc6892040fcac64797dcda959d5639 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 23 May 2016 17:58:25 -0700 Subject: [PATCH 25/60] Adding nozip option to podspec --- CodePush.podspec | 13 +++++++++++-- README.md | 10 ++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CodePush.podspec b/CodePush.podspec index daf11d3..7af6b8b 100644 --- a/CodePush.podspec +++ b/CodePush.podspec @@ -12,10 +12,19 @@ Pod::Spec.new do |s| s.homepage = 'http://microsoft.github.io/code-push/' s.source = { :git => 'https://github.com/Microsoft/react-native-code-push.git', :tag => "v#{s.version}-beta" } s.platform = :ios, '7.0' - s.source_files = 'ios/CodePush/*.{h,m}', 'ios/CodePush/SSZipArchive/*.{h,m}', 'ios/CodePush/SSZipArchive/aes/*.{h,c}', 'ios/CodePush/SSZipArchive/minizip/*.{h,c}' s.public_header_files = 'ios/CodePush/CodePush.h' s.preserve_paths = '*.js' s.library = 'z' s.dependency 'React' - + + s.default_subspec = 'Full' + + s.subspec 'Full' do |ss| + s.source_files = 'ios/CodePush/*.{h,m}', 'ios/CodePush/SSZipArchive/*.{h,m}', 'ios/CodePush/SSZipArchive/aes/*.{h,c}', 'ios/CodePush/SSZipArchive/minizip/*.{h,c}' + end + + s.subspec 'NoZip' do |ss| + s.source_files = 'ios/CodePush/*.{h,m}' + end + end \ No newline at end of file diff --git a/README.md b/README.md index 1df7996..fa8e636 100644 --- a/README.md +++ b/README.md @@ -118,12 +118,18 @@ We hope to eventually remove the need for steps #2-4, but in the meantime, RNPM pod 'CodePush', :path => './node_modules/react-native-code-push' ``` - *NOTE: The above path needs to be relative to your app's `Podfile`, so adjust it as neccessary.* + CodePush depends on an internal copy of the `SSZipArchive` library, so if your project already includes that (either directly or via a transitive dependency), then you can install a version of CodePush which excludes its by using the following subspec: + + ```ruby + pod 'CodePush', :path => './node_modules/react-native-code-push', :subspecs => ['NoZip'] + ``` + + *NOTE: The above paths needs to be relative to your app's `Podfile`, so adjust it as neccessary.* 2. Run `pod install` *NOTE: The CodePush `.podspec` depends on the `React` pod, and so in order to ensure that it can correctly use the version of React Native that your app is built with, please make sure to define the `React` dependency in your app's `Podfile` as explained [here](http://facebook.github.io/react-native/docs/embedded-app-ios.html#install-react-native-using-cocoapods).* - + #### Plugin Installation (iOS - Manual) 1. Open your app's Xcode project From 3cc0be7c42d990559fcef437c54ff080a76b5c24 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 23 May 2016 18:11:27 -0700 Subject: [PATCH 26/60] Fixing typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa8e636..203bba8 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ We hope to eventually remove the need for steps #2-4, but in the meantime, RNPM pod 'CodePush', :path => './node_modules/react-native-code-push' ``` - CodePush depends on an internal copy of the `SSZipArchive` library, so if your project already includes that (either directly or via a transitive dependency), then you can install a version of CodePush which excludes its by using the following subspec: + CodePush depends on an internal copy of the `SSZipArchive` library, so if your project already includes that (either directly or via a transitive dependency), then you can install a version of CodePush which excludes it by using the following subspec: ```ruby pod 'CodePush', :path => './node_modules/react-native-code-push', :subspecs => ['NoZip'] From 006224a0b85d5029dfaf35380b555e834a2f0153 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Tue, 24 May 2016 10:36:17 -0700 Subject: [PATCH 27/60] Adding Pepperoni mention --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 203bba8..060bc39 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This plugin provides client-side integration for the [CodePush service](http://c * [Objective-C API Reference (iOS)](#objective-c-api-reference-ios) * [Java API Reference (Android)](#java-api-reference-android) * [Debugging / Troubleshooting](#debugging--troubleshooting) -* [Example Apps](#example-apps) +* [Example Apps / Starters](#example-apps--starters) * [Continuous Integration / Delivery](#continuous-integration--delivery) ## How does it work? @@ -864,7 +864,7 @@ Constructs the CodePush client runtime and represents the `ReactPackage` instanc - __getBundleUrl(String bundleName)__ - Returns the path to the most recent version of your app's JS bundle file, using the specified resource name (e.g. `index.android.bundle`). This method has the same resolution behavior as the Objective-C equivalent described above. -## Example Apps +## Example Apps / Starters The React Native community has graciously created some awesome open source apps that can serve as examples for developers that are getting started. The following is a list of OSS React Native apps that are also using CodePush, and can therefore be used to see how others are using the service: @@ -874,6 +874,8 @@ The React Native community has graciously created some awesome open source apps * [Math Facts](https://github.com/Khan/math-facts) - An app by Khan Academy to help memorize math facts more easily. * [MoveIt!](https://github.com/multunus/moveit-react-native) - An app by [Multunus](http://www.multunus.com) that allows employees within a company to track their work-outs. +Additionally, if you're looking to get started with React Native + CodePush, and are looking for an awesome starter kit, you should check out [Pepperoni](http://getpepperoni.com/). It includes everything you'll need to get going quickly, with modern / best practices (including CodePush!). + *Note: If you've developed a React Native app using CodePush, that is also open-source, please let us know. We would love to add it to this list!* ## Debugging / Troubleshooting From dd6e76fe83bfd717664fb5fef4ae5a7bb4c6c195 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Tue, 24 May 2016 17:55:10 -0700 Subject: [PATCH 28/60] Adding docs for dis/allowRestart --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/README.md b/README.md index 060bc39..25819ce 100644 --- a/README.md +++ b/README.md @@ -450,8 +450,12 @@ The following sections describe the shape and behavior of these APIs in detail: When you require `react-native-code-push`, the module object provides the following top-level methods: +* [allowRestart](#codepushallowrestart): Re-allows programmatic restarts to occur as a result of an update being installed, and optionally, immediately restarts the app if a pending update had attempted to restart the app while restarts were disallowed. This is an advanced API and is only neccessary if your app explicitly disallowed restarts via the `disallowRestart` method. + * [checkForUpdate](#codepushcheckforupdate): Asks the CodePush service whether the configured app deployment has an update available. +* [disallowRestart](#codepushdisallowrestart): Temporarily disallows any programmatic restarts to occur as a result of a CodePush update being installed. This is an advanced API, and is useful when a component within your app (e.g. an onboarding wizard) needs to ensure that no end-user interruptions can occur during its lifetime. + * [getCurrentPackage](#codepushgetcurrentpackage): Retrieves the metadata about the currently installed update (e.g. description, installation time, size). *NOTE: As of `v1.10.3-beta` of the CodePush module, this method is deprecated in favor of [`getUpdateMetadata`](#codepushgetupdatemetadata)*. * [getUpdateMetadata](#codepushgetupdatemetadata): Retrieves the metadata for an installed update (e.g. description, mandatory). @@ -462,6 +466,30 @@ When you require `react-native-code-push`, the module object provides the follow * [sync](#codepushsync): Allows checking for an update, downloading it and installing it, all with a single call. Unless you need custom UI and/or behavior, we recommend most developers to use this method when integrating CodePush into their apps +#### codePush.allowRestart + +```javascript +codePush.allowRestart(): void; +``` + +Re-allows programmatic restarts to occur, that would have otherwise been rejected due to a previous call to `disallowRestart`. If `disallowRestart` was never called in the first place, then calling this method will simply result in a no-op. + +If a pending CodePush update is currently pending, which attempted to restart the app, but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (e.g. an onboarding wizard). + +For example, calling `allowRestart` would trigger an immediate restart if either of the three scenarios mentioned in [disallowRestart](#codepushdisallowrestart) occured after `disallowRestart` was called. However, calling `allowRestart` wouldn't trigger a restart if the following were true: + +1. No CodePush updates were installed since the last time `disallowRestart` was called, and therefore, there isn't any need to restart anyways. + +2. There is currently a pending CodePush update, but it was installed via `InstallMode.ON_NEXT_RESTART`, and therefore, doesn't require a programmatic restart. + +3. There is currently a pending CodePush update, but it was installed via `InstallMode.ON_NEXT_RESUME` and the app hasn't been put into the background yet, and therefore, there isn't a need to programmatically restart yet. + +3. No calls to `restartApp` were made since the last time `disallowRestart` was called. + +This behavior ensures that no restarts will be triggered as a result of calling `reallowRestart` unless one was explictly requested during the disallowed period. + +See [disallowRestart](#codepushdisallowrestart) for an example of how this method can be used. + #### codePush.checkForUpdate ```javascript @@ -493,6 +521,49 @@ codePush.checkForUpdate() }); ``` +#### codePush.disallowRestart + +```javascript +codePush.disallowRestart(): void; +``` + +Temporarily disallows programmatic restarts to occur as a result of either of following scenarios: + +1. A CodePush update is installed using `InstallMode.IMMEDIATE` +2. A CodePush update is installed using `InstallMode.ON_NEXT_RESUME` and the app is resumed from the background (optionally being throttled by the `minimumBackgroundDuration` property) +3. The `restartApp` method was called + +*NOTE: #1 and #2 effectively work by calling `restartApp` for you, so you can think of `disallowRestart` as blocking any call to `restartApp`, regardless if your app calls it directly or indirectly.* + +After calling this method, any calls to `sync` would still be allowed to check for an update, download it and install it, but an attempt to restart the app would be queued until `reallowRestart` is called. This way, the restart request is captured and can be "flushed" whenever you want to allow it to occur. + +This is an advanced API, and is primarily useful when individual components within your app (e.g. an onboarding wizard) need to ensure that no end-user interruptions can occur during their lifetime, while continuing to allow the app to keep syncing with the CodePush server at its own pace and using whatever install modes are appropriate. This has the benefit of allowing the app to discover and download available updates as soon as possible, while also preventing any disruptions during key end-user experiences. + +As an alternative, you could also choose to simply use `InstallMode.ON_NEXT_RESTART` whenever calling `sync` (which will never attempt to programmatically restart the app), and then explicity calling `restartApp` at points in your app that you know it is "safe" to do so. `disallowRestart` provides an alternative approach to this when the code that sychronizes with the CodePush server is seperate from the code/comopents that want to enforce a no-restart policy. + +Example Usage: + +```javascript +class OnboardingWizard extends Component { + ... + + componentWillMount() { + // Ensure that any CodePush updates which are + // synchronized in the background can't trigger + // a restart while this component is mounted. + codePush.disallowRestart(); + } + + componentWillUnmount() { + // Reallow restarts, and optionally trigger + // a restart if one was currently pending. + codePush.allowRestart(); + } + + ... +} +``` + #### codePush.getCurrentPackage *NOTE: This method is considered deprecated as of `v1.10.3-beta` of the CodePush module. If you're running this version (or newer), we would recommend using the [`codePush.getUpdateMetadata`](#codepushgetupdatemetadata) instead, since it has more predictable behavior.* From 36bad7fe8117cbe66282a58ea4d4b0ffdea1321c Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Tue, 24 May 2016 17:59:55 -0700 Subject: [PATCH 29/60] Fixing typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 25819ce..4a28a50 100644 --- a/README.md +++ b/README.md @@ -474,7 +474,7 @@ codePush.allowRestart(): void; Re-allows programmatic restarts to occur, that would have otherwise been rejected due to a previous call to `disallowRestart`. If `disallowRestart` was never called in the first place, then calling this method will simply result in a no-op. -If a pending CodePush update is currently pending, which attempted to restart the app, but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (e.g. an onboarding wizard). +If a CodePush update is currently pending, which attempted to restart the app, but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (e.g. an onboarding wizard). For example, calling `allowRestart` would trigger an immediate restart if either of the three scenarios mentioned in [disallowRestart](#codepushdisallowrestart) occured after `disallowRestart` was called. However, calling `allowRestart` wouldn't trigger a restart if the following were true: From 554c6d2bd68c6a6fffd011928c2c87b7c4d7e573 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Tue, 24 May 2016 18:03:21 -0700 Subject: [PATCH 30/60] Small tweaks --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4a28a50..2b5279c 100644 --- a/README.md +++ b/README.md @@ -474,9 +474,9 @@ codePush.allowRestart(): void; Re-allows programmatic restarts to occur, that would have otherwise been rejected due to a previous call to `disallowRestart`. If `disallowRestart` was never called in the first place, then calling this method will simply result in a no-op. -If a CodePush update is currently pending, which attempted to restart the app, but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (e.g. an onboarding wizard). +If a CodePush update is currently pending, which attempted to restart the app (e.g. it used `InstallMode.IMMEDIATE`), but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (e.g. an onboarding wizard). -For example, calling `allowRestart` would trigger an immediate restart if either of the three scenarios mentioned in [disallowRestart](#codepushdisallowrestart) occured after `disallowRestart` was called. However, calling `allowRestart` wouldn't trigger a restart if the following were true: +For example, calling `allowRestart` would trigger an immediate restart if either of the three scenarios mentioned in the [`disallowRestart` docs](#codepushdisallowrestart) occured after `disallowRestart` was called. However, calling `allowRestart` wouldn't trigger a restart if the following were true: 1. No CodePush updates were installed since the last time `disallowRestart` was called, and therefore, there isn't any need to restart anyways. @@ -486,7 +486,7 @@ For example, calling `allowRestart` would trigger an immediate restart if either 3. No calls to `restartApp` were made since the last time `disallowRestart` was called. -This behavior ensures that no restarts will be triggered as a result of calling `reallowRestart` unless one was explictly requested during the disallowed period. +This behavior ensures that no restarts will be triggered as a result of calling `reallowRestart` unless one was explictly requested during the disallowed period. In this way, `allowRestart` is somewhat similar to calling `restartApp(true)`, except the former will only trigger a restart if the currently pending update wanted to restart, whereas the later would restart as long as an update is pending. See [disallowRestart](#codepushdisallowrestart) for an example of how this method can be used. From 61906b97d67cecab6e51f340d225827d307a7bb1 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Wed, 25 May 2016 14:08:35 -0700 Subject: [PATCH 31/60] Fixig typos --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 2b5279c..e617100 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,8 @@ We hope to eventually remove the need for steps #2-4, but in the meantime, RNPM pod 'CodePush', :path => './node_modules/react-native-code-push', :subspecs => ['NoZip'] ``` - *NOTE: The above paths needs to be relative to your app's `Podfile`, so adjust it as neccessary.* + *NOTE: The above paths needs to be relative to your app's `Podfile`, so adjust it as nec + cessary.* 2. Run `pod install` @@ -409,7 +410,7 @@ code-push release-react MyApp ios code-push release-react MyApp-Android android ``` -The `release-react` command enables such a simple workflow because it provides many sensible defaults (e.g. generating a release bundle, assuming your app's entry file on iOS is either `index.ios.js` or `index.js`). However, all of these defaults can be customized to allow incremental flexibility as neccessary, which makes it a good fit for most scenarios. +The `release-react` command enables such a simple workflow because it provides many sensible defaults (e.g. generating a release bundle, assuming your app's entry file on iOS is either `index.ios.js` or `index.js`). However, all of these defaults can be customized to allow incremental flexibility as necessary, which makes it a good fit for most scenarios. ```shell # Release a mandatory update with a changelog @@ -450,11 +451,11 @@ The following sections describe the shape and behavior of these APIs in detail: When you require `react-native-code-push`, the module object provides the following top-level methods: -* [allowRestart](#codepushallowrestart): Re-allows programmatic restarts to occur as a result of an update being installed, and optionally, immediately restarts the app if a pending update had attempted to restart the app while restarts were disallowed. This is an advanced API and is only neccessary if your app explicitly disallowed restarts via the `disallowRestart` method. +* [allowRestart](#codepushallowrestart): Re-allows programmatic restarts to occur as a result of an update being installed, and optionally, immediately restarts the app if a pending update had attempted to restart the app while restarts were disallowed. This is an advanced API and is only necessary if your app explicitly disallowed restarts via the `disallowRestart` method. * [checkForUpdate](#codepushcheckforupdate): Asks the CodePush service whether the configured app deployment has an update available. -* [disallowRestart](#codepushdisallowrestart): Temporarily disallows any programmatic restarts to occur as a result of a CodePush update being installed. This is an advanced API, and is useful when a component within your app (e.g. an onboarding wizard) needs to ensure that no end-user interruptions can occur during its lifetime. +* [disallowRestart](#codepushdisallowrestart): Temporarily disallows any programmatic restarts to occur as a result of a CodePush update being installed. This is an advanced API, and is useful when a component within your app (e.g. an onboarding process) needs to ensure that no end-user interruptions can occur during its lifetime. * [getCurrentPackage](#codepushgetcurrentpackage): Retrieves the metadata about the currently installed update (e.g. description, installation time, size). *NOTE: As of `v1.10.3-beta` of the CodePush module, this method is deprecated in favor of [`getUpdateMetadata`](#codepushgetupdatemetadata)*. @@ -474,7 +475,7 @@ codePush.allowRestart(): void; Re-allows programmatic restarts to occur, that would have otherwise been rejected due to a previous call to `disallowRestart`. If `disallowRestart` was never called in the first place, then calling this method will simply result in a no-op. -If a CodePush update is currently pending, which attempted to restart the app (e.g. it used `InstallMode.IMMEDIATE`), but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (e.g. an onboarding wizard). +If a CodePush update is currently pending, which attempted to restart the app (e.g. it used `InstallMode.IMMEDIATE`), but was blocked due to `disallowRestart` having been called, then calling `allowRestart` will result in an immediate restart. This allows the update to be applied as soon as possible, without interrupting the end user during critical workflows (e.g. an onboarding process). For example, calling `allowRestart` would trigger an immediate restart if either of the three scenarios mentioned in the [`disallowRestart` docs](#codepushdisallowrestart) occured after `disallowRestart` was called. However, calling `allowRestart` wouldn't trigger a restart if the following were true: @@ -484,9 +485,9 @@ For example, calling `allowRestart` would trigger an immediate restart if either 3. There is currently a pending CodePush update, but it was installed via `InstallMode.ON_NEXT_RESUME` and the app hasn't been put into the background yet, and therefore, there isn't a need to programmatically restart yet. -3. No calls to `restartApp` were made since the last time `disallowRestart` was called. +4. No calls to `restartApp` were made since the last time `disallowRestart` was called. -This behavior ensures that no restarts will be triggered as a result of calling `reallowRestart` unless one was explictly requested during the disallowed period. In this way, `allowRestart` is somewhat similar to calling `restartApp(true)`, except the former will only trigger a restart if the currently pending update wanted to restart, whereas the later would restart as long as an update is pending. +This behavior ensures that no restarts will be triggered as a result of calling `allowRestart` unless one was explictly requested during the disallowed period. In this way, `allowRestart` is somewhat similar to calling `restartApp(true)`, except the former will only trigger a restart if the currently pending update wanted to restart, whereas the later would restart as long as an update is pending. See [disallowRestart](#codepushdisallowrestart) for an example of how this method can be used. @@ -535,16 +536,16 @@ Temporarily disallows programmatic restarts to occur as a result of either of fo *NOTE: #1 and #2 effectively work by calling `restartApp` for you, so you can think of `disallowRestart` as blocking any call to `restartApp`, regardless if your app calls it directly or indirectly.* -After calling this method, any calls to `sync` would still be allowed to check for an update, download it and install it, but an attempt to restart the app would be queued until `reallowRestart` is called. This way, the restart request is captured and can be "flushed" whenever you want to allow it to occur. +After calling this method, any calls to `sync` would still be allowed to check for an update, download it and install it, but an attempt to restart the app would be queued until `allowRestart` is called. This way, the restart request is captured and can be "flushed" whenever you want to allow it to occur. -This is an advanced API, and is primarily useful when individual components within your app (e.g. an onboarding wizard) need to ensure that no end-user interruptions can occur during their lifetime, while continuing to allow the app to keep syncing with the CodePush server at its own pace and using whatever install modes are appropriate. This has the benefit of allowing the app to discover and download available updates as soon as possible, while also preventing any disruptions during key end-user experiences. +This is an advanced API, and is primarily useful when individual components within your app (e.g. an onboarding process) need to ensure that no end-user interruptions can occur during their lifetime, while continuing to allow the app to keep syncing with the CodePush server at its own pace and using whatever install modes are appropriate. This has the benefit of allowing the app to discover and download available updates as soon as possible, while also preventing any disruptions during key end-user experiences. -As an alternative, you could also choose to simply use `InstallMode.ON_NEXT_RESTART` whenever calling `sync` (which will never attempt to programmatically restart the app), and then explicity calling `restartApp` at points in your app that you know it is "safe" to do so. `disallowRestart` provides an alternative approach to this when the code that sychronizes with the CodePush server is seperate from the code/comopents that want to enforce a no-restart policy. +As an alternative, you could also choose to simply use `InstallMode.ON_NEXT_RESTART` whenever calling `sync` (which will never attempt to programmatically restart the app), and then explicity calling `restartApp` at points in your app that you know it is "safe" to do so. `disallowRestart` provides an alternative approach to this when the code that synchronizes with the CodePush server is separate from the code/components that want to enforce a no-restart policy. Example Usage: ```javascript -class OnboardingWizard extends Component { +class OnboardingProcess extends Component { ... componentWillMount() { @@ -899,7 +900,7 @@ The `CodePush` class' methods can be thought of as composite resolvers which alw 4. Repeat #2 and #3 as the CodePush releases and app store releases continue on into infinity (and beyond?) -Because of this behavior, you can safely deploy updates to both the app store(s) and CodePush as neccesary, and rest assured that your end-users will always get the most recent version. +Because of this behavior, you can safely deploy updates to both the app store(s) and CodePush as necesary, and rest assured that your end-users will always get the most recent version. ##### Methods From 166d3da22f845e8a5b1afb5df523552d6cbc5a41 Mon Sep 17 00:00:00 2001 From: Yann Pringault Date: Thu, 26 May 2016 16:50:19 +0200 Subject: [PATCH 32/60] Update README.md Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e617100..1d23a93 100644 --- a/README.md +++ b/README.md @@ -971,7 +971,7 @@ Now you'll be able to see CodePush logs in either debug or release mode, on both | Issue / Symptom | Possible Solution | |-----------------|-------------------| | Compilation Error | Double-check that your version of React Native is [compatible](#supported-react-native-platforms) with the CodePush version you are using. | -| Network timeout / hang when calling `sync` or `checkForUpadte` in the iOS Simulator | Try resetting the simulator by selecting the `Simulator -> Reset Content and Settings..` menu item, and then re-running your app. | +| Network timeout / hang when calling `sync` or `checkForUpdate` in the iOS Simulator | Try resetting the simulator by selecting the `Simulator -> Reset Content and Settings..` menu item, and then re-running your app. | | Server responds with a `404` when calling `sync` or `checkForUpdate` | Double-check that the deployment key you added to your `Info.plist` (iOS), `build.gradle` (Android) or that you're passing to `sync`/`checkForUpdate`, is in fact correct. You can run `code-push deployment ls [APP_NAME] -k` to view the correct keys for your app deployments. | | Update not being discovered | Double-check that the version of your running app (e.g. `1.0.0`) matches the version you specified when releasing the update to CodePush. Additionally, make sure that you are releasing to the same deployment that your app is configured to sync with. | | Update not being displayed after restart | If you're not calling `sync` on app start (e.g. within `componentDidMount` of your root component), then you need to explicitly call `notifyApplicationReady` on app start, otherwise, the plugin will think your update failed and roll it back. | From ba8d5282279a1461ebae45140f5cba0b8dc6bcb1 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 30 May 2016 13:49:34 -0700 Subject: [PATCH 33/60] Adding note about rollout and disabled to checkForUpdate --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1d23a93..ef35963 100644 --- a/README.md +++ b/README.md @@ -497,16 +497,18 @@ See [disallowRestart](#codepushdisallowrestart) for an example of how this metho codePush.checkForUpdate(deploymentKey: String = null): Promise; ``` -Queries the CodePush service to see whether the configured app deployment has an update available. By default, it will use the deployment key that is configured in your `Info.plist` file (iOS), or `MainActivity.java` file (Android), but you can override that by specifying a value via the optional `deploymentKey` parameter. This can be useful when you want to dynamically "redirect" a user to a specific deployment, such as allowing "Early access" via an easter egg or a user setting switch. +Queries the CodePush service to see whether the configured app deployment has an update available. By default, it will use the deployment key that is configured in your `Info.plist` file (iOS), or `MainActivity.java` file (Android), but you can override that by specifying a value via the optional `deploymentKey` parameter. This can be useful when you want to dynamically "redirect" a user to a specific deployment, such as allowing "early access" via an easter egg or a user setting switch. This method returns a `Promise` which resolves to one of two possible values: -1. `null` if there is no update available. This occurs in the following scenarios: +1. `null` if there is no update available. This can occur in the following scenarios: 1. The configured deployment doesn't contain any releases, and therefore, nothing to update. 2. The latest release within the configured deployment is targeting a different binary version than what you're currently running (either older or newer). 3. The currently running app already has the latest release from the configured deployment, and therefore, doesn't need it again. - + 4. The latest release within the configured deployment is currently marked as disabled, and therefore, isn't allowed to be downloaded. + 5. The latest release within the configured deployment is in an "active rollout" state, and the requesting device doesn't fall within the percentage of users who are eligible for it. + 2. A [`RemotePackage`](#remotepackage) instance which represents an available update that can be inspected and/or subsequently downloaded. Example Usage: From 9aafc2af0d12c1ea4cd0279dfe68fde40547e1dd Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Thu, 2 Jun 2016 16:30:04 -0700 Subject: [PATCH 34/60] Adding multi-deplyoment docs --- README.md | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ef35963..0c6ac62 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ This plugin provides client-side integration for the [CodePush service](http://c * [Java API Reference (Android)](#java-api-reference-android) * [Debugging / Troubleshooting](#debugging--troubleshooting) * [Example Apps / Starters](#example-apps--starters) +* [Multi-Deployment Releases](#multi-deplyoment-releases) * [Continuous Integration / Delivery](#continuous-integration--delivery) ## How does it work? @@ -980,9 +981,113 @@ Now you'll be able to see CodePush logs in either debug or release mode, on both | Images dissappear after installing CodePush update | If your app is using the React Native assets system to load images (i.e. the `require(./foo.png)` syntax), then you **MUST** release your assets along with your JS bundle to CodePush. Follow [these instructions](#releasing-updates-javascript--images) to see how to do this. | | No JS bundle is being found when running your app against the iOS simulator | By default, React Native doesn't generate your JS bundle when running against the simulator. Therefore, if you're using `[CodePush bundleURL]`, and targetting the iOS simulator, you may be getting a `nil` result. This issue will be fixed in RN 0.22.0, but only for release builds. You can unblock this scenario right now by making [this change](https://github.com/facebook/react-native/commit/9ae3714f4bebdd2bcab4d7fdbf23acebdc5ed2ba) locally. +## Multi-Deployment Releases + +In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin, using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app. This way, you never release an update to your end users that you haven't been able to validate yourself. + +*NOTE: Our client-side rollback feature can help mitigate releases which result in an app crash, and server-side rollbacks (e.g. `code-push rollback`) allow you to prevent additional users from installing a bad release, however, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* + +Setting this up requires unique steps for each platform, so refer to the following sections for an example of how this can be achieved in your React Native app, depending on the platform(s) you are targeting. + +### Android + +The [Android Gradle plugin](http://google.github.io/android-gradle-dsl/current/index.html) allows you to define custom config settings for each "build type" (e.g. debug, release), which in turn are generated as properties on the `BuildConfig` class that you can reference from your Java code. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key, and your release builds to use your CodePush production deployment key. + +To set this up, perform the following steps: + +1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle`) + +2. Find the `android { buildTypes }` section and define [`buildConfigField`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:buildConfigField(java.lang.String,%20java.lang.String,%20java.lang.String) entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. + + ```groovy + android { + ... + buildTypes { + debug { + ... + buildConfigField "String", "CODEPUSH_KEY", "" + ... + } + + release { + ... + buildConfigField "String", "CODEPUSH_KEY", "" + ... + } + } + ... + } + ``` + + *NOTE: As a reminder, you can retrieve these keys by running `code-push deployment ls -k` from your terminal.* + +4. Open up your `MainAtivity.java` file and change the `CodePush` constructor to pass the deployment key in via the build config you just defined, as opposed to a string literal. + + ```java + new CodePush(BuildConfig.CODEPUSH_KEY, this, BuildConfig.DEBUG); + ``` + + *Note: If you gave your build setting a different name in your Gradle file, simply make sure to reflect that in your Java code.* + +And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. + +If you want to be able to install both debug and release builds simultaneously on the same device, then you can also specify an [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees them as seperate apps (e.g. `com.foo` and `com.foo.debug`). + +```groovy +buildTypes { + debug { + applicationIdSuffix ".debug" + } +} +``` + +Additionally, if you want to give them seperate names and/or icons, you can define new resource files (`strings.xml` and drawables) for your debug build by creating a `app/src/debug` directory. View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. + +Finally, refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#content) for details about how to configure and create release builds for your Android apps. + +### iOS + +Xcode allows you to define custom build settings for each "configuration" (e.g. debug, release), which can then be referenced as the value of keys within the `Info.plist` file. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key, and your release builds to use your CodePush production deployment key. + +To set this up, perform the following steps: + +1. Open up your Xcode project and select your project in the `Project navigator` window + +2. Select the `Build Settings` tab + +3. Click the `+` button on the toolbar and select `Add User-Defined Setting` + + ![Setting](https://cloud.githubusercontent.com/assets/116461/15764165/a16dbe30-28dd-11e6-94f2-fa3b7eb0c7de.png) + +4. Name this new setting something like `CODEPUSH_KEY`, expand it, and specify your `Staging` deployment key for the `Debug` config and your `Production` deployment key for the `Production` config. + + ![Setting Keys](https://cloud.githubusercontent.com/assets/116461/15764230/106c245c-28de-11e6-96fe-2615f9220b07.png) + + *NOTE: As a reminder, you can retrieve these keys by running `code-push deployment ls -k` from your terminal.* + +5. Open your project's `Info.plist` file and change the value of your `CodePushDeploymentKey` entry to `$(CODEPUSH_KEY)` + + ![Infoplist](https://cloud.githubusercontent.com/assets/116461/15764252/3ac8aed2-28de-11e6-8c19-2270ae9857a7.png) + +And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. + +If you want to be able to install both debug and release builds simultaneously on the same device, then you can also specify an [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees them as seperate apps (e.g. `com.foo` and `com.foo.debug`). + +```groovy +buildTypes { + debug { + applicationIdSuffix ".debug" + } +} +``` + +Additionally, if you want to give them seperate names and/or icons, you can modify the `Product Name` and `Asset Catalog App Icon Set Name` build settings, so that the debug configuration has a unique value. + +![Product name](https://cloud.githubusercontent.com/assets/116461/15764314/b3a4cfac-28de-11e6-9e8c-b1cbd8ac7c6c.png) + ## Continuous Integration / Delivery In addition to being able to use the CodePush CLI to "manually" release updates, we believe that it's important to create a repeatable and sustainable solution for contiously delivering updates to your app. That way, it's simple enough for you and/or your team to create and maintain the rhythm of performing agile deployments. In order to assist with seting up a CodePush-based CD pipeline, refer to the following integrations with various CI servers: * [Visual Studio Team Services](https://marketplace.visualstudio.com/items?itemName=ms-vsclient.code-push) - *NOTE: VSTS also has extensions for publishing to [HockeyApp](https://marketplace.visualstudio.com/items?itemName=ms.hockeyapp) and the [Google Play](https://github.com/Microsoft/google-play-vsts-extension) store, so it provides a pretty great mobile CD solution in general.* -* [Travis CI](https://github.com/mondora/code-push-travis-cli) +* [Travis CI](https://github.com/mondora/code-push-travis-cli) \ No newline at end of file From 913cc496c894f05042347cf75911ff4036b95055 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Thu, 2 Jun 2016 16:35:55 -0700 Subject: [PATCH 35/60] Fixing typo --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0c6ac62..6c8136a 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This plugin provides client-side integration for the [CodePush service](http://c * [Java API Reference (Android)](#java-api-reference-android) * [Debugging / Troubleshooting](#debugging--troubleshooting) * [Example Apps / Starters](#example-apps--starters) -* [Multi-Deployment Releases](#multi-deplyoment-releases) +* [Multi-Deployment Releases](#multi-deployment-releases) * [Continuous Integration / Delivery](#continuous-integration--delivery) ## How does it work? @@ -199,6 +199,8 @@ To let the CodePush runtime know which deployment it should query for updates ag ![Deployment list](https://cloud.githubusercontent.com/assets/116461/11601733/13011d5e-9a8a-11e5-9ce2-b100498ffb34.png) +In order to effectively make use of the `Staging` and `Production` deployments that were created along with your CodePush app, refer to the [multi-deployment releases](#multi-deployment-releases) docs below before actually moving your app's usage of CodePush into production. + ## Android Setup In order to integrate CodePush into your Android project, perform the following steps: @@ -294,6 +296,8 @@ public class MainActivity extends ReactActivity { } ``` +In order to effectively make use of the `Staging` and `Production` deployments that were created along with your CodePush app, refer to the [multi-deployment releases](#multi-deployment-releases) docs below before actually moving your app's usage of CodePush into production. + ## Windows Setup Once you've acquired the CodePush plugin, you need to integrate it into the Visual Studio project of your React Native app and configure it correctly. To do this, take the following steps: @@ -1090,4 +1094,4 @@ Additionally, if you want to give them seperate names and/or icons, you can modi In addition to being able to use the CodePush CLI to "manually" release updates, we believe that it's important to create a repeatable and sustainable solution for contiously delivering updates to your app. That way, it's simple enough for you and/or your team to create and maintain the rhythm of performing agile deployments. In order to assist with seting up a CodePush-based CD pipeline, refer to the following integrations with various CI servers: * [Visual Studio Team Services](https://marketplace.visualstudio.com/items?itemName=ms-vsclient.code-push) - *NOTE: VSTS also has extensions for publishing to [HockeyApp](https://marketplace.visualstudio.com/items?itemName=ms.hockeyapp) and the [Google Play](https://github.com/Microsoft/google-play-vsts-extension) store, so it provides a pretty great mobile CD solution in general.* -* [Travis CI](https://github.com/mondora/code-push-travis-cli) \ No newline at end of file +* [Travis CI](https://github.com/mondora/code-push-travis-cli) From 434acd1f402cc1cb97cb377a7fc12a7d923ca39a Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Thu, 2 Jun 2016 16:37:12 -0700 Subject: [PATCH 36/60] Fixing links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c8136a..b4b831c 100644 --- a/README.md +++ b/README.md @@ -1001,7 +1001,7 @@ To set this up, perform the following steps: 1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle`) -2. Find the `android { buildTypes }` section and define [`buildConfigField`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:buildConfigField(java.lang.String,%20java.lang.String,%20java.lang.String) entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. +2. Find the `android { buildTypes }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. ```groovy android { From 3c0137d6f8d755a34e718e58c045b2e34ead0062 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Thu, 2 Jun 2016 16:42:02 -0700 Subject: [PATCH 37/60] Removing duplicate content --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index b4b831c..dfa15b2 100644 --- a/README.md +++ b/README.md @@ -1074,17 +1074,7 @@ To set this up, perform the following steps: ![Infoplist](https://cloud.githubusercontent.com/assets/116461/15764252/3ac8aed2-28de-11e6-8c19-2270ae9857a7.png) And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. - -If you want to be able to install both debug and release builds simultaneously on the same device, then you can also specify an [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees them as seperate apps (e.g. `com.foo` and `com.foo.debug`). -```groovy -buildTypes { - debug { - applicationIdSuffix ".debug" - } -} -``` - Additionally, if you want to give them seperate names and/or icons, you can modify the `Product Name` and `Asset Catalog App Icon Set Name` build settings, so that the debug configuration has a unique value. ![Product name](https://cloud.githubusercontent.com/assets/116461/15764314/b3a4cfac-28de-11e6-9e8c-b1cbd8ac7c6c.png) From 118a1a3649381cc18b859baeace031ed4ef4125c Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Thu, 2 Jun 2016 17:03:10 -0700 Subject: [PATCH 38/60] Moving deployment docs up --- README.md | 191 +++++++++++++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index dfa15b2..3a962f3 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,13 @@ This plugin provides client-side integration for the [CodePush service](http://c * [Windows Setup](#windows-setup) * [Plugin Usage](#plugin-usage) * [Releasing Updates](#releasing-updates) +* [Multi-Deployment Releases](#multi-deployment-releases) * [API Reference](#api-reference) * [JavaScript API](#javascript-api-reference) * [Objective-C API Reference (iOS)](#objective-c-api-reference-ios) * [Java API Reference (Android)](#java-api-reference-android) * [Debugging / Troubleshooting](#debugging--troubleshooting) * [Example Apps / Starters](#example-apps--starters) -* [Multi-Deployment Releases](#multi-deployment-releases) * [Continuous Integration / Delivery](#continuous-integration--delivery) ## How does it work? @@ -440,6 +440,101 @@ For more details about how the `release-react` command works, as well as the var If you run into any issues, or have any questions/comments/feedback, you can ping us within the [#code-push](https://discord.gg/0ZcbPKXt5bWxFdFu) channel on Reactiflux, [e-mail us](mailto:codepushfeed@microsoft.com) and/or check out the [troubleshooting](#debugging--troubleshooting) details below. + +## Multi-Deployment Releases + +In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin, using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app. This way, you never release an update to your end users that you haven't been able to validate yourself. + +*NOTE: Our client-side rollback feature can help mitigate releases which result in an app crash, and server-side rollbacks (e.g. `code-push rollback`) allow you to prevent additional users from installing a bad release, however, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* + +Setting this up requires unique steps for each platform, so refer to the following sections for an example of how this can be achieved in your React Native app, depending on the platform(s) you are targeting. + +### Android + +The [Android Gradle plugin](http://google.github.io/android-gradle-dsl/current/index.html) allows you to define custom config settings for each "build type" (e.g. debug, release), which in turn are generated as properties on the `BuildConfig` class that you can reference from your Java code. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key, and your release builds to use your CodePush production deployment key. + +To set this up, perform the following steps: + +1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle`) + +2. Find the `android { buildTypes }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. + + ```groovy + android { + ... + buildTypes { + debug { + ... + buildConfigField "String", "CODEPUSH_KEY", "" + ... + } + + release { + ... + buildConfigField "String", "CODEPUSH_KEY", "" + ... + } + } + ... + } + ``` + + *NOTE: As a reminder, you can retrieve these keys by running `code-push deployment ls -k` from your terminal.* + +4. Open up your `MainAtivity.java` file and change the `CodePush` constructor to pass the deployment key in via the build config you just defined, as opposed to a string literal. + + ```java + new CodePush(BuildConfig.CODEPUSH_KEY, this, BuildConfig.DEBUG); + ``` + + *Note: If you gave your build setting a different name in your Gradle file, simply make sure to reflect that in your Java code.* + +And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. + +If you want to be able to install both debug and release builds simultaneously on the same device, then you can also specify an [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees them as seperate apps (e.g. `com.foo` and `com.foo.debug`). + +```groovy +buildTypes { + debug { + applicationIdSuffix ".debug" + } +} +``` + +Additionally, if you want to give them seperate names and/or icons, you can define new resource files (`strings.xml` and drawables) for your debug build by creating a `app/src/debug` directory. View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. + +Finally, refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#content) for details about how to configure and create release builds for your Android apps. + +### iOS + +Xcode allows you to define custom build settings for each "configuration" (e.g. debug, release), which can then be referenced as the value of keys within the `Info.plist` file. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key, and your release builds to use your CodePush production deployment key. + +To set this up, perform the following steps: + +1. Open up your Xcode project and select your project in the `Project navigator` window + +2. Select the `Build Settings` tab + +3. Click the `+` button on the toolbar and select `Add User-Defined Setting` + + ![Setting](https://cloud.githubusercontent.com/assets/116461/15764165/a16dbe30-28dd-11e6-94f2-fa3b7eb0c7de.png) + +4. Name this new setting something like `CODEPUSH_KEY`, expand it, and specify your `Staging` deployment key for the `Debug` config and your `Production` deployment key for the `Production` config. + + ![Setting Keys](https://cloud.githubusercontent.com/assets/116461/15764230/106c245c-28de-11e6-96fe-2615f9220b07.png) + + *NOTE: As a reminder, you can retrieve these keys by running `code-push deployment ls -k` from your terminal.* + +5. Open your project's `Info.plist` file and change the value of your `CodePushDeploymentKey` entry to `$(CODEPUSH_KEY)` + + ![Infoplist](https://cloud.githubusercontent.com/assets/116461/15764252/3ac8aed2-28de-11e6-8c19-2270ae9857a7.png) + +And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. + +Additionally, if you want to give them seperate names and/or icons, you can modify the `Product Name` and `Asset Catalog App Icon Set Name` build settings, so that the debug configuration has a unique value. + +![Product name](https://cloud.githubusercontent.com/assets/116461/15764314/b3a4cfac-28de-11e6-9e8c-b1cbd8ac7c6c.png) + --- ## API Reference @@ -985,100 +1080,6 @@ Now you'll be able to see CodePush logs in either debug or release mode, on both | Images dissappear after installing CodePush update | If your app is using the React Native assets system to load images (i.e. the `require(./foo.png)` syntax), then you **MUST** release your assets along with your JS bundle to CodePush. Follow [these instructions](#releasing-updates-javascript--images) to see how to do this. | | No JS bundle is being found when running your app against the iOS simulator | By default, React Native doesn't generate your JS bundle when running against the simulator. Therefore, if you're using `[CodePush bundleURL]`, and targetting the iOS simulator, you may be getting a `nil` result. This issue will be fixed in RN 0.22.0, but only for release builds. You can unblock this scenario right now by making [this change](https://github.com/facebook/react-native/commit/9ae3714f4bebdd2bcab4d7fdbf23acebdc5ed2ba) locally. -## Multi-Deployment Releases - -In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin, using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app. This way, you never release an update to your end users that you haven't been able to validate yourself. - -*NOTE: Our client-side rollback feature can help mitigate releases which result in an app crash, and server-side rollbacks (e.g. `code-push rollback`) allow you to prevent additional users from installing a bad release, however, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* - -Setting this up requires unique steps for each platform, so refer to the following sections for an example of how this can be achieved in your React Native app, depending on the platform(s) you are targeting. - -### Android - -The [Android Gradle plugin](http://google.github.io/android-gradle-dsl/current/index.html) allows you to define custom config settings for each "build type" (e.g. debug, release), which in turn are generated as properties on the `BuildConfig` class that you can reference from your Java code. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key, and your release builds to use your CodePush production deployment key. - -To set this up, perform the following steps: - -1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle`) - -2. Find the `android { buildTypes }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. - - ```groovy - android { - ... - buildTypes { - debug { - ... - buildConfigField "String", "CODEPUSH_KEY", "" - ... - } - - release { - ... - buildConfigField "String", "CODEPUSH_KEY", "" - ... - } - } - ... - } - ``` - - *NOTE: As a reminder, you can retrieve these keys by running `code-push deployment ls -k` from your terminal.* - -4. Open up your `MainAtivity.java` file and change the `CodePush` constructor to pass the deployment key in via the build config you just defined, as opposed to a string literal. - - ```java - new CodePush(BuildConfig.CODEPUSH_KEY, this, BuildConfig.DEBUG); - ``` - - *Note: If you gave your build setting a different name in your Gradle file, simply make sure to reflect that in your Java code.* - -And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. - -If you want to be able to install both debug and release builds simultaneously on the same device, then you can also specify an [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees them as seperate apps (e.g. `com.foo` and `com.foo.debug`). - -```groovy -buildTypes { - debug { - applicationIdSuffix ".debug" - } -} -``` - -Additionally, if you want to give them seperate names and/or icons, you can define new resource files (`strings.xml` and drawables) for your debug build by creating a `app/src/debug` directory. View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. - -Finally, refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#content) for details about how to configure and create release builds for your Android apps. - -### iOS - -Xcode allows you to define custom build settings for each "configuration" (e.g. debug, release), which can then be referenced as the value of keys within the `Info.plist` file. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key, and your release builds to use your CodePush production deployment key. - -To set this up, perform the following steps: - -1. Open up your Xcode project and select your project in the `Project navigator` window - -2. Select the `Build Settings` tab - -3. Click the `+` button on the toolbar and select `Add User-Defined Setting` - - ![Setting](https://cloud.githubusercontent.com/assets/116461/15764165/a16dbe30-28dd-11e6-94f2-fa3b7eb0c7de.png) - -4. Name this new setting something like `CODEPUSH_KEY`, expand it, and specify your `Staging` deployment key for the `Debug` config and your `Production` deployment key for the `Production` config. - - ![Setting Keys](https://cloud.githubusercontent.com/assets/116461/15764230/106c245c-28de-11e6-96fe-2615f9220b07.png) - - *NOTE: As a reminder, you can retrieve these keys by running `code-push deployment ls -k` from your terminal.* - -5. Open your project's `Info.plist` file and change the value of your `CodePushDeploymentKey` entry to `$(CODEPUSH_KEY)` - - ![Infoplist](https://cloud.githubusercontent.com/assets/116461/15764252/3ac8aed2-28de-11e6-8c19-2270ae9857a7.png) - -And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. - -Additionally, if you want to give them seperate names and/or icons, you can modify the `Product Name` and `Asset Catalog App Icon Set Name` build settings, so that the debug configuration has a unique value. - -![Product name](https://cloud.githubusercontent.com/assets/116461/15764314/b3a4cfac-28de-11e6-9e8c-b1cbd8ac7c6c.png) - ## Continuous Integration / Delivery In addition to being able to use the CodePush CLI to "manually" release updates, we believe that it's important to create a repeatable and sustainable solution for contiously delivering updates to your app. That way, it's simple enough for you and/or your team to create and maintain the rhythm of performing agile deployments. In order to assist with seting up a CodePush-based CD pipeline, refer to the following integrations with various CI servers: From c238b01205ad25f07ae30cd4c985d4f12176300f Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 3 Jun 2016 08:58:32 -0700 Subject: [PATCH 39/60] Adding workflow details --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 3a962f3..614110f 100644 --- a/README.md +++ b/README.md @@ -447,6 +447,18 @@ In our [getting started](#getting-started) docs, we illustrated how to configure *NOTE: Our client-side rollback feature can help mitigate releases which result in an app crash, and server-side rollbacks (e.g. `code-push rollback`) allow you to prevent additional users from installing a bad release, however, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* +Using these deployments, allows you to acheive a workflow like the following: + +1. Release a CodePush update to your `Staging` deployment using the `code-push release-react` command (or `code-push release` if you need more control) + +2. Run your "Staging" build of your app, sync the update from the server and verify it works as expected + +3. Promote the tested release from `Staging` to `Production` using the `code-push promote` command + +4. Run your "Production" build of your app, sync the update from the server and verify it works as expected + +*NOTE: If you want to get really fancy, you can even choose to perform a "staged rollout" as part of #3, which allows you to mitigate any potential risk with the update (e.g. did your testing in #2 touch all possible devices/conditions?) by only making the production update available to a percentage of your users (e.g. `code-push promote Staging Production -r 20%`). Then, after waiting for a reasonable amount of time to see if any crash reports or customer feedback comes in, you can expand it to your entire audience by running `code-push patch Production -r 100%`.* + Setting this up requires unique steps for each platform, so refer to the following sections for an example of how this can be achieved in your React Native app, depending on the platform(s) you are targeting. ### Android From b90124f1c217f75b5e323a2c2997a63cac73fb50 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 3 Jun 2016 09:14:44 -0700 Subject: [PATCH 40/60] Adding more detail for Android --- README.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 614110f..f395a25 100644 --- a/README.md +++ b/README.md @@ -443,11 +443,11 @@ If you run into any issues, or have any questions/comments/feedback, you can pin ## Multi-Deployment Releases -In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin, using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app. This way, you never release an update to your end users that you haven't been able to validate yourself. +In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app (or any custom deployments you may have created). This way, you never release an update to your end users that you haven't been able to validate yourself. -*NOTE: Our client-side rollback feature can help mitigate releases which result in an app crash, and server-side rollbacks (e.g. `code-push rollback`) allow you to prevent additional users from installing a bad release, however, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* +*NOTE: Our client-side rollback feature can help unblock users after installing a release that resulted in a crash, and server-side rollbacks (i.e. `code-push rollback`) allow you to prevent additional users from installing a bad release once it's been identified, however, it's obviously better if you can prevent an erroneous update from being broadly released if at all possible.* -Using these deployments, allows you to acheive a workflow like the following: +Taking advantage of the `Staging` and `Production` deployments allows you to acheive a workflow like the following (feel free to customize!): 1. Release a CodePush update to your `Staging` deployment using the `code-push release-react` command (or `code-push release` if you need more control) @@ -459,17 +459,17 @@ Using these deployments, allows you to acheive a workflow like the following: *NOTE: If you want to get really fancy, you can even choose to perform a "staged rollout" as part of #3, which allows you to mitigate any potential risk with the update (e.g. did your testing in #2 touch all possible devices/conditions?) by only making the production update available to a percentage of your users (e.g. `code-push promote Staging Production -r 20%`). Then, after waiting for a reasonable amount of time to see if any crash reports or customer feedback comes in, you can expand it to your entire audience by running `code-push patch Production -r 100%`.* -Setting this up requires unique steps for each platform, so refer to the following sections for an example of how this can be achieved in your React Native app, depending on the platform(s) you are targeting. +You'll notice that the above steps refer to a "staging build" and "prodiction build" of your app. If you're build process already generates distinct binaries per "environment" like this, then you don't need to read any further, since swapping out CodePush deployment keys is just like handling environment-specific config for any other service your app uses (e.g. Facebook). However, if you're looking for some examples on how to setup your bild process to accomodate this, then refer to the following sections, depending on the platform(s) your app is targeting. ### Android -The [Android Gradle plugin](http://google.github.io/android-gradle-dsl/current/index.html) allows you to define custom config settings for each "build type" (e.g. debug, release), which in turn are generated as properties on the `BuildConfig` class that you can reference from your Java code. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key, and your release builds to use your CodePush production deployment key. +The [Android Gradle plugin](http://google.github.io/android-gradle-dsl/current/index.html) allows you to define custom config settings for each "build type" (e.g. debug, release), which in turn are generated as properties on the `BuildConfig` class that you can reference from your Java code. This mechanism allows you to easily configure your debug builds to use your CodePush staging deployment key and your release builds to use your CodePush production deployment key. To set this up, perform the following steps: 1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle`) -2. Find the `android { buildTypes }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. +2. Find the `android { buildTypes {} }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. ```groovy android { @@ -503,7 +503,9 @@ To set this up, perform the following steps: And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. -If you want to be able to install both debug and release builds simultaneously on the same device, then you can also specify an [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees them as seperate apps (e.g. `com.foo` and `com.foo.debug`). +If you want to be able to install both debug and release builds simultaneously on the same device (highly recommended!), then you need to ensure that your debug build has a unique identity and icon. You can achieve this by performing the following steps: + +1. In your `build.gradle` file, specify the [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees it as a different app from your release/production build (e.g. `com.foo` vs. `com.foo.debug`). ```groovy buildTypes { @@ -512,10 +514,16 @@ buildTypes { } } ``` - -Additionally, if you want to give them seperate names and/or icons, you can define new resource files (`strings.xml` and drawables) for your debug build by creating a `app/src/debug` directory. View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. -Finally, refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#content) for details about how to configure and create release builds for your Android apps. +2. Create the `app/src/debug/res` directory structure in your app to allow overriding app resources for your debug builds + +3. Create a `values` directory underneath the debug res directory created in #2, and copy the existing `strings.xml` file from the `app/src/main/res/values` directory + +4. Open up the new debug `strings.xml` file and change the `` element's value to something else (e.g. `foo-debug`). + +5. Create "mirrored" directories in the `app/src/debug/res` directory for all of your app's icons that you want to change for your debug build. + +And that's it! View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. Finally, refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#content) for details about how to configure and create release builds for your Android apps. ### iOS From 50331afa7ac52f16564bac65500f2a1ebcf16430 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 3 Jun 2016 09:23:36 -0700 Subject: [PATCH 41/60] Fixing typos --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f395a25..6849434 100644 --- a/README.md +++ b/README.md @@ -445,21 +445,21 @@ If you run into any issues, or have any questions/comments/feedback, you can pin In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app (or any custom deployments you may have created). This way, you never release an update to your end users that you haven't been able to validate yourself. -*NOTE: Our client-side rollback feature can help unblock users after installing a release that resulted in a crash, and server-side rollbacks (i.e. `code-push rollback`) allow you to prevent additional users from installing a bad release once it's been identified, however, it's obviously better if you can prevent an erroneous update from being broadly released if at all possible.* +*NOTE: Our client-side rollback feature can help unblock users after installing a release that resulted in a crash, and server-side rollbacks (i.e. `code-push rollback`) allow you to prevent additional users from installing a bad release once it's been identified. Hhowever, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* Taking advantage of the `Staging` and `Production` deployments allows you to acheive a workflow like the following (feel free to customize!): 1. Release a CodePush update to your `Staging` deployment using the `code-push release-react` command (or `code-push release` if you need more control) -2. Run your "Staging" build of your app, sync the update from the server and verify it works as expected +2. Run your staging/beta build of your app, sync the update from the server, and verify it works as expected 3. Promote the tested release from `Staging` to `Production` using the `code-push promote` command -4. Run your "Production" build of your app, sync the update from the server and verify it works as expected +4. Run your production/release build of your app, sync the update from the server and verify it works as expected -*NOTE: If you want to get really fancy, you can even choose to perform a "staged rollout" as part of #3, which allows you to mitigate any potential risk with the update (e.g. did your testing in #2 touch all possible devices/conditions?) by only making the production update available to a percentage of your users (e.g. `code-push promote Staging Production -r 20%`). Then, after waiting for a reasonable amount of time to see if any crash reports or customer feedback comes in, you can expand it to your entire audience by running `code-push patch Production -r 100%`.* +*NOTE: If you want to get really fancy, you can even choose to perform a "staged rollout" as part of #3, which allows you to mitigate additional potential risk with the update (e.g. did your testing in #2 touch all possible devices/conditions?) by only making the production update available to a percentage of your users (e.g. `code-push promote Staging Production -r 20%`). Then, after waiting for a reasonable amount of time to see if any crash reports or customer feedback comes in, you can expand it to your entire audience by running `code-push patch Production -r 100%`.* -You'll notice that the above steps refer to a "staging build" and "prodiction build" of your app. If you're build process already generates distinct binaries per "environment" like this, then you don't need to read any further, since swapping out CodePush deployment keys is just like handling environment-specific config for any other service your app uses (e.g. Facebook). However, if you're looking for some examples on how to setup your bild process to accomodate this, then refer to the following sections, depending on the platform(s) your app is targeting. +You'll notice that the above steps refer to a "staging build" and "production build" of your app. If your build process already generates distinct binaries per "environment", then you don't need to read any further, since swapping out CodePush deployment keys is just like handling environment-specific config for any other service your app uses (e.g. Facebook). However, if you're looking for examples on how to setup your build process to accomodate this, then refer to the following sections, depending on the platform(s) your app is targeting. ### Android @@ -467,7 +467,7 @@ The [Android Gradle plugin](http://google.github.io/android-gradle-dsl/current/i To set this up, perform the following steps: -1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle`) +1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle` in standard React Native projects) 2. Find the `android { buildTypes {} }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. @@ -503,9 +503,9 @@ To set this up, perform the following steps: And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. -If you want to be able to install both debug and release builds simultaneously on the same device (highly recommended!), then you need to ensure that your debug build has a unique identity and icon. You can achieve this by performing the following steps: +If you want to be able to install both debug and release builds simultaneously on the same device (highly recommended!), then you need to ensure that your debug build has a unique identity and icon from your release build. Otherwise, neither the OS nor you will be able to differentiate between the two. You can achieve this by performing the following steps: -1. In your `build.gradle` file, specify the [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, so that the OS sees it as a different app from your release/production build (e.g. `com.foo` vs. `com.foo.debug`). +1. In your `build.gradle` file, specify the [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, which gives your debug build a unique identity for the OS (e.g. `com.foo` vs. `com.foo.debug`). ```groovy buildTypes { @@ -515,13 +515,13 @@ buildTypes { } ``` -2. Create the `app/src/debug/res` directory structure in your app to allow overriding app resources for your debug builds +2. Create the `app/src/debug/res` directory structure in your app, which allows overriding resources (e.g. strings, icons, layouts) for your debug builds 3. Create a `values` directory underneath the debug res directory created in #2, and copy the existing `strings.xml` file from the `app/src/main/res/values` directory -4. Open up the new debug `strings.xml` file and change the `` element's value to something else (e.g. `foo-debug`). +4. Open up the new debug `strings.xml` file and change the `` element's value to something else (e.g. `foo-debug`). This ensures that your debug build now has a distinct display name, so that you can differentiate it from your release build. -5. Create "mirrored" directories in the `app/src/debug/res` directory for all of your app's icons that you want to change for your debug build. +5. Optionally, create "mirrored" directories in the `app/src/debug/res` directory for all of your app's icons that you want to change for your debug build. This part isn't technically critical, but it can make it easier to quickly spot your debug builds on a device if its icon is noticeable different. And that's it! View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. Finally, refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#content) for details about how to configure and create release builds for your Android apps. From 63850dc75e4282469a66caae36f090ed4b103f8c Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Fri, 3 Jun 2016 09:45:16 -0700 Subject: [PATCH 42/60] Adding note about run-android command --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6849434..ccdb0f9 100644 --- a/README.md +++ b/README.md @@ -469,7 +469,7 @@ To set this up, perform the following steps: 1. Open your app's `build.gradle` file (e.g. `android/app/build.gradle` in standard React Native projects) -2. Find the `android { buildTypes {} }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. +2. Find the `android { buildTypes {} }` section and define `buildConfigField` entries for both your `debug` and `release` build types, which reference your `Staging` and `Production` deployment keys respectively. If you prefer, you can define the key literals in your `gradle.properties` file, and then reference them here. Either way will work, and it's just a matter of personal preference. ```groovy android { @@ -503,6 +503,8 @@ To set this up, perform the following steps: And that's it! Now when you run or build your app, your debug builds will automatically be configured to sync with your `Staging` deployment, and your release builds will be configured to sync with your `Production` deployment. +*NOTE: By default, the `react-native run-android` command builds and deploys the debug version of your app, so if you want to test out a release/production build, simply run `react-native run-android --variant release. Refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#conten) for details about how to configure and create release builds for your Android apps.* + If you want to be able to install both debug and release builds simultaneously on the same device (highly recommended!), then you need to ensure that your debug build has a unique identity and icon from your release build. Otherwise, neither the OS nor you will be able to differentiate between the two. You can achieve this by performing the following steps: 1. In your `build.gradle` file, specify the [`applicationIdSuffix`](http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:applicationIdSuffix) field for your debug build type, which gives your debug build a unique identity for the OS (e.g. `com.foo` vs. `com.foo.debug`). @@ -523,7 +525,7 @@ buildTypes { 5. Optionally, create "mirrored" directories in the `app/src/debug/res` directory for all of your app's icons that you want to change for your debug build. This part isn't technically critical, but it can make it easier to quickly spot your debug builds on a device if its icon is noticeable different. -And that's it! View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. Finally, refer to the [React Native docs](http://facebook.github.io/react-native/docs/signed-apk-android.html#content) for details about how to configure and create release builds for your Android apps. +And that's it! View [here](http://tools.android.com/tech-docs/new-build-system/resource-merging) for more details on how resource merging works in Android. ### iOS From 8baaf304bb2395524673a6f1bf25a3c8247402c0 Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Sun, 5 Jun 2016 12:21:35 -0700 Subject: [PATCH 43/60] Fix bug in podspec caused by spelling --- CodePush.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CodePush.podspec b/CodePush.podspec index 7af6b8b..48910d4 100644 --- a/CodePush.podspec +++ b/CodePush.podspec @@ -20,11 +20,11 @@ Pod::Spec.new do |s| s.default_subspec = 'Full' s.subspec 'Full' do |ss| - s.source_files = 'ios/CodePush/*.{h,m}', 'ios/CodePush/SSZipArchive/*.{h,m}', 'ios/CodePush/SSZipArchive/aes/*.{h,c}', 'ios/CodePush/SSZipArchive/minizip/*.{h,c}' + ss.source_files = 'ios/CodePush/*.{h,m}', 'ios/CodePush/SSZipArchive/*.{h,m}', 'ios/CodePush/SSZipArchive/aes/*.{h,c}', 'ios/CodePush/SSZipArchive/minizip/*.{h,c}' end s.subspec 'NoZip' do |ss| - s.source_files = 'ios/CodePush/*.{h,m}' + ss.source_files = 'ios/CodePush/*.{h,m}' end end \ No newline at end of file From 77c235e31a3474221d87ed93c6bfe2ef5842b7a4 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 6 Jun 2016 08:47:41 -0700 Subject: [PATCH 44/60] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed12297..b889a54 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-code-push", - "version": "1.11.0-beta", + "version": "1.12.1-beta", "description": "React Native plugin for the CodePush service", "main": "CodePush.js", "typings": "typings/react-native-code-push.d.ts", From c0a32e59adb4581aa6a316e36138edd70802179d Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 6 Jun 2016 10:19:59 -0700 Subject: [PATCH 45/60] Adding section on dynamic deployments --- README.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ccdb0f9..fc9347a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ This plugin provides client-side integration for the [CodePush service](http://c * [Windows Setup](#windows-setup) * [Plugin Usage](#plugin-usage) * [Releasing Updates](#releasing-updates) -* [Multi-Deployment Releases](#multi-deployment-releases) +* [Multi-Deployment Testing](#multi-deployment-testing) +* [Dynamic Deployment Assignment](#dynamic-deployment-assignment) * [API Reference](#api-reference) * [JavaScript API](#javascript-api-reference) * [Objective-C API Reference (iOS)](#objective-c-api-reference-ios) @@ -441,7 +442,7 @@ For more details about how the `release-react` command works, as well as the var If you run into any issues, or have any questions/comments/feedback, you can ping us within the [#code-push](https://discord.gg/0ZcbPKXt5bWxFdFu) channel on Reactiflux, [e-mail us](mailto:codepushfeed@microsoft.com) and/or check out the [troubleshooting](#debugging--troubleshooting) details below. -## Multi-Deployment Releases +## Multi-Deployment Testing In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app (or any custom deployments you may have created). This way, you never release an update to your end users that you haven't been able to validate yourself. @@ -557,6 +558,26 @@ Additionally, if you want to give them seperate names and/or icons, you can modi ![Product name](https://cloud.githubusercontent.com/assets/116461/15764314/b3a4cfac-28de-11e6-9e8c-b1cbd8ac7c6c.png) +## Dynamic Deployment Assignment + +The above section illustrated how you can leverage multiple CodePush deployments in order to effectively test your updates before broadly releasing them to your end users. However, since that workflow statically embeds the deployment assignment into the actual binary, a staging or production build will only ever sync updates from that deployment. In many cases, this is sufficient, since you only want your team, customers, stakeholders, etc. to sync with your pre-production releases, and therefore, only they need a build that knows how to sync with staging. However, if you want to be able to perform A/B tests, or provide early access of your app to certain users, it can prove very useful to be able to dynamically place specific users (or audiences) into specific deployments at runtime. + +In order to achieve this kind of workflow, all you need to do is specify the deployment key you want the current user to syncronize with when calling the `checkForUpdate` or `sync` methods. When specified, this key will override the "default" one that was provided in your app's `Info.plist` (iOS) or `MainActivity.java` (Android) files. This allows you to produce a build for staging or production, that is also capabable of being dynamically "redirected" as needed. + +```javascript +// Imagine that "userProfile" is a prop that this component received +// which includes the deployment key that the current user should use. +codePush.sync({ deploymentKey: userProfile.CODEPUSH_KEY }); +``` + +With that change in place, now it's just a matter of choosing how your app determines the right deployment key for the current user. In practice, there are typically two solutions for this: + +1. Expose a user-visible mechanism for changing deployments at any time. For example, your settings page could have a toggle for enabling "beta" access. This model works well if you're not concerned with the privacy of your pre-production updates, and you have power users that may want to opt-in to earlier (and potentially buggy) updates at their own will (kind of like Chrome channels). However, this solution puts the decision in the hands of your users, which doesn't help you perform A/B tests. + +2. Annotate the profile's of your users with an additional piece of metadata which indicates the deployment they should sync with. By default, your app could just use the embedded key, but after a user has authenticated, your server can choose to "redirect" them to a different deployment, which allows you to incrementally place certain users or groups in different deployments as needed. You could even choose to store the server-response in local storage so that it becomes the new defaul. How you store the key alongside your user's profiles is entirely up to your authentication solution (e.g. Auth0, Firebase, custom DB + REST API), but is generally pretty trivial to do. + +*NOTE: If needed, you could also implement a hybrid solution that allowed your end-users to toggle between different deployments, while also allowing your server to override that decision. This way, you have a hierarchy of "deployment resolution" that ensures your app has the ability to update itself out-of-the-box, your end users can feel rewarded by getting early access to bits, but you also have the ability to run A/B tests on your users as needed. + --- ## API Reference From 07dca5d674ae8f206763848362cdab9ddb55054c Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 6 Jun 2016 10:23:01 -0700 Subject: [PATCH 46/60] Fixing typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fc9347a..397a141 100644 --- a/README.md +++ b/README.md @@ -574,9 +574,9 @@ With that change in place, now it's just a matter of choosing how your app deter 1. Expose a user-visible mechanism for changing deployments at any time. For example, your settings page could have a toggle for enabling "beta" access. This model works well if you're not concerned with the privacy of your pre-production updates, and you have power users that may want to opt-in to earlier (and potentially buggy) updates at their own will (kind of like Chrome channels). However, this solution puts the decision in the hands of your users, which doesn't help you perform A/B tests. -2. Annotate the profile's of your users with an additional piece of metadata which indicates the deployment they should sync with. By default, your app could just use the embedded key, but after a user has authenticated, your server can choose to "redirect" them to a different deployment, which allows you to incrementally place certain users or groups in different deployments as needed. You could even choose to store the server-response in local storage so that it becomes the new defaul. How you store the key alongside your user's profiles is entirely up to your authentication solution (e.g. Auth0, Firebase, custom DB + REST API), but is generally pretty trivial to do. +2. Annotate the server-side profile's of your users with an additional piece of metadata which indicates the deployment they should sync with. By default, your app could just use the binary-embedded key, but after a user has authenticated, your server can choose to "redirect" them to a different deployment, which allows you to incrementally place certain users or groups in different deployments as needed. You could even choose to store the server-response in local storage so that it becomes the new default. How you store the key alongside your user's profiles is entirely up to your authentication solution (e.g. Auth0, Firebase, custom DB + REST API), but is generally pretty trivial to do. -*NOTE: If needed, you could also implement a hybrid solution that allowed your end-users to toggle between different deployments, while also allowing your server to override that decision. This way, you have a hierarchy of "deployment resolution" that ensures your app has the ability to update itself out-of-the-box, your end users can feel rewarded by getting early access to bits, but you also have the ability to run A/B tests on your users as needed. +*NOTE: If needed, you could also implement a hybrid solution that allowed your end-users to toggle between different deployments, while also allowing your server to override that decision. This way, you have a hierarchy of "deployment resolution" that ensures your app has the ability to update itself out-of-the-box, your end users can feel rewarded by getting early access to bits, but you also have the ability to run A/B tests on your users as needed.* --- From 679c72562f20062ce1a127e85de8db492e3a2df8 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 6 Jun 2016 10:57:09 -0700 Subject: [PATCH 47/60] Adding custom deployment description --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 397a141..0b49503 100644 --- a/README.md +++ b/README.md @@ -572,12 +572,24 @@ codePush.sync({ deploymentKey: userProfile.CODEPUSH_KEY }); With that change in place, now it's just a matter of choosing how your app determines the right deployment key for the current user. In practice, there are typically two solutions for this: -1. Expose a user-visible mechanism for changing deployments at any time. For example, your settings page could have a toggle for enabling "beta" access. This model works well if you're not concerned with the privacy of your pre-production updates, and you have power users that may want to opt-in to earlier (and potentially buggy) updates at their own will (kind of like Chrome channels). However, this solution puts the decision in the hands of your users, which doesn't help you perform A/B tests. +1. Expose a user-visible mechanism for changing deployments at any time. For example, your settings page could have a toggle for enabling "beta" access. This model works well if you're not concerned with the privacy of your pre-production updates, and you have power users that may want to opt-in to earlier (and potentially buggy) updates at their own will (kind of like Chrome channels). However, this solution puts the decision in the hands of your users, which doesn't help you perform A/B tests transparently. -2. Annotate the server-side profile's of your users with an additional piece of metadata which indicates the deployment they should sync with. By default, your app could just use the binary-embedded key, but after a user has authenticated, your server can choose to "redirect" them to a different deployment, which allows you to incrementally place certain users or groups in different deployments as needed. You could even choose to store the server-response in local storage so that it becomes the new default. How you store the key alongside your user's profiles is entirely up to your authentication solution (e.g. Auth0, Firebase, custom DB + REST API), but is generally pretty trivial to do. +2. Annotate the server-side profile of your users with an additional piece of metadata which indicates the deployment they should sync with. By default, your app could just use the binary-embedded key, but after a user has authenticated, your server can choose to "redirect" them to a different deployment, which allows you to incrementally place certain users or groups in different deployments as needed. You could even choose to store the server-response in local storage so that it becomes the new default. How you store the key alongside your user's profiles is entirely up to your authentication solution (e.g. Auth0, Firebase, custom DB + REST API), but is generally pretty trivial to do. *NOTE: If needed, you could also implement a hybrid solution that allowed your end-users to toggle between different deployments, while also allowing your server to override that decision. This way, you have a hierarchy of "deployment resolution" that ensures your app has the ability to update itself out-of-the-box, your end users can feel rewarded by getting early access to bits, but you also have the ability to run A/B tests on your users as needed.* +Since we recommend using the `Staging` deployment for pre-release testing of your updates (as explained in the previous section), it doesn't neccessarily make sense to use it for performing A/B tests on your users, as opposed to allowing early-access (as explained in option #1 above). Therefore, we recommend making full use of custom app deployments, so that you can segment your users however makes sense for your needs. For example, you could create long-term or even one-off deployments, release a variant of your app to it, and then place certain users into it in order to see how they engage. + +```javascript +// #1) Create your new deployment to hold releases of a specific app variant +code-push deployment add [APP_NAME] test-variant-one + +// #2) Target any new releases at that custom deployment +code-push release-react [APP_NAME] ios -d test-variant-one +``` + +*NOTE: The total user count that is reported in your deployment's "Install Metrics" will take into account users that have "switched" from one deployment to another. For example, if your `Production` deployment currently reports having 1 total user, but you dynamically switch that user to `Staging`, then the `Production` deployment would report 0 total users, while `Staging` would report 1 (the user that just switched). This behavior allows you to accurately track your release adoption, even in the event of using a runtime-based deployment redirection solution.* + --- ## API Reference From 287a631688a161de2e55ca99152f15477853c29e Mon Sep 17 00:00:00 2001 From: Mike Douglas Date: Tue, 7 Jun 2016 15:38:19 -0700 Subject: [PATCH 48/60] Make sure to call _pauseCallback() when modifying _paused ivar. --- ios/CodePush/CodePush.m | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ios/CodePush/CodePush.m b/ios/CodePush/CodePush.m index 25c4aa3..c703092 100644 --- a/ios/CodePush/CodePush.m +++ b/ios/CodePush/CodePush.m @@ -179,6 +179,16 @@ static NSString *bundleResourceName = @"main"; @synthesize pauseCallback = _pauseCallback; @synthesize paused = _paused; +- (void)setPaused:(BOOL)paused +{ + if (_paused != paused) { + _paused = paused; + if (_pauseCallback) { + _pauseCallback(); + } + } +} + /* * This method is used to clear updates that are installed * under a different app version and hence don't apply anymore, @@ -291,7 +301,7 @@ static NSString *bundleResourceName = @"main"; #ifdef DEBUG [self clearDebugUpdates]; #endif - _paused = YES; + self.paused = YES; NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults]; NSDictionary *pendingUpdate = [preferences objectForKey:PendingUpdateKey]; if (pendingUpdate) { @@ -512,7 +522,7 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage // Set up and unpause the frame observer so that it can emit // progress events every frame if the progress is updated. _didUpdateProgress = NO; - _paused = NO; + self.paused = NO; } [CodePushPackage @@ -530,7 +540,7 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage // updates and synchronously send the last event. if (expectedContentLength == receivedContentLength) { _didUpdateProgress = NO; - _paused = YES; + self.paused = YES; [self dispatchDownloadProgressEvent]; } } @@ -552,7 +562,7 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage // Stop observing frame updates if the download fails. _didUpdateProgress = NO; - _paused = YES; + self.paused = YES; reject([NSString stringWithFormat: @"%lu", (long)err.code], err.localizedDescription, err); }]; } From aa456010fbae4239cf1265f74edc6265d8b92162 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Tue, 7 Jun 2016 18:37:03 -0700 Subject: [PATCH 49/60] Update CodePush.js --- CodePush.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CodePush.js b/CodePush.js index 253e1c9..72aa6e1 100644 --- a/CodePush.js +++ b/CodePush.js @@ -354,7 +354,11 @@ async function syncInternal(options = {}, syncStatusChangeCallback, downloadProg const dialogButtons = [{ text: null, onPress: async () => { - resolve(await doDownloadAndInstall()); + try { + resolve(await doDownloadAndInstall()); + } catch (downloadError) { + reject(downloadError); + } } }]; @@ -451,4 +455,4 @@ if (NativeCodePush) { log("The CodePush module doesn't appear to be properly installed. Please double-check that everything is setup correctly."); } -module.exports = CodePush; \ No newline at end of file +module.exports = CodePush; From 91468e712771c859c8015ff755a6058cab00346b Mon Sep 17 00:00:00 2001 From: Ian MacLeod Date: Wed, 8 Jun 2016 10:28:19 -0700 Subject: [PATCH 50/60] Explicitly mark SSZipArchive headers as private This allows the pod to be built as a framework (the SSZipArchive headers were previously being included in the umbrella header for the framework by cocoapods) Also, moved SSZipArchive into its own subspec for clarity --- CodePush.podspec | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/CodePush.podspec b/CodePush.podspec index 48910d4..ecb3652 100644 --- a/CodePush.podspec +++ b/CodePush.podspec @@ -4,27 +4,34 @@ package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) Pod::Spec.new do |s| - s.name = 'CodePush' - s.version = package['version'].sub('-beta', '') - s.summary = 'React Native module for the CodePush service' - s.author = 'Microsoft Corporation' - s.license = 'MIT' - s.homepage = 'http://microsoft.github.io/code-push/' - s.source = { :git => 'https://github.com/Microsoft/react-native-code-push.git', :tag => "v#{s.version}-beta" } - s.platform = :ios, '7.0' - s.public_header_files = 'ios/CodePush/CodePush.h' - s.preserve_paths = '*.js' - s.library = 'z' + s.name = 'CodePush' + s.version = package['version'].sub('-beta', '') + s.summary = 'React Native module for the CodePush service' + s.author = 'Microsoft Corporation' + s.license = 'MIT' + s.homepage = 'http://microsoft.github.io/code-push/' + s.source = { :git => 'https://github.com/Microsoft/react-native-code-push.git', :tag => "v#{s.version}-beta"} + s.platform = :ios, '7.0' + s.preserve_paths = '*.js' + s.library = 'z' + s.dependency 'React' - + s.default_subspec = 'Full' - + s.subspec 'Full' do |ss| - ss.source_files = 'ios/CodePush/*.{h,m}', 'ios/CodePush/SSZipArchive/*.{h,m}', 'ios/CodePush/SSZipArchive/aes/*.{h,c}', 'ios/CodePush/SSZipArchive/minizip/*.{h,c}' + ss.dependency 'CodePush/NoZip' + ss.dependency 'CodePush/SSZipArchive' end - + s.subspec 'NoZip' do |ss| - ss.source_files = 'ios/CodePush/*.{h,m}' + ss.source_files = 'ios/CodePush/*.{h,m}' + ss.public_header_files = ['ios/CodePush/CodePush.h'] end - -end \ No newline at end of file + + s.subspec 'SSZipArchive' do |ss| + ss.source_files = 'ios/CodePush/SSZipArchive/*.{h,m}', 'ios/CodePush/SSZipArchive/aes/*.{h,c}', 'ios/CodePush/SSZipArchive/minizip/*.{h,c}' + ss.private_header_files = 'ios/CodePush/SSZipArchive/*.h', 'ios/CodePush/SSZipArchive/aes/*.h', 'ios/CodePush/SSZipArchive/minizip/*.h' + end + +end From 44ba85dab86d1de67539bf5338dfcfd5427f7ed5 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Wed, 8 Jun 2016 10:50:56 -0700 Subject: [PATCH 51/60] Update CodePush.js --- CodePush.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CodePush.js b/CodePush.js index 72aa6e1..92190bf 100644 --- a/CodePush.js +++ b/CodePush.js @@ -353,12 +353,9 @@ async function syncInternal(options = {}, syncStatusChangeCallback, downloadProg let message = null; const dialogButtons = [{ text: null, - onPress: async () => { - try { - resolve(await doDownloadAndInstall()); - } catch (downloadError) { - reject(downloadError); - } + onPress:() => { + doDownloadAndInstall() + .then(resolve, reject); } }]; From ba8e0eda088616a96496c6b4020de9aad4f83802 Mon Sep 17 00:00:00 2001 From: Ian MacLeod Date: Wed, 8 Jun 2016 11:01:39 -0700 Subject: [PATCH 52/60] NoZip -> Core --- CodePush.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CodePush.podspec b/CodePush.podspec index ecb3652..4b30b64 100644 --- a/CodePush.podspec +++ b/CodePush.podspec @@ -20,11 +20,11 @@ Pod::Spec.new do |s| s.default_subspec = 'Full' s.subspec 'Full' do |ss| - ss.dependency 'CodePush/NoZip' + ss.dependency 'CodePush/Core' ss.dependency 'CodePush/SSZipArchive' end - s.subspec 'NoZip' do |ss| + s.subspec 'Core' do |ss| ss.source_files = 'ios/CodePush/*.{h,m}' ss.public_header_files = ['ios/CodePush/CodePush.h'] end From ab75c90aef139727ea962d281f69b9506a742faf Mon Sep 17 00:00:00 2001 From: Ian MacLeod Date: Wed, 8 Jun 2016 11:35:11 -0700 Subject: [PATCH 53/60] Drop the 'Full' sub spec --- CodePush.podspec | 7 ------- 1 file changed, 7 deletions(-) diff --git a/CodePush.podspec b/CodePush.podspec index 4b30b64..a009188 100644 --- a/CodePush.podspec +++ b/CodePush.podspec @@ -17,13 +17,6 @@ Pod::Spec.new do |s| s.dependency 'React' - s.default_subspec = 'Full' - - s.subspec 'Full' do |ss| - ss.dependency 'CodePush/Core' - ss.dependency 'CodePush/SSZipArchive' - end - s.subspec 'Core' do |ss| ss.source_files = 'ios/CodePush/*.{h,m}' ss.public_header_files = ['ios/CodePush/CodePush.h'] From 683d8209225aa0d94b0d8d5a39ff51cee8b668c3 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Wed, 8 Jun 2016 11:47:10 -0700 Subject: [PATCH 54/60] Updating CocoaPods install instructions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0b49503..3e70bdf 100644 --- a/README.md +++ b/README.md @@ -120,10 +120,10 @@ We hope to eventually remove the need for steps #2-4, but in the meantime, RNPM pod 'CodePush', :path => './node_modules/react-native-code-push' ``` - CodePush depends on an internal copy of the `SSZipArchive` library, so if your project already includes that (either directly or via a transitive dependency), then you can install a version of CodePush which excludes it by using the following subspec: + CodePush depends on an internal copy of the `SSZipArchive` library, so if your project already includes it (either directly or via a transitive dependency), then you can install a version of CodePush which excludes it by depending specificaly on the `Core` subspec: ```ruby - pod 'CodePush', :path => './node_modules/react-native-code-push', :subspecs => ['NoZip'] + pod 'CodePush', :path => './node_modules/react-native-code-push', :subspecs => ['Core'] ``` *NOTE: The above paths needs to be relative to your app's `Podfile`, so adjust it as nec From ca32cb57d5be49d8d30a67aeea3373d9593dc81a Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Wed, 8 Jun 2016 12:51:39 -0700 Subject: [PATCH 55/60] Updating RN support matrix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e70bdf..71652c5 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ We try our best to maintain backwards compatability of our plugin with previous | <0.14.0 | **Unsupported** | | v0.14.0 | v1.3.0 *(introduced Android support)* | | v0.15.0-v0.18.0 | v1.4.0-v1.6.0 *(introduced iOS asset support)* | -| v0.19.0-v0.27.0 | v1.7.0+ *(introduced Android asset support)* | -| v0.28.0+ | TBD :) We work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our "official" support is. +| v0.19.0-v0.28.0 | v1.7.0+ *(introduced Android asset support)* | +| v0.29.0+ | TBD :) We work hard to respond to new RN releases, but they do occasionally break us. We will update this chart with each RN release, so that users can check to see what our "official" support is. ## Supported Components From 23e98a22821ad5ea5ae9bc46907aaebe23f3207c Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Wed, 8 Jun 2016 12:52:29 -0700 Subject: [PATCH 56/60] Bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b889a54..00c773e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-code-push", - "version": "1.12.1-beta", + "version": "1.12.2-beta", "description": "React Native plugin for the CodePush service", "main": "CodePush.js", "typings": "typings/react-native-code-push.d.ts", From db5b352ddac485da664e20cc86c456f25655a463 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Wed, 8 Jun 2016 15:27:01 -0700 Subject: [PATCH 57/60] Fixing space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71652c5..9567f5a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ When using the React Native assets sytem (i.e. using the `require("./foo.png")` | `TabBarIOS.Item` | `icon`, `selectedIcon` | | `ToolbarAndroid`
*(React Native 0.21.0+)* | `actions[].icon`, `logo`, `overflowIcon` | -The following list represents the set of components (and props) that don't currently support their assets being updated via CodePush, due to their dependency on static images (i.e. using the `{ uri: "foo"}` syntax): +The following list represents the set of components (and props) that don't currently support their assets being updated via CodePush, due to their dependency on static images (i.e. using the `{ uri: "foo" }` syntax): | Component | Prop(s) | |-------------|----------------------------------------------------------------------| From 627bb2188fb0a86f85cded6f86121fbb68541ed0 Mon Sep 17 00:00:00 2001 From: Jorge Maroto Date: Fri, 10 Jun 2016 10:29:18 +0200 Subject: [PATCH 58/60] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9567f5a..de40761 100644 --- a/README.md +++ b/README.md @@ -446,7 +446,7 @@ If you run into any issues, or have any questions/comments/feedback, you can pin In our [getting started](#getting-started) docs, we illustrated how to configure the CodePush plugin using a specific deployment key. However, in order to effectively test your releases, it is critical that you leverage the `Staging` and `Production` deployments that are auto-generated when you first created your CodePush app (or any custom deployments you may have created). This way, you never release an update to your end users that you haven't been able to validate yourself. -*NOTE: Our client-side rollback feature can help unblock users after installing a release that resulted in a crash, and server-side rollbacks (i.e. `code-push rollback`) allow you to prevent additional users from installing a bad release once it's been identified. Hhowever, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* +*NOTE: Our client-side rollback feature can help unblock users after installing a release that resulted in a crash, and server-side rollbacks (i.e. `code-push rollback`) allow you to prevent additional users from installing a bad release once it's been identified. However, it's obviously better if you can prevent an erroneous update from being broadly released in the first place.* Taking advantage of the `Staging` and `Production` deployments allows you to acheive a workflow like the following (feel free to customize!): From 03e250f87cf0f7ac275dcb85ec1e3d29d9bb2a05 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Fri, 10 Jun 2016 14:04:30 -0700 Subject: [PATCH 59/60] Prevent dialog from invoking callback twice --- .../com/microsoft/codepush/react/CodePushDialog.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java index e8d19fb..14fd613 100644 --- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java +++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java @@ -26,8 +26,15 @@ public class CodePushDialog extends ReactContextBaseJavaModule{ builder.setCancelable(false); DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() { + private boolean callbackConsumed = false; + @Override - public void onClick(DialogInterface dialog, int which) { + public synchronized void onClick(DialogInterface dialog, int which) { + if (callbackConsumed) { + return; + } + + callbackConsumed = true; dialog.cancel(); switch (which) { case DialogInterface.BUTTON_POSITIVE: From 1bc091ee15ab817721db3bc697294534b8952ed0 Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Mon, 13 Jun 2016 09:33:00 -0700 Subject: [PATCH 60/60] Adding mention to Native Starter Pro --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de40761..03bf3b0 100644 --- a/README.md +++ b/README.md @@ -1103,7 +1103,10 @@ The React Native community has graciously created some awesome open source apps * [Math Facts](https://github.com/Khan/math-facts) - An app by Khan Academy to help memorize math facts more easily. * [MoveIt!](https://github.com/multunus/moveit-react-native) - An app by [Multunus](http://www.multunus.com) that allows employees within a company to track their work-outs. -Additionally, if you're looking to get started with React Native + CodePush, and are looking for an awesome starter kit, you should check out [Pepperoni](http://getpepperoni.com/). It includes everything you'll need to get going quickly, with modern / best practices (including CodePush!). +Additionally, if you're looking to get started with React Native + CodePush, and are looking for an awesome starter kit, you should check out the following: + +* [Native Starter Pro](http://strapmobile.com/native-starter-pro/) +* [Pepperoni](http://getpepperoni.com/) *Note: If you've developed a React Native app using CodePush, that is also open-source, please let us know. We would love to add it to this list!*