Skip to content

Commit 4bbea7c

Browse files
authored
[generator-macos] Use CocoaPods to build iOS and macOS targets (#298)
* [generator-macos] Import upstream v0.62 template and add macOS target * [generator-macos] Make targets build using CP * [generator-macos] Give macOS app localhost access * [generator-macos] Update pbxproj after pod install * [generator-macos] Remove last refs to Flipper * [generator-macos] Revert some unneeded changes * [CI] Run pod install before run-macos * [CLI] No longer use legacy build system * [CLI] Don't try to parse build output
1 parent 2cd3cdb commit 4bbea7c

File tree

22 files changed

+504
-1250
lines changed

22 files changed

+504
-1250
lines changed

.ado/templates/react-native-macos-init.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ steps:
9696
script: npx react-native-macos-init --version latest --overwrite --prerelease
9797
workingDirectory: $(Agent.BuildDirectory)/testcli
9898

99+
- task: CmdLine@2
100+
displayName: Install pods
101+
inputs:
102+
script: pod install
103+
workingDirectory: $(Agent.BuildDirectory)/testcli/macos
104+
99105
- task: CmdLine@2
100106
displayName: Run macos
101107
inputs:

React/Modules/RCTUIManager.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@
3737
#endif // TODO(macOS ISS#2323203)
3838
#import "RCTShadowView+Internal.h"
3939
#import "RCTShadowView.h"
40+
#if !TARGET_OS_OSX // TODO(macOS ISS#2323203)
4041
#import "RCTSurfaceRootShadowView.h"
4142
#import "RCTSurfaceRootView.h"
43+
#endif // TODO(macOS ISS#2323203)
4244
#import "RCTUIManagerObserverCoordinator.h"
4345
#import "RCTUIManagerUtils.h"
4446
#import "RCTUtils.h"

React/React-Core.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ Pod::Spec.new do |s|
3939
# TODO(macOS GH#214)
4040
"**/MacOS/*"
4141
s.osx.exclude_files = "Modules/RCTRedBoxExtraDataViewController.{h,m}",
42-
"Modules/RCTStatusBarManager.*",
4342
"UIUtils/*",
4443
"Profiler/{RCTFPSGraph,RCTPerfMonitor}.*",
4544
"Profiler/RCTProfileTrampoline-{arm,arm64,i386}.S",
46-
"Base/{RCTPlatform,RCTKeyCommands}.*",
45+
"Base/RCTKeyCommands.*",
46+
"Base/RCTPlatform.m",
4747
"Base/Surface/SurfaceHostingView/*",
4848
"Base/Surface/RCTSurface{,Delegate,Root*}.*",
4949
"Base/RCTTV*.*",

local-cli/generator-common/index.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,35 @@
1+
// @ts-check
2+
13
const fs = require('fs');
24
const chalk = require('chalk');
35
const path = require('path');
46
const copyAndReplace = require('@react-native-community/cli/build/tools/copyAndReplace').default;
57
const walk = require('@react-native-community/cli/build/tools/walk').default;
68
const prompt = require('@react-native-community/cli/build/tools/generator/promptSync').default();
79

10+
/**
11+
* @param {string} destPath
12+
*/
813
function createDir(destPath) {
914
if (!fs.existsSync(destPath)) {
10-
fs.mkdirSync(destPath);
15+
fs.mkdirSync(destPath, { recursive: true });
1116
}
1217
}
1318

19+
/**
20+
* @todo Move this upstream to @react-native-community/cli
21+
*
22+
* @param {string} templatePath
23+
* @param {Record<string, string>} replacements
24+
*/
25+
function replaceInPath(templatePath, replacements) {
26+
let result = templatePath;
27+
Object.keys(replacements).forEach(key => {
28+
result = result.replace(key, replacements[key]);
29+
});
30+
return result;
31+
}
32+
1433
function copyAndReplaceWithChangedCallback(srcPath, destRoot, relativeDestPath, replacements, alwaysOverwrite) {
1534
if (!replacements) {
1635
replacements = {};
@@ -35,15 +54,23 @@ function copyAndReplaceWithChangedCallback(srcPath, destRoot, relativeDestPath,
3554
);
3655
}
3756

57+
/**
58+
* @param {string} srcPath
59+
* @param {string} destPath
60+
* @param {string} relativeDestDir
61+
* @param {Record<string, string>} replacements
62+
* @param {boolean} alwaysOverwrite
63+
*/
3864
function copyAndReplaceAll(srcPath, destPath, relativeDestDir, replacements, alwaysOverwrite) {
3965
walk(srcPath).forEach(absoluteSrcFilePath => {
4066
const filename = path.relative(srcPath, absoluteSrcFilePath);
41-
const relativeDestPath = path.join(relativeDestDir, filename);
67+
const relativeDestPath = path.join(relativeDestDir, replaceInPath(filename, replacements));
4268
copyAndReplaceWithChangedCallback(absoluteSrcFilePath, destPath, relativeDestPath, replacements, alwaysOverwrite);
4369
});
4470
}
4571

46-
function alwaysOverwriteContentChangedCallback( absoluteSrcFilePath,
72+
function alwaysOverwriteContentChangedCallback(
73+
absoluteSrcFilePath,
4774
relativeDestPath,
4875
contentChanged
4976
) {

local-cli/generator-macos/index.js

Lines changed: 80 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
// @ts-check
2+
13
'use strict';
4+
25
const chalk = require('chalk');
36
const path = require('path');
47
const childProcess = require('child_process');
@@ -10,7 +13,14 @@ const {
1013
} = require('../generator-common');
1114

1215
const macOSDir = 'macos';
16+
const oldProjectName = 'HelloWorld';
1317

18+
/**
19+
* @param {string} srcRootPath
20+
* @param {string} destPath
21+
* @param {string} newProjectName
22+
* @param {{ overwrite?: boolean }} options
23+
*/
1424
function copyProjectTemplateAndReplace(
1525
srcRootPath,
1626
destPath,
@@ -29,29 +39,23 @@ function copyProjectTemplateAndReplace(
2939
throw new Error('Need a project name');
3040
}
3141

32-
const projectNameMacOS = newProjectName + '-macOS';
33-
const projectNameIOS = newProjectName;
34-
const xcodeProjName = newProjectName + '.xcodeproj';
35-
const schemeNameMacOS = newProjectName + '-macOS.xcscheme';
36-
const schemeNameIOS = newProjectName + '.xcscheme';
37-
3842
createDir(path.join(destPath, macOSDir));
39-
createDir(path.join(destPath, macOSDir, projectNameIOS));
40-
createDir(path.join(destPath, macOSDir, projectNameMacOS));
41-
createDir(path.join(destPath, macOSDir, xcodeProjName));
42-
createDir(path.join(destPath, macOSDir, xcodeProjName, 'xcshareddata'));
43-
createDir(path.join(destPath, macOSDir, xcodeProjName, 'xcshareddata/xcschemes'));
43+
createDir(path.join(destPath, srcDirPath(newProjectName, 'iOS')));
44+
createDir(path.join(destPath, srcDirPath(newProjectName, 'macOS')));
45+
createDir(path.join(destPath, xcodeprojPath(newProjectName)));
46+
createDir(path.join(destPath, schemesPath(newProjectName)));
4447

4548
const templateVars = {
46-
'HelloWorld': newProjectName,
49+
[oldProjectName]: newProjectName,
4750
};
4851

4952
[
50-
{ from: path.join(srcRootPath, 'macos/HelloWorld'), to: path.join(macOSDir, projectNameIOS) },
51-
{ from: path.join(srcRootPath, 'macos/HelloWorld-macOS'), to: path.join(macOSDir, projectNameMacOS) },
52-
{ from: path.join(srcRootPath, 'macos/HelloWorld.xcodeproj'), to: path.join(macOSDir, xcodeProjName) },
53-
{ from: path.join(srcRootPath, 'macos/xcschemes/HelloWorld-macOS.xcscheme'), to: path.join(macOSDir, xcodeProjName, 'xcshareddata/xcschemes', schemeNameMacOS) },
54-
{ from: path.join(srcRootPath, 'macos/xcschemes/HelloWorld.xcscheme'), to: path.join(macOSDir, xcodeProjName, 'xcshareddata/xcschemes', schemeNameIOS) },
53+
{ from: path.join(srcRootPath, macOSDir, 'Podfile'), to: path.join(macOSDir, 'Podfile') },
54+
{ from: path.join(srcRootPath, srcDirPath(oldProjectName, 'iOS')), to: srcDirPath(newProjectName, 'iOS') },
55+
{ from: path.join(srcRootPath, srcDirPath(oldProjectName, 'macOS')), to: srcDirPath(newProjectName, 'macOS') },
56+
{ from: path.join(srcRootPath, pbxprojPath(oldProjectName)), to: pbxprojPath(newProjectName) },
57+
{ from: path.join(srcRootPath, schemePath(oldProjectName, 'iOS')), to: schemePath(newProjectName, 'iOS') },
58+
{ from: path.join(srcRootPath, schemePath(oldProjectName, 'macOS')), to: schemePath(newProjectName, 'macOS') },
5559
].forEach((mapping) => copyAndReplaceAll(mapping.from, destPath, mapping.to, templateVars, options.overwrite));
5660

5761
[
@@ -61,14 +65,70 @@ function copyProjectTemplateAndReplace(
6165

6266
console.log(`
6367
${chalk.blue(`Run instructions for ${chalk.bold('macOS')}`)}:
68+
• cd macos && pod install && cd ..
6469
• npx react-native run-macos
6570
${chalk.dim('- or -')}
66-
• Open ${macOSDir}/${xcodeProjName} in Xcode or run "xed -b ${macOSDir}"
71+
• Open ${xcworkspacePath(newProjectName)} in Xcode or run "xed -b ${macOSDir}"
6772
• yarn start:macos
6873
• Hit the Run button
6974
`);
7075
}
7176

77+
/**
78+
* @param {string} basename
79+
* @param {"iOS" | "macOS"} platform
80+
*/
81+
function projectName(basename, platform) {
82+
return basename + '-' + platform;
83+
}
84+
85+
/**
86+
* @param {string} basename
87+
* @param {"iOS" | "macOS"} platform
88+
*/
89+
function srcDirPath(basename, platform) {
90+
return path.join(macOSDir, projectName(basename, platform));
91+
}
92+
93+
/**
94+
* @param {string} basename
95+
*/
96+
function xcodeprojPath(basename) {
97+
return path.join(macOSDir, basename + '.xcodeproj');
98+
}
99+
100+
/**
101+
* @param {string} basename
102+
*/
103+
function xcworkspacePath(basename) {
104+
return path.join(macOSDir, basename + '.xcworkspace');
105+
}
106+
107+
/**
108+
* @param {string} basename
109+
*/
110+
function pbxprojPath(basename) {
111+
return path.join(xcodeprojPath(basename), 'project.pbxproj');
112+
}
113+
114+
/**
115+
* @param {string} basename
116+
*/
117+
function schemesPath(basename) {
118+
return path.join(xcodeprojPath(basename), 'xcshareddata', 'xcschemes');
119+
}
120+
121+
/**
122+
* @param {string} basename
123+
* @param {"iOS" | "macOS"} platform
124+
*/
125+
function schemePath(basename, platform) {
126+
return path.join(schemesPath(basename), projectName(basename, platform) + '.xcscheme');
127+
}
128+
129+
/**
130+
* @param {{ verbose?: boolean }=} options
131+
*/
72132
function installDependencies(options) {
73133
const cwd = process.cwd();
74134

@@ -80,6 +140,8 @@ function installDependencies(options) {
80140

81141
// Install dependencies using correct package manager
82142
const isYarn = fs.existsSync(path.join(cwd, 'yarn.lock'));
143+
144+
/** @type {{ stdio?: 'inherit' }} */
83145
const execOptions = options && options.verbose ? { stdio: 'inherit' } : {};
84146
childProcess.execSync(isYarn ? 'yarn' : 'npm i', execOptions);
85147
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
{
22
"images" : [
3-
{
4-
"idiom" : "iphone",
5-
"size" : "20x20",
6-
"scale" : "2x"
7-
},
8-
{
9-
"idiom" : "iphone",
10-
"size" : "20x20",
11-
"scale" : "3x"
12-
},
133
{
144
"idiom" : "iphone",
155
"size" : "29x29",
@@ -39,11 +29,6 @@
3929
"idiom" : "iphone",
4030
"size" : "60x60",
4131
"scale" : "3x"
42-
},
43-
{
44-
"idiom" : "ios-marketing",
45-
"size" : "1024x1024",
46-
"scale" : "1x"
4732
}
4833
],
4934
"info" : {
File renamed without changes.

0 commit comments

Comments
 (0)