Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit 5ab949a

Browse files
authored
Merge pull request #450 from Microsoft/add-postlink-hooks
Add postlink scripts
2 parents fdb628a + e40d6e4 commit 5ab949a

File tree

5 files changed

+146
-20
lines changed

5 files changed

+146
-20
lines changed

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# React Native Module for CodePush
22

3+
*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.*
4+
5+
![Switching tags](https://cloud.githubusercontent.com/assets/8598682/17350832/ce0dec40-58de-11e6-9c8c-906bb114c34f.png)
6+
37
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).
48

59
* [How does it work?](#how-does-it-work)
@@ -110,6 +114,8 @@ In order to accommodate as many developer preferences as possible, the CodePush
110114
111115
*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.*
112116
117+
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.
118+
113119
And that's it! Isn't RNPM awesome? :)
114120
115121
#### Plugin Installation (iOS - CocoaPods)
@@ -160,6 +166,8 @@ Add a new value, `$(SRCROOT)/../node_modules/react-native-code-push` and select
160166
161167
### Plugin Configuration (iOS)
162168
169+
*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.*
170+
163171
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:
164172
165173
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
230238
231239
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.
232240
233-
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`:
234-
235-
```gradle
236-
...
237-
apply from: "../../node_modules/react-native/react.gradle"
238-
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
239-
...
240-
```
241-
242241
And that's it for installation using RNPM! Continue below to the [Plugin Configuration](#plugin-configuration-android) section to complete the setup.
243242
244243
#### Plugin Installation (Android - Manual)
@@ -260,7 +259,7 @@ And that's it for installation using RNPM! Continue below to the [Plugin Configu
260259
}
261260
```
262261
263-
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`:
262+
3. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition underneath `react.gradle`:
264263
265264
```gradle
266265
...
@@ -271,7 +270,7 @@ And that's it for installation using RNPM! Continue below to the [Plugin Configu
271270
272271
### Plugin Configuration (Android)
273272
274-
*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.*
273+
*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.*
275274
276275
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:
277276

package.json

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
"url": "https://github.com/Microsoft/react-native-code-push"
1818
},
1919
"dependencies": {
20-
"code-push": "1.8.0-beta"
20+
"code-push": "1.8.0-beta",
21+
"inquirer": "1.1.2",
22+
"plist": "1.2.0"
2123
},
2224
"devDependencies": {
2325
"archiver": "latest",
@@ -33,16 +35,23 @@
3335
"run-sequence": "latest"
3436
},
3537
"rnpm": {
36-
"android": {
37-
"packageInstance": "new CodePush(${androidDeploymentKey}, this, BuildConfig.DEBUG)"
38-
},
39-
"ios": {
40-
"sharedLibraries": ["libz"]
41-
},
42-
"params": [{
38+
"android": {
39+
"packageInstance": "new CodePush(${androidDeploymentKey}, this, BuildConfig.DEBUG)"
40+
},
41+
"ios": {
42+
"sharedLibraries": [
43+
"libz"
44+
]
45+
},
46+
"params": [
47+
{
4348
"type": "input",
4449
"name": "androidDeploymentKey",
4550
"message": "What is your CodePush deployment key for Android (hit <ENTER> to ignore)"
46-
}]
51+
}
52+
],
53+
"commands": {
54+
"postlink": "node node_modules/react-native-code-push/scripts/postlink/run"
55+
}
4756
}
4857
}

scripts/postlink/android/postlink.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
var fs = require("fs");
2+
var glob = require("glob");
3+
var path = require("path");
4+
5+
var ignoreNodeModules = { ignore: "node_modules/**" };
6+
var mainApplicationPath = glob.sync("**/MainApplication.java", ignoreNodeModules)[0];
7+
var mainActivityPath = glob.sync("**/MainActivity.java", ignoreNodeModules)[0];
8+
var buildGradlePath = path.join("android", "app", "build.gradle");
9+
10+
// 1. Add the getJSBundleFile override
11+
var getJSBundleFileOverride = `
12+
@Override
13+
protected String getJSBundleFile() {
14+
return CodePush.getJSBundleFile();
15+
}
16+
`;
17+
18+
function isAlreadyOverridden(codeContents) {
19+
return /@Override\s*\n\s*protected String getJSBundleFile\(\)\s*\{[\s\S]*?\}/.test(codeContents);
20+
}
21+
22+
if (mainApplicationPath) {
23+
var mainApplicationContents = fs.readFileSync(mainApplicationPath, "utf8");
24+
if (isAlreadyOverridden(mainApplicationContents)) {
25+
console.log(`"getJSBundleFile" is already overridden`);
26+
} else {
27+
var reactNativeHostInstantiation = "new ReactNativeHost(this) {";
28+
mainApplicationContents = mainApplicationContents.replace(reactNativeHostInstantiation,
29+
`${reactNativeHostInstantiation}\n${getJSBundleFileOverride}`);
30+
fs.writeFileSync(mainApplicationPath, mainApplicationContents);
31+
}
32+
} else {
33+
var mainActivityContents = fs.readFileSync(mainActivityPath, "utf8");
34+
if (isAlreadyOverridden(mainActivityContents)) {
35+
console.log(`"getJSBundleFile" is already overridden`);
36+
} else {
37+
var mainActivityClassDeclaration = "public class MainActivity extends ReactActivity {";
38+
mainActivityContents = mainActivityContents.replace(mainActivityClassDeclaration,
39+
`${mainActivityClassDeclaration}\n${getJSBundleFileOverride}`);
40+
fs.writeFileSync(mainActivityPath, mainActivityContents);
41+
}
42+
}
43+
44+
// 2. Add the codepush.gradle build task definitions
45+
var buildGradleContents = fs.readFileSync(buildGradlePath, "utf8");
46+
var reactGradleLink = buildGradleContents.match(/\napply from: ".*?react\.gradle"/)[0];
47+
var codePushGradleLink = `apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"`;
48+
if (~buildGradleContents.indexOf(codePushGradleLink)) {
49+
console.log(`"codepush.gradle" is already linked in the build definition`);
50+
} else {
51+
buildGradleContents = buildGradleContents.replace(reactGradleLink,
52+
`${reactGradleLink}\n${codePushGradleLink}`);
53+
fs.writeFileSync(buildGradlePath, buildGradleContents);
54+
}

