forked from voxeet/voxeet-uxkit-cordova
-
Notifications
You must be signed in to change notification settings - Fork 0
/
add-swift-support.js
220 lines (188 loc) · 9.34 KB
/
add-swift-support.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
* This hook adds all the needed config to implement a Cordova plugin with Swift.
*
* - It adds a Bridging header importing Cordova/CDV.h if it's not already
* the case. Else it concats all the bridging headers in one single file.
*
* /!\ Please be sure not naming your bridging header file 'Bridging-Header.h'
* else it won't be supported.
*
* - It puts the ios deployment target to 7.0 in case your project would have a
* lesser one.
*
* - It updates the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES build setting to YES.
*
* - It updates the SWIFT_VERSION to 5.0.
*/
const fs = require('fs');
const path = require('path');
const xcode = require('xcode');
const childProcess = require('child_process');
const semver = require('semver');
const glob = require('glob');
module.exports = context => {
const projectRoot = context.opts.projectRoot;
// This script has to be executed depending on the command line arguments, not
// on the hook execution cycle.
if ((context.hook === 'after_platform_add' && context.cmdLine.includes('platform add')) ||
(context.hook === 'after_prepare' && context.cmdLine.includes('prepare')) ||
(context.hook === 'after_plugin_add' && context.cmdLine.includes('plugin add'))) {
getPlatformVersionsFromFileSystem(context, projectRoot).then(platformVersions => {
const IOS_MIN_DEPLOYMENT_TARGET = '7.0';
const platformPath = path.join(projectRoot, 'platforms', 'ios');
const config = getConfigParser(context, path.join(projectRoot, 'config.xml'));
let bridgingHeaderPath;
let bridgingHeaderContent;
let projectName;
let projectPath;
let pluginsPath;
let iosPlatformVersion;
let pbxprojPath;
let xcodeProject;
const COMMENT_KEY = /_comment$/;
let buildConfigs;
let buildConfig;
let configName;
platformVersions.forEach((platformVersion) => {
if (platformVersion.platform === 'ios') {
iosPlatformVersion = platformVersion.version;
}
});
if (!iosPlatformVersion) {
return;
}
projectName = config.name();
projectPath = path.join(platformPath, projectName);
pbxprojPath = path.join(platformPath, projectName + '.xcodeproj', 'project.pbxproj');
xcodeProject = xcode.project(pbxprojPath);
pluginsPath = path.join(projectPath, 'Plugins');
xcodeProject.parseSync();
bridgingHeaderPath = getBridgingHeaderPath(projectPath, iosPlatformVersion);
try {
fs.statSync(bridgingHeaderPath);
} catch (err) {
// If the bridging header doesn't exist, we create it with the minimum
// Cordova/CDV.h import.
bridgingHeaderContent = ['//',
'// Use this file to import your target\'s public headers that you would like to expose to Swift.',
'//',
'#import <Cordova/CDV.h>',
'#import <VoxeetSDK/VoxeetSDK.h>',
'#import <VoxeetConferenceKit/VoxeetConferenceKit.h>'];
fs.writeFileSync(bridgingHeaderPath, bridgingHeaderContent.join('\n'), { encoding: 'utf-8', flag: 'w' });
xcodeProject.addHeaderFile('Bridging-Header.h');
}
buildConfigs = xcodeProject.pbxXCBuildConfigurationSection();
const bridgingHeaderProperty = '"$(PROJECT_DIR)/$(PROJECT_NAME)' + bridgingHeaderPath.split(projectPath)[1] + '"';
for (configName in buildConfigs) {
if (!COMMENT_KEY.test(configName)) {
buildConfig = buildConfigs[configName];
if (xcodeProject.getBuildProperty('SWIFT_OBJC_BRIDGING_HEADER', buildConfig.name) !== bridgingHeaderProperty) {
xcodeProject.updateBuildProperty('SWIFT_OBJC_BRIDGING_HEADER', bridgingHeaderProperty, buildConfig.name);
console.log('Update IOS build setting SWIFT_OBJC_BRIDGING_HEADER to:', bridgingHeaderProperty, 'for build configuration', buildConfig.name);
}
}
}
// Look for any bridging header defined in the plugin
glob('**/*Bridging-Header*.h', { cwd: pluginsPath }, (error, files) => {
const bridgingHeader = path.basename(bridgingHeaderPath);
const headers = files.map((filePath) => path.basename(filePath));
// if other bridging headers are found, they are imported in the
// one already configured in the project.
let content = fs.readFileSync(bridgingHeaderPath, 'utf-8');
if (error) throw new Error(error);
headers.forEach((header) => {
if (header !== bridgingHeader && !~content.indexOf(header)) {
if (content.charAt(content.length - 1) !== '\n') {
content += '\n';
}
content += '#import "' + header + '"\n';
console.log('Importing', header, 'into', bridgingHeaderPath);
}
});
fs.writeFileSync(bridgingHeaderPath, content, 'utf-8');
for (configName in buildConfigs) {
if (!COMMENT_KEY.test(configName)) {
buildConfig = buildConfigs[configName];
if (parseFloat(xcodeProject.getBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', buildConfig.name)) < parseFloat(IOS_MIN_DEPLOYMENT_TARGET)) {
xcodeProject.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', IOS_MIN_DEPLOYMENT_TARGET, buildConfig.name);
console.log('Update IOS project deployment target to:', IOS_MIN_DEPLOYMENT_TARGET, 'for build configuration', buildConfig.name);
}
if (xcodeProject.getBuildProperty('ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', buildConfig.name) !== 'YES') {
xcodeProject.updateBuildProperty('ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', 'YES', buildConfig.name);
console.log('Update IOS build setting ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to: YES', 'for build configuration', buildConfig.name);
}
if (xcodeProject.getBuildProperty('LD_RUNPATH_SEARCH_PATHS', buildConfig.name) !== '"@executable_path/Frameworks"') {
xcodeProject.updateBuildProperty('LD_RUNPATH_SEARCH_PATHS', '"@executable_path/Frameworks"', buildConfig.name);
console.log('Update IOS build setting LD_RUNPATH_SEARCH_PATHS to: @executable_path/Frameworks', 'for build configuration', buildConfig.name);
}
// if (typeof xcodeProject.getBuildProperty('SWIFT_VERSION', buildConfig.name) === 'undefined') {
// if (config.getPreference('UseLegacySwiftLanguageVersion', 'ios')) {
// xcodeProject.updateBuildProperty('SWIFT_VERSION', '2.3', buildConfig.name);
// console.log('Use legacy Swift language version', buildConfig.name);
// } else if (config.getPreference('UseSwiftLanguageVersion', 'ios')) {
// const swiftVersion = config.getPreference('UseSwiftLanguageVersion', 'ios');
// xcodeProject.updateBuildProperty('SWIFT_VERSION', swiftVersion, buildConfig.name);
// console.log('Use Swift language version', swiftVersion);
// } else {
// xcodeProject.updateBuildProperty('SWIFT_VERSION', '5.0', buildConfig.name);
// console.log('Update SWIFT version to 5.0', buildConfig.name);
// }
// }
// Force Swift Version on 5.0
xcodeProject.updateBuildProperty('SWIFT_VERSION', '5.0', buildConfig.name);
console.log('Update SWIFT version to 5.0', buildConfig.name);
if (buildConfig.name === 'Debug') {
if (xcodeProject.getBuildProperty('SWIFT_OPTIMIZATION_LEVEL', buildConfig.name) !== '"-Onone"') {
xcodeProject.updateBuildProperty('SWIFT_OPTIMIZATION_LEVEL', '"-Onone"', buildConfig.name);
console.log('Update IOS build setting SWIFT_OPTIMIZATION_LEVEL to: -Onone', 'for build configuration', buildConfig.name);
}
}
}
}
fs.writeFileSync(pbxprojPath, xcodeProject.writeSync());
});
});
}
};
const getConfigParser = (context, configPath) => {
let ConfigParser;
if (semver.lt(context.opts.cordova.version, '5.4.0')) {
ConfigParser = context.requireCordovaModule('cordova-lib/src/ConfigParser/ConfigParser');
} else {
ConfigParser = context.requireCordovaModule('cordova-common/src/ConfigParser/ConfigParser');
}
return new ConfigParser(configPath);
};
const getBridgingHeaderPath = (projectPath, iosPlatformVersion) => {
let bridgingHeaderPath;
if (semver.lt(iosPlatformVersion, '4.0.0')) {
bridgingHeaderPath = path.posix.join(projectPath, 'Plugins', 'Bridging-Header.h');
} else {
bridgingHeaderPath = path.posix.join(projectPath, 'Bridging-Header.h');
}
return bridgingHeaderPath;
};
const getPlatformVersionsFromFileSystem = (context, projectRoot) => {
const cordovaUtil = context.requireCordovaModule('cordova-lib/src/cordova/util');
const platformsOnFs = cordovaUtil.listPlatforms(projectRoot);
const platformVersions = platformsOnFs.map(platform => {
const script = path.join(projectRoot, 'platforms', platform, 'cordova', 'version');
return new Promise((resolve, reject) => {
childProcess.exec('"' + script + '"', {}, (error, stdout, _) => {
if (error) {
reject(error);
return;
}
resolve(stdout.trim());
});
}).then(result => {
const version = result.replace(/\r?\n|\r/g, '');
return { platform, version };
}, (error) => {
console.log(error);
process.exit(1);
});
});
return Promise.all(platformVersions);
};