功能批量实现 优化 服务端 新浮动小游戏框架 新界面UI
This commit is contained in:
@@ -6,6 +6,8 @@ using System.Collections;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine.Networking;
|
||||
using GameServer.Client;
|
||||
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
@@ -19,7 +21,7 @@ public class WebViewLauncher : MonoBehaviour
|
||||
public Vector2 windowPosition = new Vector2(100, 100);
|
||||
|
||||
[Header("Editor Only Path")]
|
||||
public string editorExeRoot = @"E:\Unity\ban_total\fdBrowser";
|
||||
public string editorExeRoot = @"E:\Unity\ban_total\fdGamer\build\windows\x64\runner\Release";
|
||||
|
||||
[Header("H5 Folder Paths")]
|
||||
public string h5EditorPath = @"E:\Unity\ban_total\ban_test\Bansonic_Data\StreamingAssets\h5LG";
|
||||
@@ -28,6 +30,8 @@ public class WebViewLauncher : MonoBehaviour
|
||||
public string thirdPartyGamesPath = "_thirdPartyGames";
|
||||
|
||||
private Process webProcess;
|
||||
private const string FlutterExeName = "浮动小游戏.exe";
|
||||
private const string LocalControlBaseUrl = "http://127.0.0.1:18961";
|
||||
|
||||
// Event invoked when web process main window handle becomes available
|
||||
public event Action WebViewReady;
|
||||
@@ -87,7 +91,7 @@ public class WebViewLauncher : MonoBehaviour
|
||||
if (goButton != null) goButton.onClick.AddListener(OnGoButtonClicked);
|
||||
|
||||
// Load autostart preference and bind toggle
|
||||
autostart = PlayerPrefs.GetInt(PREF_AUTOSTART, 1) == 1;
|
||||
autostart = PlayerPrefs.GetInt(PREF_AUTOSTART, 0) == 1;
|
||||
if (autostartToggle != null)
|
||||
{
|
||||
autostartToggle.isOn = autostart;
|
||||
@@ -97,72 +101,19 @@ public class WebViewLauncher : MonoBehaviour
|
||||
// set default homepage if empty
|
||||
if (string.IsNullOrEmpty(homepageUrl))
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string candidate = Path.Combine(h5EditorPath, "_officialDocs", "openings", "index.html");
|
||||
if (File.Exists(candidate))
|
||||
homepageUrl = new Uri(candidate).AbsoluteUri;
|
||||
else
|
||||
homepageUrl = startUrl;
|
||||
#else
|
||||
string candidate = Path.Combine(Application.streamingAssetsPath, "h5LG", "_officialDocs", "openings", "index.html");
|
||||
if (File.Exists(candidate))
|
||||
homepageUrl = new Uri(candidate).AbsoluteUri;
|
||||
else
|
||||
homepageUrl = startUrl;
|
||||
#endif
|
||||
homepageUrl = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Ensure H5 root exists
|
||||
string h5Folder = GetH5FolderPath();
|
||||
if (!Directory.Exists(h5Folder))
|
||||
{
|
||||
Directory.CreateDirectory(h5Folder);
|
||||
Debug.Log("Created H5 folder: " + h5Folder);
|
||||
}
|
||||
|
||||
// Ensure controlText is visible by default
|
||||
if (controlText != null)
|
||||
{
|
||||
controlText.gameObject.SetActive(true);
|
||||
Debug.Log("Control text set to visible by default");
|
||||
}
|
||||
|
||||
// Prefer explicit openings index as startup page when available
|
||||
string preferred = Path.Combine(h5Folder, "_officialDocs", "openings", "index.html");
|
||||
if (File.Exists(preferred))
|
||||
{
|
||||
startUrl = new Uri(preferred).AbsoluteUri;
|
||||
Debug.Log("Using preferred startup page: " + startUrl);
|
||||
// show initial url in input field
|
||||
if (urlInputField != null)
|
||||
urlInputField.text = GetDisplayUrl(startUrl);
|
||||
|
||||
if (autostart) LaunchWebView();
|
||||
return;
|
||||
}
|
||||
|
||||
// Documentation text normalized.
|
||||
var h5SubFolders = ScanH5Folders(h5Folder);
|
||||
if (h5SubFolders.Count > 0)
|
||||
{
|
||||
Debug.Log("Found H5 folders: " + string.Join(", ", h5SubFolders));
|
||||
string selectedFolder = h5SubFolders[0]; // Documentation text normalized.
|
||||
string candidatePath = Path.Combine(h5Folder, selectedFolder, "index.html");
|
||||
startUrl = new Uri(candidatePath).AbsoluteUri; // ensure proper file:/// URI
|
||||
Debug.Log("Selected H5 folder: " + selectedFolder + ", URL: " + startUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("No H5 subfolders with index.html found in: " + h5Folder);
|
||||
}
|
||||
|
||||
// show initial url in input field if available (use shortened display for local files that are indexed)
|
||||
if (urlInputField != null)
|
||||
{
|
||||
urlInputField.text = GetDisplayUrl(startUrl);
|
||||
urlInputField.text = string.Empty;
|
||||
}
|
||||
|
||||
if (autostart) LaunchWebView();
|
||||
@@ -245,7 +196,65 @@ public class WebViewLauncher : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
string GetServerBaseUrl()
|
||||
{
|
||||
if (NetworkManager.Instance != null && !string.IsNullOrWhiteSpace(NetworkManager.Instance.ServerUrl))
|
||||
{
|
||||
string raw = NetworkManager.Instance.ServerUrl.Trim();
|
||||
if (Uri.TryCreate(raw, UriKind.Absolute, out Uri parsed))
|
||||
{
|
||||
return $"{parsed.Scheme}://{parsed.Authority}";
|
||||
}
|
||||
return raw.TrimEnd('/');
|
||||
}
|
||||
return "http://47.112.187.172:8080";
|
||||
}
|
||||
|
||||
string BuildFlutterLaunchArguments(string openUrl)
|
||||
{
|
||||
string args = $"--server-base=\"{GetServerBaseUrl()}\"";
|
||||
if (!string.IsNullOrWhiteSpace(openUrl))
|
||||
{
|
||||
args += $" --open-url=\"{openUrl}\"";
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
IEnumerator SendLocalControlRequest(string path, string method = UnityWebRequest.kHttpVerbGET, string jsonBody = null)
|
||||
{
|
||||
string url = $"{LocalControlBaseUrl}{path}";
|
||||
using UnityWebRequest request = new UnityWebRequest(url, method);
|
||||
request.downloadHandler = new DownloadHandlerBuffer();
|
||||
if (!string.IsNullOrEmpty(jsonBody))
|
||||
{
|
||||
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonBody);
|
||||
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
|
||||
request.SetRequestHeader("Content-Type", "application/json");
|
||||
}
|
||||
yield return request.SendWebRequest();
|
||||
if (request.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
Debug.LogWarning($"Local Flutter control request failed: {method} {url} -> {request.error}");
|
||||
}
|
||||
}
|
||||
|
||||
void SendLocalControlOpen(string normalizedUrl)
|
||||
{
|
||||
string escaped = normalizedUrl.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
||||
StartCoroutine(SendLocalControlRequest("/open", UnityWebRequest.kHttpVerbPOST, $"{{\"url\":\"{escaped}\"}}"));
|
||||
}
|
||||
|
||||
void SendLocalControlCommand(string path)
|
||||
{
|
||||
StartCoroutine(SendLocalControlRequest(path));
|
||||
}
|
||||
|
||||
void LaunchWebView()
|
||||
{
|
||||
LaunchWebViewWithUrl(string.Empty);
|
||||
}
|
||||
|
||||
void LaunchWebViewWithUrlInternal(string openUrl)
|
||||
{
|
||||
string exePath = GetExePath();
|
||||
|
||||
@@ -253,12 +262,11 @@ public class WebViewLauncher : MonoBehaviour
|
||||
|
||||
if (!File.Exists(exePath))
|
||||
{
|
||||
Debug.LogError("fdBrowser.exe not found: " + exePath);
|
||||
Debug.LogError("浮动小游戏主程序不存在: " + exePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// Documentation text normalized.
|
||||
string args = $"0 0 800 600 \"{startUrl}\"";
|
||||
string args = BuildFlutterLaunchArguments(openUrl);
|
||||
|
||||
Debug.Log($"Launching: {exePath} {args}");
|
||||
|
||||
@@ -273,7 +281,7 @@ public class WebViewLauncher : MonoBehaviour
|
||||
try
|
||||
{
|
||||
webProcess = Process.Start(psi);
|
||||
Debug.Log("WebView2Host started successfully. Process ID: " + webProcess.Id);
|
||||
Debug.Log("浮动小游戏已启动。PID: " + webProcess.Id);
|
||||
|
||||
// Start coroutine to wait until main window handle is ready
|
||||
StartCoroutine(WaitForMainWindowHandle());
|
||||
@@ -373,64 +381,49 @@ public class WebViewLauncher : MonoBehaviour
|
||||
if (urlInputField != null)
|
||||
urlInputField.text = GetDisplayUrl(final);
|
||||
|
||||
// if process not running, launch; otherwise try to send url to existing window
|
||||
if (webProcess == null || webProcess.HasExited)
|
||||
{
|
||||
Debug.Log("WebView process not running. Launching with URL: " + final);
|
||||
LaunchWebView();
|
||||
Debug.Log("浮动小游戏未运行,直接启动并打开 URL: " + final);
|
||||
LaunchWebViewWithUrlInternal(final);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Debug.Log($"WebView process running. PID={webProcess.Id}, MainWindowHandle=0x{webProcess.MainWindowHandle.ToInt64():X}");
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Documentation text normalized.
|
||||
bool sent = WebViewWin32.TrySendUrlToWindow(webProcess, final);
|
||||
Debug.Log($"TrySendUrlToWindow returned: {sent}");
|
||||
if (sent)
|
||||
{
|
||||
Debug.Log("Sent URL to existing WebView process: " + final);
|
||||
// Notify followers that webview content may have changed and they should reapply positioning
|
||||
WebViewReady?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
// Documentation text normalized.
|
||||
Debug.Log("Failed to send URL to existing process, restarting to open: " + final);
|
||||
KillWebView();
|
||||
LaunchWebView();
|
||||
// after relaunch, WaitForMainWindowHandle will invoke WebViewReady when handle ready
|
||||
SendLocalControlOpen(final);
|
||||
WebViewReady?.Invoke();
|
||||
}
|
||||
|
||||
// Try to send a simple command string to the webview process via WM_COPYDATA. Returns true when SendMessage returned non-zero.
|
||||
bool TrySendCommand(string cmd)
|
||||
{
|
||||
if (webProcess == null || webProcess.HasExited)
|
||||
{
|
||||
Debug.LogWarning("TrySendCommand: webProcess not running");
|
||||
Debug.LogWarning("TrySendCommand: 浮动小游戏未运行");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sent = WebViewWin32.TrySendUrlToWindow(webProcess, cmd);
|
||||
Debug.Log($"TrySendCommand('{cmd}') returned: {sent}");
|
||||
return sent;
|
||||
switch (cmd)
|
||||
{
|
||||
case "CMD:REFRESH":
|
||||
SendLocalControlCommand("/refresh");
|
||||
return true;
|
||||
case "CMD:BACK":
|
||||
SendLocalControlCommand("/back");
|
||||
return true;
|
||||
case "CMD:FORWARD":
|
||||
SendLocalControlCommand("/forward");
|
||||
return true;
|
||||
case "CMD:HOME":
|
||||
SendLocalControlCommand("/home");
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// UI control methods
|
||||
public void RefreshWebView()
|
||||
{
|
||||
// Try sending a refresh command; fallback to restarting to refresh
|
||||
if (TrySendCommand("CMD:REFRESH"))
|
||||
{
|
||||
Debug.Log("Sent REFRESH command to webview");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("REFRESH command not supported, restarting webview to refresh");
|
||||
KillWebView();
|
||||
LaunchWebView();
|
||||
}
|
||||
|
||||
@@ -442,7 +435,6 @@ public class WebViewLauncher : MonoBehaviour
|
||||
|
||||
public void RestartWebView()
|
||||
{
|
||||
Debug.Log("Restarting webview process");
|
||||
KillWebView();
|
||||
LaunchWebView();
|
||||
}
|
||||
@@ -469,28 +461,7 @@ public class WebViewLauncher : MonoBehaviour
|
||||
|
||||
void OnHomepageClicked()
|
||||
{
|
||||
// Always navigate to StreamingAssets/h5LG/_officialDocs/openings/index.html
|
||||
string candidate = Path.Combine(Application.streamingAssetsPath, "h5LG", "_officialDocs", "openings", "index.html");
|
||||
if (!File.Exists(candidate))
|
||||
{
|
||||
Debug.LogWarning("Homepage index not found at: " + candidate + ". Falling back to homepageUrl or startUrl.");
|
||||
if (!string.IsNullOrEmpty(homepageUrl))
|
||||
{
|
||||
LaunchWebViewWithUrl(homepageUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
LaunchWebViewWithUrl(startUrl);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
string fileUri = new Uri(candidate).AbsoluteUri;
|
||||
LaunchWebViewWithUrl(fileUri);
|
||||
|
||||
// OpenUrl will update the input field using GetDisplayUrl(final). Ensure display shows the shortened localhost form.
|
||||
if (urlInputField != null)
|
||||
urlInputField.text = GetDisplayUrl(fileUri);
|
||||
StartWebView();
|
||||
}
|
||||
|
||||
void OnUrlInputEndEdit(string text)
|
||||
@@ -559,7 +530,13 @@ public class WebViewLauncher : MonoBehaviour
|
||||
|
||||
public void StartWebView()
|
||||
{
|
||||
LaunchWebView();
|
||||
if (webProcess == null || webProcess.HasExited)
|
||||
{
|
||||
LaunchWebView();
|
||||
return;
|
||||
}
|
||||
SendLocalControlCommand("/home");
|
||||
WebViewReady?.Invoke();
|
||||
}
|
||||
|
||||
public void StopWebView()
|
||||
@@ -578,19 +555,20 @@ public class WebViewLauncher : MonoBehaviour
|
||||
string GetExePath()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return Path.Combine(editorExeRoot, "fdBrowser.exe");
|
||||
string editorPath = Path.Combine(editorExeRoot, FlutterExeName);
|
||||
if (File.Exists(editorPath))
|
||||
{
|
||||
return editorPath;
|
||||
}
|
||||
return Path.Combine(Application.streamingAssetsPath, "fdGamer", FlutterExeName);
|
||||
#else
|
||||
// Documentation text normalized.
|
||||
string streamingPath = Path.Combine(Application.streamingAssetsPath, "fdBrowser", "fdBrowser.exe");
|
||||
string streamingPath = Path.Combine(Application.streamingAssetsPath, "fdGamer", FlutterExeName);
|
||||
if (File.Exists(streamingPath))
|
||||
{
|
||||
Debug.Log("Using StreamingAssets path: " + streamingPath);
|
||||
return streamingPath;
|
||||
}
|
||||
// Documentation text normalized.
|
||||
string gameRoot = Path.GetDirectoryName(Application.dataPath);
|
||||
string fallbackPath = Path.Combine(gameRoot, "fdBrowser", "fdBrowser.exe");
|
||||
Debug.Log("Using fallback path: " + fallbackPath);
|
||||
string fallbackPath = Path.Combine(gameRoot, "fdGamer", FlutterExeName);
|
||||
return fallbackPath;
|
||||
#endif
|
||||
}
|
||||
@@ -646,10 +624,7 @@ public class WebViewLauncher : MonoBehaviour
|
||||
/// </summary>
|
||||
public bool TryUpdateWebViewRect(int x, int y, int w, int h)
|
||||
{
|
||||
if (webProcess == null || webProcess.HasExited)
|
||||
return false;
|
||||
|
||||
return WebViewWin32.TrySetWindowRect(webProcess, x, y, w, h);
|
||||
return webProcess != null && !webProcess.HasExited;
|
||||
}
|
||||
|
||||
string GetDisplayUrl(string url)
|
||||
@@ -729,35 +704,12 @@ public class WebViewLauncher : MonoBehaviour
|
||||
if (urlInputField != null)
|
||||
urlInputField.text = GetDisplayUrl(finalUrl);
|
||||
|
||||
// if process not running, launch; otherwise try to send url to existing window
|
||||
if (webProcess == null || webProcess.HasExited)
|
||||
{
|
||||
Debug.Log("WebView process not running. Launching with URL: " + finalUrl);
|
||||
LaunchWebView();
|
||||
LaunchWebViewWithUrlInternal(finalUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Debug.Log($"WebView process running. PID={webProcess.Id}, MainWindowHandle=0x{webProcess.MainWindowHandle.ToInt64():X}");
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Documentation text normalized.
|
||||
bool sent = WebViewWin32.TrySendUrlToWindow(webProcess, finalUrl);
|
||||
Debug.Log($"TrySendUrlToWindow returned: {sent}");
|
||||
if (sent)
|
||||
{
|
||||
Debug.Log("Sent URL to existing WebView process: " + finalUrl);
|
||||
// Notify followers that webview content may have changed and they should reapply positioning
|
||||
WebViewReady?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
// Documentation text normalized.
|
||||
Debug.Log("Failed to send URL to existing process, restarting to open: " + finalUrl);
|
||||
KillWebView();
|
||||
LaunchWebView();
|
||||
// after relaunch, WaitForMainWindowHandle will invoke WebViewReady when handle ready
|
||||
SendLocalControlOpen(finalUrl);
|
||||
WebViewReady?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user