Skip to content

Add postlink scripts #450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 11, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# React Native Module for CodePush

*Note: This README is only relevant to the latest version of our plugin. If you are using an older version, please switch to the relevant tag on [our GitHub repo](https://github.com/Microsoft/react-native-code-push) to view the docs for that particular version.*

![Switching tags](https://cloud.githubusercontent.com/assets/8598682/17350832/ce0dec40-58de-11e6-9c8c-906bb114c34f.png)

This plugin provides client-side integration for the [CodePush service](http://codepush.tools), allowing you to easily add a dynamic update experience to your React Native app(s).

* [How does it work?](#how-does-it-work)
@@ -110,6 +114,8 @@ In order to accommodate as many developer preferences as possible, the CodePush

*Note: If you don't already have RNPM installed, you can do so by simply running `npm i -g rnpm` and then executing the above command. If you already have RNPM installed, make sure you have v1.9.0+ in order to benefit from this one step install.*

2. You will be prompted for the deployment key you'd like to use. If you don't already have it, you can retrieve this value by running `code-push deployment ls <appName> -k`, or you can choose to ignore it (by simply hitting `<ENTER>`) and add it in later. To get started, we would recommend just using your `Staging` deployment key, so that you can test out the CodePush end-to-end.

And that's it! Isn't RNPM awesome? :)

#### Plugin Installation (iOS - CocoaPods)
@@ -160,6 +166,8 @@ Add a new value, `$(SRCROOT)/../node_modules/react-native-code-push` and select

### Plugin Configuration (iOS)

*NOTE: If you used RNPM or `react-native link` to automatically link the plugin, these steps have already been done for you so you may skip this section.*

Once your Xcode project has been setup to build/link the CodePush plugin, you need to configure your app to consult CodePush for the location of your JS bundle, since it is responsible for synchronizing it with updates that are released to the CodePush server. To do this, perform the following steps:

1. Open up the `AppDelegate.m` file, and add an import statement for the CodePush headers:
@@ -230,15 +238,6 @@ In order to accommodate as many developer preferences as possible, the CodePush

2. If you're using RNPM >=1.6.0, you will be prompted for the deployment key you'd like to use. If you don't already have it, you can retreive this value by running `code-push deployment ls <appName> -k`, or you can choose to ignore it (by simply hitting `<ENTER>`) and add it in later. To get started, we would recommend just using your `Staging` deployment key, so that you can test out the CodePush end-to-end.

3. (Only needed in v1.8.0+ of the plugin) In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition underneath `react.gradle`:

```gradle
...
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
...
```

And that's it for installation using RNPM! Continue below to the [Plugin Configuration](#plugin-configuration-android) section to complete the setup.

#### Plugin Installation (Android - Manual)
@@ -260,7 +259,7 @@ And that's it for installation using RNPM! Continue below to the [Plugin Configu
}
```

3. (Only needed in v1.8.0+ of the plugin) In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition underneath `react.gradle`:
3. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition underneath `react.gradle`:

```gradle
...
@@ -271,7 +270,7 @@ And that's it for installation using RNPM! Continue below to the [Plugin Configu

### Plugin Configuration (Android)

*Note: If you are using an older version (<=1.9.0-beta) of the CodePush plugin, please refer to [these docs](https://github.com/Microsoft/react-native-code-push/tree/e717eb024fe9d1810ac21c40c097f7bc165ea5f1#plugin-configuration-android---react-native--v0180) instead.*
*NOTE: If you used RNPM or `react-native link` to automatically link the plugin, these steps have already been done for you so you may skip this section.*

After installing the plugin and syncing your Android Studio project with Gradle, you need to configure your app to consult CodePush for the location of your JS bundle, since it will "take control" of managing the current and all future versions. To do this:

27 changes: 18 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -17,7 +17,9 @@
"url": "https://github.com/Microsoft/react-native-code-push"
},
"dependencies": {
"code-push": "1.8.0-beta"
"code-push": "1.8.0-beta",
"inquirer": "1.1.2",
"plist": "1.2.0"
},
"devDependencies": {
"archiver": "latest",
@@ -33,16 +35,23 @@
"run-sequence": "latest"
},
"rnpm": {
"android": {
"packageInstance": "new CodePush(${androidDeploymentKey}, this, BuildConfig.DEBUG)"
},
"ios": {
"sharedLibraries": ["libz"]
},
"params": [{
"android": {
"packageInstance": "new CodePush(${androidDeploymentKey}, this, BuildConfig.DEBUG)"
},
"ios": {
"sharedLibraries": [
"libz"
]
},
"params": [
{
"type": "input",
"name": "androidDeploymentKey",
"message": "What is your CodePush deployment key for Android (hit <ENTER> to ignore)"
}]
}
],
"commands": {
"postlink": "node node_modules/react-native-code-push/scripts/postlink/run"
}
}
}
54 changes: 54 additions & 0 deletions scripts/postlink/android/postlink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
var fs = require("fs");
var glob = require("glob");
var path = require("path");

var ignoreNodeModules = { ignore: "node_modules/**" };
var mainApplicationPath = glob.sync("**/MainApplication.java", ignoreNodeModules)[0];
var mainActivityPath = glob.sync("**/MainActivity.java", ignoreNodeModules)[0];
var buildGradlePath = path.join("android", "app", "build.gradle");

// 1. Add the getJSBundleFile override
var getJSBundleFileOverride = `
@Override
protected String getJSBundleFile() {
return CodePush.getJSBundleFile();
}
`;

function isAlreadyOverridden(codeContents) {
return /@Override\s*\n\s*protected String getJSBundleFile\(\)\s*\{[\s\S]*?\}/.test(codeContents);
}

if (mainApplicationPath) {
var mainApplicationContents = fs.readFileSync(mainApplicationPath, "utf8");
if (isAlreadyOverridden(mainApplicationContents)) {
console.log(`"getJSBundleFile" is already overridden`);
} else {
var reactNativeHostInstantiation = "new ReactNativeHost(this) {";
mainApplicationContents = mainApplicationContents.replace(reactNativeHostInstantiation,
`${reactNativeHostInstantiation}\n${getJSBundleFileOverride}`);
fs.writeFileSync(mainApplicationPath, mainApplicationContents);
}
} else {
var mainActivityContents = fs.readFileSync(mainActivityPath, "utf8");
if (isAlreadyOverridden(mainActivityContents)) {
console.log(`"getJSBundleFile" is already overridden`);
} else {
var mainActivityClassDeclaration = "public class MainActivity extends ReactActivity {";
mainActivityContents = mainActivityContents.replace(mainActivityClassDeclaration,
`${mainActivityClassDeclaration}\n${getJSBundleFileOverride}`);
fs.writeFileSync(mainActivityPath, mainActivityContents);
}
}

// 2. Add the codepush.gradle build task definitions
var buildGradleContents = fs.readFileSync(buildGradlePath, "utf8");
var reactGradleLink = buildGradleContents.match(/\napply from: ".*?react\.gradle"/)[0];
var codePushGradleLink = `apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"`;
if (~buildGradleContents.indexOf(codePushGradleLink)) {
console.log(`"codepush.gradle" is already linked in the build definition`);
} else {
buildGradleContents = buildGradleContents.replace(reactGradleLink,
`${reactGradleLink}\n${codePushGradleLink}`);
fs.writeFileSync(buildGradlePath, buildGradleContents);
}
62 changes: 62 additions & 0 deletions scripts/postlink/ios/postlink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
var fs = require("fs");
var glob = require("glob");
var inquirer = require('inquirer');
var path = require("path");
var plist = require("plist");

var ignoreNodeModules = { ignore: "node_modules/**" };
var appDelegatePath = glob.sync("**/AppDelegate.m", ignoreNodeModules)[0];
// Glob only allows foward slashes in patterns: https://www.npmjs.com/package/glob#windows
var plistPath = glob.sync(path.join(path.dirname(appDelegatePath), "*Info.plist").replace(/\\/g, "/"), ignoreNodeModules)[0];

var appDelegateContents = fs.readFileSync(appDelegatePath, "utf8");
var plistContents = fs.readFileSync(plistPath, "utf8");

// 1. Add the header import statement
var codePushHeaderImportStatement = `#import "CodePush.h"`;
if (~appDelegateContents.indexOf(codePushHeaderImportStatement)) {
console.log(`"CodePush.h" header already imported.`);
} else {
var appDelegateHeaderImportStatement = `#import "AppDelegate.h"`;
appDelegateContents = appDelegateContents.replace(appDelegateHeaderImportStatement,
`${appDelegateHeaderImportStatement}\n${codePushHeaderImportStatement}`);
}

// 2. Modify jsCodeLocation value assignment
var oldJsCodeLocationAssignmentStatement = appDelegateContents.match(/(jsCodeLocation = .*)\n/)[1];
var newJsCodeLocationAssignmentStatement = "jsCodeLocation = [CodePush bundleURL];";
if (~appDelegateContents.indexOf(newJsCodeLocationAssignmentStatement)) {
console.log(`"jsCodeLocation" already pointing to "[CodePush bundleURL]".`);
} else {
var jsCodeLocationPatch = `
#ifdef DEBUG
${oldJsCodeLocationAssignmentStatement}
#else
${newJsCodeLocationAssignmentStatement}
#endif`;
appDelegateContents = appDelegateContents.replace(oldJsCodeLocationAssignmentStatement,
jsCodeLocationPatch);
}

// 3. Add CodePushDeploymentKey to plist file
var parsedInfoPlist = plist.parse(plistContents);
if (parsedInfoPlist.CodePushDeploymentKey) {
console.log(`"CodePushDeploymentKey" already specified in the plist file.`);
writePatches();
} else {
inquirer.prompt({
"type": "input",
"name": "iosDeploymentKey",
"message": "What is your CodePush deployment key for iOS (hit <ENTER> to ignore)"
}).then(function(answer) {
parsedInfoPlist.CodePushDeploymentKey = answer.iosDeploymentKey || "deployment-key-here";
plistContents = plist.build(parsedInfoPlist);

writePatches();
});
}

function writePatches() {
fs.writeFileSync(appDelegatePath, appDelegateContents);
fs.writeFileSync(plistPath, plistContents);
}
2 changes: 2 additions & 0 deletions scripts/postlink/run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require("./ios/postlink");
require("./android/postlink");