scripts/postlink/ios/postlink.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
var fs = require("fs");
2+
var glob = require("glob");
3+
var inquirer = require('inquirer');
4+
var path = require("path");
5+
var plist = require("plist");
6+
7+
var ignoreNodeModules = { ignore: "node_modules/**" };
8+
var appDelegatePath = glob.sync("**/AppDelegate.m", ignoreNodeModules)[0];
9+
// Glob only allows foward slashes in patterns: https://www.npmjs.com/package/glob#windows
10+
var plistPath = glob.sync(path.join(path.dirname(appDelegatePath), "*Info.plist").replace(/\\/g, "/"), ignoreNodeModules)[0];
11+
12+
var appDelegateContents = fs.readFileSync(appDelegatePath, "utf8");
13+
var plistContents = fs.readFileSync(plistPath, "utf8");
14+
15+
// 1. Add the header import statement
16+
var codePushHeaderImportStatement = `#import "CodePush.h"`;
17+
if (~appDelegateContents.indexOf(codePushHeaderImportStatement)) {
18+
console.log(`"CodePush.h" header already imported.`);
19+
} else {
20+
var appDelegateHeaderImportStatement = `#import "AppDelegate.h"`;
21+
appDelegateContents = appDelegateContents.replace(appDelegateHeaderImportStatement,
22+
`${appDelegateHeaderImportStatement}\n${codePushHeaderImportStatement}`);
23+
}
24+
25+
// 2. Modify jsCodeLocation value assignment
26+
var oldJsCodeLocationAssignmentStatement = appDelegateContents.match(/(jsCodeLocation = .*)\n/)[1];
27+
var newJsCodeLocationAssignmentStatement = "jsCodeLocation = [CodePush bundleURL];";
28+
if (~appDelegateContents.indexOf(newJsCodeLocationAssignmentStatement)) {
29+
console.log(`"jsCodeLocation" already pointing to "[CodePush bundleURL]".`);
30+
} else {
31+
var jsCodeLocationPatch = `
32+
#ifdef DEBUG
33+
${oldJsCodeLocationAssignmentStatement}
34+
#else
35+
${newJsCodeLocationAssignmentStatement}
36+
#endif`;
37+
appDelegateContents = appDelegateContents.replace(oldJsCodeLocationAssignmentStatement,
38+
jsCodeLocationPatch);
39+
}
40+
41+
// 3. Add CodePushDeploymentKey to plist file
42+
var parsedInfoPlist = plist.parse(plistContents);
43+
if (parsedInfoPlist.CodePushDeploymentKey) {
44+
console.log(`"CodePushDeploymentKey" already specified in the plist file.`);
45+
writePatches();
46+
} else {
47+
inquirer.prompt({
48+
"type": "input",
49+
"name": "iosDeploymentKey",
50+
"message": "What is your CodePush deployment key for iOS (hit <ENTER> to ignore)"
51+
}).then(function(answer) {
52+
parsedInfoPlist.CodePushDeploymentKey = answer.iosDeploymentKey || "deployment-key-here";
53+
plistContents = plist.build(parsedInfoPlist);
54+
55+
writePatches();
56+
});
57+
}
58+
59+
function writePatches() {
60+
fs.writeFileSync(appDelegatePath, appDelegateContents);
61+
fs.writeFileSync(plistPath, plistContents);
62+
}

scripts/postlink/run.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require("./ios/postlink");
2+
require("./android/postlink");

0 commit comments

Comments
 (0)