Seamless transition from AppCenter to a fully self-hosted CodePush.
This package was created to continue using React Native CodePush without AppCenter.
It allows self-hosting of CodePush deployments while retaining essential operational features.
Note
New architecture will be supported later.
If you have been using react-native-code-push
, replace the NPM package first.
npm remove react-native-code-push
npm install @bravemobile/react-native-code-push
Then, follow the installation guide starting from '4. "CodePush-ify" your app'.
The following changes are optional but recommended for cleaning up the old configuration:
- Since the deployment key is no longer needed due to the retirement of AppCenter, it is recommended to remove it from your
Info.plist
,strings.xml
, or JavaScript code. - Thanks to Auto Linking, you can remove the
react-native-code-push
module settings fromsettings.gradle
.
npm install @bravemobile/react-native-code-push
Run cd ios && pod install && cd ..
(npx pod-install
, bundle exec pod install --project-directory=./ios
, ..)
If you have AppDelegate.swift
(>= RN 0.77)
If your project doesn't have bridging header, please create a file.
- Open your project with Xcode (e.g. CodePushDemoApp.xcworkspace)
- File β New β File from Template
- Select 'Objective-C File' and click 'Next' and write any name as you like.
- Then Xcode will ask you to create a bridging header file. Click 'Create'.
- Delete the file created in step 3.
Add the following line to the bridging header file. (e.g. CodePushDemoApp-Bridging-Header.h
)
+ #import <CodePush/CodePush.h>
Then, edit AppDelegate.swift
like below.
@main
class AppDelegate: RCTAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// ...
override func bundleURL() -> URL? {
#if DEBUG
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
- Bundle.main.url(forResource: "main", withExtension: "jsbundle")
+ CodePush.bundleURL()
#endif
}
}
Or if you have AppDelegate.mm
+ #import <CodePush/CodePush.h>
// ...
- (NSURL *)bundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
- return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
+ return [CodePush bundleURL];
#endif
}
@end
Add the following line to the end of the file.
// ...
+ apply from: "../../node_modules/@bravemobile/react-native-code-push/android/codepush.gradle"
If you have MainApplication.kt
(>= RN 0.73)
+ import com.microsoft.codepush.react.CodePush
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
// ...
+ override fun getJSBundleFile(): String = CodePush.getJSBundleFile()
}
// ...
}
Or if you have MainApplication.java
// ...
+ import com.microsoft.codepush.react.CodePush
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new DefaultReactNativeHost(this) {
// ...
+ @Override
+ override fun getJSBundleFile(): String {
+ return CodePush.getJSBundleFile()
+ }
};
// ...
}
The root component of your app should be wrapped with a higher-order component.
You should also pass configuration options, including the implementation of the releaseHistoryFetcher
function.
This function is used to find the latest CodePush update within the ReleaseHistoryInterface
data.
To enable this, you need to create a release history using the CLI tool and upload it to the remote. (The following steps explain more about the CLI.)
At runtime, the library fetches this information to keep the app up to date.
import CodePush, {
ReleaseHistoryInterface,
UpdateCheckRequest,
} from "@bravemobile/react-native-code-push";
// ... MyApp Component
async function releaseHistoryFetcher(
updateRequest: UpdateCheckRequest,
): Promise<ReleaseHistoryInterface> {
// Fetch release history for current binary app version.
// You can implement how to fetch the release history freely. (Refer to the example app if you need a guide)
const {data: releaseHistory} = await axios.get<ReleaseHistoryInterface>(
`https://your.cdn.com/histories/${platform}/${identifier}/${updateRequest.app_version}.json`,
);
return releaseHistory;
}
export default CodePush({
checkFrequency: CodePush.CheckFrequency.MANUAL, // or something else
releaseHistoryFetcher: releaseHistoryFetcher,
})(MyApp);
Note
The URL for fetching the release history should point to the resource location generated by the CLI tool.
Tip
For a more detailed and practical example, refer to the CodePushDemoApp
in example
directory. (link)
(1) Create a code-push.config.ts
file in the root directory of your project.
Then, implement three functions to upload the bundle file and create/update the release history. The CLI tool uses these functions to release CodePush updates and manage releases. (These functions are not used at runtime by the library.)
You can copy and paste the following code and modify it as needed.
import {
CliConfigInterface,
ReleaseHistoryInterface,
} from "@bravemobile/react-native-code-push";
const Config: CliConfigInterface = {
bundleUploader: async (
source: string,
platform: "ios" | "android",
identifier,
): Promise<{downloadUrl: string}> => {
// ...
},
getReleaseHistory: async (
targetBinaryVersion: string,
platform: "ios" | "android",
identifier,
): Promise<ReleaseHistoryInterface> => {
// ...
},
setReleaseHistory: async (
targetBinaryVersion: string,
jsonFilePath: string,
releaseInfo: ReleaseHistoryInterface,
platform: "ios" | "android",
identifier,
): Promise<void> => {
// ...
},
};
module.exports = Config;
bundleUploader
- Implements a function to upload the bundle file.
- The
downloadUrl
returned by this function is recorded inReleaseHistoryInterface
data and is used by the library runtime to download the bundle file from this URL. - Used in the following cases:
- Creating a new CodePush update with the
release
command.
- Creating a new CodePush update with the
getReleaseHistory
- Retrieves the release history of a specific binary app by fetching a JSON file or calling an API.
- Used in the following cases:
- Printing the release history with the
show-history
command. - Loading existing release history during the
release
command. - Fetching release history to modify information in the
update-history
command.
- Printing the release history with the
(Similar to the releaseHistoryFetcher
function in the library runtime options.)
setReleaseHistory
- Uploads a JSON file located at
jsonFilePath
or calls an API usingreleaseInfo
metadata. - If using a JSON file, modifying the existing file should be allowed. (Overwriting the file is recommended.)
- Used in the following cases:
- Creating a new release record for a new binary build with the
create-history
command. - Appending a new record to an existing release history with the
release
command. - Modifying an existing release history with the
update-history
command.
- Creating a new release record for a new binary build with the
(2) For code-push.config.ts
(TypeScript) to work properly, you may need to update your tsconfig.json
.
{
"extends": "@react-native/typescript-config/tsconfig.json",
// ...
+ "ts-node": {
+ "compilerOptions": {
+ "module": "CommonJS",
+ "types": ["node"]
+ }
+ }
}
Tip
You can use --help
command to see the available commands and options.
(interactive mode not supported yet)
Create a new release history for a specific binary app version.
- Use this command whenever you release a new binary app to the app store. This ensures that the library runtime recognizes the binary app as the latest version and determines that no CodePush update is available for it.
Example:
- Create a new release history for the binary app version
1.0.0
.
npx code-push create-history --binary-version 1.0.0 --platform ios --identifier staging
Display the release history for a specific binary app version.
Example:
- Show the release history for the binary app version
1.0.0
.
npx code-push show-history --binary-version 1.0.0 --platform ios --identifier staging
Release a CodePush update for a specific binary app version.
- This command creates a CodePush bundle file, uploads it, and updates the release history with the new release information.
Example:
- Release a CodePush update
1.0.1
targeting the binary app version1.0.0
.
npx code-push release --target-binary-version 1.0.0 --app-version 1.0.1 \
--platform ios --identifier staging --entry-file index.js \
--mandatory true
--target-binary-version
: The version of the binary app that the CodePush update is targeting.--app-version
: The version of the CodePush update itself.
Important
--app-version
should be greater than --target-binary-version
(SemVer comparison).
Update the release history for a specific CodePush update.
- Use the
--enable
option to disable a specific release for rollback. (or enable it) - Use the
--mandatory
option to make the update as mandatory or optional.
Example:
- Rollback the CodePush update
1.0.1
(targeting the binary app version1.0.0
).
npx code-push update-history --target-binary-version 1.0.0 --app-version 1.0.1 \
--platform ios --identifier staging \
--enable false
Create a CodePush bundle file.
Example:
npx code-push bundle --platform android --entry-file index.js
By default, the bundle file is created in the /build/bundleOutput
directory.
(The file name represents a hash value of the bundle content.)