Skip to content
Source
Sign inSign up

withShareExtensionDisplayName.cjs

87 lines3.0 KB

1"use strict";
2​
3// Expo replaces the empty signing team with appleTeamId. Reverse-ordered mods run after extension creation.
4​
5const fs = require("fs");
6const path = require("path");
7const { withDangerousMod, withXcodeProject } = require("expo/config-plugins");
8​
9const TARGET_NAME = "expo-sharing-extension";
10​
11function stripComments(section) {
12 return Object.fromEntries(
13 Object.entries(section ?? {}).filter(([key]) => !key.endsWith("_comment")),
14 );
16​
17function findByName(section, name) {
18 return Object.entries(stripComments(section)).find(([, value]) => value?.name === name) ?? null;
20​
21function escapeXml(value) {
22 return value
23 .replaceAll("&", "&")
24 .replaceAll("<", "&lt;")
25 .replaceAll(">", "&gt;")
26 .replaceAll('"', "&quot;")
27 .replaceAll("'", "&apos;");
29​
30function withDisplayNamePlist(config, displayName) {
31 return withDangerousMod(config, [
32 "ios",
33 (cfg) => {
34 const plistPath = path.join(cfg.modRequest.platformProjectRoot, TARGET_NAME, "Info.plist");
35 if (!fs.existsSync(plistPath)) {
36 throw new Error(
37 `${TARGET_NAME}/Info.plist was not generated. Register withShareExtensionDisplayName before expo-sharing.`,
38 );
39 }
40 const source = fs.readFileSync(plistPath, "utf8");
41 const displayNamePattern = /(<key>CFBundleDisplayName<\/key>\s*<string>)[^<]*(<\/string>)/;
42 if (!displayNamePattern.test(source)) {
43 throw new Error(`Could not update CFBundleDisplayName in ${plistPath}.`);
44 }
45 const next = source.replace(displayNamePattern, `$1${escapeXml(displayName)}$2`);
46 if (next !== source) {
47 fs.writeFileSync(plistPath, next);
48 }
49 return cfg;
50 },
51 ]);
53​
54function withExtensionDisplayNameBuildSetting(config, displayName) {
55 return withXcodeProject(config, (cfg) => {
56 const objects = cfg.modResults.hash.project.objects;
57 const targetEntry = findByName(objects.PBXNativeTarget, TARGET_NAME);
58 if (!targetEntry) {
59 throw new Error(
60 `${TARGET_NAME} Xcode target was not generated. Register withShareExtensionDisplayName before expo-sharing.`,
61 );
62 }
63 const target = targetEntry[1];
64 const configurationList = stripComments(objects.XCConfigurationList)[
65 target.buildConfigurationList
66 ];
67 if (!configurationList) {
68 throw new Error(`Could not find build configurations for ${TARGET_NAME}.`);
69 }
70 const buildConfigurations = stripComments(objects.XCBuildConfiguration);
71 for (const reference of configurationList.buildConfigurations ?? []) {
72 const buildConfiguration = buildConfigurations[reference.value];
73 if (buildConfiguration?.buildSettings) {
74 buildConfiguration.buildSettings.INFOPLIST_KEY_CFBundleDisplayName = `"${displayName}"`;
75 }
76 }
77 return cfg;
78 });
80​
81module.exports = function withShareExtensionDisplayName(config) {
82 const displayName = config.name;
83 return withExtensionDisplayNameBuildSetting(
84 withDisplayNamePlist(config, displayName),
85 displayName,
86 );
87};