catalyst-core 0.2.0-beta.2 → 0.3.0-beta.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/babel.native.config.cjs +8 -0
- package/bin/catalyst.js +49 -105
- package/changelog.md +8 -0
- package/dist/caching.js +1 -1
- package/dist/index.jsx +8 -0
- package/dist/logger.js +74 -3
- package/dist/native/androidProject/app/build.gradle.kts +1 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +143 -4
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +26 -6
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MetricsMonitor.kt +143 -17
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +6 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/WebCacheManager.kt +26 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +56 -1
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/KeyboardUtil.kt +48 -8
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/PerfDeliveryState.kt +36 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/PerfEventBuffer.kt +289 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/ProfilerNavigationState.kt +13 -0
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/ProfilerLifecycleTest.kt +51 -0
- package/dist/native/androidSetup.js +300 -8
- package/dist/native/bridge/WebBridge.js +481 -59
- package/dist/native/bridge/constants/NativeInterfaces.js +290 -44
- package/dist/native/bridge/errors.js +250 -26
- package/dist/native/bridge/hooks/index.js +125 -1
- package/dist/native/bridge/hooks/useCamera.js +347 -9
- package/dist/native/bridge/hooks/useDataProtection.js +200 -2
- package/dist/native/bridge/hooks/useDeviceInfo.js +71 -2
- package/dist/native/bridge/hooks/useFilePicker.js +429 -2
- package/dist/native/bridge/hooks/useGoogleSignIn.js +81 -1
- package/dist/native/bridge/hooks/useHapticFeedback.js +196 -1
- package/dist/native/bridge/hooks/useIntent.js +95 -1
- package/dist/native/bridge/hooks/useNativeTransition.js +202 -27
- package/dist/native/bridge/hooks/useNetworkStatus.js +84 -3
- package/dist/native/bridge/hooks/useNotification.js +318 -2
- package/dist/native/bridge/hooks/useSafeArea.js +84 -2
- package/dist/native/bridge/hooks/useVideoStream.js +434 -6
- package/dist/native/bridge/hooks/utils.js +27 -1
- package/dist/native/bridge/hooks.js +16 -1
- package/dist/native/bridge/perf/collectors/ApiCollector.js +85 -0
- package/dist/native/bridge/perf/collectors/CacheCollector.js +215 -0
- package/dist/native/bridge/perf/collectors/HookCollector.js +165 -0
- package/dist/native/bridge/perf/collectors/InsightsCollector.js +505 -0
- package/dist/native/bridge/perf/collectors/InteractionCollector.js +273 -0
- package/dist/native/bridge/perf/collectors/KeyboardCollector.js +124 -0
- package/dist/native/bridge/perf/collectors/NavigationCollector.js +294 -0
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +183 -0
- package/dist/native/bridge/perf/collectors/RenderCollector.js +284 -0
- package/dist/native/bridge/perf/collectors/ScrollCollector.js +111 -0
- package/dist/native/bridge/perf/collectors/ThreadCollector.js +111 -0
- package/dist/native/bridge/perf/core/constants.js +126 -0
- package/dist/native/bridge/perf/core/measure.js +189 -0
- package/dist/native/bridge/perf/core/session.js +100 -0
- package/dist/native/bridge/perf/core/store.js +554 -0
- package/dist/native/bridge/perf/core/summary.js +174 -0
- package/dist/native/bridge/perf/core/traceExport.js +240 -0
- package/dist/native/bridge/perf/core/waterfalls.js +146 -0
- package/dist/native/bridge/perf/index.js +402 -0
- package/dist/native/bridge/safeArea.js +53 -5
- package/dist/native/bridge/standardizedHooks.js +595 -82
- package/dist/native/bridge/useBaseHook.js +274 -38
- package/dist/native/bridge/utils/CameraUtils.js +201 -56
- package/dist/native/bridge/utils/FileObjectConverter.js +129 -18
- package/dist/native/bridge/utils/NativeBridge.js +425 -141
- package/dist/native/buildAndroid/assets.js +510 -13
- package/dist/native/buildAndroid/build.js +296 -19
- package/dist/native/buildAndroid/config.js +87 -1
- package/dist/native/buildAndroid/index.js +374 -1
- package/dist/native/buildAppAndroid.js +34 -2
- package/dist/native/buildAppIos.js +62 -2
- package/dist/native/buildIos/assets.js +609 -8
- package/dist/native/buildIos/build.js +639 -20
- package/dist/native/buildIos/config.js +294 -12
- package/dist/native/buildIos/index.js +343 -6
- package/dist/native/buildIos/plugins.js +343 -16
- package/dist/native/internal-plugins/device-info-plugin/android/DeviceInfoPlugin.kt +43 -0
- package/dist/native/internal-plugins/device-info-plugin/ios/DeviceInfoPlugin.swift +28 -0
- package/dist/native/internal-plugins/device-info-plugin/manifest.json +19 -0
- package/dist/native/internalPluginUtils.js +232 -7
- package/dist/native/iosnativeWebView/Sources/Core/Constants/CatalystConstants.swift +19 -0
- package/dist/native/iosnativeWebView/Sources/Core/Constants/ConfigConstants.swift +4 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/BootTimingUtility.swift +5 -1
- package/dist/native/iosnativeWebView/Sources/Core/Utils/CacheManager.swift +10 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/DisplayLinkPerfMonitor.swift +89 -0
- package/dist/native/iosnativeWebView/Sources/Core/Utils/PerfEventBuffer.swift +373 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeFileHandler.swift +35 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +24 -11
- package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +9 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +126 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +75 -1
- package/dist/native/iosnativeWebView/iosnativeWebViewTests/BridgeMessageValidatorTests.swift +13 -0
- package/dist/native/package.json +3 -0
- package/dist/native/plugin-bridge/PluginBridge.js +227 -1
- package/dist/native/pluginComposerAndroid.js +407 -23
- package/dist/native/pluginComposerIos.js +435 -11
- package/dist/native/renameAndroidProject.js +1094 -88
- package/dist/native/setupEmulatorIos.js +289 -22
- package/dist/native/setupServer.js +160 -19
- package/dist/native/terminalProgress.js +199 -11
- package/dist/native/utils.js +193 -15
- package/dist/offline/catalyst-sw.js +145 -1
- package/dist/offline/registerServiceWorker.js +33 -1
- package/dist/otel.js +375 -46
- package/dist/router/ClientRouter.js +14 -2
- package/dist/router/ServerRouter.js +9 -1
- package/dist/router.js +1 -1
- package/dist/scripts/build.js +112 -3
- package/dist/scripts/checkVersion.js +3 -1
- package/dist/scripts/cleanCache.js +30 -1
- package/dist/scripts/generateOfflineManifest.js +116 -1
- package/dist/scripts/loadEnvironmentVariables.js +32 -6
- package/dist/scripts/plugins.js +309 -1
- package/dist/scripts/preServerInit.js +13 -0
- package/dist/scripts/scriptUtils.js +54 -3
- package/dist/scripts/serve.js +51 -4
- package/dist/scripts/start.js +47 -10
- package/dist/scripts/validator.js +149 -1
- package/dist/sentry.cjs +127 -0
- package/dist/sentry.js +125 -5
- package/dist/server/expressServer.js +250 -5
- package/dist/server/manifestCache.js +36 -0
- package/dist/server/renderer/ChunkExtractor.js +144 -0
- package/dist/server/renderer/document/Body.jsx +59 -0
- package/dist/server/renderer/document/FastRefresh.jsx +20 -0
- package/dist/server/renderer/document/Head.jsx +60 -0
- package/dist/server/renderer/document/index.jsx +2 -0
- package/dist/server/renderer/extract.js +149 -31
- package/dist/server/renderer/handler.jsx +433 -0
- package/dist/server/renderer/index.js +8 -1
- package/dist/server/renderer/render.js +47 -0
- package/dist/server/utils/botDetectionMiddleware.js +29 -0
- package/dist/server/utils/cjsRequire.js +10 -0
- package/dist/server/utils/userAgentUtil.js +87 -9
- package/dist/server/utils/validator.js +164 -1
- package/dist/vite/FastRefresh.jsx +20 -0
- package/dist/vite/inject-cache-key-plugin.js +276 -0
- package/dist/vite/loadCustomViteConfig.js +22 -0
- package/dist/vite/manifest-categorization-plugin.js +455 -0
- package/dist/vite/node-loader.mjs +458 -0
- package/dist/vite/scssParams.js +21 -0
- package/dist/vite/vite.config.client.js +130 -0
- package/dist/vite/vite.config.js +422 -0
- package/dist/vite/vite.config.server.js +84 -0
- package/dist/web-router/components/MetaTag.jsx +34 -0
- package/dist/web-router/components/RouterDataProvider.jsx +332 -0
- package/dist/web-router/components/Split.jsx +200 -0
- package/dist/web-router/components/SplitInview.jsx +106 -0
- package/dist/web-router/components/SsrRequestContext.jsx +14 -0
- package/dist/web-router/context.jsx +12 -0
- package/dist/web-router/hooks.jsx +72 -0
- package/dist/web-router/types/components/MetaTag.d.ts +2 -0
- package/dist/web-router/types/components/RouterDataProvider.d.ts +95 -0
- package/dist/web-router/types/context.d.ts +14 -0
- package/dist/web-router/types/hooks.d.ts +1 -0
- package/dist/web-router/types/index.d.ts +3 -0
- package/dist/web-router/types/utils/metaDataUtils.d.ts +24 -0
- package/dist/web-router/utils/metaDataUtils.jsx +119 -0
- package/mcp_v2/conversion-tasks.json +35 -17
- package/mcp_v2/knowledge-base.json +124 -13
- package/mcp_v2/lib/helpers.js +10 -0
- package/mcp_v2/mcp.js +4 -4
- package/mcp_v2/package.json +1 -0
- package/mcp_v2/tools/build.js +116 -20
- package/mcp_v2/tools/conversion.js +106 -5
- package/mcp_v2/tools/tasks.js +18 -14
- package/package.json +35 -68
- package/babel.config.js +0 -32
- package/dist/index.js +0 -1
- package/dist/scripts/devBuild.js +0 -3
- package/dist/scripts/devServe.js +0 -3
- package/dist/scripts/loadScriptsBeforeServerStarts.js +0 -4
- package/dist/scripts/registerAliases.js +0 -6
- package/dist/server/renderer/document/Body.js +0 -11
- package/dist/server/renderer/document/Head.js +0 -9
- package/dist/server/renderer/document/index.js +0 -1
- package/dist/server/renderer/handler.js +0 -47
- package/dist/server/startServer.js +0 -57
- package/dist/webpack/babel-plugins/remove-client.plugin.js +0 -5
- package/dist/webpack/babel-plugins/remove-ssr.plugin.js +0 -5
- package/dist/webpack/babel.config.client.js +0 -1
- package/dist/webpack/babel.config.ssr.js +0 -1
- package/dist/webpack/base.babel.js +0 -7
- package/dist/webpack/development.client.babel.js +0 -10
- package/dist/webpack/production.client.babel.js +0 -4
- package/dist/webpack/production.ssr.babel.js +0 -8
- package/dist/webpack/scssParams.js +0 -9
|
@@ -1,89 +1,1095 @@
|
|
|
1
|
-
/* eslint-disable no-extra-semi */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
progress.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
progress.log(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
1
|
+
/* eslint-disable no-extra-semi */
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
5
|
+
var _path = _interopRequireDefault(require("path"));
|
|
6
|
+
var _utils = require("./utils.js");
|
|
7
|
+
function _interopRequireDefault(e) {
|
|
8
|
+
return e && e.__esModule ? e : {
|
|
9
|
+
default: e
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Simple progress logging without TerminalProgress dependency
|
|
14
|
+
class SimpleProgress {
|
|
15
|
+
constructor(title) {
|
|
16
|
+
this.title = title;
|
|
17
|
+
this.currentStep = null;
|
|
18
|
+
console.log(`\n=== ${title} ===\n`);
|
|
19
|
+
}
|
|
20
|
+
start(stepId) {
|
|
21
|
+
this.currentStep = {
|
|
22
|
+
id: stepId
|
|
23
|
+
};
|
|
24
|
+
console.log(`⏳ Starting: ${stepId}`);
|
|
25
|
+
}
|
|
26
|
+
complete(stepId) {
|
|
27
|
+
console.log(`✅ Completed: ${stepId}`);
|
|
28
|
+
this.currentStep = null;
|
|
29
|
+
}
|
|
30
|
+
fail(stepId, message) {
|
|
31
|
+
console.log(`❌ Failed: ${stepId} - ${message}`);
|
|
32
|
+
}
|
|
33
|
+
log(message, type = "info") {
|
|
34
|
+
const prefix = type === "error" ? "❌" : type === "warning" ? "⚠️ " : type === "success" ? "✅" : "ℹ️ ";
|
|
35
|
+
console.log(` ${prefix} ${message}`);
|
|
36
|
+
}
|
|
37
|
+
printTreeContent(title, items) {
|
|
38
|
+
console.log(`\n📋 ${title}:`);
|
|
39
|
+
items.forEach(item => {
|
|
40
|
+
if (typeof item === "string") {
|
|
41
|
+
console.log(item);
|
|
42
|
+
} else {
|
|
43
|
+
const indent = " ".repeat(item.indent || 0);
|
|
44
|
+
const prefix = item.prefix || "";
|
|
45
|
+
console.log(`${indent}${prefix}${item.text}`);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
console.log("");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const progress = new SimpleProgress("Android AAB Builder");
|
|
52
|
+
async function createKeystore(projectPaths, androidConfig) {
|
|
53
|
+
const {
|
|
54
|
+
newProjectPath
|
|
55
|
+
} = projectPaths;
|
|
56
|
+
const {
|
|
57
|
+
keystoreConfig
|
|
58
|
+
} = androidConfig;
|
|
59
|
+
if (!keystoreConfig) {
|
|
60
|
+
progress.log("Keystore configuration not found, skipping keystore creation", "info");
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
progress.log("Checking keystore configuration...", "info");
|
|
64
|
+
|
|
65
|
+
// Validate keystore passwords are not placeholder values
|
|
66
|
+
if (keystoreConfig.storePassword === "your_store_password" || keystoreConfig.keyPassword === "your_key_password" || keystoreConfig.storePassword === "your_password" || keystoreConfig.keyPassword === "your_password") {
|
|
67
|
+
throw new Error('Please update keystore passwords in config file. Do not use placeholder values like "your_store_password" or "your_key_password".');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Define keystore path
|
|
71
|
+
const keystorePath = _path.default.join(newProjectPath, "app", "keystore.jks");
|
|
72
|
+
|
|
73
|
+
// Check if keystore already exists
|
|
74
|
+
if (_fs.default.existsSync(keystorePath)) {
|
|
75
|
+
progress.log("Keystore already exists, verifying accessibility...", "info");
|
|
76
|
+
|
|
77
|
+
// Test keystore accessibility
|
|
78
|
+
try {
|
|
79
|
+
const testCommand = `keytool -list -keystore "${keystorePath}" -storepass "${keystoreConfig.storePassword}" -alias "${keystoreConfig.keyAlias}"`;
|
|
80
|
+
(0, _utils.runCommand)(testCommand);
|
|
81
|
+
progress.log("Existing keystore verified successfully", "success");
|
|
82
|
+
return keystorePath;
|
|
83
|
+
} catch (testError) {
|
|
84
|
+
progress.log("Existing keystore verification failed, creating new one...", "warning");
|
|
85
|
+
// Remove the faulty keystore
|
|
86
|
+
_fs.default.unlinkSync(keystorePath);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
progress.log("Creating new keystore...", "info");
|
|
90
|
+
try {
|
|
91
|
+
// Validate required keystore configuration
|
|
92
|
+
const requiredFields = ["keyAlias", "storePassword", "keyPassword", "organizationInfo"];
|
|
93
|
+
for (const field of requiredFields) {
|
|
94
|
+
if (!keystoreConfig[field]) {
|
|
95
|
+
throw new Error(`Missing required keystore config field: ${field}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const {
|
|
99
|
+
organizationInfo
|
|
100
|
+
} = keystoreConfig;
|
|
101
|
+
const requiredOrgFields = ["companyName", "city", "state", "countryCode"];
|
|
102
|
+
for (const field of requiredOrgFields) {
|
|
103
|
+
if (!organizationInfo[field]) {
|
|
104
|
+
throw new Error(`Missing required organization info field: ${field}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Create keystore directory if it doesn't exist
|
|
109
|
+
const keystoreDir = _path.default.dirname(keystorePath);
|
|
110
|
+
if (!_fs.default.existsSync(keystoreDir)) {
|
|
111
|
+
_fs.default.mkdirSync(keystoreDir, {
|
|
112
|
+
recursive: true
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Build the distinguished name (DN) for the certificate
|
|
117
|
+
const dn = [`CN=${organizationInfo.companyName}`, `OU=${organizationInfo.department || organizationInfo.companyName}`, `O=${organizationInfo.organization || organizationInfo.companyName}`, `L=${organizationInfo.city}`, `ST=${organizationInfo.state}`, `C=${organizationInfo.countryCode}`].join(", ");
|
|
118
|
+
|
|
119
|
+
// For PKCS12 keystores (default), store and key passwords must be the same
|
|
120
|
+
// Use store password for both to avoid PKCS12 compatibility issues
|
|
121
|
+
const effectiveKeyPassword = keystoreConfig.storePassword;
|
|
122
|
+
if (keystoreConfig.keyPassword !== keystoreConfig.storePassword) {
|
|
123
|
+
progress.log("Note: Using store password for key password (PKCS12 requirement)", "info");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Generate keystore using keytool with PKCS12 format explicitly
|
|
127
|
+
const validityDays = (keystoreConfig.validityYears || 25) * 365;
|
|
128
|
+
const keystoreCommand = ["keytool", "-genkeypair", "-v", `-storetype PKCS12`, `-keystore "${keystorePath}"`, `-alias "${keystoreConfig.keyAlias}"`, `-keyalg RSA`, `-keysize 2048`, `-validity ${validityDays}`, `-storepass "${keystoreConfig.storePassword}"`, `-keypass "${effectiveKeyPassword}"`, `-dname "${dn}"`].join(" ");
|
|
129
|
+
progress.log("Executing keytool command...", "info");
|
|
130
|
+
(0, _utils.runCommand)(keystoreCommand);
|
|
131
|
+
|
|
132
|
+
// Verify keystore was created
|
|
133
|
+
if (!_fs.default.existsSync(keystorePath)) {
|
|
134
|
+
throw new Error("Keystore file was not created successfully");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Test the newly created keystore
|
|
138
|
+
try {
|
|
139
|
+
const testCommand = `keytool -list -keystore "${keystorePath}" -storepass "${keystoreConfig.storePassword}" -alias "${keystoreConfig.keyAlias}"`;
|
|
140
|
+
(0, _utils.runCommand)(testCommand);
|
|
141
|
+
progress.log("New keystore verified successfully", "success");
|
|
142
|
+
} catch (testError) {
|
|
143
|
+
throw new Error(`Created keystore failed verification: ${testError.message}`);
|
|
144
|
+
}
|
|
145
|
+
progress.log(`Keystore created successfully at: ${keystorePath}`, "success");
|
|
146
|
+
progress.log(`Key alias: ${keystoreConfig.keyAlias}`, "info");
|
|
147
|
+
progress.log(`Validity: ${keystoreConfig.validityYears || 25} years`, "info");
|
|
148
|
+
progress.log(`Store type: PKCS12`, "info");
|
|
149
|
+
return keystorePath;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
throw new Error(`Failed to create keystore: ${error.message}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function createSignedAAB(projectPaths, androidConfig, keystorePath) {
|
|
155
|
+
const {
|
|
156
|
+
newProjectPath
|
|
157
|
+
} = projectPaths;
|
|
158
|
+
const {
|
|
159
|
+
keystoreConfig
|
|
160
|
+
} = androidConfig;
|
|
161
|
+
if (!keystoreConfig || !keystorePath) {
|
|
162
|
+
throw new Error("Keystore configuration and keystore path are required for signed AAB creation");
|
|
163
|
+
}
|
|
164
|
+
progress.log("Building signed Android App Bundle (AAB)...", "info");
|
|
165
|
+
try {
|
|
166
|
+
// Verify keystore exists
|
|
167
|
+
if (!_fs.default.existsSync(keystorePath)) {
|
|
168
|
+
throw new Error(`Keystore not found at: ${keystorePath}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Get absolute path for the project directory
|
|
172
|
+
const absoluteProjectPath = _path.default.resolve(newProjectPath);
|
|
173
|
+
|
|
174
|
+
// Change to project directory
|
|
175
|
+
const originalCwd = process.cwd();
|
|
176
|
+
process.chdir(absoluteProjectPath);
|
|
177
|
+
progress.log(`Changed to project directory: ${absoluteProjectPath}`, "info");
|
|
178
|
+
|
|
179
|
+
// Verify gradlew exists using absolute path
|
|
180
|
+
const gradlewPath = _path.default.join(absoluteProjectPath, "gradlew");
|
|
181
|
+
progress.log(`Looking for gradlew at: ${gradlewPath}`, "info");
|
|
182
|
+
if (!_fs.default.existsSync(gradlewPath)) {
|
|
183
|
+
// List files in the project directory for debugging
|
|
184
|
+
try {
|
|
185
|
+
const files = _fs.default.readdirSync(absoluteProjectPath);
|
|
186
|
+
progress.log(`Files in project directory: ${files.join(", ")}`, "info");
|
|
187
|
+
|
|
188
|
+
// Check if there's a gradlew file with different permissions or name
|
|
189
|
+
const gradlewFiles = files.filter(file => file.toLowerCase().includes("gradle"));
|
|
190
|
+
if (gradlewFiles.length > 0) {
|
|
191
|
+
progress.log(`Found gradle-related files: ${gradlewFiles.join(", ")}`, "info");
|
|
192
|
+
}
|
|
193
|
+
} catch (listError) {
|
|
194
|
+
progress.log(`Could not list directory contents: ${listError.message}`, "warning");
|
|
195
|
+
}
|
|
196
|
+
throw new Error(`gradlew not found at: ${gradlewPath}. Ensure this is a valid Android project.`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Make gradlew executable
|
|
200
|
+
try {
|
|
201
|
+
;
|
|
202
|
+
(0, _utils.runCommand)(`chmod +x ./gradlew`);
|
|
203
|
+
} catch (chmodError) {
|
|
204
|
+
progress.log(`Warning: Could not make gradlew executable: ${chmodError.message}`, "warning");
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
// Clean previous builds
|
|
208
|
+
progress.log("Cleaning previous builds...", "info");
|
|
209
|
+
try {
|
|
210
|
+
;
|
|
211
|
+
(0, _utils.runCommand)("./gradlew clean");
|
|
212
|
+
progress.log("Clean completed successfully", "success");
|
|
213
|
+
} catch (cleanError) {
|
|
214
|
+
progress.log(`Warning: Clean failed: ${cleanError.message}`, "warning");
|
|
215
|
+
// Continue anyway as this might not be critical
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Build signed AAB with PKCS12-compatible parameters
|
|
219
|
+
progress.log("Building signed AAB...", "info");
|
|
220
|
+
|
|
221
|
+
// For PKCS12 keystores, use store password for both store and key
|
|
222
|
+
const effectiveKeyPassword = keystoreConfig.storePassword;
|
|
223
|
+
const bundleCommand = ["./gradlew bundleRelease --quiet --console=rich", `-Pandroid.injected.signing.store.file="${keystorePath}"`, `-Pandroid.injected.signing.store.password="${keystoreConfig.storePassword}"`, `-Pandroid.injected.signing.key.alias="${keystoreConfig.keyAlias}"`, `-Pandroid.injected.signing.key.password="${effectiveKeyPassword}"`].join(" ");
|
|
224
|
+
progress.log(`Executing: ${bundleCommand}`, "info");
|
|
225
|
+
(0, _utils.runCommand)(bundleCommand);
|
|
226
|
+
progress.log("Bundle build completed", "success");
|
|
227
|
+
|
|
228
|
+
// Find the generated AAB file
|
|
229
|
+
const aabPath = _path.default.join(newProjectPath, "app", "build", "outputs", "bundle", "release", "app-release.aab");
|
|
230
|
+
progress.log(`Looking for AAB file at: ${aabPath}`, "info");
|
|
231
|
+
if (!_fs.default.existsSync(aabPath)) {
|
|
232
|
+
// Try to find AAB files in the build output directory
|
|
233
|
+
const bundleDir = _path.default.join(newProjectPath, "app", "build", "outputs", "bundle");
|
|
234
|
+
progress.log(`AAB not found at expected location. Checking bundle directory: ${bundleDir}`, "warning");
|
|
235
|
+
if (_fs.default.existsSync(bundleDir)) {
|
|
236
|
+
try {
|
|
237
|
+
const findAabCommand = `find "${bundleDir}" -name "*.aab" -type f`;
|
|
238
|
+
const foundAabs = (0, _utils.runCommand)(findAabCommand);
|
|
239
|
+
if (foundAabs.trim()) {
|
|
240
|
+
progress.log(`Found AAB files: ${foundAabs.trim()}`, "info");
|
|
241
|
+
} else {
|
|
242
|
+
progress.log("No AAB files found in bundle directory", "warning");
|
|
243
|
+
}
|
|
244
|
+
} catch (findError) {
|
|
245
|
+
progress.log(`Error searching for AAB files: ${findError.message}`, "warning");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
throw new Error("Signed AAB file was not generated successfully");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Get file size
|
|
252
|
+
const stats = _fs.default.statSync(aabPath);
|
|
253
|
+
const fileSizeMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
254
|
+
progress.log(`Signed AAB created successfully!`, "success");
|
|
255
|
+
progress.log(`AAB location: ${aabPath}`, "info");
|
|
256
|
+
progress.log(`AAB size: ${fileSizeMB} MB`, "info");
|
|
257
|
+
|
|
258
|
+
// Optionally copy AAB to a more accessible location
|
|
259
|
+
const outputDir = _path.default.join(newProjectPath, "release");
|
|
260
|
+
if (!_fs.default.existsSync(outputDir)) {
|
|
261
|
+
_fs.default.mkdirSync(outputDir, {
|
|
262
|
+
recursive: true
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
const outputAabPath = _path.default.join(outputDir, `${androidConfig.newProjectName}-release.aab`);
|
|
266
|
+
_fs.default.copyFileSync(aabPath, outputAabPath);
|
|
267
|
+
progress.log(`AAB copied to: ${outputAabPath}`, "success");
|
|
268
|
+
return {
|
|
269
|
+
aabPath,
|
|
270
|
+
outputAabPath,
|
|
271
|
+
fileSize: fileSizeMB
|
|
272
|
+
};
|
|
273
|
+
} finally {
|
|
274
|
+
// Restore original working directory
|
|
275
|
+
process.chdir(originalCwd);
|
|
276
|
+
}
|
|
277
|
+
} catch (error) {
|
|
278
|
+
throw new Error(`Failed to create signed AAB: ${error.message}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async function initializeConfig(configPath) {
|
|
282
|
+
if (!configPath) {
|
|
283
|
+
throw new Error("Config path is required");
|
|
284
|
+
}
|
|
285
|
+
if (!_fs.default.existsSync(configPath)) {
|
|
286
|
+
throw new Error(`Config file not found at: ${configPath}`);
|
|
287
|
+
}
|
|
288
|
+
progress.log(`Reading config from: ${configPath}`, "info");
|
|
289
|
+
const configFile = _fs.default.readFileSync(configPath, "utf8");
|
|
290
|
+
const config = JSON.parse(configFile);
|
|
291
|
+
if (!config.android) {
|
|
292
|
+
throw new Error("Android configuration missing in config file");
|
|
293
|
+
}
|
|
294
|
+
const {
|
|
295
|
+
android
|
|
296
|
+
} = config;
|
|
297
|
+
|
|
298
|
+
// Validate required fields (only newProjectName is truly required)
|
|
299
|
+
if (!android.newProjectName) {
|
|
300
|
+
throw new Error("newProjectName is required in android config");
|
|
301
|
+
}
|
|
302
|
+
progress.log(`Project path: ${android.projectPath}`, "info");
|
|
303
|
+
progress.log(`Old project name: ${android.oldProjectName}`, "info");
|
|
304
|
+
progress.log(`New project name: ${android.newProjectName}`, "info");
|
|
305
|
+
if (android.outputPath) {
|
|
306
|
+
progress.log(`Custom output path: ${android.outputPath}`, "info");
|
|
307
|
+
} else {
|
|
308
|
+
const parentDir = _path.default.dirname(android.projectPath);
|
|
309
|
+
const defaultOutputPath = _path.default.join(parentDir, "build-output");
|
|
310
|
+
progress.log(`Default output path: ${defaultOutputPath}`, "info");
|
|
311
|
+
}
|
|
312
|
+
if (android.createSignedAAB) {
|
|
313
|
+
progress.log(`Signed AAB creation: Enabled`, "info");
|
|
314
|
+
if (android.keystoreConfig) {
|
|
315
|
+
// Check for placeholder passwords
|
|
316
|
+
if (android.keystoreConfig.storePassword === "your_store_password" || android.keystoreConfig.keyPassword === "your_key_password" || android.keystoreConfig.storePassword === "your_password" || android.keystoreConfig.keyPassword === "your_password") {
|
|
317
|
+
progress.log(`Warning: Keystore contains placeholder passwords. Please update them.`, "warning");
|
|
318
|
+
} else {
|
|
319
|
+
progress.log(`Keystore configuration: Valid`, "success");
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
progress.log(`Warning: Keystore configuration missing for AAB creation`, "warning");
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
progress.log(`Signed AAB creation: Disabled (set createSignedAAB: true to enable)`, "info");
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
android,
|
|
329
|
+
config
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
async function diagnoseAndroidProject(projectPath) {
|
|
333
|
+
progress.log("Diagnosing Android project structure...", "info");
|
|
334
|
+
if (!_fs.default.existsSync(projectPath)) {
|
|
335
|
+
throw new Error(`Project path does not exist: ${projectPath}`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Check for common Android project patterns (supporting both .gradle and .gradle.kts)
|
|
339
|
+
const patterns = [{
|
|
340
|
+
files: ["build.gradle", "build.gradle.kts"],
|
|
341
|
+
description: "Root build gradle",
|
|
342
|
+
type: "either"
|
|
343
|
+
}, {
|
|
344
|
+
files: ["settings.gradle", "settings.gradle.kts"],
|
|
345
|
+
description: "Settings gradle",
|
|
346
|
+
type: "either"
|
|
347
|
+
}, {
|
|
348
|
+
files: ["gradlew"],
|
|
349
|
+
description: "Gradle wrapper script",
|
|
350
|
+
type: "single"
|
|
351
|
+
}, {
|
|
352
|
+
files: ["gradle.properties"],
|
|
353
|
+
description: "Gradle properties",
|
|
354
|
+
type: "single"
|
|
355
|
+
}, {
|
|
356
|
+
files: ["app/build.gradle", "app/build.gradle.kts"],
|
|
357
|
+
description: "App module build gradle",
|
|
358
|
+
type: "either"
|
|
359
|
+
}, {
|
|
360
|
+
files: ["app/src/main/AndroidManifest.xml"],
|
|
361
|
+
description: "Android manifest",
|
|
362
|
+
type: "single"
|
|
363
|
+
}, {
|
|
364
|
+
files: ["app/src/main/java"],
|
|
365
|
+
description: "Java source directory",
|
|
366
|
+
type: "single"
|
|
367
|
+
}, {
|
|
368
|
+
files: ["app/src/main/res"],
|
|
369
|
+
description: "Android resources",
|
|
370
|
+
type: "single"
|
|
371
|
+
}];
|
|
372
|
+
const diagnostics = {
|
|
373
|
+
foundFiles: [],
|
|
374
|
+
missingFiles: [],
|
|
375
|
+
projectType: "unknown",
|
|
376
|
+
usesKotlinDSL: false
|
|
377
|
+
};
|
|
378
|
+
for (const pattern of patterns) {
|
|
379
|
+
let found = false;
|
|
380
|
+
let foundFile = null;
|
|
381
|
+
if (pattern.type === "either") {
|
|
382
|
+
// Check if either variant exists
|
|
383
|
+
for (const file of pattern.files) {
|
|
384
|
+
const fullPath = _path.default.join(projectPath, file);
|
|
385
|
+
if (_fs.default.existsSync(fullPath)) {
|
|
386
|
+
found = true;
|
|
387
|
+
foundFile = file;
|
|
388
|
+
if (file.endsWith(".kts")) {
|
|
389
|
+
diagnostics.usesKotlinDSL = true;
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
// Check single file
|
|
396
|
+
const fullPath = _path.default.join(projectPath, pattern.files[0]);
|
|
397
|
+
if (_fs.default.existsSync(fullPath)) {
|
|
398
|
+
found = true;
|
|
399
|
+
foundFile = pattern.files[0];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (found) {
|
|
403
|
+
diagnostics.foundFiles.push({
|
|
404
|
+
...pattern,
|
|
405
|
+
foundFile
|
|
406
|
+
});
|
|
407
|
+
progress.log(`✅ Found: ${pattern.description}${foundFile ? ` (${foundFile})` : ""}`, "success");
|
|
408
|
+
} else {
|
|
409
|
+
diagnostics.missingFiles.push(pattern);
|
|
410
|
+
progress.log(`❌ Missing: ${pattern.description}`, "warning");
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Determine project type
|
|
415
|
+
const hasRootBuildFile = diagnostics.foundFiles.some(f => f.files.includes("build.gradle") || f.files.includes("build.gradle.kts"));
|
|
416
|
+
const hasAppBuildFile = diagnostics.foundFiles.some(f => f.files.includes("app/build.gradle") || f.files.includes("app/build.gradle.kts"));
|
|
417
|
+
const hasGradlew = diagnostics.foundFiles.some(f => f.files.includes("gradlew"));
|
|
418
|
+
if (hasRootBuildFile && hasAppBuildFile) {
|
|
419
|
+
diagnostics.projectType = "standard-android";
|
|
420
|
+
} else if (hasGradlew) {
|
|
421
|
+
diagnostics.projectType = "gradle-project";
|
|
422
|
+
} else {
|
|
423
|
+
diagnostics.projectType = "incomplete";
|
|
424
|
+
}
|
|
425
|
+
progress.log(`Project type detected: ${diagnostics.projectType}`, "info");
|
|
426
|
+
if (diagnostics.usesKotlinDSL) {
|
|
427
|
+
progress.log(`Project uses Kotlin DSL (.kts files)`, "info");
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Try to find build files in unexpected locations
|
|
431
|
+
if (diagnostics.missingFiles.length > 0) {
|
|
432
|
+
progress.log("Searching for missing files in alternate locations...", "info");
|
|
433
|
+
try {
|
|
434
|
+
const findBuildFiles = `find "${projectPath}" \\( -name "build.gradle" -o -name "build.gradle.kts" -o -name "settings.gradle" -o -name "settings.gradle.kts" -o -name "AndroidManifest.xml" \\) -type f`;
|
|
435
|
+
const foundFiles = (0, _utils.runCommand)(findBuildFiles);
|
|
436
|
+
if (foundFiles.trim()) {
|
|
437
|
+
progress.log("Found build files in unexpected locations:", "info");
|
|
438
|
+
foundFiles.trim().split("\n").forEach(file => {
|
|
439
|
+
progress.log(` ${file}`, "info");
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
} catch (searchError) {
|
|
443
|
+
progress.log("Could not search for alternative file locations", "warning");
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return diagnostics;
|
|
447
|
+
}
|
|
448
|
+
async function validateProjectStructure(androidConfig) {
|
|
449
|
+
const {
|
|
450
|
+
projectPath,
|
|
451
|
+
oldProjectName
|
|
452
|
+
} = androidConfig;
|
|
453
|
+
progress.log("Validating project structure...", "info");
|
|
454
|
+
if (!_fs.default.existsSync(projectPath)) {
|
|
455
|
+
throw new Error(`Project path does not exist: ${projectPath}`);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Run comprehensive diagnostics
|
|
459
|
+
const diagnostics = await diagnoseAndroidProject(projectPath);
|
|
460
|
+
if (diagnostics.projectType === "incomplete") {
|
|
461
|
+
throw new Error(`Android project appears to be incomplete. Missing critical files: ${diagnostics.missingFiles.map(f => f.description).join(", ")}`);
|
|
462
|
+
}
|
|
463
|
+
if (diagnostics.projectType !== "standard-android") {
|
|
464
|
+
progress.log(`Warning: Project type "${diagnostics.projectType}" may not be fully compatible`, "warning");
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Check if the old project name exists in the path
|
|
468
|
+
if (!projectPath.includes(oldProjectName)) {
|
|
469
|
+
progress.log(`Warning: Project path doesn't contain old project name "${oldProjectName}"`, "warning");
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Get the parent directory
|
|
473
|
+
const parentDir = _path.default.dirname(projectPath);
|
|
474
|
+
const currentProjectDir = _path.default.basename(projectPath);
|
|
475
|
+
if (currentProjectDir !== oldProjectName) {
|
|
476
|
+
progress.log(`Warning: Current directory name "${currentProjectDir}" differs from old project name "${oldProjectName}"`, "warning");
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Create output directory path - where final AAB will be saved
|
|
480
|
+
const outputPath = androidConfig.outputPath ? _path.default.resolve(androidConfig.outputPath) : _path.default.resolve(parentDir, "build-output");
|
|
481
|
+
progress.log(`Original project: ${projectPath}`, "info");
|
|
482
|
+
progress.log(`Output directory: ${outputPath}`, "info");
|
|
483
|
+
progress.log("Project structure validation completed", "success");
|
|
484
|
+
return {
|
|
485
|
+
parentDir,
|
|
486
|
+
currentProjectDir,
|
|
487
|
+
oldProjectPath: projectPath,
|
|
488
|
+
outputPath,
|
|
489
|
+
diagnostics
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
async function createBackup(projectPaths, androidConfig) {
|
|
493
|
+
if (!androidConfig.createBackup) {
|
|
494
|
+
progress.log("Backup creation skipped (not requested)", "info");
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
progress.log("Creating project backup...", "info");
|
|
498
|
+
const backupPath = `${projectPaths.oldProjectPath}_backup_${Date.now()}`;
|
|
499
|
+
try {
|
|
500
|
+
;
|
|
501
|
+
(0, _utils.runCommand)(`cp -r "${projectPaths.oldProjectPath}" "${backupPath}"`);
|
|
502
|
+
progress.log(`Backup created at: ${backupPath}`, "success");
|
|
503
|
+
return backupPath;
|
|
504
|
+
} catch (error) {
|
|
505
|
+
throw new Error(`Failed to create backup: ${error.message}`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
async function createTempDeploymentProject(projectPaths, androidConfig) {
|
|
509
|
+
const {
|
|
510
|
+
oldProjectPath
|
|
511
|
+
} = projectPaths;
|
|
512
|
+
const {
|
|
513
|
+
oldProjectName,
|
|
514
|
+
newProjectName,
|
|
515
|
+
packageName
|
|
516
|
+
} = androidConfig;
|
|
517
|
+
progress.log("Creating temporary deployment project...", "info");
|
|
518
|
+
|
|
519
|
+
// Create a temporary directory based on package name (if available) or timestamp
|
|
520
|
+
const tempDirSuffix = packageName ? packageName.replace(/\./g, "_") : Date.now().toString();
|
|
521
|
+
const tempDir = _path.default.join(_path.default.dirname(oldProjectPath), `temp_build_${tempDirSuffix}`);
|
|
522
|
+
|
|
523
|
+
// Remove existing temp directory with same name if it exists
|
|
524
|
+
if (_fs.default.existsSync(tempDir)) {
|
|
525
|
+
progress.log(`Removing existing temp directory: ${tempDir}`, "info");
|
|
526
|
+
try {
|
|
527
|
+
;
|
|
528
|
+
(0, _utils.runCommand)(`rm -rf "${tempDir}"`);
|
|
529
|
+
} catch (cleanupError) {
|
|
530
|
+
progress.log(`Warning: Could not remove existing temp directory: ${cleanupError.message}`, "warning");
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
// First, let's check what's actually in the source directory
|
|
535
|
+
progress.log(`Inspecting source directory: ${oldProjectPath}`, "info");
|
|
536
|
+
if (!_fs.default.existsSync(oldProjectPath)) {
|
|
537
|
+
throw new Error(`Source project path does not exist: ${oldProjectPath}`);
|
|
538
|
+
}
|
|
539
|
+
const sourceFiles = _fs.default.readdirSync(oldProjectPath);
|
|
540
|
+
progress.log(`Source directory contents: ${sourceFiles.join(", ")}`, "info");
|
|
541
|
+
|
|
542
|
+
// Copy the entire project to the temporary location using rsync for better file preservation
|
|
543
|
+
progress.log(`Copying project to temporary location...`, "info");
|
|
544
|
+
progress.log(`Source: ${oldProjectPath}`, "info");
|
|
545
|
+
progress.log(`Temp destination: ${tempDir}`, "info")
|
|
546
|
+
|
|
547
|
+
// Use rsync to preserve all file attributes and handle symlinks properly
|
|
548
|
+
;
|
|
549
|
+
(0, _utils.runCommand)(`rsync -av "${oldProjectPath}/" "${tempDir}/"`);
|
|
550
|
+
progress.log(`Created temporary copy for building`, "success");
|
|
551
|
+
|
|
552
|
+
// Only check for gradlew which is absolutely essential for building
|
|
553
|
+
const gradlewPath = _path.default.join(tempDir, "gradlew");
|
|
554
|
+
if (!_fs.default.existsSync(gradlewPath)) {
|
|
555
|
+
throw new Error("Critical file missing: gradlew not found. This is required for building the project.");
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Log what we have (for debugging purposes only, not validation)
|
|
559
|
+
progress.log(`Checking copied files (informational only):`, "info");
|
|
560
|
+
const filesToCheck = [{
|
|
561
|
+
path: "gradlew",
|
|
562
|
+
desc: "Gradle wrapper"
|
|
563
|
+
}, {
|
|
564
|
+
path: "build.gradle",
|
|
565
|
+
desc: "Root build.gradle"
|
|
566
|
+
}, {
|
|
567
|
+
path: "build.gradle.kts",
|
|
568
|
+
desc: "Root build.gradle.kts"
|
|
569
|
+
}, {
|
|
570
|
+
path: "app/build.gradle",
|
|
571
|
+
desc: "App build.gradle"
|
|
572
|
+
}, {
|
|
573
|
+
path: "app/build.gradle.kts",
|
|
574
|
+
desc: "App build.gradle.kts"
|
|
575
|
+
}, {
|
|
576
|
+
path: "settings.gradle",
|
|
577
|
+
desc: "Settings gradle"
|
|
578
|
+
}, {
|
|
579
|
+
path: "settings.gradle.kts",
|
|
580
|
+
desc: "Settings gradle.kts"
|
|
581
|
+
}, {
|
|
582
|
+
path: "app/src/main/AndroidManifest.xml",
|
|
583
|
+
desc: "Android manifest"
|
|
584
|
+
}];
|
|
585
|
+
filesToCheck.forEach(file => {
|
|
586
|
+
const fullPath = _path.default.join(tempDir, file.path);
|
|
587
|
+
const exists = _fs.default.existsSync(fullPath);
|
|
588
|
+
progress.log(` ${file.desc}: ${exists ? "✅ Found" : "⚠️ Not found"}`, exists ? "info" : "warning");
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
// List all files in temp directory for debugging
|
|
592
|
+
if (_fs.default.existsSync(tempDir)) {
|
|
593
|
+
const tempFiles = _fs.default.readdirSync(tempDir);
|
|
594
|
+
progress.log(`Temp directory contents: ${tempFiles.join(", ")}`, "info");
|
|
595
|
+
}
|
|
596
|
+
} catch (error) {
|
|
597
|
+
// Clean up on error
|
|
598
|
+
if (_fs.default.existsSync(tempDir)) {
|
|
599
|
+
try {
|
|
600
|
+
;
|
|
601
|
+
(0, _utils.runCommand)(`rm -rf "${tempDir}"`);
|
|
602
|
+
} catch (cleanupError) {
|
|
603
|
+
progress.log(`Warning: Could not cleanup temp directory: ${cleanupError.message}`, "warning");
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
throw new Error(`Failed to create temporary deployment copy: ${error.message}`);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Find and rename any subdirectories that contain the old project name within the temp copy
|
|
610
|
+
try {
|
|
611
|
+
const findCommand = `find "${tempDir}" -type d -name "*${oldProjectName}*"`;
|
|
612
|
+
const result = (0, _utils.runCommand)(findCommand);
|
|
613
|
+
if (result.trim()) {
|
|
614
|
+
const dirsToRename = result.trim().split("\n").filter(dir => dir.trim());
|
|
615
|
+
for (const dir of dirsToRename) {
|
|
616
|
+
const newDirName = dir.split(oldProjectName).join(newProjectName);
|
|
617
|
+
if (dir !== newDirName) {
|
|
618
|
+
;
|
|
619
|
+
(0, _utils.runCommand)(`mv "${dir}" "${newDirName}"`);
|
|
620
|
+
progress.log(`Renamed subdirectory: ${_path.default.basename(dir)} → ${_path.default.basename(newDirName)}`, "success");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
} catch (error) {
|
|
625
|
+
progress.log(`Warning: Error finding subdirectories to rename: ${error.message}`, "warning");
|
|
626
|
+
}
|
|
627
|
+
progress.log("Temporary deployment project created successfully", "success");
|
|
628
|
+
return tempDir;
|
|
629
|
+
}
|
|
630
|
+
async function finalizeAABAndCleanup(projectPaths, androidConfig, aabResult, tempDeploymentPath) {
|
|
631
|
+
const {
|
|
632
|
+
oldProjectPath
|
|
633
|
+
} = projectPaths;
|
|
634
|
+
progress.log("Finalizing AAB and cleaning up temporary files...", "info");
|
|
635
|
+
try {
|
|
636
|
+
// Create final output directory next to original project
|
|
637
|
+
const outputDir = androidConfig.outputPath || _path.default.join(_path.default.dirname(oldProjectPath), "build-output");
|
|
638
|
+
if (!_fs.default.existsSync(outputDir)) {
|
|
639
|
+
_fs.default.mkdirSync(outputDir, {
|
|
640
|
+
recursive: true
|
|
641
|
+
});
|
|
642
|
+
progress.log(`Created output directory: ${outputDir}`, "success");
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Copy AAB to final location with descriptive name
|
|
646
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").split("T")[0];
|
|
647
|
+
const finalAabName = `${androidConfig.newProjectName}-release-${timestamp}.aab`;
|
|
648
|
+
const finalAabPath = _path.default.join(outputDir, finalAabName);
|
|
649
|
+
_fs.default.copyFileSync(aabResult.outputAabPath, finalAabPath);
|
|
650
|
+
progress.log(`AAB saved to final location: ${finalAabPath}`, "success");
|
|
651
|
+
|
|
652
|
+
// Copy keystore to output directory for future use
|
|
653
|
+
const keystorePath = _path.default.join(tempDeploymentPath, "app", "keystore.jks");
|
|
654
|
+
if (_fs.default.existsSync(keystorePath)) {
|
|
655
|
+
const finalKeystorePath = _path.default.join(outputDir, `${androidConfig.newProjectName}-keystore.jks`);
|
|
656
|
+
_fs.default.copyFileSync(keystorePath, finalKeystorePath);
|
|
657
|
+
progress.log(`Keystore copied to: ${finalKeystorePath}`, "success");
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Clean up temporary deployment directory
|
|
661
|
+
await cleanupTempDeployment(tempDeploymentPath);
|
|
662
|
+
return {
|
|
663
|
+
...aabResult,
|
|
664
|
+
finalAabPath,
|
|
665
|
+
finalAabName,
|
|
666
|
+
outputDir
|
|
667
|
+
};
|
|
668
|
+
} catch (error) {
|
|
669
|
+
throw new Error(`Failed to finalize AAB: ${error.message}`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
async function cleanupTempDeployment(tempDeploymentPath) {
|
|
673
|
+
if (!tempDeploymentPath || !_fs.default.existsSync(tempDeploymentPath)) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
try {
|
|
677
|
+
progress.log("Cleaning up temporary deployment files...", "info");
|
|
678
|
+
(0, _utils.runCommand)(`rm -rf "${tempDeploymentPath}"`);
|
|
679
|
+
progress.log("Temporary files cleaned up successfully", "success");
|
|
680
|
+
} catch (error) {
|
|
681
|
+
progress.log(`Warning: Could not cleanup temporary directory: ${error.message}`, "warning");
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
async function updateFileContents(projectPaths, androidConfig) {
|
|
685
|
+
const {
|
|
686
|
+
newProjectPath
|
|
687
|
+
} = projectPaths;
|
|
688
|
+
const {
|
|
689
|
+
oldProjectName,
|
|
690
|
+
newProjectName,
|
|
691
|
+
packageName
|
|
692
|
+
} = androidConfig;
|
|
693
|
+
progress.log("Updating file contents and names...", "info");
|
|
694
|
+
try {
|
|
695
|
+
// STEP 1: Update packageName in build.gradle.kts and source files
|
|
696
|
+
if (packageName) {
|
|
697
|
+
const OLD_PACKAGE = "io.yourname.androidproject";
|
|
698
|
+
progress.log(`Replacing package name: ${OLD_PACKAGE} → ${packageName}`, "info");
|
|
699
|
+
|
|
700
|
+
// Update build.gradle.kts
|
|
701
|
+
const buildGradlePath = _path.default.join(newProjectPath, "app", "build.gradle.kts");
|
|
702
|
+
if (_fs.default.existsSync(buildGradlePath)) {
|
|
703
|
+
let content = _fs.default.readFileSync(buildGradlePath, "utf8");
|
|
704
|
+
content = content.replace(/namespace = "io\.yourname\.androidproject"/g, `namespace = "${packageName}"`);
|
|
705
|
+
content = content.replace(/applicationId = "io\.yourname\.androidproject"/g, `applicationId = "${packageName}"`);
|
|
706
|
+
_fs.default.writeFileSync(buildGradlePath, content, "utf8");
|
|
707
|
+
progress.log(`✅ Updated build.gradle.kts with package: ${packageName}`, "success");
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Update source directory structure for all source sets
|
|
711
|
+
const sourceSets = ["main", "test", "noFcm", "withFcm"];
|
|
712
|
+
const newPackageParts = packageName.split(".");
|
|
713
|
+
let totalUpdatedFiles = 0;
|
|
714
|
+
for (const sourceSet of sourceSets) {
|
|
715
|
+
const oldPackagePath = _path.default.join(newProjectPath, "app", "src", sourceSet, "java", "io", "yourname", "androidproject");
|
|
716
|
+
if (_fs.default.existsSync(oldPackagePath)) {
|
|
717
|
+
const newPackagePath = _path.default.join(newProjectPath, "app", "src", sourceSet, "java", ...newPackageParts);
|
|
718
|
+
const packagePathChanged = _path.default.resolve(oldPackagePath) !== _path.default.resolve(newPackagePath);
|
|
719
|
+
if (packagePathChanged) {
|
|
720
|
+
// Create new package directory
|
|
721
|
+
const newPackageDir = _path.default.dirname(newPackagePath);
|
|
722
|
+
_fs.default.mkdirSync(newPackageDir, {
|
|
723
|
+
recursive: true
|
|
724
|
+
})
|
|
725
|
+
|
|
726
|
+
// Move source files
|
|
727
|
+
;
|
|
728
|
+
(0, _utils.runCommand)(`mv "${oldPackagePath}" "${newPackagePath}"`);
|
|
729
|
+
progress.log(`✅ Moved ${sourceSet} source files to: ${newPackagePath}`, "success");
|
|
730
|
+
} else {
|
|
731
|
+
progress.log(`Package path unchanged for ${sourceSet}; skipping source directory move`, "info");
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Update package declarations in source files
|
|
735
|
+
const findCommand = `find "${newPackagePath}" -type f \\( -name "*.kt" -o -name "*.java" \\)`;
|
|
736
|
+
const sourceFiles = (0, _utils.runCommand)(findCommand).trim().split("\n").filter(f => f.trim());
|
|
737
|
+
let updatedCount = 0;
|
|
738
|
+
for (const file of sourceFiles) {
|
|
739
|
+
let content = _fs.default.readFileSync(file, "utf8");
|
|
740
|
+
if (content.includes(OLD_PACKAGE)) {
|
|
741
|
+
content = content.replace(new RegExp(OLD_PACKAGE, "g"), packageName);
|
|
742
|
+
_fs.default.writeFileSync(file, content, "utf8");
|
|
743
|
+
updatedCount++;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
totalUpdatedFiles += updatedCount;
|
|
747
|
+
progress.log(`✅ Updated package declarations in ${updatedCount} ${sourceSet} files`, "success");
|
|
748
|
+
|
|
749
|
+
// Clean up old empty directories
|
|
750
|
+
try {
|
|
751
|
+
;
|
|
752
|
+
(0, _utils.runCommand)(`find "${_path.default.join(newProjectPath, "app", "src", sourceSet, "java")}" -type d -empty -delete`);
|
|
753
|
+
} catch (err) {
|
|
754
|
+
// Ignore cleanup errors
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
if (totalUpdatedFiles > 0) {
|
|
759
|
+
progress.log(`✅ Total package declarations updated: ${totalUpdatedFiles} files`, "success");
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Update AndroidManifest.xml
|
|
763
|
+
const manifestPath = _path.default.join(newProjectPath, "app", "src", "main", "AndroidManifest.xml");
|
|
764
|
+
if (_fs.default.existsSync(manifestPath)) {
|
|
765
|
+
let content = _fs.default.readFileSync(manifestPath, "utf8");
|
|
766
|
+
if (content.includes(OLD_PACKAGE)) {
|
|
767
|
+
content = content.replace(new RegExp(OLD_PACKAGE, "g"), packageName);
|
|
768
|
+
_fs.default.writeFileSync(manifestPath, content, "utf8");
|
|
769
|
+
progress.log(`✅ Updated AndroidManifest.xml with package: ${packageName}`, "success");
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Update proguard-rules.pro
|
|
774
|
+
const proguardPath = _path.default.join(newProjectPath, "app", "proguard-rules.pro");
|
|
775
|
+
if (_fs.default.existsSync(proguardPath)) {
|
|
776
|
+
let content = _fs.default.readFileSync(proguardPath, "utf8");
|
|
777
|
+
if (content.includes(OLD_PACKAGE)) {
|
|
778
|
+
content = content.replace(new RegExp(OLD_PACKAGE.replace(/\./g, "\\."), "g"), packageName);
|
|
779
|
+
_fs.default.writeFileSync(proguardPath, content, "utf8");
|
|
780
|
+
progress.log(`✅ Updated proguard-rules.pro with package: ${packageName}`, "success");
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// STEP 2: Find and rename files that contain the old project name
|
|
786
|
+
const findFilesCommand = `find "${newProjectPath}" -type f -name "*${oldProjectName}*"`;
|
|
787
|
+
const fileResult = (0, _utils.runCommand)(findFilesCommand);
|
|
788
|
+
if (fileResult.trim()) {
|
|
789
|
+
const filesToRename = fileResult.trim().split("\n").filter(file => file.trim());
|
|
790
|
+
for (const file of filesToRename) {
|
|
791
|
+
const newFileName = file.split(oldProjectName).join(newProjectName);
|
|
792
|
+
if (file !== newFileName) {
|
|
793
|
+
;
|
|
794
|
+
(0, _utils.runCommand)(`mv "${file}" "${newFileName}"`);
|
|
795
|
+
progress.log(`Renamed file: ${_path.default.basename(file)} → ${_path.default.basename(newFileName)}`, "success");
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// STEP 3: Update file contents that reference the old project name
|
|
801
|
+
const fileTypes = ["*.gradle", "*.gradle.kts", "*.xml", "*.json", "*.properties", "*.java", "*.kt", "*.kts", "*.js", "*.ts", "*.md"];
|
|
802
|
+
for (const fileType of fileTypes) {
|
|
803
|
+
try {
|
|
804
|
+
const findContentCommand = `find "${newProjectPath}" -name "${fileType}" -type f`;
|
|
805
|
+
const files = (0, _utils.runCommand)(findContentCommand);
|
|
806
|
+
if (files.trim()) {
|
|
807
|
+
const fileList = files.trim().split("\n").filter(file => file.trim());
|
|
808
|
+
for (const file of fileList) {
|
|
809
|
+
try {
|
|
810
|
+
const content = _fs.default.readFileSync(file, "utf8");
|
|
811
|
+
if (content.includes(oldProjectName)) {
|
|
812
|
+
const updatedContent = content.split(oldProjectName).join(newProjectName);
|
|
813
|
+
_fs.default.writeFileSync(file, updatedContent, "utf8");
|
|
814
|
+
progress.log(`Updated content in: ${_path.default.relative(newProjectPath, file)}`, "info");
|
|
815
|
+
}
|
|
816
|
+
} catch (fileError) {
|
|
817
|
+
progress.log(`Warning: Could not update file ${file}: ${fileError.message}`, "warning");
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
} catch (typeError) {
|
|
822
|
+
// Continue with other file types if one fails
|
|
823
|
+
progress.log(`Warning: Error processing ${fileType} files: ${typeError.message}`, "warning");
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
progress.log("File content updates completed", "success");
|
|
827
|
+
} catch (error) {
|
|
828
|
+
throw new Error(`Error updating file contents: ${error.message}`);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
async function buildAndroidAAB(configPathOrConfig) {
|
|
832
|
+
let androidConfig;
|
|
833
|
+
let projectPaths;
|
|
834
|
+
let backupPath;
|
|
835
|
+
let tempDeploymentPath;
|
|
836
|
+
try {
|
|
837
|
+
// Initialize configuration - handle both config path and direct config object
|
|
838
|
+
progress.start("config");
|
|
839
|
+
if (typeof configPathOrConfig === "string") {
|
|
840
|
+
const {
|
|
841
|
+
android
|
|
842
|
+
} = await initializeConfig(configPathOrConfig);
|
|
843
|
+
androidConfig = android;
|
|
844
|
+
} else {
|
|
845
|
+
// Direct config object passed (from buildAppAndroid.js)
|
|
846
|
+
// All defaults should already be applied in buildAppAndroid.js
|
|
847
|
+
androidConfig = configPathOrConfig;
|
|
848
|
+
|
|
849
|
+
// Validate required fields
|
|
850
|
+
if (!androidConfig.newProjectName) {
|
|
851
|
+
throw new Error("newProjectName is required in android config");
|
|
852
|
+
}
|
|
853
|
+
if (!androidConfig.projectPath) {
|
|
854
|
+
throw new Error("projectPath is required in android config");
|
|
855
|
+
}
|
|
856
|
+
if (!androidConfig.oldProjectName) {
|
|
857
|
+
throw new Error("oldProjectName is required in android config");
|
|
858
|
+
}
|
|
859
|
+
progress.log(`Using configuration from buildAppAndroid.js`, "info");
|
|
860
|
+
progress.log(`Project path: ${androidConfig.projectPath}`, "info");
|
|
861
|
+
progress.log(`Old project name: ${androidConfig.oldProjectName}`, "info");
|
|
862
|
+
progress.log(`New project name: ${androidConfig.newProjectName}`, "info");
|
|
863
|
+
progress.log(`Deployment path: ${androidConfig.deploymentPath || "Not specified"}`, "info");
|
|
864
|
+
progress.log(`Overwrite existing: ${androidConfig.overwriteExisting}`, "info");
|
|
865
|
+
}
|
|
866
|
+
progress.complete("config");
|
|
867
|
+
|
|
868
|
+
// Validate project structure
|
|
869
|
+
progress.start("validation");
|
|
870
|
+
projectPaths = await validateProjectStructure(androidConfig);
|
|
871
|
+
progress.complete("validation");
|
|
872
|
+
|
|
873
|
+
// Create backup if requested
|
|
874
|
+
progress.start("backup");
|
|
875
|
+
backupPath = await createBackup(projectPaths, androidConfig);
|
|
876
|
+
progress.complete("backup");
|
|
877
|
+
|
|
878
|
+
// Create temporary deployment project copy
|
|
879
|
+
progress.start("createTempDeployment");
|
|
880
|
+
tempDeploymentPath = await createTempDeploymentProject(projectPaths, androidConfig);
|
|
881
|
+
progress.complete("createTempDeployment");
|
|
882
|
+
|
|
883
|
+
// Update file contents in temp deployment
|
|
884
|
+
progress.start("updateFileContents");
|
|
885
|
+
await updateFileContents({
|
|
886
|
+
...projectPaths,
|
|
887
|
+
newProjectPath: tempDeploymentPath
|
|
888
|
+
}, androidConfig);
|
|
889
|
+
progress.complete("updateFileContents");
|
|
890
|
+
|
|
891
|
+
// Create keystore if needed
|
|
892
|
+
progress.start("createKeystore");
|
|
893
|
+
const keystorePath = await createKeystore({
|
|
894
|
+
...projectPaths,
|
|
895
|
+
newProjectPath: tempDeploymentPath
|
|
896
|
+
}, androidConfig);
|
|
897
|
+
progress.complete("createKeystore");
|
|
898
|
+
|
|
899
|
+
// Create signed AAB if keystore was created/found and enabled in config
|
|
900
|
+
let aabResult = null;
|
|
901
|
+
if (keystorePath && androidConfig.createSignedAAB) {
|
|
902
|
+
progress.start("createSignedAAB");
|
|
903
|
+
aabResult = await createSignedAAB({
|
|
904
|
+
...projectPaths,
|
|
905
|
+
newProjectPath: tempDeploymentPath
|
|
906
|
+
}, androidConfig, keystorePath);
|
|
907
|
+
progress.complete("createSignedAAB");
|
|
908
|
+
|
|
909
|
+
// Copy AAB to final location and cleanup temp deployment
|
|
910
|
+
if (aabResult) {
|
|
911
|
+
progress.start("finalizeAAB");
|
|
912
|
+
aabResult = await finalizeAABAndCleanup(projectPaths, androidConfig, aabResult, tempDeploymentPath);
|
|
913
|
+
progress.complete("finalizeAAB");
|
|
914
|
+
}
|
|
915
|
+
} else if (!androidConfig.createSignedAAB) {
|
|
916
|
+
progress.log("Signed AAB creation skipped (not enabled in config)", "info");
|
|
917
|
+
// DON'T Clean up temp deployment - keep it for verification
|
|
918
|
+
progress.log(`Temp renamed project kept at: ${tempDeploymentPath}`, "info");
|
|
919
|
+
// await cleanupTempDeployment(tempDeploymentPath)
|
|
920
|
+
} else if (!keystorePath) {
|
|
921
|
+
progress.log("Signed AAB creation skipped (no keystore available)", "warning");
|
|
922
|
+
// DON'T Clean up temp deployment - keep it for verification
|
|
923
|
+
progress.log(`Temp renamed project kept at: ${tempDeploymentPath}`, "info");
|
|
924
|
+
// await cleanupTempDeployment(tempDeploymentPath)
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// Print completion summary
|
|
928
|
+
progress.printTreeContent("Build Summary", ["Android AAB build completed successfully:", {
|
|
929
|
+
text: `Original project: ${projectPaths.oldProjectPath}`,
|
|
930
|
+
indent: 1,
|
|
931
|
+
prefix: "├─ ",
|
|
932
|
+
color: "gray"
|
|
933
|
+
}, {
|
|
934
|
+
text: `Project name: ${androidConfig.oldProjectName} → ${androidConfig.newProjectName}`,
|
|
935
|
+
indent: 1,
|
|
936
|
+
prefix: "├─ ",
|
|
937
|
+
color: "gray"
|
|
938
|
+
}, {
|
|
939
|
+
text: `Deployment path: ${androidConfig.deploymentPath || "Not specified"}`,
|
|
940
|
+
indent: 1,
|
|
941
|
+
prefix: "├─ ",
|
|
942
|
+
color: "gray"
|
|
943
|
+
}, {
|
|
944
|
+
text: `Overwrite existing: ${androidConfig.overwriteExisting}`,
|
|
945
|
+
indent: 1,
|
|
946
|
+
prefix: "├─ ",
|
|
947
|
+
color: "gray"
|
|
948
|
+
}, {
|
|
949
|
+
text: `Backup created: ${backupPath ? "Yes" : "No"}`,
|
|
950
|
+
indent: 1,
|
|
951
|
+
prefix: "├─ ",
|
|
952
|
+
color: "gray"
|
|
953
|
+
}, {
|
|
954
|
+
text: `Keystore: ${keystorePath ? "Created/Verified" : "Skipped"}`,
|
|
955
|
+
indent: 1,
|
|
956
|
+
prefix: "├─ ",
|
|
957
|
+
color: "gray"
|
|
958
|
+
}, {
|
|
959
|
+
text: `Signed AAB: ${aabResult ? "Created" : "Skipped"}`,
|
|
960
|
+
indent: 1,
|
|
961
|
+
prefix: "└─ ",
|
|
962
|
+
color: "gray"
|
|
963
|
+
}, "", "Output Files:", {
|
|
964
|
+
text: `Original preserved at: ${projectPaths.oldProjectPath}`,
|
|
965
|
+
indent: 1,
|
|
966
|
+
prefix: "├─ ",
|
|
967
|
+
color: "green"
|
|
968
|
+
}, ...(backupPath ? [{
|
|
969
|
+
text: `Backup: ${backupPath}`,
|
|
970
|
+
indent: 1,
|
|
971
|
+
prefix: "├─ ",
|
|
972
|
+
color: "gray"
|
|
973
|
+
}] : []), ...(aabResult ? [{
|
|
974
|
+
text: `AAB file: ${aabResult.finalAabPath}`,
|
|
975
|
+
indent: 1,
|
|
976
|
+
prefix: "├─ ",
|
|
977
|
+
color: "green"
|
|
978
|
+
}, {
|
|
979
|
+
text: `AAB size: ${aabResult.fileSize} MB`,
|
|
980
|
+
indent: 1,
|
|
981
|
+
prefix: "└─ ",
|
|
982
|
+
color: "green"
|
|
983
|
+
}] : [{
|
|
984
|
+
text: `No AAB created`,
|
|
985
|
+
indent: 1,
|
|
986
|
+
prefix: "└─ ",
|
|
987
|
+
color: "gray"
|
|
988
|
+
}])]);
|
|
989
|
+
process.exit(0);
|
|
990
|
+
} catch (error) {
|
|
991
|
+
// Clean up temp deployment on error
|
|
992
|
+
if (tempDeploymentPath) {
|
|
993
|
+
await cleanupTempDeployment(tempDeploymentPath);
|
|
994
|
+
}
|
|
995
|
+
if (progress.currentStep) {
|
|
996
|
+
progress.fail(progress.currentStep.id, error.message);
|
|
997
|
+
progress.printTreeContent("Troubleshooting Guide", ["Build operation failed. Please check the following:", {
|
|
998
|
+
text: "Verify config file exists and contains required android configuration",
|
|
999
|
+
indent: 1,
|
|
1000
|
+
prefix: "├─ ",
|
|
1001
|
+
color: "yellow"
|
|
1002
|
+
}, {
|
|
1003
|
+
text: "Ensure project path exists and is accessible",
|
|
1004
|
+
indent: 1,
|
|
1005
|
+
prefix: "├─ ",
|
|
1006
|
+
color: "yellow"
|
|
1007
|
+
}, {
|
|
1008
|
+
text: "Check file/directory permissions",
|
|
1009
|
+
indent: 1,
|
|
1010
|
+
prefix: "├─ ",
|
|
1011
|
+
color: "yellow"
|
|
1012
|
+
}, {
|
|
1013
|
+
text: "Verify no processes are using the project directory",
|
|
1014
|
+
indent: 1,
|
|
1015
|
+
prefix: "├─ ",
|
|
1016
|
+
color: "yellow"
|
|
1017
|
+
}, {
|
|
1018
|
+
text: "Ensure sufficient disk space for project copy",
|
|
1019
|
+
indent: 1,
|
|
1020
|
+
prefix: "├─ ",
|
|
1021
|
+
color: "yellow"
|
|
1022
|
+
}, {
|
|
1023
|
+
text: 'Update keystore passwords (do not use "your_store_password")',
|
|
1024
|
+
indent: 1,
|
|
1025
|
+
prefix: "└─ ",
|
|
1026
|
+
color: "yellow"
|
|
1027
|
+
}, "\nConfiguration Details:", {
|
|
1028
|
+
text: `Config: ${typeof configPathOrConfig === "string" ? configPathOrConfig : "Direct object from buildAppAndroid.js"}`,
|
|
1029
|
+
indent: 1,
|
|
1030
|
+
prefix: "├─ ",
|
|
1031
|
+
color: "gray"
|
|
1032
|
+
}, {
|
|
1033
|
+
text: `Project path: ${androidConfig?.projectPath || "Not loaded"}`,
|
|
1034
|
+
indent: 1,
|
|
1035
|
+
prefix: "├─ ",
|
|
1036
|
+
color: "gray"
|
|
1037
|
+
}, {
|
|
1038
|
+
text: `Deployment path: ${androidConfig?.deploymentPath || "Not loaded"}`,
|
|
1039
|
+
indent: 1,
|
|
1040
|
+
prefix: "├─ ",
|
|
1041
|
+
color: "gray"
|
|
1042
|
+
}, {
|
|
1043
|
+
text: `Old project name: ${androidConfig?.oldProjectName || "Not loaded"}`,
|
|
1044
|
+
indent: 1,
|
|
1045
|
+
prefix: "├─ ",
|
|
1046
|
+
color: "gray"
|
|
1047
|
+
}, {
|
|
1048
|
+
text: `New project name: ${androidConfig?.newProjectName || "Not loaded"}`,
|
|
1049
|
+
indent: 1,
|
|
1050
|
+
prefix: "├─ ",
|
|
1051
|
+
color: "gray"
|
|
1052
|
+
}, {
|
|
1053
|
+
text: `Overwrite existing: ${androidConfig?.overwriteExisting !== undefined ? androidConfig.overwriteExisting : "Not loaded"}`,
|
|
1054
|
+
indent: 1,
|
|
1055
|
+
prefix: "└─ ",
|
|
1056
|
+
color: "gray"
|
|
1057
|
+
}, "\nFor keystore issues, ensure your config has:", {
|
|
1058
|
+
text: "Real passwords (not placeholder values)",
|
|
1059
|
+
indent: 1,
|
|
1060
|
+
prefix: "├─ ",
|
|
1061
|
+
color: "cyan"
|
|
1062
|
+
}, {
|
|
1063
|
+
text: "Valid organization information",
|
|
1064
|
+
indent: 1,
|
|
1065
|
+
prefix: "├─ ",
|
|
1066
|
+
color: "cyan"
|
|
1067
|
+
}, {
|
|
1068
|
+
text: "Consistent store and key passwords for PKCS12",
|
|
1069
|
+
indent: 1,
|
|
1070
|
+
prefix: "└─ ",
|
|
1071
|
+
color: "cyan"
|
|
1072
|
+
}]);
|
|
1073
|
+
}
|
|
1074
|
+
process.exit(1);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
// Export functions for use as a module - using the same export pattern as buildAppAndroid.js
|
|
87
1079
|
// This allows the functions to be imported with ES6 import syntax from other modules
|
|
88
|
-
exports.buildAndroidAAB=buildAndroidAAB;
|
|
89
|
-
|
|
1080
|
+
exports.buildAndroidAAB = buildAndroidAAB;
|
|
1081
|
+
exports.createAndroidDeployment = buildAndroidAAB;
|
|
1082
|
+
exports.renameAndroidProject = buildAndroidAAB;
|
|
1083
|
+
|
|
1084
|
+
// Execute if run directly
|
|
1085
|
+
if (require.main === module) {
|
|
1086
|
+
const configPath = process.argv[2];
|
|
1087
|
+
if (!configPath) {
|
|
1088
|
+
console.error("Usage: node renameAndroidProject.js <config-path>");
|
|
1089
|
+
process.exit(1);
|
|
1090
|
+
}
|
|
1091
|
+
buildAndroidAAB(configPath).catch(error => {
|
|
1092
|
+
console.error("Script failed:", error.message);
|
|
1093
|
+
process.exit(1);
|
|
1094
|
+
});
|
|
1095
|
+
}
|