Skip to content

Commit ae074f2

Browse files
alexandergoncharov-zzYuri Kulikov
authored and
Yuri Kulikov
committed
Сreate postunlink scripts (#1588)
1 parent 06b875d commit ae074f2

File tree

8 files changed

+388
-175
lines changed

8 files changed

+388
-175
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
]
5151
},
5252
"commands": {
53-
"postlink": "node node_modules/react-native-code-push/scripts/postlink/run"
53+
"postlink": "node node_modules/react-native-code-push/scripts/postlink/run",
54+
"postunlink": "node node_modules/react-native-code-push/scripts/postunlink/run"
5455
}
5556
}
5657
}

scripts/postlink/android/postlink.js

+15-48
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,37 @@
1+
var linkTools = require('../../tools/linkToolsAndroid');
12
var fs = require("fs");
2-
var glob = require("glob");
3-
var path = require("path");
43
var inquirer = require('inquirer');
54

65
module.exports = () => {
76

87
console.log("Running android postlink script");
98

10-
var ignoreFolders = { ignore: ["node_modules/**", "**/build/**"] };
11-
var buildGradlePath = path.join("android", "app", "build.gradle");
12-
var manifestPath = glob.sync("**/AndroidManifest.xml", ignoreFolders)[0];
13-
14-
function findMainApplication() {
15-
if (!manifestPath) {
16-
return null;
17-
}
18-
19-
var manifest = fs.readFileSync(manifestPath, "utf8");
20-
21-
// Android manifest must include single 'application' element
22-
var matchResult = manifest.match(/application\s+android:name\s*=\s*"(.*?)"/);
23-
if (matchResult) {
24-
var appName = matchResult[1];
25-
} else {
26-
return null;
27-
}
28-
29-
var nameParts = appName.split('.');
30-
var searchPath = glob.sync("**/" + nameParts[nameParts.length - 1] + ".java", ignoreFolders)[0];
31-
return searchPath;
32-
}
33-
34-
var mainApplicationPath = findMainApplication() || glob.sync("**/MainApplication.java", ignoreFolders)[0];
9+
var buildGradlePath = linkTools.getBuildGradlePath();
10+
var mainApplicationPath = linkTools.getMainApplicationLocation();
3511

3612
// 1. Add the getJSBundleFile override
37-
var getJSBundleFileOverride = `
38-
@Override
39-
protected String getJSBundleFile() {
40-
return CodePush.getJSBundleFile();
41-
}
42-
`;
43-
44-
function isAlreadyOverridden(codeContents) {
45-
return /@Override\s*\n\s*protected String getJSBundleFile\(\)\s*\{[\s\S]*?\}/.test(codeContents);
46-
}
13+
var getJSBundleFileOverride = linkTools.getJSBundleFileOverride;
4714

4815
if (mainApplicationPath) {
4916
var mainApplicationContents = fs.readFileSync(mainApplicationPath, "utf8");
50-
if (isAlreadyOverridden(mainApplicationContents)) {
17+
if (linkTools.isJsBundleOverridden(mainApplicationContents)) {
5118
console.log(`"getJSBundleFile" is already overridden`);
5219
} else {
53-
var reactNativeHostInstantiation = "new ReactNativeHost(this) {";
20+
var reactNativeHostInstantiation = linkTools.reactNativeHostInstantiation;
5421
mainApplicationContents = mainApplicationContents.replace(reactNativeHostInstantiation,
55-
`${reactNativeHostInstantiation}\n${getJSBundleFileOverride}`);
22+
`${reactNativeHostInstantiation}${getJSBundleFileOverride}`);
5623
fs.writeFileSync(mainApplicationPath, mainApplicationContents);
5724
}
5825
} else {
59-
var mainActivityPath = glob.sync("**/MainActivity.java", ignoreFolders)[0];
26+
var mainActivityPath = linkTools.getMainActivityPath();
6027
if (mainActivityPath) {
6128
var mainActivityContents = fs.readFileSync(mainActivityPath, "utf8");
62-
if (isAlreadyOverridden(mainActivityContents)) {
29+
if (linkTools.isJsBundleOverridden(mainActivityContents)) {
6330
console.log(`"getJSBundleFile" is already overridden`);
6431
} else {
65-
var mainActivityClassDeclaration = "public class MainActivity extends ReactActivity {";
32+
var mainActivityClassDeclaration = linkTools.mainActivityClassDeclaration;
6633
mainActivityContents = mainActivityContents.replace(mainActivityClassDeclaration,
67-
`${mainActivityClassDeclaration}\n${getJSBundleFileOverride}`);
34+
`${mainActivityClassDeclaration}${getJSBundleFileOverride}`);
6835
fs.writeFileSync(mainActivityPath, mainActivityContents);
6936
}
7037
} else {
@@ -83,22 +50,22 @@ module.exports = () => {
8350
// 2. Add the codepush.gradle build task definitions
8451
var buildGradleContents = fs.readFileSync(buildGradlePath, "utf8");
8552
var reactGradleLink = buildGradleContents.match(/\napply from: ["'].*?react\.gradle["']/)[0];
86-
var codePushGradleLink = `apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"`;
53+
var codePushGradleLink = linkTools.codePushGradleLink;
8754
if (~buildGradleContents.indexOf(codePushGradleLink)) {
8855
console.log(`"codepush.gradle" is already linked in the build definition`);
8956
} else {
9057
buildGradleContents = buildGradleContents.replace(reactGradleLink,
91-
`${reactGradleLink}\n${codePushGradleLink}`);
58+
`${reactGradleLink}${codePushGradleLink}`);
9259
fs.writeFileSync(buildGradlePath, buildGradleContents);
9360
}
9461

9562
//3. Add deployment key
96-
var stringsResourcesPath = glob.sync("**/strings.xml", ignoreFolders)[0];
63+
var stringsResourcesPath = linkTools.getStringsResourcesPath();
9764
if (!stringsResourcesPath) {
9865
return Promise.reject(new Error(`Couldn't find strings.xml. You might need to update it manually.`));
9966
} else {
10067
var stringsResourcesContent = fs.readFileSync(stringsResourcesPath, "utf8");
101-
var deploymentKeyName = "reactNativeCodePush_androidDeploymentKey";
68+
var deploymentKeyName = linkTools.deploymentKeyName;
10269
if (~stringsResourcesContent.indexOf(deploymentKeyName)) {
10370
console.log(`${deploymentKeyName} already specified in the strings.xml`);
10471
} else {

scripts/postlink/ios/postlink.js

+12-126
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1+
2+
var linkTools = require('../../tools/linkToolsIos');
13
var fs = require("fs");
2-
var glob = require("glob");
34
var inquirer = require('inquirer');
4-
var path = require("path");
55
var plist = require("plist");
6-
var xcode = require("xcode");
76
var semver = require('semver');
87

98
var package = require('../../../../../package.json');
@@ -12,15 +11,7 @@ module.exports = () => {
1211

1312
console.log("Running ios postlink script");
1413

15-
var ignoreNodeModules = { ignore: "node_modules/**" };
16-
var ignoreNodeModulesAndPods = { ignore: ["node_modules/**", "ios/Pods/**"] };
17-
var appDelegatePaths = glob.sync("**/AppDelegate.+(mm|m)", ignoreNodeModules);
18-
19-
// Fix for https://github.com/Microsoft/react-native-code-push/issues/477
20-
// Typical location of AppDelegate.m for newer RN versions: $PROJECT_ROOT/ios/<project_name>/AppDelegate.m
21-
// Let's try to find that path by filtering the whole array for any path containing <project_name>
22-
// If we can't find it there, play dumb and pray it is the first path we find.
23-
var appDelegatePath = findFileByAppName(appDelegatePaths, package ? package.name : null) || appDelegatePaths[0];
14+
var appDelegatePath = linkTools.getAppDeletePath();
2415

2516
if (!appDelegatePath) {
2617
return Promise.reject(`Couldn't find AppDelegate. You might need to update it manually \
@@ -31,13 +22,12 @@ module.exports = () => {
3122
var appDelegateContents = fs.readFileSync(appDelegatePath, "utf8");
3223

3324
// 1. Add the header import statement
34-
var codePushHeaderImportStatement = `#import <CodePush/CodePush.h>`;
35-
if (~appDelegateContents.indexOf(codePushHeaderImportStatement)) {
25+
if (~appDelegateContents.indexOf(linkTools.codePushHeaderImportStatement)) {
3626
console.log(`"CodePush.h" header already imported.`);
3727
} else {
3828
var appDelegateHeaderImportStatement = `#import "AppDelegate.h"`;
3929
appDelegateContents = appDelegateContents.replace(appDelegateHeaderImportStatement,
40-
`${appDelegateHeaderImportStatement}\n${codePushHeaderImportStatement}`);
30+
`${appDelegateHeaderImportStatement}${linkTools.codePushHeaderImportStatementFormatted}`);
4131
}
4232

4333
// 2. Modify jsCodeLocation value assignment
@@ -46,8 +36,8 @@ module.exports = () => {
4636
if (!reactNativeVersion) {
4737
console.log(`Can't take react-native version from package.json`);
4838
} else if (semver.gte(semver.coerce(reactNativeVersion), "0.59.0")) {
49-
var oldBundleUrl = "[[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"]";
50-
var codePushBundleUrl = "[CodePush bundleURL]";
39+
var oldBundleUrl = linkTools.oldBundleUrl;
40+
var codePushBundleUrl = linkTools.codePushBundleUrl;
5141

5242
if (~appDelegateContents.indexOf(codePushBundleUrl)) {
5343
console.log(`"BundleUrl" already pointing to "[CodePush bundleURL]".`);
@@ -65,21 +55,16 @@ module.exports = () => {
6555
console.log('Couldn\'t find jsCodeLocation setting in AppDelegate.');
6656
}
6757

68-
var newJsCodeLocationAssignmentStatement = "jsCodeLocation = [CodePush bundleURL];";
58+
var newJsCodeLocationAssignmentStatement = linkTools.codePushGradleLink;
6959
if (~appDelegateContents.indexOf(newJsCodeLocationAssignmentStatement)) {
7060
console.log(`"jsCodeLocation" already pointing to "[CodePush bundleURL]".`);
7161
} else {
7262
if (jsCodeLocations.length === 1) {
73-
// If there is one `jsCodeLocation` it means that react-native app version is lower than 0.57.8
63+
// If there is one `jsCodeLocation` it means that react-native app version is not the 0.57.8 or 0.57.0 and lower than 0.59
7464
// and we should replace this line with DEBUG ifdef statement and add CodePush call for Release case
7565

7666
var oldJsCodeLocationAssignmentStatement = jsCodeLocations[0];
77-
var jsCodeLocationPatch = `
78-
#ifdef DEBUG
79-
${oldJsCodeLocationAssignmentStatement}
80-
#else
81-
${newJsCodeLocationAssignmentStatement}
82-
#endif`;
67+
var jsCodeLocationPatch = linkTools.getJsCodeLocationPatch(oldJsCodeLocationAssignmentStatement);
8368
appDelegateContents = appDelegateContents.replace(oldJsCodeLocationAssignmentStatement,
8469
jsCodeLocationPatch);
8570
} else if (jsCodeLocations.length === 2) {
@@ -94,7 +79,7 @@ module.exports = () => {
9479
}
9580
}
9681

97-
var plistPath = getPlistPath();
82+
var plistPath = linkTools.getPlistPath();
9883

9984
if (!plistPath) {
10085
return Promise.reject(`Couldn't find .plist file. You might need to update it manually \
@@ -128,103 +113,4 @@ module.exports = () => {
128113
fs.writeFileSync(appDelegatePath, appDelegateContents);
129114
fs.writeFileSync(plistPath, plistContents);
130115
}
131-
132-
// Helper that filters an array with AppDelegate.m paths for a path with the app name inside it
133-
// Should cover nearly all cases
134-
function findFileByAppName(array, appName) {
135-
if (array.length === 0 || !appName) return null;
136-
137-
for (var i = 0; i < array.length; i++) {
138-
var path = array[i];
139-
if (path && path.indexOf(appName) !== -1) {
140-
return path;
141-
}
142-
}
143-
144-
return null;
145-
}
146-
147-
function getDefaultPlistPath() {
148-
//this is old logic in case we are unable to find PLIST from xcode/pbxproj - at least we can fallback to default solution
149-
return glob.sync(`**/${package.name}/*Info.plist`, ignoreNodeModules)[0];
150-
}
151-
152-
// This is enhanced version of standard implementation of xcode 'getBuildProperty' function
153-
// but allows us to narrow results by PRODUCT_NAME property also.
154-
// So we suppose that proj name should be the same as package name, otherwise fallback to default plist path searching logic
155-
function getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, prop, targetProductName, build){
156-
var target;
157-
var COMMENT_KEY = /_comment$/;
158-
var PRODUCT_NAME_PROJECT_KEY = 'PRODUCT_NAME';
159-
var TV_OS_DEPLOYMENT_TARGET_PROPERTY_NAME = 'TVOS_DEPLOYMENT_TARGET';
160-
var TEST_HOST_PROPERTY_NAME = 'TEST_HOST';
161-
162-
var configs = parsedXCodeProj.pbxXCBuildConfigurationSection();
163-
for (var configName in configs) {
164-
if (!COMMENT_KEY.test(configName)) {
165-
var config = configs[configName];
166-
if ( (build && config.name === build) || (build === undefined) ) {
167-
if (targetProductName) {
168-
if (config.buildSettings[prop] !== undefined && config.buildSettings[PRODUCT_NAME_PROJECT_KEY] == targetProductName) {
169-
target = config.buildSettings[prop];
170-
}
171-
} else {
172-
if (config.buildSettings[prop] !== undefined &&
173-
//exclude tvOS projects
174-
config.buildSettings[TV_OS_DEPLOYMENT_TARGET_PROPERTY_NAME] == undefined &&
175-
//exclude test app
176-
config.buildSettings[TEST_HOST_PROPERTY_NAME] == undefined) {
177-
target = config.buildSettings[prop];
178-
}
179-
}
180-
}
181-
}
182-
}
183-
return target;
184-
}
185-
186-
function getPlistPath(){
187-
var xcodeProjectPaths = glob.sync(`**/*.xcodeproj/project.pbxproj`, ignoreNodeModulesAndPods);
188-
if (!xcodeProjectPaths){
189-
return getDefaultPlistPath();
190-
}
191-
192-
if (xcodeProjectPaths.length !== 1) {
193-
console.log('Could not determine correct xcode proj path to retrieve related plist file, there are multiple xcodeproj under the solution.');
194-
return getDefaultPlistPath();
195-
}
196-
197-
var xcodeProjectPath = xcodeProjectPaths[0];
198-
var parsedXCodeProj;
199-
200-
try {
201-
var proj = xcode.project(xcodeProjectPath);
202-
//use sync version because there are some problems with async version of xcode lib as of current version
203-
parsedXCodeProj = proj.parseSync();
204-
}
205-
catch(e) {
206-
console.log('Couldn\'t read info.plist path from xcode project - error: ' + e.message);
207-
return getDefaultPlistPath();
208-
}
209-
210-
var INFO_PLIST_PROJECT_KEY = 'INFOPLIST_FILE';
211-
var RELEASE_BUILD_PROPERTY_NAME = "Release";
212-
var targetProductName = package ? package.name : null;
213-
214-
//Try to get 'Release' build of ProductName matching the package name first and if it doesn't exist then try to get any other if existing
215-
var plistPathValue = getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY, targetProductName, RELEASE_BUILD_PROPERTY_NAME) ||
216-
getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY, targetProductName) ||
217-
getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY, null, RELEASE_BUILD_PROPERTY_NAME) ||
218-
getBuildSettingsPropertyMatchingTargetProductName(parsedXCodeProj, INFO_PLIST_PROJECT_KEY) ||
219-
parsedXCodeProj.getBuildProperty(INFO_PLIST_PROJECT_KEY, RELEASE_BUILD_PROPERTY_NAME) ||
220-
parsedXCodeProj.getBuildProperty(INFO_PLIST_PROJECT_KEY);
221-
222-
if (!plistPathValue){
223-
return getDefaultPlistPath();
224-
}
225-
226-
//also remove surrounding quotes from plistPathValue to get correct path resolved
227-
//(see https://github.com/Microsoft/react-native-code-push/issues/534#issuecomment-302069326 for details)
228-
return path.resolve(path.dirname(xcodeProjectPath), '..', plistPathValue.replace(/^"(.*)"$/, '$1'));
229-
}
230-
}
116+
}
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
var linkTools = require('../../tools/linkToolsAndroid');
2+
var fs = require("fs");
3+
4+
module.exports = () => {
5+
6+
console.log("Running android postunlink script");
7+
8+
var mainApplicationPath = linkTools.getMainApplicationLocation();
9+
10+
// 1. Remove the getJSBundleFile override
11+
var getJSBundleFileOverride = linkTools.getJSBundleFileOverride;
12+
13+
if (mainApplicationPath) {
14+
var mainApplicationContents = fs.readFileSync(mainApplicationPath, "utf8");
15+
if (!linkTools.isJsBundleOverridden(mainApplicationContents)) {
16+
console.log(`"getJSBundleFile" is already removed`);
17+
} else {
18+
mainApplicationContents = mainApplicationContents.replace(`${getJSBundleFileOverride}`, "");
19+
fs.writeFileSync(mainApplicationPath, mainApplicationContents);
20+
}
21+
} else {
22+
var mainActivityPath = linkTools.getMainActivityPath();
23+
if (mainActivityPath) {
24+
var mainActivityContents = fs.readFileSync(mainActivityPath, "utf8");
25+
if (!linkTools.isJsBundleOverridden(mainActivityContents)) {
26+
console.log(`"getJSBundleFile" is already removed`);
27+
} else {
28+
mainActivityContents = mainActivityContents.replace(getJSBundleFileOverride, "");
29+
fs.writeFileSync(mainActivityPath, mainActivityContents);
30+
}
31+
} else {
32+
console.log(`Couldn't find Android application entry point. You might need to update it manually. \
33+
Please refer to plugin configuration section for Android at \
34+
https://github.com/microsoft/react-native-code-push#plugin-configuration-android for more details`);
35+
}
36+
}
37+
38+
// 2. Remove the codepush.gradle build task definitions
39+
var buildGradlePath = linkTools.getBuildGradlePath();
40+
41+
if (!fs.existsSync(buildGradlePath)) {
42+
console.log(`Couldn't find build.gradle file. You might need to update it manually. \
43+
Please refer to plugin installation section for Android at \
44+
https://github.com/microsoft/react-native-code-push#plugin-installation-android---manual`);
45+
} else {
46+
var buildGradleContents = fs.readFileSync(buildGradlePath, "utf8");
47+
var codePushGradleLink = linkTools.codePushGradleLink;
48+
if (!~buildGradleContents.indexOf(codePushGradleLink)) {
49+
console.log(`"codepush.gradle" is already unlinked in the build definition`);
50+
} else {
51+
buildGradleContents = buildGradleContents.replace(`${codePushGradleLink}`,"");
52+
fs.writeFileSync(buildGradlePath, buildGradleContents);
53+
}
54+
}
55+
56+
// 3. Remove deployment key
57+
var stringsResourcesPath = linkTools.getStringsResourcesPath();
58+
if (!stringsResourcesPath) {
59+
return Promise.reject(new Error("Couldn't find strings.xml. You might need to update it manually."));
60+
} else {
61+
var stringsResourcesContent = fs.readFileSync(stringsResourcesPath, "utf8");
62+
var deploymentKeyName = linkTools.deploymentKeyName;
63+
if (!~stringsResourcesContent.indexOf(deploymentKeyName)) {
64+
console.log(`${deploymentKeyName} already removed from the strings.xml`);
65+
} else {
66+
var AndroidDeploymentKey = stringsResourcesContent.match(/(<string moduleConfig="true" name="reactNativeCodePush_androidDeploymentKey">.*<\/string>)/);
67+
if (AndroidDeploymentKey) {
68+
stringsResourcesContent = stringsResourcesContent.replace(`\n\t${AndroidDeploymentKey[0]}`,"");
69+
fs.writeFileSync(stringsResourcesPath, stringsResourcesContent);
70+
}
71+
}
72+
}
73+
return Promise.resolve();
74+
}

0 commit comments

Comments
 (0)