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}");
}
}
}