vxrn 2.0.0-beta.131.1 → 2.0.0-beta.133.1
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/dist/exports/prebuildWithoutExpo.mjs +283 -60
- package/dist/exports/prebuildWithoutExpo.mjs.map +1 -1
- package/dist/exports/prebuildWithoutExpo.native.js +425 -85
- package/dist/exports/prebuildWithoutExpo.native.js.map +1 -1
- package/dist/utils/nativeRun.mjs +9 -14
- package/dist/utils/nativeRun.mjs.map +1 -1
- package/dist/utils/nativeRun.native.js +11 -15
- package/dist/utils/nativeRun.native.js.map +1 -1
- package/package.json +10 -10
- package/src/exports/prebuildWithoutExpo.test.ts +225 -7
- package/src/exports/prebuildWithoutExpo.ts +364 -60
- package/src/utils/nativeRun.test.ts +8 -5
- package/src/utils/nativeRun.ts +12 -17
- package/types/exports/prebuildWithoutExpo.d.ts.map +1 -1
- package/types/utils/nativeRun.d.ts.map +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
import module from "node:module";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { pathToFileURL } from "node:url";
|
|
@@ -247,6 +248,54 @@ function patchIosPbxprojSceneDelegate(rendered, appName) {
|
|
|
247
248
|
}
|
|
248
249
|
return patched;
|
|
249
250
|
}
|
|
251
|
+
function fontFileName(font) {
|
|
252
|
+
return path.basename(font);
|
|
253
|
+
}
|
|
254
|
+
function pbxprojId(seed) {
|
|
255
|
+
return createHash("sha1").update(seed).digest("hex").slice(0, 24).toUpperCase();
|
|
256
|
+
}
|
|
257
|
+
const GOOGLE_SERVICES_PLIST = "GoogleService-Info.plist";
|
|
258
|
+
const GOOGLE_SERVICES_VERSION = "4.4.4";
|
|
259
|
+
function iosResourceFiles(app) {
|
|
260
|
+
return [...(app.fonts ?? []).map(fontFileName), ...app.ios?.googleServicesFile ? [GOOGLE_SERVICES_PLIST] : []];
|
|
261
|
+
}
|
|
262
|
+
function patchIosPbxprojResources(rendered, appName, names) {
|
|
263
|
+
let patched = rendered;
|
|
264
|
+
for (const name of names) {
|
|
265
|
+
const fileRef = pbxprojId(`one-resource-file:${name}`);
|
|
266
|
+
const buildFile = pbxprojId(`one-resource-build:${name}`);
|
|
267
|
+
const fileType = name.endsWith(".plist") ? "text.plist.xml" : "file";
|
|
268
|
+
const edits = [
|
|
269
|
+
["/* Images.xcassets in Resources */ = {isa = PBXBuildFile;", ` ${buildFile} /* ${name} in Resources */ = {isa = PBXBuildFile; fileRef = ${fileRef} /* ${name} */; };`],
|
|
270
|
+
["/* Images.xcassets */ = {isa = PBXFileReference;", ` ${fileRef} /* ${name} */ = {isa = PBXFileReference; lastKnownFileType = ${fileType}; name = ${name}; path = ${appName}/${name}; sourceTree = "<group>"; };`],
|
|
271
|
+
["/* Images.xcassets */,", ` ${fileRef} /* ${name} */,`],
|
|
272
|
+
["/* Images.xcassets in Resources */,", ` ${buildFile} /* ${name} in Resources */,`]
|
|
273
|
+
];
|
|
274
|
+
for (const [anchor, insertion] of edits) {
|
|
275
|
+
const next = insertAfterLine(patched, anchor, insertion);
|
|
276
|
+
if (next === patched) {
|
|
277
|
+
throw new Error(`[vxrn] prebuild template project.pbxproj lost its Images.xcassets anchor (${anchor})`);
|
|
278
|
+
}
|
|
279
|
+
patched = next;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return patched;
|
|
283
|
+
}
|
|
284
|
+
function copyAppResources({ root, dest, platform, app }) {
|
|
285
|
+
const copies = (app.fonts ?? []).map((font) => [font, platform === "ios" ? path.join(dest, app.name, fontFileName(font)) : path.join(dest, "app", "src", "main", "assets", "fonts", fontFileName(font))]);
|
|
286
|
+
const googleServices = platform === "ios" ? app.ios?.googleServicesFile : app.android?.googleServicesFile;
|
|
287
|
+
if (googleServices) {
|
|
288
|
+
copies.push([googleServices, platform === "ios" ? path.join(dest, app.name, GOOGLE_SERVICES_PLIST) : path.join(dest, "app", "google-services.json")]);
|
|
289
|
+
}
|
|
290
|
+
for (const [file, target] of copies) {
|
|
291
|
+
const source = path.resolve(root, file);
|
|
292
|
+
if (!FSExtra.existsSync(source)) {
|
|
293
|
+
throw new Error(`[vxrn] native.app names ${file}, which does not exist`);
|
|
294
|
+
}
|
|
295
|
+
FSExtra.mkdirSync(path.dirname(target), { recursive: true });
|
|
296
|
+
FSExtra.copyFileSync(source, target);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
250
299
|
function patchIosPbxprojAppEntitlements(rendered, appName) {
|
|
251
300
|
const edits = [["/* AppDelegate.swift */ = {isa = PBXFileReference;", ` ${PUSH_ENTITLEMENTS_FILE_REF_ID} /* ${appName}.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = ${appName}.entitlements; path = ${appName}/${appName}.entitlements; sourceTree = "<group>"; };`], ["/* AppDelegate.swift */,", ` ${PUSH_ENTITLEMENTS_FILE_REF_ID} /* ${appName}.entitlements */,`]];
|
|
252
301
|
let patched = rendered;
|
|
@@ -286,7 +335,7 @@ ${renderPlistValue(value, indent)}`).join("\n");
|
|
|
286
335
|
function appEntitlements(app) {
|
|
287
336
|
const modeled = {};
|
|
288
337
|
if (app.notifications?.push === true || app.ios?.widgets?.pushNotifications) {
|
|
289
|
-
modeled["aps-environment"] = notificationsHost.apsEnvironment;
|
|
338
|
+
modeled["aps-environment"] = app.notifications?.apsEnvironment ?? notificationsHost.apsEnvironment;
|
|
290
339
|
}
|
|
291
340
|
if (app.ios?.widgets) {
|
|
292
341
|
modeled["com.apple.security.application-groups"] = [app.ios.widgets.appGroup];
|
|
@@ -1049,41 +1098,135 @@ ${adaptiveIcon.monochrome ? " <monochrome android:drawable=\"@mipmap/ic_launc
|
|
|
1049
1098
|
FSExtra.writeFileSync(path.join(anydpi, filename), adaptiveXml);
|
|
1050
1099
|
}
|
|
1051
1100
|
}
|
|
1101
|
+
const IOS_DARK_APPEARANCE = [{
|
|
1102
|
+
appearance: "luminosity",
|
|
1103
|
+
value: "dark"
|
|
1104
|
+
}];
|
|
1105
|
+
function srgb(hex) {
|
|
1106
|
+
return {
|
|
1107
|
+
red: Number.parseInt(hex.slice(1, 3), 16) / 255,
|
|
1108
|
+
green: Number.parseInt(hex.slice(3, 5), 16) / 255,
|
|
1109
|
+
blue: Number.parseInt(hex.slice(5, 7), 16) / 255
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
function xcodeColorSet(light, dark) {
|
|
1113
|
+
const entry = (hex) => {
|
|
1114
|
+
const { red, green, blue } = srgb(hex);
|
|
1115
|
+
return {
|
|
1116
|
+
color: {
|
|
1117
|
+
"color-space": "srgb",
|
|
1118
|
+
components: {
|
|
1119
|
+
red: red.toFixed(3),
|
|
1120
|
+
green: green.toFixed(3),
|
|
1121
|
+
blue: blue.toFixed(3),
|
|
1122
|
+
alpha: "1.000"
|
|
1123
|
+
}
|
|
1124
|
+
},
|
|
1125
|
+
idiom: "universal"
|
|
1126
|
+
};
|
|
1127
|
+
};
|
|
1128
|
+
return `${JSON.stringify({
|
|
1129
|
+
colors: [entry(light), ...dark ? [{
|
|
1130
|
+
appearances: IOS_DARK_APPEARANCE,
|
|
1131
|
+
...entry(dark)
|
|
1132
|
+
}] : []],
|
|
1133
|
+
info: {
|
|
1134
|
+
author: "xcode",
|
|
1135
|
+
version: 1
|
|
1136
|
+
}
|
|
1137
|
+
}, null, 2)}
|
|
1138
|
+
`;
|
|
1139
|
+
}
|
|
1140
|
+
function generateAccentColor(args) {
|
|
1141
|
+
const accent = args.app.ios?.accentColor;
|
|
1142
|
+
if (!accent) return;
|
|
1143
|
+
const colorDir = path.join(args.dest, args.app.name, "Images.xcassets", "AccentColor.colorset");
|
|
1144
|
+
FSExtra.mkdirSync(colorDir, { recursive: true });
|
|
1145
|
+
FSExtra.writeFileSync(path.join(colorDir, "Contents.json"), xcodeColorSet(accent.light, accent.dark));
|
|
1146
|
+
}
|
|
1052
1147
|
async function generateSplashScreen(args) {
|
|
1053
1148
|
const { root, dest, platform, app } = args;
|
|
1054
1149
|
if (!app.splash) return;
|
|
1055
|
-
const source = path.resolve(root, app.splash.source);
|
|
1056
|
-
if (!FSExtra.existsSync(source)) {
|
|
1057
|
-
throw new Error(`[vxrn] native.app.splash source does not exist: ${source}`);
|
|
1058
|
-
}
|
|
1059
1150
|
const cover = app.splash.resizeMode === "cover";
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1151
|
+
const prepareArtwork = async (sourcePath, backgroundColor) => {
|
|
1152
|
+
const source = path.resolve(root, sourcePath);
|
|
1153
|
+
if (!FSExtra.existsSync(source)) {
|
|
1154
|
+
throw new Error(`[vxrn] native.app.splash source does not exist: ${source}`);
|
|
1155
|
+
}
|
|
1156
|
+
const { width: sourceWidth, format } = await sharp(source).metadata();
|
|
1157
|
+
const density = format === "svg" && sourceWidth && !cover ? Math.min(2400, Math.ceil(72 * 4 * (app.splash?.width ?? 200) / sourceWidth)) : void 0;
|
|
1158
|
+
const image = sharp(source, density ? { density } : {}).rotate();
|
|
1159
|
+
const prepared = await (cover ? image : image.trim({ background: backgroundColor })).png().toBuffer({ resolveWithObject: true });
|
|
1160
|
+
if (!prepared.info.width || !prepared.info.height) {
|
|
1161
|
+
throw new Error("[vxrn] native.app.splash source must be an image");
|
|
1162
|
+
}
|
|
1163
|
+
return prepared;
|
|
1164
|
+
};
|
|
1165
|
+
const { data: artwork, info: metadata } = await prepareArtwork(app.splash.source, app.splash.backgroundColor);
|
|
1166
|
+
const dark = app.splash.dark;
|
|
1167
|
+
const darkArtwork = dark?.source ? (await prepareArtwork(dark.source, dark.backgroundColor)).data : void 0;
|
|
1065
1168
|
const artworkWidth = app.splash.width ?? 200;
|
|
1066
1169
|
const artworkHeight = Number((artworkWidth * (metadata.height / metadata.width)).toFixed(3));
|
|
1067
1170
|
if (platform === "ios") {
|
|
1068
1171
|
const appDir = path.join(dest, app.name);
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1172
|
+
const assets = path.join(appDir, "Images.xcassets");
|
|
1173
|
+
const writeImageSet = async (name, light, dark2, pointWidth) => {
|
|
1174
|
+
const dir = path.join(assets, `${name}.imageset`);
|
|
1175
|
+
FSExtra.mkdirSync(dir, { recursive: true });
|
|
1176
|
+
const scales = pointWidth === void 0 ? [1] : [
|
|
1177
|
+
1,
|
|
1178
|
+
2,
|
|
1179
|
+
3
|
|
1180
|
+
];
|
|
1181
|
+
const images = [];
|
|
1182
|
+
for (const [variant, suffix, appearances] of [[
|
|
1183
|
+
light,
|
|
1184
|
+
"",
|
|
1185
|
+
void 0
|
|
1186
|
+
], [
|
|
1187
|
+
dark2,
|
|
1188
|
+
"-dark",
|
|
1189
|
+
IOS_DARK_APPEARANCE
|
|
1190
|
+
]]) {
|
|
1191
|
+
if (!variant) continue;
|
|
1192
|
+
for (const scale of scales) {
|
|
1193
|
+
const filename = `${name.toLowerCase()}${suffix}${scale === 1 ? "" : `@${scale}x`}.png`;
|
|
1194
|
+
const output = sharp(variant);
|
|
1195
|
+
await (pointWidth === void 0 ? output : output.resize({ width: Math.round(pointWidth * scale) })).png().toFile(path.join(dir, filename));
|
|
1196
|
+
images.push({
|
|
1197
|
+
...appearances ? { appearances } : {},
|
|
1198
|
+
filename,
|
|
1199
|
+
idiom: "universal",
|
|
1200
|
+
scale: `${scale}x`
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
FSExtra.writeFileSync(path.join(dir, "Contents.json"), `${JSON.stringify({
|
|
1205
|
+
images,
|
|
1206
|
+
info: {
|
|
1207
|
+
author: "xcode",
|
|
1208
|
+
version: 1
|
|
1209
|
+
}
|
|
1210
|
+
}, null, 2)}
|
|
1083
1211
|
`);
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
const
|
|
1212
|
+
};
|
|
1213
|
+
await writeImageSet("Splash", artwork, darkArtwork, cover ? void 0 : artworkWidth);
|
|
1214
|
+
const readBackground = (sourcePath) => {
|
|
1215
|
+
const source = path.resolve(root, sourcePath);
|
|
1216
|
+
if (!FSExtra.existsSync(source)) {
|
|
1217
|
+
throw new Error(`[vxrn] native.app.splash backgroundImage does not exist: ${source}`);
|
|
1218
|
+
}
|
|
1219
|
+
return sharp(source).rotate().png().toBuffer({ resolveWithObject: true });
|
|
1220
|
+
};
|
|
1221
|
+
const background = app.splash.backgroundImage ? await readBackground(app.splash.backgroundImage) : void 0;
|
|
1222
|
+
const darkBackground = dark?.backgroundImage ? (await readBackground(dark.backgroundImage)).data : void 0;
|
|
1223
|
+
if (background) {
|
|
1224
|
+
await writeImageSet("SplashBackgroundImage", background.data, darkBackground, void 0);
|
|
1225
|
+
}
|
|
1226
|
+
const colorDir = path.join(assets, "SplashBackground.colorset");
|
|
1227
|
+
FSExtra.mkdirSync(colorDir, { recursive: true });
|
|
1228
|
+
FSExtra.writeFileSync(path.join(colorDir, "Contents.json"), xcodeColorSet(app.splash.backgroundColor, dark?.backgroundColor));
|
|
1229
|
+
const { red, green, blue } = srgb(app.splash.backgroundColor);
|
|
1087
1230
|
FSExtra.writeFileSync(path.join(appDir, "LaunchScreen.storyboard"), `<?xml version="1.0" encoding="UTF-8"?>
|
|
1088
1231
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="launch-controller">
|
|
1089
1232
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
|
@@ -1098,11 +1241,16 @@ async function generateSplashScreen(args) {
|
|
|
1098
1241
|
<viewController id="launch-controller" sceneMemberID="viewController">
|
|
1099
1242
|
<view key="view" contentMode="scaleToFill" id="launch-view">
|
|
1100
1243
|
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
|
1101
|
-
<subviews
|
|
1244
|
+
<subviews>${background ? `
|
|
1245
|
+
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" image="SplashBackgroundImage" translatesAutoresizingMaskIntoConstraints="NO" id="splash-background"/>` : ""}
|
|
1102
1246
|
<imageView userInteractionEnabled="NO" contentMode="${cover ? "scaleAspectFill" : "scaleAspectFit"}" image="Splash" translatesAutoresizingMaskIntoConstraints="NO" id="splash-image"/>
|
|
1103
1247
|
</subviews>
|
|
1104
|
-
<color key="backgroundColor"
|
|
1105
|
-
<constraints
|
|
1248
|
+
<color key="backgroundColor" name="SplashBackground"/>
|
|
1249
|
+
<constraints>${background ? `
|
|
1250
|
+
<constraint firstItem="splash-background" firstAttribute="leading" secondItem="launch-view" secondAttribute="leading" id="splash-background-leading"/>
|
|
1251
|
+
<constraint firstItem="splash-background" firstAttribute="trailing" secondItem="launch-view" secondAttribute="trailing" id="splash-background-trailing"/>
|
|
1252
|
+
<constraint firstItem="splash-background" firstAttribute="top" secondItem="launch-view" secondAttribute="top" id="splash-background-top"/>
|
|
1253
|
+
<constraint firstItem="splash-background" firstAttribute="bottom" secondItem="launch-view" secondAttribute="bottom" id="splash-background-bottom"/>` : ""}
|
|
1106
1254
|
${cover ? ` <constraint firstItem="splash-image" firstAttribute="leading" secondItem="launch-view" secondAttribute="leading" id="splash-leading"/>
|
|
1107
1255
|
<constraint firstItem="splash-image" firstAttribute="trailing" secondItem="launch-view" secondAttribute="trailing" id="splash-trailing"/>
|
|
1108
1256
|
<constraint firstItem="splash-image" firstAttribute="top" secondItem="launch-view" secondAttribute="top" id="splash-top"/>
|
|
@@ -1118,7 +1266,11 @@ ${cover ? ` <constraint firstItem="splash-image" firstAttribute="le
|
|
|
1118
1266
|
</scene>
|
|
1119
1267
|
</scenes>
|
|
1120
1268
|
<resources>
|
|
1121
|
-
<image name="Splash" width="${metadata.width}" height="${metadata.height}"
|
|
1269
|
+
<image name="Splash" width="${cover ? metadata.width : artworkWidth}" height="${cover ? metadata.height : artworkHeight}"/>${background ? `
|
|
1270
|
+
<image name="SplashBackgroundImage" width="${background.info.width}" height="${background.info.height}"/>` : ""}
|
|
1271
|
+
<namedColor name="SplashBackground">
|
|
1272
|
+
<color red="${red}" green="${green}" blue="${blue}" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
1273
|
+
</namedColor>
|
|
1122
1274
|
</resources>
|
|
1123
1275
|
</document>
|
|
1124
1276
|
`);
|
|
@@ -1126,35 +1278,39 @@ ${cover ? ` <constraint firstItem="splash-image" firstAttribute="le
|
|
|
1126
1278
|
}
|
|
1127
1279
|
const mainRes = path.join(dest, "app", "src", "main", "res");
|
|
1128
1280
|
const drawable = path.join(mainRes, "drawable");
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
const
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1281
|
+
const variants = [[artwork, "drawable"]];
|
|
1282
|
+
if (darkArtwork) variants.push([darkArtwork, "drawable-night"]);
|
|
1283
|
+
for (const [variantArtwork, drawablePrefix] of variants) {
|
|
1284
|
+
for (const [density, multiplier] of Object.entries(ANDROID_DENSITIES)) {
|
|
1285
|
+
const canvasSize = 288 * multiplier;
|
|
1286
|
+
const imageSize = Math.round(artworkWidth * multiplier);
|
|
1287
|
+
const contained = await sharp(variantArtwork).resize(imageSize, imageSize, {
|
|
1288
|
+
fit: "contain",
|
|
1289
|
+
background: {
|
|
1290
|
+
r: 0,
|
|
1291
|
+
g: 0,
|
|
1292
|
+
b: 0,
|
|
1293
|
+
alpha: 0
|
|
1294
|
+
}
|
|
1295
|
+
}).png().toBuffer();
|
|
1296
|
+
const drawableDensity = path.join(mainRes, `${drawablePrefix}-${density}`);
|
|
1297
|
+
FSExtra.mkdirSync(drawableDensity, { recursive: true });
|
|
1298
|
+
await sharp({ create: {
|
|
1299
|
+
width: canvasSize,
|
|
1300
|
+
height: canvasSize,
|
|
1301
|
+
channels: 4,
|
|
1302
|
+
background: {
|
|
1303
|
+
r: 0,
|
|
1304
|
+
g: 0,
|
|
1305
|
+
b: 0,
|
|
1306
|
+
alpha: 0
|
|
1307
|
+
}
|
|
1308
|
+
} }).composite([{
|
|
1309
|
+
input: contained,
|
|
1310
|
+
left: Math.round((canvasSize - imageSize) / 2),
|
|
1311
|
+
top: Math.round((canvasSize - imageSize) / 2)
|
|
1312
|
+
}]).png().toFile(path.join(drawableDensity, "splash.png"));
|
|
1313
|
+
}
|
|
1158
1314
|
}
|
|
1159
1315
|
FSExtra.writeFileSync(path.join(drawable, "launch_screen.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
1160
1316
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
@@ -1169,6 +1325,14 @@ ${cover ? ` <constraint firstItem="splash-image" firstAttribute="le
|
|
|
1169
1325
|
<color name="splash_background">${app.splash.backgroundColor}</color>
|
|
1170
1326
|
</resources>
|
|
1171
1327
|
`);
|
|
1328
|
+
if (dark) {
|
|
1329
|
+
FSExtra.mkdirSync(path.join(mainRes, "values-night"), { recursive: true });
|
|
1330
|
+
FSExtra.writeFileSync(path.join(mainRes, "values-night", "colors.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
1331
|
+
<resources>
|
|
1332
|
+
<color name="splash_background">${dark.backgroundColor}</color>
|
|
1333
|
+
</resources>
|
|
1334
|
+
`);
|
|
1335
|
+
}
|
|
1172
1336
|
const stylesPath = path.join(mainRes, "values", "styles.xml");
|
|
1173
1337
|
const styles = FSExtra.readFileSync(stylesPath, "utf8").replace(" <!-- Customize your theme here. -->", " <item name=\"android:windowBackground\">@drawable/launch_screen</item>");
|
|
1174
1338
|
FSExtra.writeFileSync(stylesPath, styles);
|
|
@@ -1223,6 +1387,9 @@ ${schemes.map((scheme) => ` <string>${scheme}</string>`).join("\n")}
|
|
|
1223
1387
|
stamps.push(` <key>ITSAppUsesNonExemptEncryption</key>
|
|
1224
1388
|
<${app.ios.usesNonExemptEncryption ? "true" : "false"}/>`);
|
|
1225
1389
|
}
|
|
1390
|
+
if (app.ios?.accentColor) {
|
|
1391
|
+
stamps.push(" <key>NSAccentColorName</key>\n <string>AccentColor</string>");
|
|
1392
|
+
}
|
|
1226
1393
|
if (app.ios?.fileSharing) {
|
|
1227
1394
|
stamps.push(` <key>UIFileSharingEnabled</key>
|
|
1228
1395
|
<true/>
|
|
@@ -1250,6 +1417,12 @@ ${schemes.map((scheme) => ` <string>${scheme}</string>`).join("\n")}
|
|
|
1250
1417
|
}
|
|
1251
1418
|
stamps.push(` <key>${updatesHost.runtimeVersionInfoPlistKey}</key>
|
|
1252
1419
|
<string>${escapeXml(app.updates.runtimeVersion)}</string>`);
|
|
1420
|
+
}
|
|
1421
|
+
if (app.fonts?.length) {
|
|
1422
|
+
stamps.push(` <key>UIAppFonts</key>
|
|
1423
|
+
<array>
|
|
1424
|
+
${app.fonts.map((font) => ` <string>${escapeXml(fontFileName(font))}</string>`).join("\n")}
|
|
1425
|
+
</array>`);
|
|
1253
1426
|
}
|
|
1254
1427
|
if (app.userInterfaceStyle !== void 0) {
|
|
1255
1428
|
stamps.push(` <key>UIUserInterfaceStyle</key>
|
|
@@ -1523,6 +1696,9 @@ end`);
|
|
|
1523
1696
|
rendered = patchIosPbxprojAppEntitlements(rendered, appName);
|
|
1524
1697
|
}
|
|
1525
1698
|
if (app.ios?.widgets) rendered = patchIosPbxprojWidgets(rendered, app);
|
|
1699
|
+
if (iosResourceFiles(app).length) {
|
|
1700
|
+
rendered = patchIosPbxprojResources(rendered, appName, iosResourceFiles(app));
|
|
1701
|
+
}
|
|
1526
1702
|
}
|
|
1527
1703
|
if (platform === "ios" && relativePath === "Podfile") {
|
|
1528
1704
|
if (app.ios?.ccache) rendered = `ENV['USE_CCACHE'] ||= '1'
|
|
@@ -1565,6 +1741,43 @@ use_frameworks! :linkage => :${app.ios.useFrameworks}`);
|
|
|
1565
1741
|
}
|
|
1566
1742
|
rendered = rendered.replace(hardcodedGradlePlugin, `includeBuild(new File(["node", "--print", "require('module').createRequire(require.resolve('react-native/package.json')).resolve('@react-native/gradle-plugin/package.json')"].execute(null, settingsDir).text.trim()).parentFile.canonicalPath)`);
|
|
1567
1743
|
}
|
|
1744
|
+
if (platform === "android" && relativePath === "app/build.gradle" && app.android?.minify) {
|
|
1745
|
+
const minify = "def enableProguardInReleaseBuilds = false";
|
|
1746
|
+
const minifyEnabled = "minifyEnabled enableProguardInReleaseBuilds";
|
|
1747
|
+
if (!rendered.includes(minify) || !rendered.includes(minifyEnabled)) {
|
|
1748
|
+
throw new Error("[vxrn] prebuild template app/build.gradle lost its proguard switch");
|
|
1749
|
+
}
|
|
1750
|
+
rendered = rendered.replace(minify, "def enableProguardInReleaseBuilds = true");
|
|
1751
|
+
if (app.android.shrinkResources) {
|
|
1752
|
+
rendered = rendered.replace(minifyEnabled, `${minifyEnabled}
|
|
1753
|
+
shrinkResources true`);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
if (platform === "android" && app.android?.googleServicesFile) {
|
|
1757
|
+
const edits = [[
|
|
1758
|
+
"build.gradle",
|
|
1759
|
+
"classpath(\"org.jetbrains.kotlin:kotlin-gradle-plugin\")",
|
|
1760
|
+
` classpath("com.google.gms:google-services:${GOOGLE_SERVICES_VERSION}")`
|
|
1761
|
+
], [
|
|
1762
|
+
"app/build.gradle",
|
|
1763
|
+
"apply plugin: \"com.facebook.react\"",
|
|
1764
|
+
"apply plugin: \"com.google.gms.google-services\""
|
|
1765
|
+
]];
|
|
1766
|
+
for (const [file, anchor, insertion] of edits) {
|
|
1767
|
+
if (relativePath !== file) continue;
|
|
1768
|
+
const next = insertAfterLine(rendered, anchor, insertion);
|
|
1769
|
+
if (next === rendered) {
|
|
1770
|
+
throw new Error(`[vxrn] prebuild template ${file} lost its ${anchor} anchor`);
|
|
1771
|
+
}
|
|
1772
|
+
rendered = next;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
if (platform === "android" && relativePath === "app/proguard-rules.pro" && app.android?.proguardRules) {
|
|
1776
|
+
rendered = `${rendered.trimEnd()}
|
|
1777
|
+
|
|
1778
|
+
${app.android.proguardRules.trim()}
|
|
1779
|
+
`;
|
|
1780
|
+
}
|
|
1568
1781
|
for (const [field, setting] of [
|
|
1569
1782
|
["minSdk", "minSdkVersion"],
|
|
1570
1783
|
["targetSdk", "targetSdkVersion"],
|
|
@@ -1640,6 +1853,16 @@ const generateForPlatform = async (root, platform, app, outDir = path.resolve(ro
|
|
|
1640
1853
|
platform,
|
|
1641
1854
|
app
|
|
1642
1855
|
});
|
|
1856
|
+
if (platform === "ios") generateAccentColor({
|
|
1857
|
+
dest,
|
|
1858
|
+
app
|
|
1859
|
+
});
|
|
1860
|
+
copyAppResources({
|
|
1861
|
+
root,
|
|
1862
|
+
dest,
|
|
1863
|
+
platform,
|
|
1864
|
+
app
|
|
1865
|
+
});
|
|
1643
1866
|
generateSceneDelegate({
|
|
1644
1867
|
dest,
|
|
1645
1868
|
platform,
|