Skip to content

Commit 387e73e

Browse files
committed
Fix HMR on android
1 parent 7f512d1 commit 387e73e

File tree

4 files changed

+73
-2
lines changed

4 files changed

+73
-2
lines changed

ANDROID.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,16 @@ This will:
212212
3. Compile Android APK
213213
4. Install and launch on connected device/emulator
214214

215+
Note: Dev mode does not rebuild the `dist/` folder. Tauri will load from `devUrl` during `tauri android dev` and falls back to `dist/` only if the dev server is unreachable. If you need a fresh fallback, build the web assets first:
216+
```bash
217+
yarn build
218+
yarn tauri:dev:android
219+
```
220+
Alternatively, use the convenience script to build dist then run dev:
221+
```bash
222+
yarn tauri:dev:android:with-dist
223+
```
224+
215225
#### Live Reload Setup
216226
To enable hot module replacement on the emulator:
217227

package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,21 @@
3232
"android:emu:start:host": "run-script-os",
3333
"android:emu:start:host:win32": "start \"\" \"%ANDROID_HOME%\\emulator\\emulator.exe\" -avd Medium_Phone_API_35 -gpu host -no-snapshot-load",
3434
"android:emu:start:host:default": "QT_QPA_PLATFORM=xcb $ANDROID_HOME/emulator/emulator -avd ${AVD:-Medium_Phone_API_35} -gpu host -no-snapshot-load &",
35+
"android:adb:wait": "run-script-os",
36+
"android:adb:wait:win32": "%ANDROID_HOME%\\platform-tools\\adb.exe wait-for-device",
37+
"android:adb:wait:default": "$ANDROID_HOME/platform-tools/adb wait-for-device && until $ANDROID_HOME/platform-tools/adb shell getprop sys.boot_completed 2>/dev/null | grep -q 1; do sleep 1; done",
38+
"android:adb:reverse": "run-script-os",
39+
"android:adb:reverse:win32": "%ANDROID_HOME%\\platform-tools\\adb.exe reverse tcp:8000 tcp:8000",
40+
"android:adb:reverse:default": "$ANDROID_HOME/platform-tools/adb reverse tcp:8000 tcp:8000",
3541
"format": "prettier --write {src,test}/**/*.{js,vue,css,less}",
3642
"storybook": "start-storybook -p 6006",
3743
"prepare": "husky install",
3844
"tauri:dev": "tauri dev",
3945
"tauri:build": "tauri build",
4046
"tauri:dev:android": "run-script-os",
41-
"tauri:dev:android:win32": "start \"\" \"%ANDROID_HOME%\\emulator\\emulator.exe\" -avd Medium_Phone_API_35 -gpu swiftshader_indirect -no-snapshot-load && tauri android dev",
42-
"tauri:dev:android:default": "yarn android:emu:start && tauri android dev",
47+
"tauri:dev:android:win32": "start \"\" \"%ANDROID_HOME%\\emulator\\emulator.exe\" -avd Medium_Phone_API_35 -gpu swiftshader_indirect -no-snapshot-load && %ANDROID_HOME%\\platform-tools\\adb.exe wait-for-device && %ANDROID_HOME%\\platform-tools\\adb.exe reverse tcp:8000 tcp:8000 && tauri android dev",
48+
"tauri:dev:android:default": "yarn android:emu:start && yarn android:adb:wait && yarn android:adb:reverse && tauri android dev",
49+
"tauri:dev:android:with-dist": "yarn build && yarn tauri:dev:android",
4350
"tauri:build:android": "tauri android build"
4451
},
4552
"window": {

src/js/utils/checkBrowserCompatibility.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,51 @@
11
import { Capacitor } from "@capacitor/core";
22
import { isTauri } from "@tauri-apps/api/core";
33

4+
// In dev on Android/WebView, a previously installed service worker can cache assets
5+
// and prevent hot updates from Vite. Proactively unregister all SW and clear caches
6+
// when running in dev or in a native (Capacitor/Tauri) context.
7+
async function disableServiceWorkersForDev() {
8+
try {
9+
const isDev = (() => {
10+
try {
11+
return !!(import.meta && import.meta.env && import.meta.env.DEV);
12+
} catch (_) {
13+
return false;
14+
}
15+
})();
16+
const isNative = Capacitor?.isNativePlatform?.() === true;
17+
if ((isDev || isNative) && typeof navigator !== "undefined" && "serviceWorker" in navigator) {
18+
const regs = await navigator.serviceWorker.getRegistrations();
19+
for (const r of regs) {
20+
try {
21+
await r.unregister();
22+
} catch (_) {}
23+
}
24+
if (typeof caches !== "undefined" && caches?.keys) {
25+
const keys = await caches.keys();
26+
for (const k of keys) {
27+
try {
28+
await caches.delete(k);
29+
} catch (_) {}
30+
}
31+
}
32+
// Also attempt to stop active controller
33+
if (navigator.serviceWorker.controller) {
34+
try {
35+
navigator.serviceWorker.controller.postMessage({ type: "SKIP_WAITING" });
36+
} catch (_) {}
37+
}
38+
// Small delay to ensure SW is cleared before app logic proceeds
39+
await new Promise((res) => setTimeout(res, 50));
40+
}
41+
} catch (_) {
42+
// best-effort; ignore
43+
}
44+
}
45+
46+
// Fire and forget; we don't block app init
47+
// disableServiceWorkersForDev();
48+
449
// Detects OS using modern userAgentData API with fallback to legacy platform
550
// Returns standardized OS name string or "unknown"
651
export function getOS() {

vite.config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ export default defineConfig({
8686
}),
8787
VitePWA({
8888
registerType: "prompt",
89+
devOptions: {
90+
enabled: false,
91+
},
8992
workbox: {
9093
globPatterns: ["**/*.{js,css,html,ico,png,svg,json,mcm}"],
9194
// 5MB
@@ -123,6 +126,12 @@ export default defineConfig({
123126
server: {
124127
port: 8000,
125128
strictPort: true,
129+
host: true,
130+
hmr: {
131+
protocol: "ws",
132+
host: "localhost",
133+
clientPort: 8000,
134+
},
126135
},
127136
preview: {
128137
port: 8080,

0 commit comments

Comments
 (0)