vxrn 2.13.8 → 2.13.9
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/cli.mjs +3 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/cli.native.js +5 -2
- package/dist/cli.native.js.map +1 -1
- package/dist/config/getBaseViteConfigOnly.mjs +3 -3
- package/dist/config/getBaseViteConfigOnly.mjs.map +1 -1
- package/dist/config/getBaseViteConfigOnly.native.js +3 -3
- package/dist/config/getBaseViteConfigOnly.native.js.map +1 -1
- package/dist/config/getOptionsFilled.mjs +24 -2
- package/dist/config/getOptionsFilled.mjs.map +1 -1
- package/dist/config/getOptionsFilled.native.js +25 -2
- package/dist/config/getOptionsFilled.native.js.map +1 -1
- package/dist/config/getServerOptionsFilled.mjs +119 -1
- package/dist/config/getServerOptionsFilled.mjs.map +1 -1
- package/dist/config/getServerOptionsFilled.native.js +137 -1
- package/dist/config/getServerOptionsFilled.native.js.map +1 -1
- package/dist/exports/build.mjs +5 -5
- package/dist/exports/build.mjs.map +1 -1
- package/dist/exports/build.native.js +5 -5
- package/dist/exports/build.native.js.map +1 -1
- package/dist/exports/dev.mjs +4 -6
- package/dist/exports/dev.mjs.map +1 -1
- package/dist/exports/dev.native.js +6 -6
- package/dist/exports/dev.native.js.map +1 -1
- package/dist/exports/prebuild.mjs +4 -4
- package/dist/exports/prebuild.mjs.map +1 -1
- package/dist/exports/prebuild.native.js +4 -4
- package/dist/exports/prebuild.native.js.map +1 -1
- package/dist/exports/prebuildWithoutExpo.mjs +95 -88
- package/dist/exports/prebuildWithoutExpo.mjs.map +1 -1
- package/dist/exports/prebuildWithoutExpo.native.js +95 -88
- package/dist/exports/prebuildWithoutExpo.native.js.map +1 -1
- package/dist/plugins/autoDepOptimizePlugin.mjs +3 -3
- package/dist/plugins/autoDepOptimizePlugin.mjs.map +1 -1
- package/dist/plugins/autoDepOptimizePlugin.native.js +3 -3
- package/dist/plugins/autoDepOptimizePlugin.native.js.map +1 -1
- package/dist/plugins/reactNativeDevAssetPlugin.mjs +4 -4
- package/dist/plugins/reactNativeDevAssetPlugin.mjs.map +1 -1
- package/dist/plugins/reactNativeDevAssetPlugin.native.js +4 -4
- package/dist/plugins/reactNativeDevAssetPlugin.native.js.map +1 -1
- package/dist/rn-commands/bundle/buildBundle.mjs +18 -5
- package/dist/rn-commands/bundle/buildBundle.mjs.map +1 -1
- package/dist/rn-commands/bundle/buildBundle.native.js +18 -5
- package/dist/rn-commands/bundle/buildBundle.native.js.map +1 -1
- package/dist/user-interface/index.mjs +1 -1
- package/dist/user-interface/index.mjs.map +1 -1
- package/dist/user-interface/index.native.js +1 -1
- package/dist/user-interface/index.native.js.map +1 -1
- package/dist/utils/env-editor.mjs +198 -0
- package/dist/utils/env-editor.mjs.map +1 -0
- package/dist/utils/env-editor.native.js +266 -0
- package/dist/utils/env-editor.native.js.map +1 -0
- package/dist/utils/fs.mjs +48 -0
- package/dist/utils/fs.mjs.map +1 -0
- package/dist/utils/fs.native.js +48 -0
- package/dist/utils/fs.native.js.map +1 -0
- package/dist/utils/getVitePath.mjs +2 -2
- package/dist/utils/getVitePath.mjs.map +1 -1
- package/dist/utils/getVitePath.native.js +2 -2
- package/dist/utils/getVitePath.native.js.map +1 -1
- package/dist/utils/patches.mjs +38 -29
- package/dist/utils/patches.mjs.map +1 -1
- package/dist/utils/patches.native.js +38 -29
- package/dist/utils/patches.native.js.map +1 -1
- package/dist/utils/scanDepsToOptimize.mjs +12 -11
- package/dist/utils/scanDepsToOptimize.mjs.map +1 -1
- package/dist/utils/scanDepsToOptimize.native.js +12 -11
- package/dist/utils/scanDepsToOptimize.native.js.map +1 -1
- package/dist/utils/state.mjs +5 -5
- package/dist/utils/state.mjs.map +1 -1
- package/dist/utils/state.native.js +5 -5
- package/dist/utils/state.native.js.map +1 -1
- package/dist/utils/utils.mjs +4 -3
- package/dist/utils/utils.mjs.map +1 -1
- package/dist/utils/utils.native.js +4 -3
- package/dist/utils/utils.native.js.map +1 -1
- package/package.json +12 -18
- package/src/cli.ts +5 -4
- package/src/config/getBaseViteConfigOnly.ts +3 -3
- package/src/config/getOptionsFilled.ts +35 -2
- package/src/config/getServerOptionsFilled.test.ts +37 -0
- package/src/config/getServerOptionsFilled.ts +57 -1
- package/src/exports/build.ts +5 -5
- package/src/exports/clean.test.ts +1 -1
- package/src/exports/dev.ts +5 -6
- package/src/exports/prebuild.ts +4 -4
- package/src/exports/prebuildWithoutExpo.ts +102 -89
- package/src/plugins/autoDepOptimizePlugin.ts +3 -3
- package/src/plugins/reactNativeDevAssetPlugin.ts +4 -4
- package/src/rn-commands/bundle/buildBundle.ts +15 -5
- package/src/user-interface/index.ts +1 -1
- package/src/utils/env-editor.LICENSE +9 -0
- package/src/utils/env-editor.ts +214 -0
- package/src/utils/fs.ts +59 -0
- package/src/utils/getVitePath.ts +2 -2
- package/src/utils/patches.test.ts +36 -36
- package/src/utils/patches.ts +39 -27
- package/src/utils/scanDepsToOptimize.test.ts +2 -2
- package/src/utils/scanDepsToOptimize.ts +6 -5
- package/src/utils/state.ts +5 -7
- package/src/utils/utils.ts +5 -5
- package/types/config/getOptionsFilled.d.ts +9 -2
- package/types/config/getOptionsFilled.d.ts.map +1 -1
- package/types/config/getServerOptionsFilled.d.ts.map +1 -1
- package/types/exports/build.d.ts +1 -1
- package/types/exports/dev.d.ts.map +1 -1
- package/types/exports/prebuildWithoutExpo.d.ts.map +1 -1
- package/types/rn-commands/bundle/buildBundle.d.ts.map +1 -1
- package/types/user-interface/index.d.ts.map +1 -1
- package/types/utils/env-editor.d.ts +9 -0
- package/types/utils/env-editor.d.ts.map +1 -0
- package/types/utils/fs.d.ts +9 -0
- package/types/utils/fs.d.ts.map +1 -0
- package/types/utils/patches.d.ts.map +1 -1
- package/types/utils/scanDepsToOptimize.d.ts.map +1 -1
- package/types/utils/state.d.ts.map +1 -1
- package/types/utils/utils.d.ts +2 -2
- package/types/utils/utils.d.ts.map +1 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
+
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
|
|
3
4
|
import module from "node:module";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { pathToFileURL } from "node:url";
|
|
6
7
|
import { androidAppPermissions, androidIconSuffix, appIconPreviewResources, iosUsageDescriptions, validateNativeApp } from "@vxrn/utils/nativeAppManifest";
|
|
7
|
-
import FSExtra from "fs-extra";
|
|
8
8
|
import sharp from "sharp";
|
|
9
|
+
import { readJSONSync } from "../utils/fs.mjs";
|
|
9
10
|
import { swiftPackageDirectories } from "../utils/swiftPackageId.mjs";
|
|
10
11
|
|
|
11
12
|
const requireVxrn = module.createRequire(import.meta.url);
|
|
@@ -186,7 +187,7 @@ ${imports.join("\n")}
|
|
|
186
187
|
`;
|
|
187
188
|
}
|
|
188
189
|
function generateOneBridgingHeader(dest, app) {
|
|
189
|
-
|
|
190
|
+
writeFileSync(path.join(dest, app.name, ONE_BRIDGING_HEADER_NAME), renderOneBridgingHeader(app));
|
|
190
191
|
}
|
|
191
192
|
function patchIosPbxprojOneBridgingHeader(project, appName) {
|
|
192
193
|
const anchor = `INFOPLIST_FILE = ${appName}/Info.plist;`;
|
|
@@ -312,11 +313,11 @@ function copyAppResources({ root, dest, platform, app }) {
|
|
|
312
313
|
}
|
|
313
314
|
for (const [file, target] of copies) {
|
|
314
315
|
const source = path.resolve(root, file);
|
|
315
|
-
if (!
|
|
316
|
+
if (!existsSync(source)) {
|
|
316
317
|
throw new Error(`[vxrn] native.app names ${file}, which does not exist`);
|
|
317
318
|
}
|
|
318
|
-
|
|
319
|
-
|
|
319
|
+
mkdirSync(path.dirname(target), { recursive: true });
|
|
320
|
+
copyFileSync(source, target);
|
|
320
321
|
}
|
|
321
322
|
}
|
|
322
323
|
function patchIosPbxprojAppEntitlements(rendered, appName) {
|
|
@@ -522,29 +523,29 @@ ${value}`);
|
|
|
522
523
|
function generateSceneDelegate(args) {
|
|
523
524
|
const { dest, platform, app } = args;
|
|
524
525
|
if (platform !== "ios") return;
|
|
525
|
-
|
|
526
|
+
writeFileSync(path.join(dest, app.name, "SceneDelegate.swift"), renderSceneDelegateSwift(app.name));
|
|
526
527
|
const entitlements = appEntitlements(app);
|
|
527
528
|
if (Object.keys(entitlements).length && !app.ios?.widgets) {
|
|
528
|
-
|
|
529
|
+
writeFileSync(path.join(dest, app.name, `${app.name}.entitlements`), renderEntitlements(entitlements));
|
|
529
530
|
}
|
|
530
531
|
}
|
|
531
532
|
function generateIosAppIntents(dest, platform, app) {
|
|
532
533
|
if (platform !== "ios" || !app.ios?.appIntents) return;
|
|
533
|
-
|
|
534
|
+
writeFileSync(path.join(dest, app.name, "OneAppIntents.swift"), renderIosAppIntentsSwift(app.ios.appIntents.actions));
|
|
534
535
|
}
|
|
535
536
|
function generateIosWidgets(dest, app) {
|
|
536
537
|
const widgets = app.ios?.widgets;
|
|
537
538
|
if (!widgets) return;
|
|
538
539
|
const appDir = path.join(dest, app.name);
|
|
539
540
|
const extensionDir = path.join(dest, "OneWidgets");
|
|
540
|
-
|
|
541
|
+
mkdirSync(extensionDir, { recursive: true });
|
|
541
542
|
const entitlements = `<?xml version="1.0" encoding="UTF-8"?>
|
|
542
543
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
543
544
|
<plist version="1.0"><dict><key>com.apple.security.application-groups</key><array><string>${escapeXml(widgets.appGroup)}</string></array></dict></plist>
|
|
544
545
|
`;
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
546
|
+
writeFileSync(path.join(appDir, "OneAppWidgets.entitlements"), renderEntitlements(appEntitlements(app)));
|
|
547
|
+
writeFileSync(path.join(extensionDir, "OneWidgets.entitlements"), entitlements);
|
|
548
|
+
writeFileSync(path.join(extensionDir, "WidgetInfo.plist"), `<?xml version="1.0" encoding="UTF-8"?>
|
|
548
549
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
549
550
|
<plist version="1.0"><dict>
|
|
550
551
|
<key>CFBundleDevelopmentRegion</key><string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
@@ -559,7 +560,7 @@ function generateIosWidgets(dest, app) {
|
|
|
559
560
|
<key>NSExtension</key><dict><key>NSExtensionPointIdentifier</key><string>com.apple.widgetkit-extension</string></dict>
|
|
560
561
|
</dict></plist>
|
|
561
562
|
`);
|
|
562
|
-
|
|
563
|
+
writeFileSync(path.join(appDir, "OneWidgetContract.swift"), `import Foundation
|
|
563
564
|
import ActivityKit
|
|
564
565
|
|
|
565
566
|
enum OneWidgetContract {
|
|
@@ -584,7 +585,7 @@ enum OneWidgetContract {
|
|
|
584
585
|
}
|
|
585
586
|
}
|
|
586
587
|
`);
|
|
587
|
-
|
|
588
|
+
writeFileSync(path.join(extensionDir, "OneWidget.swift"), `import SwiftUI
|
|
588
589
|
import WidgetKit
|
|
589
590
|
import ActivityKit
|
|
590
591
|
|
|
@@ -872,7 +873,7 @@ struct OneWidgetsBundle: WidgetBundle {
|
|
|
872
873
|
}
|
|
873
874
|
}
|
|
874
875
|
`);
|
|
875
|
-
|
|
876
|
+
writeFileSync(path.join(appDir, "OneWidgetsBridge.m"), `#import <React/RCTBridgeModule.h>
|
|
876
877
|
#import <React/RCTEventEmitter.h>
|
|
877
878
|
|
|
878
879
|
@interface RCT_EXTERN_MODULE(OneWidgetsBridge, RCTEventEmitter)
|
|
@@ -886,7 +887,7 @@ RCT_EXTERN_METHOD(end:(NSString *)identifier resolver:(RCTPromiseResolveBlock)re
|
|
|
886
887
|
RCT_EXTERN_METHOD(pushToken:(NSString *)identifier resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
887
888
|
@end
|
|
888
889
|
`);
|
|
889
|
-
|
|
890
|
+
writeFileSync(path.join(appDir, "OneWidgetsBridge.swift"), `import Foundation
|
|
890
891
|
import React
|
|
891
892
|
import WidgetKit
|
|
892
893
|
import ActivityKit
|
|
@@ -1062,7 +1063,7 @@ async function writeAppearanceIcon(args) {
|
|
|
1062
1063
|
const variantSource = (variant) => {
|
|
1063
1064
|
if (!variant?.source) return source;
|
|
1064
1065
|
const resolved = path.resolve(root, variant.source);
|
|
1065
|
-
if (!
|
|
1066
|
+
if (!existsSync(resolved)) {
|
|
1066
1067
|
throw new Error(`[vxrn] native.app icon appearance source does not exist: ${resolved}`);
|
|
1067
1068
|
}
|
|
1068
1069
|
return resolved;
|
|
@@ -1094,7 +1095,7 @@ async function writeAppearanceIcon(args) {
|
|
|
1094
1095
|
await render("icon-1024-tinted.png", variantSource(icon.tinted), icon.tinted.backgroundColor ?? "#000000", true);
|
|
1095
1096
|
images.push(entry("icon-1024-tinted.png", "tinted"));
|
|
1096
1097
|
}
|
|
1097
|
-
|
|
1098
|
+
writeFileSync(path.join(iconDir, "Contents.json"), `${JSON.stringify({
|
|
1098
1099
|
images,
|
|
1099
1100
|
info: {
|
|
1100
1101
|
author: "xcode",
|
|
@@ -1108,11 +1109,11 @@ async function generateAppIcons(args) {
|
|
|
1108
1109
|
if (!app.icon) return;
|
|
1109
1110
|
if (platform === "ios") {
|
|
1110
1111
|
const assetsDir = path.join(dest, app.name, "Images.xcassets");
|
|
1111
|
-
const template = JSON.parse(
|
|
1112
|
+
const template = JSON.parse(readFileSync(path.join(assetsDir, "AppIcon.appiconset", "Contents.json"), "utf8"));
|
|
1112
1113
|
const icons = [["AppIcon", app.icon], ...Object.entries(app.alternateIcons ?? {})];
|
|
1113
1114
|
for (const [name, icon] of icons) {
|
|
1114
1115
|
const source2 = path.resolve(root, icon.source);
|
|
1115
|
-
if (!
|
|
1116
|
+
if (!existsSync(source2)) {
|
|
1116
1117
|
throw new Error(`[vxrn] native.app icon source does not exist: ${source2}`);
|
|
1117
1118
|
}
|
|
1118
1119
|
const metadata2 = await sharp(source2).metadata();
|
|
@@ -1120,7 +1121,7 @@ async function generateAppIcons(args) {
|
|
|
1120
1121
|
throw new Error(`[vxrn] native.app icon source must be a square image at least 1024px wide: ${source2}`);
|
|
1121
1122
|
}
|
|
1122
1123
|
const iconDir = path.join(assetsDir, `${name}.appiconset`);
|
|
1123
|
-
|
|
1124
|
+
mkdirSync(iconDir, { recursive: true });
|
|
1124
1125
|
if (icon.dark || icon.tinted) {
|
|
1125
1126
|
await writeAppearanceIcon({
|
|
1126
1127
|
root,
|
|
@@ -1148,13 +1149,13 @@ async function generateAppIcons(args) {
|
|
|
1148
1149
|
image.filename = filename;
|
|
1149
1150
|
await sharp(source2).rotate().resize(pixels, pixels, { fit: "cover" }).flatten({ background: icon.backgroundColor }).png().toFile(path.join(iconDir, filename));
|
|
1150
1151
|
}
|
|
1151
|
-
|
|
1152
|
+
writeFileSync(path.join(iconDir, "Contents.json"), `${JSON.stringify(contents, null, 2)}
|
|
1152
1153
|
`);
|
|
1153
1154
|
}
|
|
1154
1155
|
return;
|
|
1155
1156
|
}
|
|
1156
1157
|
const source = path.resolve(root, app.icon.source);
|
|
1157
|
-
if (!
|
|
1158
|
+
if (!existsSync(source)) {
|
|
1158
1159
|
throw new Error(`[vxrn] native.app.icon source does not exist: ${source}`);
|
|
1159
1160
|
}
|
|
1160
1161
|
const metadata = await sharp(source).metadata();
|
|
@@ -1167,7 +1168,7 @@ async function generateAppIcons(args) {
|
|
|
1167
1168
|
source
|
|
1168
1169
|
], ...await Promise.all(Object.entries(app.alternateIcons ?? {}).map(async ([name, icon]) => {
|
|
1169
1170
|
const alternateSource = path.resolve(root, icon.source);
|
|
1170
|
-
if (!
|
|
1171
|
+
if (!existsSync(alternateSource)) {
|
|
1171
1172
|
throw new Error(`[vxrn] native.app icon source does not exist: ${alternateSource}`);
|
|
1172
1173
|
}
|
|
1173
1174
|
const alternate = await sharp(alternateSource).metadata();
|
|
@@ -1234,8 +1235,8 @@ function generateAndroidIconForwarder(dest, app) {
|
|
|
1234
1235
|
if (!app.alternateIcons || !app.android) return;
|
|
1235
1236
|
const packageName = app.android.applicationId;
|
|
1236
1237
|
const file = path.join(dest, "app", "src", "main", "java", ...packageName.split("."), "AppIconLauncherActivity.kt");
|
|
1237
|
-
|
|
1238
|
-
|
|
1238
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
1239
|
+
writeFileSync(file, `package ${packageName}
|
|
1239
1240
|
|
|
1240
1241
|
import android.app.Activity
|
|
1241
1242
|
import android.content.Intent
|
|
@@ -1262,12 +1263,12 @@ async function generateAppIconPreviews(args) {
|
|
|
1262
1263
|
const resources = appIconPreviewResources(name);
|
|
1263
1264
|
if (platform === "android") {
|
|
1264
1265
|
const dir2 = path.join(dest, "app", "src", "main", "res", "drawable-nodpi");
|
|
1265
|
-
|
|
1266
|
+
mkdirSync(dir2, { recursive: true });
|
|
1266
1267
|
await preview(3).toFile(path.join(dir2, `${resources.android}.png`));
|
|
1267
1268
|
continue;
|
|
1268
1269
|
}
|
|
1269
1270
|
const dir = path.join(dest, app.name, "Images.xcassets", `${resources.ios}.imageset`);
|
|
1270
|
-
|
|
1271
|
+
mkdirSync(dir, { recursive: true });
|
|
1271
1272
|
const images = [];
|
|
1272
1273
|
for (const scale of [
|
|
1273
1274
|
1,
|
|
@@ -1282,7 +1283,7 @@ async function generateAppIconPreviews(args) {
|
|
|
1282
1283
|
scale: `${scale}x`
|
|
1283
1284
|
});
|
|
1284
1285
|
}
|
|
1285
|
-
|
|
1286
|
+
writeFileSync(path.join(dir, "Contents.json"), `${JSON.stringify({
|
|
1286
1287
|
images,
|
|
1287
1288
|
info: {
|
|
1288
1289
|
author: "xcode",
|
|
@@ -1305,7 +1306,7 @@ async function generateAdaptiveIcon(args) {
|
|
|
1305
1306
|
for (const [layer, file] of Object.entries(layers)) {
|
|
1306
1307
|
if (!file) continue;
|
|
1307
1308
|
const source = path.resolve(root, file);
|
|
1308
|
-
if (!
|
|
1309
|
+
if (!existsSync(source)) {
|
|
1309
1310
|
throw new Error(`[vxrn] native.app.android.adaptiveIcon.${layer} does not exist: ${source}`);
|
|
1310
1311
|
}
|
|
1311
1312
|
for (const [density, multiplier] of Object.entries(ANDROID_DENSITIES)) {
|
|
@@ -1314,7 +1315,7 @@ async function generateAdaptiveIcon(args) {
|
|
|
1314
1315
|
}
|
|
1315
1316
|
}
|
|
1316
1317
|
if (!adaptiveIcon.background) {
|
|
1317
|
-
|
|
1318
|
+
writeFileSync(path.join(res, "values", "ic_launcher_background.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
1318
1319
|
<resources>
|
|
1319
1320
|
<color name="ic_launcher_background">${adaptiveIcon.backgroundColor ?? "#FFFFFF"}</color>
|
|
1320
1321
|
</resources>
|
|
@@ -1327,9 +1328,9 @@ async function generateAdaptiveIcon(args) {
|
|
|
1327
1328
|
${adaptiveIcon.monochrome ? " <monochrome android:drawable=\"@mipmap/ic_launcher_monochrome\"/>\n" : ""}</adaptive-icon>
|
|
1328
1329
|
`;
|
|
1329
1330
|
const anydpi = path.join(res, "mipmap-anydpi-v26");
|
|
1330
|
-
|
|
1331
|
+
mkdirSync(anydpi, { recursive: true });
|
|
1331
1332
|
for (const filename of ["ic_launcher.xml", "ic_launcher_round.xml"]) {
|
|
1332
|
-
|
|
1333
|
+
writeFileSync(path.join(anydpi, filename), adaptiveXml);
|
|
1333
1334
|
}
|
|
1334
1335
|
}
|
|
1335
1336
|
const IOS_DARK_APPEARANCE = [{
|
|
@@ -1375,8 +1376,8 @@ function generateAccentColor(args) {
|
|
|
1375
1376
|
const accent = args.app.ios?.accentColor;
|
|
1376
1377
|
if (!accent) return;
|
|
1377
1378
|
const colorDir = path.join(args.dest, args.app.name, "Images.xcassets", "AccentColor.colorset");
|
|
1378
|
-
|
|
1379
|
-
|
|
1379
|
+
mkdirSync(colorDir, { recursive: true });
|
|
1380
|
+
writeFileSync(path.join(colorDir, "Contents.json"), xcodeColorSet(accent.light, accent.dark));
|
|
1380
1381
|
}
|
|
1381
1382
|
async function generateSplashScreen(args) {
|
|
1382
1383
|
const { root, dest, platform, app } = args;
|
|
@@ -1384,7 +1385,7 @@ async function generateSplashScreen(args) {
|
|
|
1384
1385
|
const cover = app.splash.resizeMode === "cover";
|
|
1385
1386
|
const prepareArtwork = async (sourcePath, backgroundColor) => {
|
|
1386
1387
|
const source = path.resolve(root, sourcePath);
|
|
1387
|
-
if (!
|
|
1388
|
+
if (!existsSync(source)) {
|
|
1388
1389
|
throw new Error(`[vxrn] native.app.splash source does not exist: ${source}`);
|
|
1389
1390
|
}
|
|
1390
1391
|
const { width: sourceWidth, format } = await sharp(source).metadata();
|
|
@@ -1403,7 +1404,7 @@ async function generateSplashScreen(args) {
|
|
|
1403
1404
|
const artworkHeight = Number((artworkWidth * (metadata.height / metadata.width)).toFixed(3));
|
|
1404
1405
|
const readBackground = (sourcePath) => {
|
|
1405
1406
|
const source = path.resolve(root, sourcePath);
|
|
1406
|
-
if (!
|
|
1407
|
+
if (!existsSync(source)) {
|
|
1407
1408
|
throw new Error(`[vxrn] native.app.splash backgroundImage does not exist: ${source}`);
|
|
1408
1409
|
}
|
|
1409
1410
|
return sharp(source).rotate().png().toBuffer({ resolveWithObject: true });
|
|
@@ -1413,7 +1414,7 @@ async function generateSplashScreen(args) {
|
|
|
1413
1414
|
const assets = path.join(appDir, "Images.xcassets");
|
|
1414
1415
|
const writeImageSet = async (name, light, dark2, pointWidth) => {
|
|
1415
1416
|
const dir = path.join(assets, `${name}.imageset`);
|
|
1416
|
-
|
|
1417
|
+
mkdirSync(dir, { recursive: true });
|
|
1417
1418
|
const scales = pointWidth === void 0 ? [1] : [
|
|
1418
1419
|
1,
|
|
1419
1420
|
2,
|
|
@@ -1442,7 +1443,7 @@ async function generateSplashScreen(args) {
|
|
|
1442
1443
|
});
|
|
1443
1444
|
}
|
|
1444
1445
|
}
|
|
1445
|
-
|
|
1446
|
+
writeFileSync(path.join(dir, "Contents.json"), `${JSON.stringify({
|
|
1446
1447
|
images,
|
|
1447
1448
|
info: {
|
|
1448
1449
|
author: "xcode",
|
|
@@ -1458,10 +1459,10 @@ async function generateSplashScreen(args) {
|
|
|
1458
1459
|
await writeImageSet("SplashBackgroundImage", background2.data, darkBackground2, void 0);
|
|
1459
1460
|
}
|
|
1460
1461
|
const colorDir = path.join(assets, "SplashBackground.colorset");
|
|
1461
|
-
|
|
1462
|
-
|
|
1462
|
+
mkdirSync(colorDir, { recursive: true });
|
|
1463
|
+
writeFileSync(path.join(colorDir, "Contents.json"), xcodeColorSet(app.splash.backgroundColor, dark?.backgroundColor));
|
|
1463
1464
|
const { red, green, blue } = srgb(app.splash.backgroundColor);
|
|
1464
|
-
|
|
1465
|
+
writeFileSync(path.join(appDir, "LaunchScreen.storyboard"), `<?xml version="1.0" encoding="UTF-8"?>
|
|
1465
1466
|
<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">
|
|
1466
1467
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
|
1467
1468
|
<dependencies>
|
|
@@ -1528,7 +1529,7 @@ ${cover ? ` <constraint firstItem="splash-image" firstAttribute="le
|
|
|
1528
1529
|
}
|
|
1529
1530
|
}).png().toBuffer();
|
|
1530
1531
|
const drawableDensity = path.join(mainRes, `${drawablePrefix}-${density}`);
|
|
1531
|
-
|
|
1532
|
+
mkdirSync(drawableDensity, { recursive: true });
|
|
1532
1533
|
await sharp({ create: {
|
|
1533
1534
|
width: canvasSize,
|
|
1534
1535
|
height: canvasSize,
|
|
@@ -1550,15 +1551,15 @@ ${cover ? ` <constraint firstItem="splash-image" firstAttribute="le
|
|
|
1550
1551
|
const darkBackground = dark?.backgroundImage ? (await readBackground(dark.backgroundImage)).data : void 0;
|
|
1551
1552
|
if (background) {
|
|
1552
1553
|
const nodpi = path.join(mainRes, "drawable-nodpi");
|
|
1553
|
-
|
|
1554
|
-
|
|
1554
|
+
mkdirSync(nodpi, { recursive: true });
|
|
1555
|
+
writeFileSync(path.join(nodpi, "splash_background.png"), background.data);
|
|
1555
1556
|
if (darkBackground) {
|
|
1556
1557
|
const nightNodpi = path.join(mainRes, "drawable-night-nodpi");
|
|
1557
|
-
|
|
1558
|
-
|
|
1558
|
+
mkdirSync(nightNodpi, { recursive: true });
|
|
1559
|
+
writeFileSync(path.join(nightNodpi, "splash_background.png"), darkBackground);
|
|
1559
1560
|
}
|
|
1560
1561
|
}
|
|
1561
|
-
|
|
1562
|
+
writeFileSync(path.join(drawable, "launch_screen.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
1562
1563
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
1563
1564
|
<item android:drawable="@color/splash_background" />
|
|
1564
1565
|
${background ? ` <item>
|
|
@@ -1569,28 +1570,28 @@ ${background ? ` <item>
|
|
|
1569
1570
|
</item>
|
|
1570
1571
|
</layer-list>
|
|
1571
1572
|
`);
|
|
1572
|
-
|
|
1573
|
+
writeFileSync(path.join(mainRes, "values", "colors.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
1573
1574
|
<resources>
|
|
1574
1575
|
<color name="splash_background">${app.splash.backgroundColor}</color>
|
|
1575
1576
|
</resources>
|
|
1576
1577
|
`);
|
|
1577
1578
|
if (dark) {
|
|
1578
|
-
|
|
1579
|
-
|
|
1579
|
+
mkdirSync(path.join(mainRes, "values-night"), { recursive: true });
|
|
1580
|
+
writeFileSync(path.join(mainRes, "values-night", "colors.xml"), `<?xml version="1.0" encoding="utf-8"?>
|
|
1580
1581
|
<resources>
|
|
1581
1582
|
<color name="splash_background">${dark.backgroundColor}</color>
|
|
1582
1583
|
</resources>
|
|
1583
1584
|
`);
|
|
1584
1585
|
}
|
|
1585
1586
|
const stylesPath = path.join(mainRes, "values", "styles.xml");
|
|
1586
|
-
const styles =
|
|
1587
|
-
|
|
1587
|
+
const styles = readFileSync(stylesPath, "utf8").replace(" <!-- Customize your theme here. -->", " <item name=\"android:windowBackground\">@drawable/launch_screen</item>");
|
|
1588
|
+
writeFileSync(stylesPath, styles);
|
|
1588
1589
|
const stylesV31 = path.join(mainRes, "values-v31");
|
|
1589
|
-
|
|
1590
|
+
mkdirSync(stylesV31, { recursive: true });
|
|
1590
1591
|
if (!styles.includes("</style>")) {
|
|
1591
1592
|
throw new Error("[vxrn] prebuild template styles.xml lost its AppTheme </style> anchor");
|
|
1592
1593
|
}
|
|
1593
|
-
|
|
1594
|
+
writeFileSync(path.join(stylesV31, "styles.xml"), styles.replace("</style>", ` <item name="android:windowSplashScreenBackground">@color/splash_background</item>
|
|
1594
1595
|
<item name="android:windowSplashScreenAnimatedIcon">@drawable/splash</item>
|
|
1595
1596
|
</style>`));
|
|
1596
1597
|
}
|
|
@@ -2126,17 +2127,20 @@ const generateForPlatform = async (root, platform, app, outDir = path.resolve(ro
|
|
|
2126
2127
|
}
|
|
2127
2128
|
const files = [...walkFn(src)].sort();
|
|
2128
2129
|
const nitroWebImage = platform === "ios" && nativeProjectPatches.hasNitroWebImage(root);
|
|
2129
|
-
|
|
2130
|
+
rmSync(dest, {
|
|
2131
|
+
recursive: true,
|
|
2132
|
+
force: true
|
|
2133
|
+
});
|
|
2130
2134
|
for (const absoluteSrc of files) {
|
|
2131
2135
|
const relativeFilePath = path.relative(src, absoluteSrc);
|
|
2132
|
-
const stat =
|
|
2136
|
+
const stat = lstatSync(absoluteSrc);
|
|
2133
2137
|
if (stat.isDirectory()) continue;
|
|
2134
2138
|
const extension = path.extname(absoluteSrc);
|
|
2135
2139
|
const raw = [
|
|
2136
2140
|
".png",
|
|
2137
2141
|
".jar",
|
|
2138
2142
|
".keystore"
|
|
2139
|
-
].includes(extension) ? null :
|
|
2143
|
+
].includes(extension) ? null : readFileSync(absoluteSrc, "utf8");
|
|
2140
2144
|
const { destRelativePath, content } = renderPrebuildFile({
|
|
2141
2145
|
relativePath: relativeFilePath,
|
|
2142
2146
|
content: raw,
|
|
@@ -2145,13 +2149,13 @@ const generateForPlatform = async (root, platform, app, outDir = path.resolve(ro
|
|
|
2145
2149
|
nitroWebImage
|
|
2146
2150
|
});
|
|
2147
2151
|
const destPath = path.resolve(dest, destRelativePath);
|
|
2148
|
-
|
|
2152
|
+
mkdirSync(path.dirname(destPath), { recursive: true });
|
|
2149
2153
|
console.info("copying", "\"" + absoluteSrc + "\"", "to", "\"" + destPath + "\"");
|
|
2150
2154
|
if (content === null) {
|
|
2151
|
-
|
|
2155
|
+
copyFileSync(absoluteSrc, destPath);
|
|
2152
2156
|
continue;
|
|
2153
2157
|
}
|
|
2154
|
-
|
|
2158
|
+
writeFileSync(destPath, content, {
|
|
2155
2159
|
encoding: "utf8",
|
|
2156
2160
|
mode: stat.mode
|
|
2157
2161
|
});
|
|
@@ -2215,14 +2219,14 @@ const KOTLIN_IMPORT_ARTIFACTS = [{
|
|
|
2215
2219
|
}];
|
|
2216
2220
|
function kotlinSourceImports(dir) {
|
|
2217
2221
|
const imports = /* @__PURE__ */ new Set();
|
|
2218
|
-
if (!
|
|
2222
|
+
if (!existsSync(dir)) return imports;
|
|
2219
2223
|
const visit = (entry) => {
|
|
2220
|
-
if (
|
|
2221
|
-
for (const child of
|
|
2224
|
+
if (statSync(entry).isDirectory()) {
|
|
2225
|
+
for (const child of readdirSync(entry)) visit(path.join(entry, child));
|
|
2222
2226
|
return;
|
|
2223
2227
|
}
|
|
2224
2228
|
if (!entry.endsWith(".kt")) return;
|
|
2225
|
-
for (const line of
|
|
2229
|
+
for (const line of readFileSync(entry, "utf8").split("\n")) {
|
|
2226
2230
|
const match = /^\s*import\s+([A-Za-z0-9_.]+)/.exec(line);
|
|
2227
2231
|
if (match) imports.add(match[1]);
|
|
2228
2232
|
}
|
|
@@ -2232,18 +2236,18 @@ function kotlinSourceImports(dir) {
|
|
|
2232
2236
|
}
|
|
2233
2237
|
function enableAppComposeIntegration(dest) {
|
|
2234
2238
|
const rootBuildGradlePath = path.join(dest, "build.gradle");
|
|
2235
|
-
if (
|
|
2236
|
-
let content =
|
|
2239
|
+
if (existsSync(rootBuildGradlePath)) {
|
|
2240
|
+
let content = readFileSync(rootBuildGradlePath, "utf8");
|
|
2237
2241
|
const composePluginClasspath = " classpath(\"org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:$kotlinVersion\")";
|
|
2238
2242
|
if (!content.includes("org.jetbrains.kotlin.plugin.compose")) {
|
|
2239
2243
|
const anchor = content.includes("classpath(\"org.jetbrains.kotlin:kotlin-gradle-plugin\")") ? "classpath(\"org.jetbrains.kotlin:kotlin-gradle-plugin\")" : "classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin\"";
|
|
2240
2244
|
content = insertAfterLine(content, anchor, composePluginClasspath);
|
|
2241
|
-
|
|
2245
|
+
writeFileSync(rootBuildGradlePath, content, "utf8");
|
|
2242
2246
|
}
|
|
2243
2247
|
}
|
|
2244
2248
|
const appBuildGradlePath = path.join(dest, "app/build.gradle");
|
|
2245
|
-
if (
|
|
2246
|
-
let content =
|
|
2249
|
+
if (existsSync(appBuildGradlePath)) {
|
|
2250
|
+
let content = readFileSync(appBuildGradlePath, "utf8");
|
|
2247
2251
|
if (!content.includes("org.jetbrains.kotlin.plugin.compose")) {
|
|
2248
2252
|
const pluginAnchor = content.includes("apply plugin: \"org.jetbrains.kotlin.android\"") ? "apply plugin: \"org.jetbrains.kotlin.android\"" : "apply plugin: 'org.jetbrains.kotlin.android'";
|
|
2249
2253
|
content = insertAfterLine(content, pluginAnchor, "apply plugin: \"org.jetbrains.kotlin.plugin.compose\"");
|
|
@@ -2272,7 +2276,7 @@ function enableAppComposeIntegration(dest) {
|
|
|
2272
2276
|
const anchor = content.includes("androidx.compose.material3:material3") ? "androidx.compose.material3:material3" : reactAnchor;
|
|
2273
2277
|
content = insertAfterLine(content, anchor, [` def ${rule.versionKey} = rootProject.ext.has("${rule.versionKey}") ? rootProject.ext.get("${rule.versionKey}") : "${rule.version}"`, ` implementation "${rule.artifact}:$${rule.versionKey}"`].join("\n"));
|
|
2274
2278
|
}
|
|
2275
|
-
|
|
2279
|
+
writeFileSync(appBuildGradlePath, content, "utf8");
|
|
2276
2280
|
}
|
|
2277
2281
|
}
|
|
2278
2282
|
async function generateKotlinSources({ root, dest }) {
|
|
@@ -2289,7 +2293,7 @@ async function generateKotlinSources({ root, dest }) {
|
|
|
2289
2293
|
"evidence"
|
|
2290
2294
|
]);
|
|
2291
2295
|
const sources = [];
|
|
2292
|
-
const manifest =
|
|
2296
|
+
const manifest = existsSync(path.join(root, "package.json")) ? readJSONSync(path.join(root, "package.json")) : {};
|
|
2293
2297
|
const workspacePatterns = Array.isArray(manifest.workspaces) ? manifest.workspaces : manifest.workspaces?.packages ?? [];
|
|
2294
2298
|
const { default: glob } = await import("fast-glob");
|
|
2295
2299
|
const workspaceRoots = new Set(glob.sync(workspacePatterns, {
|
|
@@ -2303,8 +2307,8 @@ async function generateKotlinSources({ root, dest }) {
|
|
|
2303
2307
|
]
|
|
2304
2308
|
}).map((directory) => path.resolve(directory)));
|
|
2305
2309
|
const collect = (dir) => {
|
|
2306
|
-
if (dir !== root &&
|
|
2307
|
-
for (const entry of
|
|
2310
|
+
if (dir !== root && existsSync(path.join(dir, "package.json")) && !workspaceRoots.has(dir)) return;
|
|
2311
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
2308
2312
|
if (entry.name.startsWith(".") || skip.has(entry.name)) continue;
|
|
2309
2313
|
const source = path.join(dir, entry.name);
|
|
2310
2314
|
if (entry.isDirectory()) collect(source);
|
|
@@ -2313,19 +2317,22 @@ async function generateKotlinSources({ root, dest }) {
|
|
|
2313
2317
|
};
|
|
2314
2318
|
collect(root);
|
|
2315
2319
|
const output = path.join(dest, "app/src/main/java/one/source");
|
|
2316
|
-
|
|
2320
|
+
rmSync(output, {
|
|
2321
|
+
recursive: true,
|
|
2322
|
+
force: true
|
|
2323
|
+
});
|
|
2317
2324
|
if (sources.length === 0) return;
|
|
2318
2325
|
const { kotlinSourceId, renderKotlinSourceGlue, writeNativeSourceDeclaration } = await import("../utils/nativeSourceContract.mjs");
|
|
2319
2326
|
let hasViews = false;
|
|
2320
2327
|
for (const source of sources) {
|
|
2321
2328
|
const id = kotlinSourceId(root, source);
|
|
2322
2329
|
const target = path.join(output, id);
|
|
2323
|
-
|
|
2324
|
-
|
|
2330
|
+
mkdirSync(target, { recursive: true });
|
|
2331
|
+
copyFileSync(source, path.join(target, path.basename(source)));
|
|
2325
2332
|
const contract = writeNativeSourceDeclaration(source);
|
|
2326
2333
|
if (contract.views.length > 0) hasViews = true;
|
|
2327
2334
|
if (contract.modules.length > 0 || contract.views.length > 0) {
|
|
2328
|
-
|
|
2335
|
+
writeFileSync(path.join(target, `OneNativeSource_${id}.kt`), renderKotlinSourceGlue(id, contract).source);
|
|
2329
2336
|
}
|
|
2330
2337
|
}
|
|
2331
2338
|
if (hasViews) {
|
|
@@ -2346,10 +2353,10 @@ async function generateSwiftPackages({ root, dest }) {
|
|
|
2346
2353
|
const { swiftPodManifest, writeSwiftPackageArtifacts } = await import("../utils/nativeSourceContract.mjs");
|
|
2347
2354
|
for (const [id, packageDir] of packages) {
|
|
2348
2355
|
const podDir = path.join(dest, "OneSwiftPackages", id);
|
|
2349
|
-
const manifest = swiftPodManifest(path.join(packageDir, "Package.swift"),
|
|
2356
|
+
const manifest = swiftPodManifest(path.join(packageDir, "Package.swift"), readFileSync(path.join(packageDir, "Package.swift"), "utf8"));
|
|
2350
2357
|
const sources = [];
|
|
2351
2358
|
const collect = (dir) => {
|
|
2352
|
-
for (const entry of
|
|
2359
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
2353
2360
|
if (entry.name.startsWith(".") || skip.has(entry.name)) continue;
|
|
2354
2361
|
const full = path.join(dir, entry.name);
|
|
2355
2362
|
if (entry.isDirectory()) collect(full);
|
|
@@ -2365,13 +2372,13 @@ async function generateSwiftPackages({ root, dest }) {
|
|
|
2365
2372
|
}
|
|
2366
2373
|
for (const source of sources) {
|
|
2367
2374
|
const link = path.join(podDir, "Sources", path.relative(packageDir, source));
|
|
2368
|
-
|
|
2369
|
-
|
|
2375
|
+
mkdirSync(path.dirname(link), { recursive: true });
|
|
2376
|
+
symlinkSync(realpathSync(source), link);
|
|
2370
2377
|
}
|
|
2371
2378
|
if (artifacts.glue) {
|
|
2372
|
-
|
|
2379
|
+
writeFileSync(path.join(podDir, "Sources", "OneNativeSource.generated.swift"), artifacts.glue);
|
|
2373
2380
|
}
|
|
2374
|
-
|
|
2381
|
+
writeFileSync(path.join(podDir, `${id}.podspec`), `Pod::Spec.new do |s|
|
|
2375
2382
|
s.name = '${id}'
|
|
2376
2383
|
s.version = '0.0.0'
|
|
2377
2384
|
s.summary = 'swift package ${path.relative(root, packageDir) || "."}'
|
|
@@ -2387,7 +2394,7 @@ async function generateSwiftPackages({ root, dest }) {
|
|
|
2387
2394
|
}
|
|
2388
2395
|
end
|
|
2389
2396
|
`);
|
|
2390
|
-
|
|
2397
|
+
writeFileSync(path.join(podDir, "Register.m"), hasView ? `#import <Foundation/Foundation.h>
|
|
2391
2398
|
|
|
2392
2399
|
extern int ${id}_main(int argc, char **argv);
|
|
2393
2400
|
extern void OneSwiftRegisterPackage(const char *name, int (*entry)(int, char **));
|
|
@@ -2409,11 +2416,11 @@ function applyAndroidDependencyPatches(args) {
|
|
|
2409
2416
|
return;
|
|
2410
2417
|
}
|
|
2411
2418
|
const activityPath = path.join(root, "android", "app", "src", "main", "java", ...app.android.applicationId.split("."), "MainActivity.kt");
|
|
2412
|
-
const rendered = nativeProjectPatches.holdLaunchScreenInMainActivity(nativeProjectPatches.addReactNativeScreensFix(
|
|
2419
|
+
const rendered = nativeProjectPatches.holdLaunchScreenInMainActivity(nativeProjectPatches.addReactNativeScreensFix(readFileSync(activityPath, "utf8")));
|
|
2413
2420
|
if (!rendered.includes("RNScreensFragmentFactory")) {
|
|
2414
2421
|
throw new Error("[vxrn] failed to apply the react-native-screens activity patch");
|
|
2415
2422
|
}
|
|
2416
|
-
|
|
2423
|
+
writeFileSync(activityPath, rendered);
|
|
2417
2424
|
}
|
|
2418
2425
|
async function getNativeDependencyInventory(root) {
|
|
2419
2426
|
const cliConfigPath = requireVxrn.resolve("@react-native-community/cli-config");
|
|
@@ -2425,7 +2432,7 @@ async function getNativeDependencyInventory(root) {
|
|
|
2425
2432
|
const depRoot = dependency.root;
|
|
2426
2433
|
let version = "unknown";
|
|
2427
2434
|
try {
|
|
2428
|
-
version = JSON.parse(
|
|
2435
|
+
version = JSON.parse(readFileSync(path.join(depRoot, "package.json"), "utf8")).version ?? "unknown";
|
|
2429
2436
|
} catch {}
|
|
2430
2437
|
const platforms = Object.entries(dependency.platforms).filter(([, platformConfig]) => platformConfig !== null).map(([platform]) => platform).sort();
|
|
2431
2438
|
if (platforms.length > 0) inventory.push({
|