@bacons/apple-targets 3.0.5 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/build/colorset/{withIosColorset.js → with-ios-colorset.js} +2 -2
- package/build/config-plugin.js +9 -10
- package/build/config.d.ts +0 -2
- package/build/{withXcodeChanges.d.ts → configuration-list.d.ts} +2 -2
- package/build/configuration-list.js +656 -0
- package/build/target.d.ts +473 -2
- package/build/target.js +281 -239
- package/build/util.d.ts +18 -0
- package/build/util.js +48 -0
- package/build/{withXcparse.js → with-bacons-xcode.js} +5 -2
- package/build/{withEasCredentials.js → with-eas-credentials.js} +2 -2
- package/build/{withWidget.js → with-widget.js} +24 -65
- package/build/with-xcode-changes.d.ts +3 -0
- package/build/with-xcode-changes.js +401 -0
- package/package.json +7 -2
- package/build/template/XCBuildConfiguration.json +0 -759
- package/build/withXcodeChanges.js +0 -1039
- /package/build/colorset/{customColorFromCSS.d.ts → custom-color-from-css.d.ts} +0 -0
- /package/build/colorset/{customColorFromCSS.js → custom-color-from-css.js} +0 -0
- /package/build/colorset/{withIosColorset.d.ts → with-ios-colorset.d.ts} +0 -0
- /package/build/icon/{withImageAsset.d.ts → with-image-asset.d.ts} +0 -0
- /package/build/icon/{withImageAsset.js → with-image-asset.js} +0 -0
- /package/build/icon/{withIosIcon.d.ts → with-ios-icon.d.ts} +0 -0
- /package/build/icon/{withIosIcon.js → with-ios-icon.js} +0 -0
- /package/build/{withXcparse.d.ts → with-bacons-xcode.d.ts} +0 -0
- /package/build/{withEasCredentials.d.ts → with-eas-credentials.d.ts} +0 -0
- /package/build/{withPodTargetExtension.d.ts → with-pod-target-extension.d.ts} +0 -0
- /package/build/{withPodTargetExtension.js → with-pod-target-extension.js} +0 -0
- /package/build/{withWidget.d.ts → with-widget.d.ts} +0 -0
|
@@ -22,12 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
25
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
29
|
exports.withXcodeProjectBetaBaseMod = exports.withXcodeProjectBeta = void 0;
|
|
27
30
|
const xcode_1 = require("@bacons/xcode");
|
|
28
31
|
const xcodeParse = __importStar(require("@bacons/xcode/json"));
|
|
29
32
|
const config_plugins_1 = require("@expo/config-plugins");
|
|
30
|
-
const
|
|
33
|
+
const fs_1 = __importDefault(require("fs"));
|
|
31
34
|
const customModName = "xcodeProjectBeta2";
|
|
32
35
|
const withXcodeProjectBeta = (config, action) => {
|
|
33
36
|
return (0, config_plugins_1.withMod)(config, {
|
|
@@ -67,7 +70,7 @@ const withXcodeProjectBetaBaseModInternal = (config) => {
|
|
|
67
70
|
}
|
|
68
71
|
const contents = xcodeParse.build(modResults.toJSON());
|
|
69
72
|
if (contents.trim().length) {
|
|
70
|
-
await
|
|
73
|
+
await fs_1.default.promises.writeFile(filePath, contents);
|
|
71
74
|
}
|
|
72
75
|
},
|
|
73
76
|
}),
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getEASCredentialsForXcodeProject = exports.withAutoEasExtensionCredentials = exports.withEASTargets = void 0;
|
|
4
4
|
const target_1 = require("./target");
|
|
5
|
-
const
|
|
5
|
+
const with_bacons_xcode_1 = require("./with-bacons-xcode");
|
|
6
6
|
const debug = require("debug")("expo:target:eas");
|
|
7
7
|
function safeSet(obj, key, value) {
|
|
8
8
|
const segments = key.split(".");
|
|
@@ -52,7 +52,7 @@ const withEASTargets = (config, { bundleIdentifier, targetName, entitlements })
|
|
|
52
52
|
};
|
|
53
53
|
exports.withEASTargets = withEASTargets;
|
|
54
54
|
const withAutoEasExtensionCredentials = (config) => {
|
|
55
|
-
return (0,
|
|
55
|
+
return (0, with_bacons_xcode_1.withXcodeProjectBeta)(config, async (config) => {
|
|
56
56
|
safeSet(config, "extra.eas.build.experimental.ios.appExtensions", []);
|
|
57
57
|
const creds = getEASCredentialsForXcodeProject(config.modResults);
|
|
58
58
|
// Warn about duplicates
|
|
@@ -9,45 +9,17 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
9
9
|
const glob_1 = require("glob");
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
12
|
+
const with_ios_colorset_1 = require("./colorset/with-ios-colorset");
|
|
13
|
+
const with_image_asset_1 = require("./icon/with-image-asset");
|
|
14
|
+
const with_ios_icon_1 = require("./icon/with-ios-icon");
|
|
15
15
|
const target_1 = require("./target");
|
|
16
|
-
const
|
|
17
|
-
const
|
|
16
|
+
const with_eas_credentials_1 = require("./with-eas-credentials");
|
|
17
|
+
const with_xcode_changes_1 = require("./with-xcode-changes");
|
|
18
|
+
const util_1 = require("./util");
|
|
18
19
|
const DEFAULT_DEPLOYMENT_TARGET = "18.0";
|
|
19
|
-
function memoize(fn) {
|
|
20
|
-
const cache = new Map();
|
|
21
|
-
return ((...args) => {
|
|
22
|
-
const key = JSON.stringify(args);
|
|
23
|
-
if (cache.has(key)) {
|
|
24
|
-
return cache.get(key);
|
|
25
|
-
}
|
|
26
|
-
const result = fn(...args);
|
|
27
|
-
cache.set(key, result);
|
|
28
|
-
return result;
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
const warnOnce = memoize(console.warn);
|
|
32
|
-
const logOnce = memoize(console.log);
|
|
33
|
-
function createLogQueue() {
|
|
34
|
-
const queue = [];
|
|
35
|
-
const flush = () => {
|
|
36
|
-
queue.forEach((fn) => fn());
|
|
37
|
-
queue.length = 0;
|
|
38
|
-
};
|
|
39
|
-
return {
|
|
40
|
-
flush,
|
|
41
|
-
add: (fn) => {
|
|
42
|
-
queue.push(fn);
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
// Queue up logs so they only run when prebuild is actually running and not during standard config reads.
|
|
47
|
-
const prebuildLogQueue = createLogQueue();
|
|
48
20
|
const withWidget = (config, props) => {
|
|
49
21
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
50
|
-
|
|
22
|
+
util_1.LOG_QUEUE.add(() => (0, util_1.warnOnce)((0, chalk_1.default) `\nUsing experimental Config Plugin {bold @bacons/apple-targets} that is subject to breaking changes.`));
|
|
51
23
|
// TODO: Magically based on the top-level folders in the `ios-widgets/` folder
|
|
52
24
|
if (props.icon && !/https?:\/\//.test(props.icon)) {
|
|
53
25
|
props.icon = path_1.default.join(props.directory, props.icon);
|
|
@@ -55,9 +27,9 @@ const withWidget = (config, props) => {
|
|
|
55
27
|
// This value should be used for the target name and other internal uses.
|
|
56
28
|
const targetDirName = path_1.default.basename(path_1.default.dirname(props.configPath));
|
|
57
29
|
// Sanitized for general usage. This name just needs to resemble the input value since it shouldn't be used for user-facing values such as the home screen or app store.
|
|
58
|
-
const productName = sanitizeNameForNonDisplayUse(props.name || targetDirName) ||
|
|
59
|
-
sanitizeNameForNonDisplayUse(targetDirName) ||
|
|
60
|
-
sanitizeNameForNonDisplayUse(props.type);
|
|
30
|
+
const productName = (0, util_1.sanitizeNameForNonDisplayUse)(props.name || targetDirName) ||
|
|
31
|
+
(0, util_1.sanitizeNameForNonDisplayUse)(targetDirName) ||
|
|
32
|
+
(0, util_1.sanitizeNameForNonDisplayUse)(props.type);
|
|
61
33
|
// This should never happen.
|
|
62
34
|
if (!productName) {
|
|
63
35
|
throw new Error(`[bacons/apple-targets][${props.type}] Target name does not contain any valid characters: ${targetDirName}`);
|
|
@@ -89,7 +61,7 @@ const withWidget = (config, props) => {
|
|
|
89
61
|
if (!associatedDomains ||
|
|
90
62
|
!Array.isArray(associatedDomains) ||
|
|
91
63
|
associatedDomains.length === 0) {
|
|
92
|
-
warnOnce((0, chalk_1.default) `{yellow [${targetDirName}]} Apple App Clip may require the associated domains entitlement but none were found in the Expo config.\nExample:\n${JSON.stringify({
|
|
64
|
+
(0, util_1.warnOnce)((0, chalk_1.default) `{yellow [${targetDirName}]} Apple App Clip may require the associated domains entitlement but none were found in the Expo config.\nExample:\n${JSON.stringify({
|
|
93
65
|
ios: {
|
|
94
66
|
associatedDomains: [`applinks:placeholder.expo.app`],
|
|
95
67
|
},
|
|
@@ -112,7 +84,7 @@ const withWidget = (config, props) => {
|
|
|
112
84
|
.filter(Boolean);
|
|
113
85
|
const unique = [...new Set(sanitizedUrls)];
|
|
114
86
|
if (unique.length) {
|
|
115
|
-
warnOnce((0, chalk_1.default) `{gray [${targetDirName}]} Apple App Clip expo-target.config.js missing associated domains entitlements in the target config. Using the following defaults:\n${JSON.stringify({
|
|
87
|
+
(0, util_1.warnOnce)((0, chalk_1.default) `{gray [${targetDirName}]} Apple App Clip expo-target.config.js missing associated domains entitlements in the target config. Using the following defaults:\n${JSON.stringify({
|
|
116
88
|
entitlements: {
|
|
117
89
|
[associatedDomainsKey]: [
|
|
118
90
|
`appclips:${unique[0] || "mywebsite.expo.app"}`,
|
|
@@ -138,14 +110,14 @@ const withWidget = (config, props) => {
|
|
|
138
110
|
if (Array.isArray(mainAppGroups) && mainAppGroups.length > 0) {
|
|
139
111
|
// Then set the target app groups to match the main app.
|
|
140
112
|
entitlements[APP_GROUP_KEY] = mainAppGroups;
|
|
141
|
-
|
|
142
|
-
logOnce((0, chalk_1.default) `[${targetDirName}] Syncing app groups with main app. {dim Define entitlements[${JSON.stringify(APP_GROUP_KEY)}] in the {bold expo-target.config} file to override.}`);
|
|
113
|
+
util_1.LOG_QUEUE.add(() => {
|
|
114
|
+
(0, util_1.logOnce)((0, chalk_1.default) `[${targetDirName}] Syncing app groups with main app. {dim Define entitlements[${JSON.stringify(APP_GROUP_KEY)}] in the {bold expo-target.config} file to override.}`);
|
|
143
115
|
});
|
|
144
116
|
}
|
|
145
117
|
else {
|
|
146
|
-
|
|
118
|
+
util_1.LOG_QUEUE.add(() => {
|
|
147
119
|
var _a, _b;
|
|
148
|
-
return warnOnce((0, chalk_1.default) `{yellow [${targetDirName}]} Apple target may require the App Groups entitlement but none were found in the Expo config.\nExample:\n${JSON.stringify({
|
|
120
|
+
return (0, util_1.warnOnce)((0, chalk_1.default) `{yellow [${targetDirName}]} Apple target may require the App Groups entitlement but none were found in the Expo config.\nExample:\n${JSON.stringify({
|
|
149
121
|
ios: {
|
|
150
122
|
entitlements: {
|
|
151
123
|
[APP_GROUP_KEY]: [
|
|
@@ -191,10 +163,10 @@ const withWidget = (config, props) => {
|
|
|
191
163
|
(0, config_plugins_1.withDangerousMod)(config, [
|
|
192
164
|
"ios",
|
|
193
165
|
async (config) => {
|
|
194
|
-
|
|
166
|
+
util_1.LOG_QUEUE.flush();
|
|
195
167
|
fs_1.default.mkdirSync(targetDirAbsolutePath, { recursive: true });
|
|
196
168
|
const files = [
|
|
197
|
-
["Info.plist", (0, target_1.getTargetInfoPlistForType)(props.type)],
|
|
169
|
+
["Info.plist", plist_1.default.build((0, target_1.getTargetInfoPlistForType)(props.type))],
|
|
198
170
|
];
|
|
199
171
|
// if (props.type === "widget") {
|
|
200
172
|
// files.push(
|
|
@@ -236,14 +208,14 @@ const withWidget = (config, props) => {
|
|
|
236
208
|
bundleId += ".";
|
|
237
209
|
// Generate the bundle identifier. This logic needs to remain generally stable since it's used for a permanent value.
|
|
238
210
|
// Key here is simplicity and predictability since it's already appended to the main app's bundle identifier.
|
|
239
|
-
return mainAppBundleId + "." + getSanitizedBundleIdentifier(props.type);
|
|
211
|
+
return mainAppBundleId + "." + (0, util_1.getSanitizedBundleIdentifier)(props.type);
|
|
240
212
|
})();
|
|
241
213
|
const deviceFamilies = ((_d = config.ios) === null || _d === void 0 ? void 0 : _d.isTabletOnly)
|
|
242
214
|
? ["tablet"]
|
|
243
215
|
: ((_e = config.ios) === null || _e === void 0 ? void 0 : _e.supportsTablet)
|
|
244
216
|
? ["phone", "tablet"]
|
|
245
217
|
: ["phone"];
|
|
246
|
-
(0,
|
|
218
|
+
(0, with_xcode_changes_1.withXcodeChanges)(config, {
|
|
247
219
|
productName,
|
|
248
220
|
configPath: props.configPath,
|
|
249
221
|
name: targetDisplayName,
|
|
@@ -266,14 +238,14 @@ const withWidget = (config, props) => {
|
|
|
266
238
|
// Assume App Clips are used for React Native.
|
|
267
239
|
props.type === "clip",
|
|
268
240
|
});
|
|
269
|
-
config = (0,
|
|
241
|
+
config = (0, with_eas_credentials_1.withEASTargets)(config, {
|
|
270
242
|
targetName: productName,
|
|
271
243
|
bundleIdentifier: bundleId,
|
|
272
244
|
entitlements: entitlementsJson,
|
|
273
245
|
});
|
|
274
246
|
if (props.images) {
|
|
275
247
|
Object.entries(props.images).forEach(([name, image]) => {
|
|
276
|
-
(0,
|
|
248
|
+
(0, with_image_asset_1.withImageAsset)(config, {
|
|
277
249
|
image,
|
|
278
250
|
name,
|
|
279
251
|
cwd: props.directory,
|
|
@@ -282,7 +254,7 @@ const withWidget = (config, props) => {
|
|
|
282
254
|
}
|
|
283
255
|
withConfigColors(config, props);
|
|
284
256
|
if (props.icon) {
|
|
285
|
-
(0,
|
|
257
|
+
(0, with_ios_icon_1.withIosIcon)(config, {
|
|
286
258
|
type: props.type,
|
|
287
259
|
cwd: props.directory,
|
|
288
260
|
// TODO: read from the top-level icon.png file in the folder -- ERR this doesn't allow for URLs
|
|
@@ -304,7 +276,7 @@ const withConfigColors = (config, props) => {
|
|
|
304
276
|
// if (props.accentColor) colors["AccentColor"] = props.accentColor;
|
|
305
277
|
if (props.colors) {
|
|
306
278
|
Object.entries(props.colors).forEach(([name, color]) => {
|
|
307
|
-
(0,
|
|
279
|
+
(0, with_ios_colorset_1.withIosColorset)(config, {
|
|
308
280
|
cwd: props.directory,
|
|
309
281
|
name,
|
|
310
282
|
color: typeof color === "string" ? color : color.light,
|
|
@@ -316,16 +288,3 @@ const withConfigColors = (config, props) => {
|
|
|
316
288
|
return config;
|
|
317
289
|
};
|
|
318
290
|
exports.default = withWidget;
|
|
319
|
-
function getSanitizedBundleIdentifier(value) {
|
|
320
|
-
// According to the behavior observed when using the UI in Xcode.
|
|
321
|
-
// Must start with a letter, period, or hyphen (not number).
|
|
322
|
-
// Can only contain alphanumeric characters, periods, and hyphens.
|
|
323
|
-
// Can have empty segments (e.g. com.example..app).
|
|
324
|
-
return value.replace(/(^[^a-zA-Z.-]|[^a-zA-Z0-9-.])/g, "-");
|
|
325
|
-
}
|
|
326
|
-
function sanitizeNameForNonDisplayUse(name) {
|
|
327
|
-
return name
|
|
328
|
-
.replace(/[\W_]+/g, "")
|
|
329
|
-
.normalize("NFD")
|
|
330
|
-
.replace(/[\u0300-\u036f]/g, "");
|
|
331
|
-
}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.withXcodeChanges = void 0;
|
|
7
|
+
const xcode_1 = require("@bacons/xcode");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const glob_1 = require("glob");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const target_1 = require("./target");
|
|
12
|
+
const with_bacons_xcode_1 = require("./with-bacons-xcode");
|
|
13
|
+
const assert_1 = __importDefault(require("assert"));
|
|
14
|
+
const configuration_list_1 = require("./configuration-list");
|
|
15
|
+
const util_1 = require("./util");
|
|
16
|
+
const withXcodeChanges = (config, props) => {
|
|
17
|
+
return (0, with_bacons_xcode_1.withXcodeProjectBeta)(config, async (config) => {
|
|
18
|
+
await applyXcodeChanges(config, config.modResults, props);
|
|
19
|
+
return config;
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
exports.withXcodeChanges = withXcodeChanges;
|
|
23
|
+
// function getMainMarketingVersion(project: XcodeProject) {
|
|
24
|
+
// const mainTarget = getMainAppTarget(project);
|
|
25
|
+
// const config = mainTarget.getDefaultConfiguration();
|
|
26
|
+
// const info = config.getInfoPlist();
|
|
27
|
+
// const version = info.CFBundleShortVersionString;
|
|
28
|
+
// // console.log('getMainMarketingVersion', mainTarget.getDisplayName(), version)
|
|
29
|
+
// if (!version || version === "$(MARKETING_VERSION)") {
|
|
30
|
+
// // console.log('getMainMarketingVersion.fallback', config.props.buildSettings.MARKETING_VERSION)
|
|
31
|
+
// return config.props.buildSettings.MARKETING_VERSION;
|
|
32
|
+
// }
|
|
33
|
+
// return version;
|
|
34
|
+
// }
|
|
35
|
+
async function applyXcodeChanges(config, project, props) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
var _c;
|
|
38
|
+
const mainAppTarget = (0, target_1.getMainAppTarget)(project);
|
|
39
|
+
// Special setting for share extensions.
|
|
40
|
+
if ((0, target_1.needsEmbeddedSwift)(props.type)) {
|
|
41
|
+
// Add ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to the main app target
|
|
42
|
+
mainAppTarget.setBuildSetting("ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
|
|
43
|
+
}
|
|
44
|
+
function getExtensionTargets() {
|
|
45
|
+
return project.rootObject.props.targets.filter((target) => {
|
|
46
|
+
return (xcode_1.PBXNativeTarget.is(target) && (0, target_1.isNativeTargetOfType)(target, props.type));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const targets = getExtensionTargets();
|
|
50
|
+
const productName = props.productName;
|
|
51
|
+
let targetToUpdate = (_a = targets.find((target) => target.props.productName === productName)) !== null && _a !== void 0 ? _a : targets[0];
|
|
52
|
+
if (targetToUpdate) {
|
|
53
|
+
(0, util_1.warnOnce)(`Target "${targetToUpdate.props.productName}" already exists, updating instead of creating a new one`);
|
|
54
|
+
}
|
|
55
|
+
const magicCwd = path_1.default.join(config._internal.projectRoot, "ios", props.cwd);
|
|
56
|
+
function applyDevelopmentTeamIdToTargets() {
|
|
57
|
+
var _a, _b;
|
|
58
|
+
var _c, _d, _e;
|
|
59
|
+
// Set to the provided value or any value.
|
|
60
|
+
const devTeamId = props.teamId ||
|
|
61
|
+
project.rootObject.props.targets
|
|
62
|
+
.map((target) => target.getDefaultBuildSetting("DEVELOPMENT_TEAM"))
|
|
63
|
+
.find(Boolean);
|
|
64
|
+
project.rootObject.props.targets.forEach((target) => {
|
|
65
|
+
if (devTeamId) {
|
|
66
|
+
target.setBuildSetting("DEVELOPMENT_TEAM", devTeamId);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
target.removeBuildSetting("DEVELOPMENT_TEAM");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
for (const target of project.rootObject.props.targets) {
|
|
73
|
+
(_a = (_c = project.rootObject.props.attributes).TargetAttributes) !== null && _a !== void 0 ? _a : (_c.TargetAttributes = {});
|
|
74
|
+
// idk, attempting to prevent EAS Build from failing when it codesigns
|
|
75
|
+
(_b = (_d = project.rootObject.props.attributes.TargetAttributes)[_e = target.uuid]) !== null && _b !== void 0 ? _b : (_d[_e] = {
|
|
76
|
+
CreatedOnToolsVersion: "14.3",
|
|
77
|
+
ProvisioningStyle: "Automatic",
|
|
78
|
+
DevelopmentTeam: devTeamId,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function configureTargetWithKnownSettings(target) {
|
|
83
|
+
var _a, _b;
|
|
84
|
+
if ((_a = props.colors) === null || _a === void 0 ? void 0 : _a.$accent) {
|
|
85
|
+
target.setBuildSetting("ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME", "$accent");
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
target.removeBuildSetting("ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME");
|
|
89
|
+
}
|
|
90
|
+
if ((_b = props.colors) === null || _b === void 0 ? void 0 : _b.$widgetBackground) {
|
|
91
|
+
target.setBuildSetting("ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME", "$widgetBackground");
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
target.removeBuildSetting("ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function configureTargetWithEntitlements(target) {
|
|
98
|
+
const entitlements = (0, glob_1.globSync)("*.entitlements", {
|
|
99
|
+
absolute: false,
|
|
100
|
+
cwd: magicCwd,
|
|
101
|
+
});
|
|
102
|
+
if (entitlements.length > 0) {
|
|
103
|
+
target.setBuildSetting("CODE_SIGN_ENTITLEMENTS", props.cwd + "/" + entitlements[0]);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
target.removeBuildSetting("CODE_SIGN_ENTITLEMENTS");
|
|
107
|
+
}
|
|
108
|
+
return entitlements;
|
|
109
|
+
// CODE_SIGN_ENTITLEMENTS = MattermostShare/MattermostShare.entitlements;
|
|
110
|
+
}
|
|
111
|
+
function syncMarketingVersions() {
|
|
112
|
+
var _a;
|
|
113
|
+
// In Expo managed projects, the version will always be overwritten.
|
|
114
|
+
// Because the overwrite happens after this script runs, we just set it to the config value.
|
|
115
|
+
const mainVersion = ((_a = config.ios) === null || _a === void 0 ? void 0 : _a.version) || config.version || '1.0.0';
|
|
116
|
+
// const mainVersion = getMainMarketingVersion(project);
|
|
117
|
+
project.rootObject.props.targets.forEach((target) => {
|
|
118
|
+
if (xcode_1.PBXNativeTarget.is(target)) {
|
|
119
|
+
target.setBuildSetting("MARKETING_VERSION", mainVersion);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function configureTargetWithPreview(target) {
|
|
124
|
+
const assets = (0, glob_1.globSync)("preview/*.xcassets", {
|
|
125
|
+
absolute: true,
|
|
126
|
+
cwd: magicCwd,
|
|
127
|
+
})[0];
|
|
128
|
+
if (assets) {
|
|
129
|
+
target.setBuildSetting("DEVELOPMENT_ASSET_PATHS", `"${props.cwd + "/preview"}"`);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
target.removeBuildSetting("DEVELOPMENT_ASSET_PATHS");
|
|
133
|
+
}
|
|
134
|
+
return assets;
|
|
135
|
+
}
|
|
136
|
+
function configureJsExport(target) {
|
|
137
|
+
if (props.exportJs) {
|
|
138
|
+
const shellScript = mainAppTarget.props.buildPhases.find((phase) => xcode_1.PBXShellScriptBuildPhase.is(phase) &&
|
|
139
|
+
phase.props.name === "Bundle React Native code and images");
|
|
140
|
+
if (!shellScript) {
|
|
141
|
+
console.warn('Failed to find the "Bundle React Native code and images" build phase in the main app target. Will not be able to configure: ' +
|
|
142
|
+
props.type);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const currentShellScript = target.props.buildPhases.find((phase) => xcode_1.PBXShellScriptBuildPhase.is(phase) &&
|
|
146
|
+
phase.props.name === "Bundle React Native code and images");
|
|
147
|
+
if (!currentShellScript) {
|
|
148
|
+
// Link the same build script across targets to simplify updates.
|
|
149
|
+
target.props.buildPhases.push(shellScript);
|
|
150
|
+
// Alternatively, create a duplicate.
|
|
151
|
+
// target.createBuildPhase(PBXShellScriptBuildPhase, {
|
|
152
|
+
// ...shellScript.props,
|
|
153
|
+
// });
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// If there already is a bundler shell script and it's not the one from the main target, then update it.
|
|
157
|
+
if (currentShellScript.uuid !== shellScript.uuid) {
|
|
158
|
+
for (const key in shellScript.props) {
|
|
159
|
+
// @ts-expect-error
|
|
160
|
+
currentShellScript.props[key] = shellScript.props[key];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// Remove the shell script build phase if it exists from a subsequent build.
|
|
167
|
+
const shellScript = target.props.buildPhases.findIndex((phase) => xcode_1.PBXShellScriptBuildPhase.is(phase) &&
|
|
168
|
+
phase.props.name === "Bundle React Native code and images");
|
|
169
|
+
if (shellScript !== -1) {
|
|
170
|
+
target.props.buildPhases.splice(shellScript, 1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (targetToUpdate) {
|
|
175
|
+
// Remove existing build phases
|
|
176
|
+
targetToUpdate.props.buildConfigurationList.props.buildConfigurations.forEach((config) => {
|
|
177
|
+
config.getReferrers().forEach((ref) => {
|
|
178
|
+
ref.removeReference(config.uuid);
|
|
179
|
+
});
|
|
180
|
+
config.removeFromProject();
|
|
181
|
+
});
|
|
182
|
+
// Remove existing build configuration list
|
|
183
|
+
targetToUpdate.props.buildConfigurationList
|
|
184
|
+
.getReferrers()
|
|
185
|
+
.forEach((ref) => {
|
|
186
|
+
ref.removeReference(targetToUpdate.props.buildConfigurationList.uuid);
|
|
187
|
+
});
|
|
188
|
+
targetToUpdate.props.buildConfigurationList.removeFromProject();
|
|
189
|
+
// Create new build phases
|
|
190
|
+
targetToUpdate.props.buildConfigurationList =
|
|
191
|
+
(0, configuration_list_1.createConfigurationListForType)(project, props);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
const productType = (0, target_1.productTypeForType)(props.type);
|
|
195
|
+
const isExtension = productType === "com.apple.product-type.app-extension";
|
|
196
|
+
const isExtensionKit = productType === "com.apple.product-type.extensionkit-extension";
|
|
197
|
+
const appExtensionBuildFile = xcode_1.PBXBuildFile.create(project, {
|
|
198
|
+
fileRef: xcode_1.PBXFileReference.create(project, {
|
|
199
|
+
explicitFileType: isExtensionKit
|
|
200
|
+
? "wrapper.extensionkit-extension"
|
|
201
|
+
: "wrapper.app-extension",
|
|
202
|
+
includeInIndex: 0,
|
|
203
|
+
path: props.name + (isExtension ? ".appex" : ".app"),
|
|
204
|
+
sourceTree: "BUILT_PRODUCTS_DIR",
|
|
205
|
+
}),
|
|
206
|
+
settings: {
|
|
207
|
+
ATTRIBUTES: ["RemoveHeadersOnCopy"],
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
project.rootObject.ensureProductGroup().props.children.push(
|
|
211
|
+
// @ts-expect-error
|
|
212
|
+
appExtensionBuildFile.props.fileRef);
|
|
213
|
+
targetToUpdate = project.rootObject.createNativeTarget({
|
|
214
|
+
buildConfigurationList: (0, configuration_list_1.createConfigurationListForType)(project, props),
|
|
215
|
+
name: props.name,
|
|
216
|
+
productName,
|
|
217
|
+
// @ts-expect-error
|
|
218
|
+
productReference: appExtensionBuildFile.props.fileRef /* alphaExtension.appex */,
|
|
219
|
+
productType: productType,
|
|
220
|
+
});
|
|
221
|
+
const copyPhase = mainAppTarget.getCopyBuildPhaseForTarget(targetToUpdate);
|
|
222
|
+
if (!copyPhase.getBuildFile(appExtensionBuildFile.props.fileRef)) {
|
|
223
|
+
copyPhase.props.files.push(appExtensionBuildFile);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
configureTargetWithKnownSettings(targetToUpdate);
|
|
227
|
+
configureTargetWithEntitlements(targetToUpdate);
|
|
228
|
+
configureTargetWithPreview(targetToUpdate);
|
|
229
|
+
targetToUpdate.ensureFrameworks(props.frameworks);
|
|
230
|
+
targetToUpdate.getSourcesBuildPhase();
|
|
231
|
+
targetToUpdate.getResourcesBuildPhase();
|
|
232
|
+
configureJsExport(targetToUpdate);
|
|
233
|
+
mainAppTarget.addDependency(targetToUpdate);
|
|
234
|
+
const assetsDir = path_1.default.join(magicCwd, "assets");
|
|
235
|
+
// TODO: Maybe just limit this to Safari extensions?
|
|
236
|
+
const explicitFolders = !fs_1.default.existsSync(assetsDir)
|
|
237
|
+
? []
|
|
238
|
+
: fs_1.default
|
|
239
|
+
.readdirSync(assetsDir)
|
|
240
|
+
.filter((file) => file !== ".DS_Store" &&
|
|
241
|
+
fs_1.default.statSync(path_1.default.join(assetsDir, file)).isDirectory())
|
|
242
|
+
.map((file) => path_1.default.join("assets", file));
|
|
243
|
+
const protectedGroup = ensureProtectedGroup(project, path_1.default.dirname(props.cwd));
|
|
244
|
+
const sharedAssets = (0, glob_1.globSync)("_shared/*", {
|
|
245
|
+
absolute: false,
|
|
246
|
+
cwd: magicCwd,
|
|
247
|
+
});
|
|
248
|
+
// Also look for global shared assets in the parent targets/_shared directory
|
|
249
|
+
const targetsDir = path_1.default.dirname(magicCwd);
|
|
250
|
+
const globalSharedAssets = (0, glob_1.globSync)("_shared/*", {
|
|
251
|
+
absolute: false,
|
|
252
|
+
cwd: targetsDir,
|
|
253
|
+
});
|
|
254
|
+
let syncRootGroup = protectedGroup.props.children.find((child) => child.props.path === path_1.default.basename(props.cwd));
|
|
255
|
+
if (!syncRootGroup) {
|
|
256
|
+
syncRootGroup = xcode_1.PBXFileSystemSynchronizedRootGroup.create(project, {
|
|
257
|
+
path: path_1.default.basename(props.cwd),
|
|
258
|
+
exceptions: [
|
|
259
|
+
xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet.create(project, {
|
|
260
|
+
target: targetToUpdate,
|
|
261
|
+
membershipExceptions: [
|
|
262
|
+
// TODO: What other files belong here, why is this here?
|
|
263
|
+
"Info.plist",
|
|
264
|
+
// Exclude the config path
|
|
265
|
+
path_1.default.relative(magicCwd, props.configPath),
|
|
266
|
+
].sort(),
|
|
267
|
+
}),
|
|
268
|
+
],
|
|
269
|
+
explicitFileTypes: {},
|
|
270
|
+
explicitFolders: [
|
|
271
|
+
// Replaces the previous `lastKnownFileType: "folder",` system that's used in things like Safari extensions to include folders of assets.
|
|
272
|
+
// ex: `"Resources/_locales", "Resources/images"`
|
|
273
|
+
...explicitFolders,
|
|
274
|
+
],
|
|
275
|
+
sourceTree: "<group>",
|
|
276
|
+
});
|
|
277
|
+
if (!targetToUpdate.props.fileSystemSynchronizedGroups) {
|
|
278
|
+
targetToUpdate.props.fileSystemSynchronizedGroups = [];
|
|
279
|
+
}
|
|
280
|
+
targetToUpdate.props.fileSystemSynchronizedGroups.push(syncRootGroup);
|
|
281
|
+
protectedGroup.props.children.push(syncRootGroup);
|
|
282
|
+
}
|
|
283
|
+
// If there's a `_shared` folder, create a PBXFileSystemSynchronizedBuildFileExceptionSet and set the `target` to the main app target. Then add exceptions to the new target's PBXFileSystemSynchronizedRootGroup's exceptions. Finally, ensure the relative paths for each file in the _shared folder are added to the `membershipExceptions` array.
|
|
284
|
+
(0, assert_1.default)(syncRootGroup instanceof xcode_1.PBXFileSystemSynchronizedRootGroup);
|
|
285
|
+
(_b = (_c = syncRootGroup.props).exceptions) !== null && _b !== void 0 ? _b : (_c.exceptions = []);
|
|
286
|
+
const existingExceptionSet = syncRootGroup.props.exceptions.find((exception) => exception instanceof xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet &&
|
|
287
|
+
exception.props.target === mainAppTarget);
|
|
288
|
+
if (sharedAssets.length) {
|
|
289
|
+
const exceptionSet = existingExceptionSet ||
|
|
290
|
+
xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet.create(project, {
|
|
291
|
+
target: mainAppTarget,
|
|
292
|
+
});
|
|
293
|
+
exceptionSet.props.membershipExceptions = sharedAssets.sort();
|
|
294
|
+
syncRootGroup.props.exceptions.push(exceptionSet);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
// Remove the exception set if there are no shared assets.
|
|
298
|
+
existingExceptionSet === null || existingExceptionSet === void 0 ? void 0 : existingExceptionSet.removeFromProject();
|
|
299
|
+
}
|
|
300
|
+
function configureTargetWithGlobalSharedAssets(target) {
|
|
301
|
+
var _a;
|
|
302
|
+
var _b;
|
|
303
|
+
if (!globalSharedAssets.length)
|
|
304
|
+
return;
|
|
305
|
+
// Create or find the global shared synchronized root group
|
|
306
|
+
let globalSharedSyncGroup = protectedGroup.props.children.find((child) => child.props.path === "_shared" &&
|
|
307
|
+
child instanceof xcode_1.PBXFileSystemSynchronizedRootGroup);
|
|
308
|
+
if (!globalSharedSyncGroup) {
|
|
309
|
+
globalSharedSyncGroup = xcode_1.PBXFileSystemSynchronizedRootGroup.create(project, {
|
|
310
|
+
path: "_shared",
|
|
311
|
+
exceptions: [
|
|
312
|
+
// Create exception set for the main app target
|
|
313
|
+
xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet.create(project, {
|
|
314
|
+
target: mainAppTarget,
|
|
315
|
+
membershipExceptions: globalSharedAssets.sort(),
|
|
316
|
+
}),
|
|
317
|
+
// Create exception set for the extension target
|
|
318
|
+
xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet.create(project, {
|
|
319
|
+
target: target,
|
|
320
|
+
membershipExceptions: globalSharedAssets.sort(),
|
|
321
|
+
}),
|
|
322
|
+
],
|
|
323
|
+
explicitFileTypes: {},
|
|
324
|
+
explicitFolders: [],
|
|
325
|
+
sourceTree: "<group>",
|
|
326
|
+
});
|
|
327
|
+
// Add to both targets' fileSystemSynchronizedGroups
|
|
328
|
+
if (!mainAppTarget.props.fileSystemSynchronizedGroups) {
|
|
329
|
+
mainAppTarget.props.fileSystemSynchronizedGroups = [];
|
|
330
|
+
}
|
|
331
|
+
mainAppTarget.props.fileSystemSynchronizedGroups.push(globalSharedSyncGroup);
|
|
332
|
+
if (!target.props.fileSystemSynchronizedGroups) {
|
|
333
|
+
target.props.fileSystemSynchronizedGroups = [];
|
|
334
|
+
}
|
|
335
|
+
target.props.fileSystemSynchronizedGroups.push(globalSharedSyncGroup);
|
|
336
|
+
protectedGroup.props.children.push(globalSharedSyncGroup);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
// Update existing synchronized group with current global shared assets
|
|
340
|
+
(_a = (_b = globalSharedSyncGroup.props).exceptions) !== null && _a !== void 0 ? _a : (_b.exceptions = []);
|
|
341
|
+
// Update or create exception set for main app target
|
|
342
|
+
let mainAppExceptionSet = globalSharedSyncGroup.props.exceptions.find((exception) => exception instanceof xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet &&
|
|
343
|
+
exception.props.target === mainAppTarget);
|
|
344
|
+
if (!mainAppExceptionSet) {
|
|
345
|
+
mainAppExceptionSet =
|
|
346
|
+
xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet.create(project, {
|
|
347
|
+
target: mainAppTarget,
|
|
348
|
+
membershipExceptions: globalSharedAssets.sort(),
|
|
349
|
+
});
|
|
350
|
+
globalSharedSyncGroup.props.exceptions.push(mainAppExceptionSet);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
mainAppExceptionSet.props.membershipExceptions =
|
|
354
|
+
globalSharedAssets.sort();
|
|
355
|
+
}
|
|
356
|
+
// Update or create exception set for extension target
|
|
357
|
+
let extensionExceptionSet = globalSharedSyncGroup.props.exceptions.find((exception) => exception instanceof xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet &&
|
|
358
|
+
exception.props.target === target);
|
|
359
|
+
if (!extensionExceptionSet) {
|
|
360
|
+
extensionExceptionSet =
|
|
361
|
+
xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet.create(project, {
|
|
362
|
+
target: target,
|
|
363
|
+
membershipExceptions: globalSharedAssets.sort(),
|
|
364
|
+
});
|
|
365
|
+
globalSharedSyncGroup.props.exceptions.push(extensionExceptionSet);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
extensionExceptionSet.props.membershipExceptions =
|
|
369
|
+
globalSharedAssets.sort();
|
|
370
|
+
}
|
|
371
|
+
// Ensure the current target has the synchronized group in its fileSystemSynchronizedGroups
|
|
372
|
+
if (!target.props.fileSystemSynchronizedGroups) {
|
|
373
|
+
target.props.fileSystemSynchronizedGroups = [];
|
|
374
|
+
}
|
|
375
|
+
// Check if this target already has the synchronized group
|
|
376
|
+
const hasGroup = target.props.fileSystemSynchronizedGroups.some((group) => group === globalSharedSyncGroup);
|
|
377
|
+
if (!hasGroup) {
|
|
378
|
+
target.props.fileSystemSynchronizedGroups.push(globalSharedSyncGroup);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
configureTargetWithGlobalSharedAssets(targetToUpdate);
|
|
383
|
+
applyDevelopmentTeamIdToTargets();
|
|
384
|
+
syncMarketingVersions();
|
|
385
|
+
return project;
|
|
386
|
+
}
|
|
387
|
+
const PROTECTED_GROUP_NAME = "expo:targets";
|
|
388
|
+
function ensureProtectedGroup(project, relativePath = "../targets") {
|
|
389
|
+
const hasProtectedGroup = project.rootObject.props.mainGroup
|
|
390
|
+
.getChildGroups()
|
|
391
|
+
.find((group) => group.getDisplayName() === PROTECTED_GROUP_NAME);
|
|
392
|
+
const protectedGroup = hasProtectedGroup !== null && hasProtectedGroup !== void 0 ? hasProtectedGroup : xcode_1.PBXGroup.create(project, {
|
|
393
|
+
name: PROTECTED_GROUP_NAME,
|
|
394
|
+
path: relativePath,
|
|
395
|
+
sourceTree: "<group>",
|
|
396
|
+
});
|
|
397
|
+
if (!hasProtectedGroup) {
|
|
398
|
+
project.rootObject.props.mainGroup.props.children.unshift(protectedGroup);
|
|
399
|
+
}
|
|
400
|
+
return protectedGroup;
|
|
401
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bacons/apple-targets",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.7",
|
|
4
4
|
"description": "Generate Apple Targets with Expo Prebuild",
|
|
5
5
|
"main": "build/ExtensionStorage.js",
|
|
6
6
|
"types": "build/ExtensionStorage.d.ts",
|
|
7
|
+
"homepage": "https://github.com/evanbacon/expo-apple-targets",
|
|
7
8
|
"files": [
|
|
8
9
|
"app.plugin.js",
|
|
9
10
|
"app.plugin.d.ts",
|
|
@@ -30,7 +31,11 @@
|
|
|
30
31
|
"config-plugins",
|
|
31
32
|
"apple-targets"
|
|
32
33
|
],
|
|
33
|
-
"author":
|
|
34
|
+
"author": {
|
|
35
|
+
"email": "baconbrix@gmail.com",
|
|
36
|
+
"name": "Evan Bacon",
|
|
37
|
+
"url": "https://evanbacon.dev"
|
|
38
|
+
},
|
|
34
39
|
"license": "MIT",
|
|
35
40
|
"dependencies": {
|
|
36
41
|
"@bacons/xcode": "1.0.0-alpha.27",
|