mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 14:45:49 +01:00
Merge 75eaaf29fb into bb4fbf9574
This commit is contained in:
commit
4ccee28a2d
3 changed files with 166 additions and 17 deletions
|
|
@ -139,8 +139,11 @@ static void executeJavaScriptOnBridge(const char* js) {
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
|
|
@ -148,8 +151,6 @@ import (
|
|||
"time"
|
||||
"unsafe"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/wailsapp/wails/v3/internal/runtime"
|
||||
)
|
||||
|
||||
|
|
@ -221,6 +222,12 @@ func (a *App) platformRun() {
|
|||
globalApp = a
|
||||
globalAppLock.Unlock()
|
||||
|
||||
// Create MessageProcessor so JNI message callbacks can route runtime calls
|
||||
messageProc := NewMessageProcessor(slog.Default())
|
||||
globalMessageProcLock.Lock()
|
||||
globalMessageProc = messageProc
|
||||
globalMessageProcLock.Unlock()
|
||||
|
||||
// Signal that the app is ready to serve requests
|
||||
signalAppReady()
|
||||
|
||||
|
|
@ -259,6 +266,9 @@ func newPlatformApp(app *App) *androidApp {
|
|||
func (a *androidApp) run() error {
|
||||
androidLogf("info", "🤖 [application_android.go] androidApp.run() called")
|
||||
|
||||
// Wire platform events → common events (same as non-CGO build)
|
||||
a.setupCommonEvents()
|
||||
|
||||
// Emit application started event
|
||||
a.parent.Event.Emit("ApplicationStarted")
|
||||
|
||||
|
|
@ -433,7 +443,7 @@ func Java_com_wails_app_WailsBridge_nativeOnPageFinished(env *C.JNIEnv, obj C.jo
|
|||
if win != nil {
|
||||
androidLogf("info", "🤖 [JNI] Injecting runtime.Core() into window %d", id)
|
||||
// Get the runtime core JavaScript
|
||||
runtimeJS := runtime.Core()
|
||||
runtimeJS := runtime.Core(app.impl.GetFlags(app.options))
|
||||
androidLogf("info", "🤖 [JNI] Runtime JS length: %d bytes", len(runtimeJS))
|
||||
app.windowsLock.RUnlock()
|
||||
// IMPORTANT: We must bypass win.ExecJS because it queues if runtimeLoaded is false.
|
||||
|
|
@ -621,16 +631,60 @@ func serveAssetForAndroid(app *App, path string) ([]byte, error) {
|
|||
return body, nil
|
||||
}
|
||||
|
||||
// Global MessageProcessor for Android JNI callbacks
|
||||
var (
|
||||
globalMessageProc *MessageProcessor
|
||||
globalMessageProcLock sync.RWMutex
|
||||
)
|
||||
|
||||
func handleMessageForAndroid(app *App, message string) string {
|
||||
// Parse the message
|
||||
var msg map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(message), &msg); err != nil {
|
||||
// Some messages are plain strings (e.g. "wails:runtime:ready"), not JSON.
|
||||
// The JS bridge sends: typeof m==='string' ? m : JSON.stringify(m)
|
||||
if len(message) == 0 || message[0] != '{' {
|
||||
androidLogf("debug", "🤖 [handleMessageForAndroid] Non-JSON message: %s", message)
|
||||
return `{"success":true}`
|
||||
}
|
||||
|
||||
var req RuntimeRequest
|
||||
if err := json.Unmarshal([]byte(message), &req); err != nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] Failed to parse: %v", err)
|
||||
return fmt.Sprintf(`{"error":"%s"}`, err.Error())
|
||||
}
|
||||
|
||||
// TODO: Route to appropriate handler based on message type
|
||||
// For now, return success
|
||||
return `{"success":true}`
|
||||
// Fill in a window ID if none was provided (Android typically has one window)
|
||||
if req.WebviewWindowID == 0 && req.WebviewWindowName == "" {
|
||||
windows := app.Window.GetAll()
|
||||
if len(windows) > 0 {
|
||||
req.WebviewWindowID = uint32(windows[0].ID())
|
||||
}
|
||||
}
|
||||
|
||||
globalMessageProcLock.RLock()
|
||||
messageProc := globalMessageProc
|
||||
globalMessageProcLock.RUnlock()
|
||||
|
||||
if messageProc == nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] MessageProcessor not initialized")
|
||||
return `{"error":"MessageProcessor not initialized"}`
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
result, err := messageProc.HandleRuntimeCallWithIDs(ctx, &req)
|
||||
if err != nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] Error: %v", err)
|
||||
return fmt.Sprintf(`{"error":"%s"}`, err.Error())
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return `{"success":true}`
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] Marshal error: %v", err)
|
||||
return fmt.Sprintf(`{"error":"%s"}`, err.Error())
|
||||
}
|
||||
return string(resp)
|
||||
}
|
||||
|
||||
func getMimeTypeForPath(path string) string {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -38,6 +39,12 @@ func (a *App) platformRun() {
|
|||
globalApp = a
|
||||
globalAppLock.Unlock()
|
||||
|
||||
// Create MessageProcessor so message callbacks can route runtime calls
|
||||
messageProc := NewMessageProcessor(slog.Default())
|
||||
globalMessageProcLock.Lock()
|
||||
globalMessageProc = messageProc
|
||||
globalMessageProcLock.Unlock()
|
||||
|
||||
androidLogf("info", "🤖 [application_android.go] Waiting for Android lifecycle...")
|
||||
|
||||
// Block forever - Android manages the app lifecycle via JNI callbacks
|
||||
|
|
@ -171,16 +178,58 @@ func serveAssetForAndroid(app *App, path string) ([]byte, error) {
|
|||
return nil, fmt.Errorf("asset serving not yet implemented: %s", path)
|
||||
}
|
||||
|
||||
// Global MessageProcessor for message callbacks
|
||||
var (
|
||||
globalMessageProc *MessageProcessor
|
||||
globalMessageProcLock sync.RWMutex
|
||||
)
|
||||
|
||||
func handleMessageForAndroid(app *App, message string) string {
|
||||
// Parse the message
|
||||
var msg map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(message), &msg); err != nil {
|
||||
// Some messages are plain strings (e.g. "wails:runtime:ready"), not JSON.
|
||||
if len(message) == 0 || message[0] != '{' {
|
||||
androidLogf("debug", "🤖 [handleMessageForAndroid] Non-JSON message: %s", message)
|
||||
return `{"success":true}`
|
||||
}
|
||||
|
||||
var req RuntimeRequest
|
||||
if err := json.Unmarshal([]byte(message), &req); err != nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] Failed to parse: %v", err)
|
||||
return fmt.Sprintf(`{"error":"%s"}`, err.Error())
|
||||
}
|
||||
|
||||
// TODO: Route to appropriate handler based on message type
|
||||
// For now, return success
|
||||
return `{"success":true}`
|
||||
if req.WebviewWindowID == 0 && req.WebviewWindowName == "" {
|
||||
windows := app.Window.GetAll()
|
||||
if len(windows) > 0 {
|
||||
req.WebviewWindowID = uint32(windows[0].ID())
|
||||
}
|
||||
}
|
||||
|
||||
globalMessageProcLock.RLock()
|
||||
messageProc := globalMessageProc
|
||||
globalMessageProcLock.RUnlock()
|
||||
|
||||
if messageProc == nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] MessageProcessor not initialized")
|
||||
return `{"error":"MessageProcessor not initialized"}`
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
result, err := messageProc.HandleRuntimeCallWithIDs(ctx, &req)
|
||||
if err != nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] Error: %v", err)
|
||||
return fmt.Sprintf(`{"error":"%s"}`, err.Error())
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
return `{"success":true}`
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
androidLogf("error", "🤖 [handleMessageForAndroid] Marshal error: %v", err)
|
||||
return fmt.Sprintf(`{"error":"%s"}`, err.Error())
|
||||
}
|
||||
return string(resp)
|
||||
}
|
||||
|
||||
func getMimeTypeForPath(path string) string {
|
||||
|
|
|
|||
|
|
@ -523,6 +523,40 @@ func newIOSEvents() iosEvents {
|
|||
}
|
||||
}
|
||||
|
||||
var Android = newAndroidEvents()
|
||||
|
||||
type androidEvents struct {
|
||||
ActivityCreated ApplicationEventType
|
||||
ActivityStarted ApplicationEventType
|
||||
ActivityResumed ApplicationEventType
|
||||
ActivityPaused ApplicationEventType
|
||||
ActivityStopped ApplicationEventType
|
||||
ActivityDestroyed ApplicationEventType
|
||||
ApplicationLowMemory ApplicationEventType
|
||||
ApplicationConfigChanged ApplicationEventType
|
||||
WebViewDidStartNavigation WindowEventType
|
||||
WebViewDidFinishNavigation WindowEventType
|
||||
WebViewDidFailNavigation WindowEventType
|
||||
WebViewReceivedError WindowEventType
|
||||
}
|
||||
|
||||
func newAndroidEvents() androidEvents {
|
||||
return androidEvents{
|
||||
ActivityCreated: 1259,
|
||||
ActivityStarted: 1260,
|
||||
ActivityResumed: 1261,
|
||||
ActivityPaused: 1262,
|
||||
ActivityStopped: 1263,
|
||||
ActivityDestroyed: 1264,
|
||||
ApplicationLowMemory: 1265,
|
||||
ApplicationConfigChanged: 1266,
|
||||
WebViewDidStartNavigation: 1267,
|
||||
WebViewDidFinishNavigation: 1268,
|
||||
WebViewDidFailNavigation: 1269,
|
||||
WebViewReceivedError: 1270,
|
||||
}
|
||||
}
|
||||
|
||||
func JSEvent(event uint) string {
|
||||
return eventToJS[event]
|
||||
}
|
||||
|
|
@ -763,4 +797,16 @@ var eventToJS = map[uint]string{
|
|||
1256: "ios:WebViewDidFinishNavigation",
|
||||
1257: "ios:WebViewDidFailNavigation",
|
||||
1258: "ios:WebViewDecidePolicyForNavigationAction",
|
||||
1259: "android:ActivityCreated",
|
||||
1260: "android:ActivityStarted",
|
||||
1261: "android:ActivityResumed",
|
||||
1262: "android:ActivityPaused",
|
||||
1263: "android:ActivityStopped",
|
||||
1264: "android:ActivityDestroyed",
|
||||
1265: "android:ApplicationLowMemory",
|
||||
1266: "android:ApplicationConfigChanged",
|
||||
1267: "android:WebViewDidStartNavigation",
|
||||
1268: "android:WebViewDidFinishNavigation",
|
||||
1269: "android:WebViewDidFailNavigation",
|
||||
1270: "android:WebViewReceivedError",
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue