html2apk 0.3.0 → 0.5.0
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/README.md +114 -31
- package/examples/minimal/dist/MeuApp-1.0.0-debug.apk +0 -0
- package/package.json +1 -1
- package/src/cordova/project.js +19 -1
- package/src/core/build-apk.js +268 -30
- package/src/desktop/main.js +132 -1
- package/src/desktop/preload.js +13 -0
- package/src/desktop/renderer/index.html +3 -2
- package/src/desktop/renderer/renderer.js +997 -39
- package/src/desktop/renderer/styles.css +60 -2
- package/src/templates/cordova-plugin-html2apk-bridge/plugin.xml +2 -0
- package/src/templates/cordova-plugin-html2apk-bridge/src/android/Html2ApkBridge.java +458 -34
- package/src/templates/cordova-plugin-html2apk-bridge/src/android/NotificationClickReceiver.java +28 -0
- package/src/templates/cordova-plugin-html2apk-bridge/src/android/NotificationReceiver.java +1 -1
- package/src/templates/cordova-plugin-html2apk-bridge/www/html2apk-bridge.js +306 -10
- package/src/templates/html2apk-early-bridge.js +860 -0
- package/src/templates/html2apk-onesignal.js +1 -1
- package/src/utils/command-runner.js +3 -0
package/src/desktop/main.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
const nodeFs = require("fs");
|
|
3
4
|
const fs = require("fs/promises");
|
|
4
5
|
const path = require("path");
|
|
5
6
|
const { spawn } = require("child_process");
|
|
6
7
|
const { app, BrowserWindow, dialog, ipcMain, screen, shell } = require("electron");
|
|
7
|
-
const { buildApk } = require("../core/build-apk");
|
|
8
|
+
const { buildApk, runDebugUsb } = require("../core/build-apk");
|
|
8
9
|
const {
|
|
9
10
|
REQUIRED_ANDROID_BUILD_TOOLS,
|
|
10
11
|
REQUIRED_ANDROID_PLATFORM,
|
|
@@ -13,6 +14,9 @@ const {
|
|
|
13
14
|
const { runDoctor, formatDoctorReport } = require("../runtime-manager/doctor");
|
|
14
15
|
|
|
15
16
|
let mainWindow = null;
|
|
17
|
+
let projectWatcher = null;
|
|
18
|
+
let projectWatchTimer = null;
|
|
19
|
+
let watchedProjectRoot = null;
|
|
16
20
|
const smokeTest = process.env.HTML2APK_DESKTOP_SMOKE === "1";
|
|
17
21
|
const APP_ID = "dev.caiomultiversando.html2apk";
|
|
18
22
|
const APP_NAME = "html2apk";
|
|
@@ -135,6 +139,90 @@ async function inspectProject(projectRoot) {
|
|
|
135
139
|
};
|
|
136
140
|
}
|
|
137
141
|
|
|
142
|
+
function shouldIgnoreProjectWatchPath(fileName) {
|
|
143
|
+
const normalized = String(fileName || "").replace(/\\/g, "/");
|
|
144
|
+
return normalized
|
|
145
|
+
&& (normalized.includes(".html2apk-doctor-")
|
|
146
|
+
|| normalized.startsWith("dist/")
|
|
147
|
+
|| normalized === "dist"
|
|
148
|
+
|| normalized.startsWith("node_modules/")
|
|
149
|
+
|| normalized === "node_modules"
|
|
150
|
+
|| normalized.startsWith(".git/")
|
|
151
|
+
|| normalized === ".git");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function stopProjectWatcher() {
|
|
155
|
+
if (projectWatchTimer) {
|
|
156
|
+
clearTimeout(projectWatchTimer);
|
|
157
|
+
projectWatchTimer = null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (projectWatcher) {
|
|
161
|
+
projectWatcher.close();
|
|
162
|
+
projectWatcher = null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
watchedProjectRoot = null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function startProjectWatcher(projectRoot, sender) {
|
|
169
|
+
stopProjectWatcher();
|
|
170
|
+
watchedProjectRoot = projectRoot;
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
projectWatcher = nodeFs.watch(projectRoot, { recursive: true }, (eventType, fileName) => {
|
|
174
|
+
if (shouldIgnoreProjectWatchPath(fileName)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const changedPath = path.join(projectRoot, String(fileName || ""));
|
|
179
|
+
if (projectWatchTimer) {
|
|
180
|
+
clearTimeout(projectWatchTimer);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
projectWatchTimer = setTimeout(async () => {
|
|
184
|
+
projectWatchTimer = null;
|
|
185
|
+
try {
|
|
186
|
+
if (watchedProjectRoot !== projectRoot) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const project = await inspectProject(projectRoot);
|
|
191
|
+
sender.send("project:changed", {
|
|
192
|
+
eventType,
|
|
193
|
+
changedPath,
|
|
194
|
+
project,
|
|
195
|
+
time: new Date().toISOString()
|
|
196
|
+
});
|
|
197
|
+
} catch (error) {
|
|
198
|
+
sender.send("project:watch-error", {
|
|
199
|
+
message: error.message,
|
|
200
|
+
time: new Date().toISOString()
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}, 350);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
projectWatcher.on("error", (error) => {
|
|
207
|
+
sender.send("project:watch-error", {
|
|
208
|
+
message: error.message,
|
|
209
|
+
time: new Date().toISOString()
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
ok: true,
|
|
215
|
+
projectRoot
|
|
216
|
+
};
|
|
217
|
+
} catch (error) {
|
|
218
|
+
stopProjectWatcher();
|
|
219
|
+
return {
|
|
220
|
+
ok: false,
|
|
221
|
+
message: error.message
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
138
226
|
function cleanBuildOptions(options = {}) {
|
|
139
227
|
const output = {
|
|
140
228
|
projectRoot: options.projectRoot,
|
|
@@ -365,6 +453,7 @@ app.whenReady().then(() => {
|
|
|
365
453
|
});
|
|
366
454
|
|
|
367
455
|
app.on("window-all-closed", () => {
|
|
456
|
+
stopProjectWatcher();
|
|
368
457
|
if (process.platform !== "darwin") {
|
|
369
458
|
app.quit();
|
|
370
459
|
}
|
|
@@ -440,6 +529,15 @@ ipcMain.handle("project:inspect", async (_event, projectRoot) => {
|
|
|
440
529
|
return inspectProject(projectRoot);
|
|
441
530
|
});
|
|
442
531
|
|
|
532
|
+
ipcMain.handle("project:watch", async (event, projectRoot) => {
|
|
533
|
+
return startProjectWatcher(projectRoot, event.sender);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
ipcMain.handle("project:unwatch", async () => {
|
|
537
|
+
stopProjectWatcher();
|
|
538
|
+
return { ok: true };
|
|
539
|
+
});
|
|
540
|
+
|
|
443
541
|
ipcMain.handle("doctor:run", async (_event, projectRoot) => {
|
|
444
542
|
const report = await runDoctor({ projectRoot });
|
|
445
543
|
return {
|
|
@@ -517,6 +615,39 @@ ipcMain.handle("build:run", async (event, options) => {
|
|
|
517
615
|
}
|
|
518
616
|
});
|
|
519
617
|
|
|
618
|
+
ipcMain.handle("build:run-usb-debug", async (event, options) => {
|
|
619
|
+
const buildOptions = cleanBuildOptions(options);
|
|
620
|
+
const sendLog = (line, kind = "raw") => {
|
|
621
|
+
event.sender.send("build:log", {
|
|
622
|
+
line,
|
|
623
|
+
kind,
|
|
624
|
+
time: new Date().toISOString()
|
|
625
|
+
});
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
try {
|
|
629
|
+
sendLog("Starting html2apk USB debug build.", "system");
|
|
630
|
+
const result = await runDebugUsb({
|
|
631
|
+
...buildOptions,
|
|
632
|
+
release: false,
|
|
633
|
+
onLog: (line) => sendLog(line)
|
|
634
|
+
});
|
|
635
|
+
sendLog(`USB debug installed on device: ${result.device?.id || "Android device"}`, "success");
|
|
636
|
+
return {
|
|
637
|
+
ok: true,
|
|
638
|
+
result
|
|
639
|
+
};
|
|
640
|
+
} catch (error) {
|
|
641
|
+
sendLog(error.message, "error");
|
|
642
|
+
return {
|
|
643
|
+
ok: false,
|
|
644
|
+
message: error.message,
|
|
645
|
+
logs: error.logs || [],
|
|
646
|
+
buildDir: error.buildDir || null
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
|
|
520
651
|
ipcMain.handle("shell:open-path", async (_event, targetPath) => {
|
|
521
652
|
if (!targetPath) {
|
|
522
653
|
return false;
|
package/src/desktop/preload.js
CHANGED
|
@@ -7,9 +7,12 @@ contextBridge.exposeInMainWorld("html2apkDesktop", {
|
|
|
7
7
|
selectFolder: () => ipcRenderer.invoke("dialog:select-folder"),
|
|
8
8
|
selectIcon: () => ipcRenderer.invoke("dialog:select-icon"),
|
|
9
9
|
inspectProject: (projectRoot) => ipcRenderer.invoke("project:inspect", projectRoot),
|
|
10
|
+
watchProject: (projectRoot) => ipcRenderer.invoke("project:watch", projectRoot),
|
|
11
|
+
unwatchProject: () => ipcRenderer.invoke("project:unwatch"),
|
|
10
12
|
runDoctor: (projectRoot) => ipcRenderer.invoke("doctor:run", projectRoot),
|
|
11
13
|
installAndroidRequirements: () => ipcRenderer.invoke("install:android-requirements"),
|
|
12
14
|
runBuild: (options) => ipcRenderer.invoke("build:run", options),
|
|
15
|
+
runUsbDebugBuild: (options) => ipcRenderer.invoke("build:run-usb-debug", options),
|
|
13
16
|
openPath: (targetPath) => ipcRenderer.invoke("shell:open-path", targetPath),
|
|
14
17
|
showItem: (targetPath) => ipcRenderer.invoke("shell:show-item", targetPath),
|
|
15
18
|
openExternalUrl: (targetUrl) => ipcRenderer.invoke("shell:open-external", targetUrl),
|
|
@@ -27,5 +30,15 @@ contextBridge.exposeInMainWorld("html2apkDesktop", {
|
|
|
27
30
|
const handler = (_event, payload) => listener(payload);
|
|
28
31
|
ipcRenderer.on("install:log", handler);
|
|
29
32
|
return () => ipcRenderer.removeListener("install:log", handler);
|
|
33
|
+
},
|
|
34
|
+
onProjectChanged: (listener) => {
|
|
35
|
+
const handler = (_event, payload) => listener(payload);
|
|
36
|
+
ipcRenderer.on("project:changed", handler);
|
|
37
|
+
return () => ipcRenderer.removeListener("project:changed", handler);
|
|
38
|
+
},
|
|
39
|
+
onProjectWatchError: (listener) => {
|
|
40
|
+
const handler = (_event, payload) => listener(payload);
|
|
41
|
+
ipcRenderer.on("project:watch-error", handler);
|
|
42
|
+
return () => ipcRenderer.removeListener("project:watch-error", handler);
|
|
30
43
|
}
|
|
31
44
|
});
|
|
@@ -287,6 +287,7 @@
|
|
|
287
287
|
</div>
|
|
288
288
|
<section class="action-strip">
|
|
289
289
|
<button id="buildButton" class="primary-action" type="button" disabled data-i18n="startBuild">Gerar APK</button>
|
|
290
|
+
<button id="usbDebugButton" class="secondary-action" type="button" disabled data-i18n="startUsbDebug">Testar no USB</button>
|
|
290
291
|
</section>
|
|
291
292
|
<div id="resultPanel" class="result-panel hidden">
|
|
292
293
|
<div>
|
|
@@ -304,8 +305,8 @@
|
|
|
304
305
|
<div class="success-panel">
|
|
305
306
|
<img src="../../../html2apk.png" alt="" class="success-icon">
|
|
306
307
|
<p class="eyebrow" data-i18n="successEyebrow">Concluido</p>
|
|
307
|
-
<h1 data-i18n="successTitle">APK gerado com sucesso</h1>
|
|
308
|
-
<p data-i18n="successText">Seu arquivo Android esta pronto na pasta dist.</p>
|
|
308
|
+
<h1 id="successTitle" data-i18n="successTitle">APK gerado com sucesso</h1>
|
|
309
|
+
<p id="successText" data-i18n="successText">Seu arquivo Android esta pronto na pasta dist.</p>
|
|
309
310
|
<code id="successApkPath">-</code>
|
|
310
311
|
<div class="result-actions">
|
|
311
312
|
<button id="successOpenDistButton" class="secondary-action" type="button" data-i18n="openDist">Abrir dist</button>
|