Add dev live-reload tooling
DevPlugin (native + TS) lets the running app switch its webview to a Vite dev server via DEV_URL, toggled from a hidden DevMenu (5 taps on the app title).
This commit is contained in:
@@ -3,10 +3,26 @@ package com.tiptoisync.app
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import com.getcapacitor.BridgeActivity
|
import com.getcapacitor.BridgeActivity
|
||||||
|
import com.getcapacitor.CapConfig
|
||||||
|
|
||||||
class MainActivity : BridgeActivity() {
|
class MainActivity : BridgeActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
// Dev-URL aus SharedPreferences lesen, bevor die Bridge initialisiert wird.
|
||||||
|
// "CapacitorStorage" ist der von @capacitor/preferences genutzte SharedPreferences-Name.
|
||||||
|
val devUrl = getSharedPreferences("CapacitorStorage", MODE_PRIVATE)
|
||||||
|
.getString("devServerUrl", null)
|
||||||
|
|
||||||
|
if (devUrl != null) {
|
||||||
|
// CapConfig mit der Dev-Server-URL überschreiben – die Bridge lädt dann
|
||||||
|
// direkt vom Vite Dev-Server und injiziert die Bridge trotzdem korrekt.
|
||||||
|
config = CapConfig.Builder(this)
|
||||||
|
.setServerUrl(devUrl)
|
||||||
|
.setAllowMixedContent(true)
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
registerPlugin(TiptoiPlugin::class.java)
|
registerPlugin(TiptoiPlugin::class.java)
|
||||||
|
registerPlugin(DevPlugin::class.java)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { createSignal, onMount, Show } from 'solid-js'
|
||||||
|
import { Preferences } from '@capacitor/preferences'
|
||||||
|
import { Dev } from '../native/DevPlugin'
|
||||||
|
|
||||||
|
const DEV_URL_KEY = 'devServerUrl'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DevMenu(props: Props) {
|
||||||
|
const [url, setUrl] = createSignal('')
|
||||||
|
const [saved, setSaved] = createSignal<string | null>(null)
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const { value } = await Preferences.get({ key: DEV_URL_KEY })
|
||||||
|
setSaved(value)
|
||||||
|
setUrl(value ?? '')
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
const trimmed = url().trim()
|
||||||
|
if (!trimmed) return
|
||||||
|
// Speichern + Activity-Neustart → Bridge initialisiert sich mit Dev-URL
|
||||||
|
await Dev.activate({ url: trimmed })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClear = async () => {
|
||||||
|
// Entfernen + Activity-Neustart → Bridge initialisiert sich mit gebundelter App
|
||||||
|
await Dev.deactivate()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="dev-menu-backdrop" onClick={props.onClose}>
|
||||||
|
<div class="dev-menu" onClick={e => e.stopPropagation()}>
|
||||||
|
<div class="dev-menu__header">
|
||||||
|
<span class="dev-menu__title">⚙️ Dev-Modus</span>
|
||||||
|
<button class="dev-menu__close" onClick={props.onClose}>✕</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="dev-menu__desc">
|
||||||
|
Vite Dev-Server URL eintragen. Die App lädt dann JavaScript direkt
|
||||||
|
vom Dev-Server – inkl. Hot Reload. Native Plugins bleiben aktiv.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Show when={saved()}>
|
||||||
|
<div class="dev-menu__active">
|
||||||
|
<span class="dev-menu__active-dot" />
|
||||||
|
Aktiv: <code>{saved()}</code>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<div class="dev-menu__row">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
type="url"
|
||||||
|
placeholder="http://192.168.1.42:5173"
|
||||||
|
value={url()}
|
||||||
|
onInput={e => setUrl(e.currentTarget.value)}
|
||||||
|
onKeyDown={e => e.key === 'Enter' && handleSave()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dev-menu__actions">
|
||||||
|
<button
|
||||||
|
class="btn"
|
||||||
|
onClick={handleSave}
|
||||||
|
disabled={!url().trim() || url().trim() === saved()}
|
||||||
|
>
|
||||||
|
Speichern & verbinden
|
||||||
|
</button>
|
||||||
|
<Show when={saved()}>
|
||||||
|
<button class="btn btn--ghost" onClick={handleClear}>
|
||||||
|
Dev-Modus deaktivieren
|
||||||
|
</button>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { registerPlugin } from '@capacitor/core'
|
||||||
|
|
||||||
|
export interface DevPlugin {
|
||||||
|
activate(options: { url: string }): Promise<void>
|
||||||
|
deactivate(): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Dev = registerPlugin<DevPlugin>('Dev')
|
||||||
Reference in New Issue
Block a user