vxrn 2.0.0-beta.129.1 → 2.0.0-beta.131.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 +175 -15
- package/dist/exports/prebuildWithoutExpo.mjs.map +1 -1
- package/dist/exports/prebuildWithoutExpo.native.js +306 -50
- package/dist/exports/prebuildWithoutExpo.native.js.map +1 -1
- package/dist/plugins/reactNativeDevServer.mjs +46 -22
- package/dist/plugins/reactNativeDevServer.mjs.map +1 -1
- package/dist/plugins/reactNativeDevServer.native.js +52 -26
- package/dist/plugins/reactNativeDevServer.native.js.map +1 -1
- package/package.json +10 -10
- package/src/exports/prebuildWithoutExpo.test.ts +253 -2
- package/src/exports/prebuildWithoutExpo.ts +277 -29
- package/src/plugins/reactNativeDevServer.ts +77 -24
- package/types/exports/prebuildWithoutExpo.d.ts.map +1 -1
- package/types/plugins/reactNativeDevServer.d.ts.map +1 -1
|
@@ -10,6 +10,8 @@ import { swiftPackageDirectories } from "../utils/swiftPackageId.mjs";
|
|
|
10
10
|
const nativeProjectPatches = module.createRequire(import.meta.url)("../../native-project-patches.cjs");
|
|
11
11
|
const notificationsHost = nativeProjectPatches.ONE_NOTIFICATIONS;
|
|
12
12
|
const updatesHost = nativeProjectPatches.ONE_UPDATES;
|
|
13
|
+
const PORTRAIT_ORIENTATIONS = ["UIInterfaceOrientationPortrait", "UIInterfaceOrientationPortraitUpsideDown"];
|
|
14
|
+
const LANDSCAPE_ORIENTATIONS = ["UIInterfaceOrientationLandscapeLeft", "UIInterfaceOrientationLandscapeRight"];
|
|
13
15
|
const validatePrebuildApp = validateNativeApp;
|
|
14
16
|
const ANDROID_DENSITIES = {
|
|
15
17
|
mdpi: 1,
|
|
@@ -245,7 +247,7 @@ function patchIosPbxprojSceneDelegate(rendered, appName) {
|
|
|
245
247
|
}
|
|
246
248
|
return patched;
|
|
247
249
|
}
|
|
248
|
-
function
|
|
250
|
+
function patchIosPbxprojAppEntitlements(rendered, appName) {
|
|
249
251
|
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 */,`]];
|
|
250
252
|
let patched = rendered;
|
|
251
253
|
for (const [anchor, insertion] of edits) {
|
|
@@ -262,13 +264,55 @@ function patchIosPbxprojPushEntitlements(rendered, appName) {
|
|
|
262
264
|
return patched.split(setting).join(`${setting}
|
|
263
265
|
CODE_SIGN_ENTITLEMENTS = ${appName}/${appName}.entitlements;`);
|
|
264
266
|
}
|
|
265
|
-
function
|
|
267
|
+
function renderPlistValue(value, indent) {
|
|
268
|
+
if (typeof value === "string") return `${indent}<string>${escapeXml(value)}</string>`;
|
|
269
|
+
if (typeof value === "boolean") return `${indent}<${value}/>`;
|
|
270
|
+
if (typeof value === "number") {
|
|
271
|
+
return Number.isInteger(value) ? `${indent}<integer>${value}</integer>` : `${indent}<real>${value}</real>`;
|
|
272
|
+
}
|
|
273
|
+
if (Array.isArray(value)) {
|
|
274
|
+
return `${indent}<array>
|
|
275
|
+
${value.map((item) => renderPlistValue(item, `${indent} `)).join("\n")}
|
|
276
|
+
${indent}</array>`;
|
|
277
|
+
}
|
|
278
|
+
return `${indent}<dict>
|
|
279
|
+
${renderPlistEntries(value, `${indent} `)}
|
|
280
|
+
${indent}</dict>`;
|
|
281
|
+
}
|
|
282
|
+
function renderPlistEntries(entries, indent) {
|
|
283
|
+
return Object.entries(entries).map(([key, value]) => `${indent}<key>${escapeXml(key)}</key>
|
|
284
|
+
${renderPlistValue(value, indent)}`).join("\n");
|
|
285
|
+
}
|
|
286
|
+
function appEntitlements(app) {
|
|
287
|
+
const modeled = {};
|
|
288
|
+
if (app.notifications?.push === true || app.ios?.widgets?.pushNotifications) {
|
|
289
|
+
modeled["aps-environment"] = notificationsHost.apsEnvironment;
|
|
290
|
+
}
|
|
291
|
+
if (app.ios?.widgets) {
|
|
292
|
+
modeled["com.apple.security.application-groups"] = [app.ios.widgets.appGroup];
|
|
293
|
+
}
|
|
294
|
+
if (app.ios?.associatedDomains?.length) {
|
|
295
|
+
modeled["com.apple.developer.associated-domains"] = app.ios.associatedDomains;
|
|
296
|
+
}
|
|
297
|
+
if (app.ios?.usesAppleSignIn) {
|
|
298
|
+
modeled["com.apple.developer.applesignin"] = ["Default"];
|
|
299
|
+
}
|
|
300
|
+
for (const key of Object.keys(app.ios?.entitlements ?? {})) {
|
|
301
|
+
if (key in modeled) {
|
|
302
|
+
throw new Error(`[vxrn] native.app.ios.entitlements sets ${key}, which native.app already writes: use its field`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
...modeled,
|
|
307
|
+
...app.ios?.entitlements
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function renderEntitlements(entries) {
|
|
266
311
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
267
312
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
268
313
|
<plist version="1.0">
|
|
269
314
|
<dict>
|
|
270
|
-
|
|
271
|
-
<string>${notificationsHost.apsEnvironment}</string>
|
|
315
|
+
${renderPlistEntries(entries, " ")}
|
|
272
316
|
</dict>
|
|
273
317
|
</plist>
|
|
274
318
|
`;
|
|
@@ -407,8 +451,9 @@ function generateSceneDelegate(args) {
|
|
|
407
451
|
const { dest, platform, app } = args;
|
|
408
452
|
if (platform !== "ios") return;
|
|
409
453
|
FSExtra.writeFileSync(path.join(dest, app.name, "SceneDelegate.swift"), renderSceneDelegateSwift(app.name));
|
|
410
|
-
|
|
411
|
-
|
|
454
|
+
const entitlements = appEntitlements(app);
|
|
455
|
+
if (Object.keys(entitlements).length && !app.ios?.widgets) {
|
|
456
|
+
FSExtra.writeFileSync(path.join(dest, app.name, `${app.name}.entitlements`), renderEntitlements(entitlements));
|
|
412
457
|
}
|
|
413
458
|
}
|
|
414
459
|
function generateIosWidgets(dest, app) {
|
|
@@ -421,7 +466,7 @@ function generateIosWidgets(dest, app) {
|
|
|
421
466
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
422
467
|
<plist version="1.0"><dict><key>com.apple.security.application-groups</key><array><string>${escapeXml(widgets.appGroup)}</string></array></dict></plist>
|
|
423
468
|
`;
|
|
424
|
-
FSExtra.writeFileSync(path.join(appDir, "OneAppWidgets.entitlements"),
|
|
469
|
+
FSExtra.writeFileSync(path.join(appDir, "OneAppWidgets.entitlements"), renderEntitlements(appEntitlements(app)));
|
|
425
470
|
FSExtra.writeFileSync(path.join(extensionDir, "OneWidgets.entitlements"), entitlements);
|
|
426
471
|
FSExtra.writeFileSync(path.join(extensionDir, "WidgetInfo.plist"), `<?xml version="1.0" encoding="UTF-8"?>
|
|
427
472
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -964,6 +1009,46 @@ async function generateAppIcons(args) {
|
|
|
964
1009
|
}
|
|
965
1010
|
}
|
|
966
1011
|
}
|
|
1012
|
+
async function generateAdaptiveIcon(args) {
|
|
1013
|
+
const { root, dest, app } = args;
|
|
1014
|
+
const adaptiveIcon = app.android?.adaptiveIcon;
|
|
1015
|
+
if (!adaptiveIcon) return;
|
|
1016
|
+
const res = path.join(dest, "app", "src", "main", "res");
|
|
1017
|
+
const layers = {
|
|
1018
|
+
foreground: adaptiveIcon.foreground,
|
|
1019
|
+
background: adaptiveIcon.background,
|
|
1020
|
+
monochrome: adaptiveIcon.monochrome
|
|
1021
|
+
};
|
|
1022
|
+
for (const [layer, file] of Object.entries(layers)) {
|
|
1023
|
+
if (!file) continue;
|
|
1024
|
+
const source = path.resolve(root, file);
|
|
1025
|
+
if (!FSExtra.existsSync(source)) {
|
|
1026
|
+
throw new Error(`[vxrn] native.app.android.adaptiveIcon.${layer} does not exist: ${source}`);
|
|
1027
|
+
}
|
|
1028
|
+
for (const [density, multiplier] of Object.entries(ANDROID_DENSITIES)) {
|
|
1029
|
+
const pixels = 108 * multiplier;
|
|
1030
|
+
await sharp(source).rotate().resize(pixels, pixels, { fit: "cover" }).png().toFile(path.join(res, `mipmap-${density}`, `ic_launcher_${layer}.png`));
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
if (!adaptiveIcon.background) {
|
|
1034
|
+
FSExtra.writeFileSync(path.join(res, "values", "ic_launcher_background.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
1035
|
+
<resources>
|
|
1036
|
+
<color name="ic_launcher_background">${adaptiveIcon.backgroundColor ?? "#FFFFFF"}</color>
|
|
1037
|
+
</resources>
|
|
1038
|
+
`);
|
|
1039
|
+
}
|
|
1040
|
+
const adaptiveXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
1041
|
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
1042
|
+
<background android:drawable="${adaptiveIcon.background ? "@mipmap/ic_launcher_background" : "@color/ic_launcher_background"}"/>
|
|
1043
|
+
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
1044
|
+
${adaptiveIcon.monochrome ? " <monochrome android:drawable=\"@mipmap/ic_launcher_monochrome\"/>\n" : ""}</adaptive-icon>
|
|
1045
|
+
`;
|
|
1046
|
+
const anydpi = path.join(res, "mipmap-anydpi-v26");
|
|
1047
|
+
FSExtra.mkdirSync(anydpi, { recursive: true });
|
|
1048
|
+
for (const filename of ["ic_launcher.xml", "ic_launcher_round.xml"]) {
|
|
1049
|
+
FSExtra.writeFileSync(path.join(anydpi, filename), adaptiveXml);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
967
1052
|
async function generateSplashScreen(args) {
|
|
968
1053
|
const { root, dest, platform, app } = args;
|
|
969
1054
|
if (!app.splash) return;
|
|
@@ -971,7 +1056,9 @@ async function generateSplashScreen(args) {
|
|
|
971
1056
|
if (!FSExtra.existsSync(source)) {
|
|
972
1057
|
throw new Error(`[vxrn] native.app.splash source does not exist: ${source}`);
|
|
973
1058
|
}
|
|
974
|
-
const
|
|
1059
|
+
const cover = app.splash.resizeMode === "cover";
|
|
1060
|
+
const image = sharp(source).rotate();
|
|
1061
|
+
const { data: artwork, info: metadata } = await (cover ? image : image.trim({ background: app.splash.backgroundColor })).png().toBuffer({ resolveWithObject: true });
|
|
975
1062
|
if (!metadata.width || !metadata.height) {
|
|
976
1063
|
throw new Error("[vxrn] native.app.splash source must be an image");
|
|
977
1064
|
}
|
|
@@ -1012,14 +1099,17 @@ async function generateSplashScreen(args) {
|
|
|
1012
1099
|
<view key="view" contentMode="scaleToFill" id="launch-view">
|
|
1013
1100
|
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
|
|
1014
1101
|
<subviews>
|
|
1015
|
-
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" image="Splash" translatesAutoresizingMaskIntoConstraints="NO" id="splash-image"/>
|
|
1102
|
+
<imageView userInteractionEnabled="NO" contentMode="${cover ? "scaleAspectFill" : "scaleAspectFit"}" image="Splash" translatesAutoresizingMaskIntoConstraints="NO" id="splash-image"/>
|
|
1016
1103
|
</subviews>
|
|
1017
1104
|
<color key="backgroundColor" red="${red}" green="${green}" blue="${blue}" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
1018
1105
|
<constraints>
|
|
1019
|
-
<constraint firstItem="splash-image" firstAttribute="
|
|
1106
|
+
${cover ? ` <constraint firstItem="splash-image" firstAttribute="leading" secondItem="launch-view" secondAttribute="leading" id="splash-leading"/>
|
|
1107
|
+
<constraint firstItem="splash-image" firstAttribute="trailing" secondItem="launch-view" secondAttribute="trailing" id="splash-trailing"/>
|
|
1108
|
+
<constraint firstItem="splash-image" firstAttribute="top" secondItem="launch-view" secondAttribute="top" id="splash-top"/>
|
|
1109
|
+
<constraint firstItem="splash-image" firstAttribute="bottom" secondItem="launch-view" secondAttribute="bottom" id="splash-bottom"/>` : ` <constraint firstItem="splash-image" firstAttribute="centerX" secondItem="launch-view" secondAttribute="centerX" id="splash-center-x"/>
|
|
1020
1110
|
<constraint firstItem="splash-image" firstAttribute="centerY" secondItem="launch-view" secondAttribute="centerY" id="splash-center-y"/>
|
|
1021
1111
|
<constraint firstItem="splash-image" firstAttribute="width" constant="${artworkWidth}" id="splash-width"/>
|
|
1022
|
-
<constraint firstItem="splash-image" firstAttribute="height" constant="${artworkHeight}" id="splash-height"
|
|
1112
|
+
<constraint firstItem="splash-image" firstAttribute="height" constant="${artworkHeight}" id="splash-height"/>`}
|
|
1023
1113
|
</constraints>
|
|
1024
1114
|
</view>
|
|
1025
1115
|
</viewController>
|
|
@@ -1161,6 +1251,27 @@ ${schemes.map((scheme) => ` <string>${scheme}</string>`).join("\n")}
|
|
|
1161
1251
|
stamps.push(` <key>${updatesHost.runtimeVersionInfoPlistKey}</key>
|
|
1162
1252
|
<string>${escapeXml(app.updates.runtimeVersion)}</string>`);
|
|
1163
1253
|
}
|
|
1254
|
+
if (app.userInterfaceStyle !== void 0) {
|
|
1255
|
+
stamps.push(` <key>UIUserInterfaceStyle</key>
|
|
1256
|
+
<string>${app.userInterfaceStyle === "light" ? "Light" : app.userInterfaceStyle === "dark" ? "Dark" : "Automatic"}</string>`);
|
|
1257
|
+
}
|
|
1258
|
+
if (app.orientation !== void 0) {
|
|
1259
|
+
const phoneOrientations = app.orientation === "portrait" ? PORTRAIT_ORIENTATIONS : app.orientation === "landscape" ? LANDSCAPE_ORIENTATIONS : [...PORTRAIT_ORIENTATIONS, ...LANDSCAPE_ORIENTATIONS];
|
|
1260
|
+
const phoneList = /\t<key>UISupportedInterfaceOrientations<\/key>\n\t<array>\n[\s\S]*?\t<\/array>/;
|
|
1261
|
+
if (!phoneList.test(rendered)) {
|
|
1262
|
+
throw new Error(`[vxrn] prebuild template ${relativePath} lost its UISupportedInterfaceOrientations list`);
|
|
1263
|
+
}
|
|
1264
|
+
rendered = rendered.replace(phoneList, ` <key>UISupportedInterfaceOrientations</key>
|
|
1265
|
+
<array>
|
|
1266
|
+
${phoneOrientations.map((orientation) => ` <string>${orientation}</string>`).join("\n")}
|
|
1267
|
+
</array>`);
|
|
1268
|
+
}
|
|
1269
|
+
for (const [key, value] of Object.entries(app.ios?.infoPlist ?? {})) {
|
|
1270
|
+
if (rendered.includes(`<key>${key}</key>`) || stamps.some((stamp) => stamp.includes(`<key>${key}</key>`))) {
|
|
1271
|
+
throw new Error(`[vxrn] native.app.ios.infoPlist sets ${key}, which the template or native.app already writes: use its field`);
|
|
1272
|
+
}
|
|
1273
|
+
stamps.push(renderPlistEntries({ [key]: value }, " "));
|
|
1274
|
+
}
|
|
1164
1275
|
if (stamps.length) {
|
|
1165
1276
|
const anchor = " <key>LSRequiresIPhoneOS</key>";
|
|
1166
1277
|
if (!rendered.includes(anchor)) throw new Error(`[vxrn] prebuild template ${relativePath} lost its LSRequiresIPhoneOS anchor`);
|
|
@@ -1265,6 +1376,44 @@ ${line}
|
|
|
1265
1376
|
`;
|
|
1266
1377
|
}
|
|
1267
1378
|
}
|
|
1379
|
+
if (platform === "android" && relativePath === "app/src/main/res/values/styles.xml" && (app.userInterfaceStyle === "light" || app.userInterfaceStyle === "dark")) {
|
|
1380
|
+
const dayNight = "parent=\"Theme.AppCompat.DayNight.NoActionBar\"";
|
|
1381
|
+
if (!rendered.includes(dayNight)) {
|
|
1382
|
+
throw new Error(`[vxrn] cannot lock userInterfaceStyle: expected ${dayNight} in app/src/main/res/values/styles.xml`);
|
|
1383
|
+
}
|
|
1384
|
+
rendered = rendered.replace(dayNight, app.userInterfaceStyle === "light" ? "parent=\"Theme.AppCompat.Light.NoActionBar\"" : "parent=\"Theme.AppCompat.NoActionBar\"");
|
|
1385
|
+
}
|
|
1386
|
+
if (platform === "android" && relativePath === "app/src/main/AndroidManifest.xml" && (app.android?.permissions?.length || app.android?.blockedPermissions?.length)) {
|
|
1387
|
+
const anchor = "<uses-permission android:name=\"android.permission.INTERNET\" />";
|
|
1388
|
+
if (!rendered.includes(anchor)) {
|
|
1389
|
+
throw new Error("[vxrn] cannot stamp permissions: expected the INTERNET permission in app/src/main/AndroidManifest.xml");
|
|
1390
|
+
}
|
|
1391
|
+
const permissionName = (name) => name.includes(".") ? name : `android.permission.${name}`;
|
|
1392
|
+
const lines = [...(app.android?.permissions ?? []).map((name) => ` <uses-permission android:name="${permissionName(name)}" />`), ...(app.android?.blockedPermissions ?? []).map((name) => ` <uses-permission android:name="${permissionName(name)}" tools:node="remove" />`)];
|
|
1393
|
+
rendered = rendered.replace(anchor, `${anchor}
|
|
1394
|
+
${lines.join("\n")}`);
|
|
1395
|
+
if (app.android?.blockedPermissions?.length && !rendered.includes("xmlns:tools=")) {
|
|
1396
|
+
rendered = rendered.replace("xmlns:android=\"http://schemas.android.com/apk/res/android\"", "xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools=\"http://schemas.android.com/tools\"");
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
if (platform === "android" && relativePath === "app/src/main/AndroidManifest.xml" && app.android?.appLinks?.length) {
|
|
1400
|
+
rendered = rendered.replace(" </activity>", ` <intent-filter android:autoVerify="true">
|
|
1401
|
+
<action android:name="android.intent.action.VIEW" />
|
|
1402
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
1403
|
+
<category android:name="android.intent.category.BROWSABLE" />
|
|
1404
|
+
<data android:scheme="https" />
|
|
1405
|
+
${app.android.appLinks.map((link) => ` <data android:host="${link.host}"${link.pathPrefix ? ` android:pathPrefix="${link.pathPrefix}"` : ""} />`).join("\n")}
|
|
1406
|
+
</intent-filter>
|
|
1407
|
+
</activity>`);
|
|
1408
|
+
}
|
|
1409
|
+
if (platform === "android" && relativePath === "app/src/main/AndroidManifest.xml" && app.orientation !== void 0) {
|
|
1410
|
+
const anchor = "android:name=\".MainActivity\"";
|
|
1411
|
+
if (!rendered.includes(anchor)) {
|
|
1412
|
+
throw new Error("[vxrn] cannot stamp the orientation: expected .MainActivity in app/src/main/AndroidManifest.xml");
|
|
1413
|
+
}
|
|
1414
|
+
rendered = rendered.replace(anchor, `${anchor}
|
|
1415
|
+
android:screenOrientation="${app.orientation === "default" ? "unspecified" : app.orientation}"`);
|
|
1416
|
+
}
|
|
1268
1417
|
if (platform === "android" && relativePath === "app/src/main/AndroidManifest.xml" && app.pictureInPicture) {
|
|
1269
1418
|
const anchor = "android:name=\".MainActivity\"";
|
|
1270
1419
|
if (!rendered.includes(anchor)) {
|
|
@@ -1370,8 +1519,8 @@ end`);
|
|
|
1370
1519
|
rendered = patchIosBundlePhase(rendered, app.updates?.runtimeVersion);
|
|
1371
1520
|
rendered = patchIosPbxprojSceneDelegate(rendered, appName);
|
|
1372
1521
|
rendered = patchIosPbxprojOneBridgingHeader(rendered, appName);
|
|
1373
|
-
if (app.
|
|
1374
|
-
rendered =
|
|
1522
|
+
if (Object.keys(appEntitlements(app)).length && !app.ios?.widgets) {
|
|
1523
|
+
rendered = patchIosPbxprojAppEntitlements(rendered, appName);
|
|
1375
1524
|
}
|
|
1376
1525
|
if (app.ios?.widgets) rendered = patchIosPbxprojWidgets(rendered, app);
|
|
1377
1526
|
}
|
|
@@ -1416,8 +1565,14 @@ use_frameworks! :linkage => :${app.ios.useFrameworks}`);
|
|
|
1416
1565
|
}
|
|
1417
1566
|
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)`);
|
|
1418
1567
|
}
|
|
1419
|
-
|
|
1420
|
-
|
|
1568
|
+
for (const [field, setting] of [
|
|
1569
|
+
["minSdk", "minSdkVersion"],
|
|
1570
|
+
["targetSdk", "targetSdkVersion"],
|
|
1571
|
+
["compileSdk", "compileSdkVersion"]
|
|
1572
|
+
]) {
|
|
1573
|
+
const value = platform === "android" ? app.android?.[field] : void 0;
|
|
1574
|
+
if (value === void 0) continue;
|
|
1575
|
+
rendered = rendered.replace(new RegExp(`${setting} = \\d+`, "g"), `${setting} = ${value}`);
|
|
1421
1576
|
}
|
|
1422
1577
|
}
|
|
1423
1578
|
return {
|
|
@@ -1474,6 +1629,11 @@ const generateForPlatform = async (root, platform, app, outDir = path.resolve(ro
|
|
|
1474
1629
|
platform,
|
|
1475
1630
|
app
|
|
1476
1631
|
});
|
|
1632
|
+
if (platform === "android") await generateAdaptiveIcon({
|
|
1633
|
+
root,
|
|
1634
|
+
dest,
|
|
1635
|
+
app
|
|
1636
|
+
});
|
|
1477
1637
|
await generateSplashScreen({
|
|
1478
1638
|
root,
|
|
1479
1639
|
dest,
|