From 22be520625cf1231a4c93f20c61acd6f6c0e1587 Mon Sep 17 00:00:00 2001 From: Geoffrey Goh Date: Tue, 2 Aug 2016 15:54:31 -0700 Subject: [PATCH] add postlink hooks --- package.json | 27 ++++++++---- scripts/postlink/android/postlink.js | 54 ++++++++++++++++++++++++ scripts/postlink/ios/postlink.js | 62 ++++++++++++++++++++++++++++ scripts/postlink/run.js | 2 + 4 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 scripts/postlink/android/postlink.js create mode 100644 scripts/postlink/ios/postlink.js create mode 100644 scripts/postlink/run.js diff --git a/package.json b/package.json index d917e6a..92d0063 100644 --- a/package.json +++ b/package.json @@ -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 to ignore)" - }] + } + ], + "commands": { + "postlink": "node node_modules/react-native-code-push/scripts/postlink/run" + } } } diff --git a/scripts/postlink/android/postlink.js b/scripts/postlink/android/postlink.js new file mode 100644 index 0000000..611c3a4 --- /dev/null +++ b/scripts/postlink/android/postlink.js @@ -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); +} \ No newline at end of file diff --git a/scripts/postlink/ios/postlink.js b/scripts/postlink/ios/postlink.js new file mode 100644 index 0000000..01db1e4 --- /dev/null +++ b/scripts/postlink/ios/postlink.js @@ -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 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); +} \ No newline at end of file diff --git a/scripts/postlink/run.js b/scripts/postlink/run.js new file mode 100644 index 0000000..6910f7f --- /dev/null +++ b/scripts/postlink/run.js @@ -0,0 +1,2 @@ +require("./ios/postlink"); +require("./android/postlink"); \ No newline at end of file