using System.Text.Json; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Data.Sqlite; using Hua.Todo.Application; using Hua.Todo.Application.CloudSync; using Hua.Todo.Application.Data; using Hua.Todo.Maui.Models; using Hua.Todo.Maui.Services; using Hua.Todo.Maui.Services.Platforms; namespace Hua.Todo.Maui; /// /// MAUI 程序启动类 /// public static partial class MauiProgram { /// /// 创建并配置 MAUI 应用程序 /// public static MauiApp CreateMauiApp() { ConfigurePlatformWebViewContainer(); var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); // 加载应用程序配置 var appSettings = LoadAppSettings(); // 如果未提供连接字符串,则设置默认的 SQLite 连接字符串 if (string.IsNullOrEmpty(appSettings.WebServer.ConnectionString)) { var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var dbDir = Path.Combine(localAppData, "Hua.Todo"); if (!Directory.Exists(dbDir)) { Directory.CreateDirectory(dbDir); } var dbPath = Path.Combine(dbDir, "Hua.Todo.db"); appSettings.WebServer.ConnectionString = $"Data Source={dbPath};Cache=Shared"; } builder.Services.AddSingleton(appSettings); var connectionString = appSettings.WebServer.ConnectionString; // 注册应用服务 builder.Services.AddApplicationServices(connectionString); builder.Services.AddTransient(); // 注册热键设置服务 builder.Services.AddSingleton(sp => new HotKeySettingsService(sp.GetRequiredService())); // 注册全局热键服务(工厂模式) builder.Services.AddSingleton(sp => GlobalHotKeyServiceFactory.Create()); // 注册系统托盘服务(平台相关) builder.Services.AddSingleton(sp => { #if WINDOWS return new WindowsSystemTrayService(); #else return new NullSystemTrayService(); #endif }); // 注册嵌入式 Web 服务器(平台相关) #if WINDOWS // Windows 平台下嵌入式 WebServer 的启用策略: // - 静态托管模式(IsUsingStatic=true):由 MAUI 内置 WebServer 提供 wwwroot 与本地 API。 // - 开发三件套模式(IsUsingStatic=false,前端走 Vite):API 由独立 Host(5173) 提供,避免在 MAUI 内启动 WebServer 导致注入覆盖前端代理配置。 if (appSettings.WebServer.IsUsingStatic) { builder.Services.AddSingleton(); } else { builder.Services.AddSingleton(); } #elif ANDROID builder.Services.AddSingleton(); #else builder.Services.AddSingleton(); #endif #if DEBUG builder.Logging.AddDebug(); #endif var app = builder.Build(); // 异步初始化数据库和 Web 服务器 _ = Task.Run(async () => { try { // 优先启动内嵌 WebServer,确保 WebView 加载时不再 ERR_CONNECTION_REFUSED。 await StartWebServer(app.Services); InitializeDatabase(app.Services, connectionString); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"App initialization failed: {ex}"); } }); return app; } static partial void ConfigurePlatformWebViewContainer(); /// /// 从 appsettings.json 加载配置 /// private static AppSettings LoadAppSettings() { try { using var stream = FileSystem.OpenAppPackageFileAsync("appsettings.json").GetAwaiter().GetResult(); using var reader = new StreamReader(stream); var json = reader.ReadToEnd(); return JsonSerializer.Deserialize(json) ?? new AppSettings(); } catch { try { var settingsPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); if (!File.Exists(settingsPath)) { return new AppSettings(); } var json = File.ReadAllText(settingsPath); return JsonSerializer.Deserialize(json) ?? new AppSettings(); } catch { return new AppSettings(); } } } /// /// 初始化数据库(执行迁移) /// private static void InitializeDatabase(IServiceProvider services, string connectionString) { using var scope = services.CreateScope(); try { var dbContext = scope.ServiceProvider.GetRequiredService(); var sqliteBuilder = new SqliteConnectionStringBuilder(connectionString); var actualDbPath = sqliteBuilder.DataSource; if (!string.IsNullOrEmpty(actualDbPath)) { var dbDir = Path.GetDirectoryName(actualDbPath); if (!string.IsNullOrEmpty(dbDir) && !Directory.Exists(dbDir)) { Directory.CreateDirectory(dbDir); } } // 确保使用 WAL 模式以避免锁定问题 dbContext.Database.ExecuteSqlRaw("PRAGMA journal_mode=WAL;"); dbContext.Database.Migrate(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Database initialization failed: {ex.Message}"); try { var context = scope.ServiceProvider.GetRequiredService(); context.Database.EnsureCreated(); } catch { } } } /// /// 启动嵌入式 Web 服务器 /// private static async Task StartWebServer(IServiceProvider services) { try { var webServer = services.GetRequiredService(); await webServer.StartAsync(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"Web server start failed: {ex}"); } } }