feat(macos): 实现 macOS 系统菜单栏多语言支持与闪退修复
本次提交完成 macOS 端多项关键优化与修复: 1. 修复启动期竞态闪退问题,通过前移窗口属性初始化、串行化特效调用、跳过首次同步实现稳定启动 2. 实现系统菜单栏多语言本地化,支持中英日韩繁五种语言,软件内切换语言可同步更新菜单栏 3. 移除视图菜单中重复的全屏按钮,统一窗口标题栏逻辑 4. 新增 macOS App Store 打包配置与本地化资源
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
|
||||
/// ============================================================
|
||||
/// 闲言APP — 桌面端系统托盘服务抽象
|
||||
/// 创建时间: 2026-06-18
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
/// ============================================================
|
||||
/// 闲言APP — macOS 窗口特效服务实现
|
||||
/// 创建时间: 2026-06-18
|
||||
/// 更新时间: 2026-06-18
|
||||
/// 更新时间: 2026-06-24
|
||||
/// 作用: 基于 macos_window_utils 实现 macOS 窗口特效(标题栏融合/侧边栏毛玻璃)
|
||||
/// 上次更新: 初始创建,实现 DesktopWindowEffectService 接口
|
||||
/// 上次更新: 修复 Release 模式闪退 — 添加互斥锁串行化 applyEffect 调用,
|
||||
/// 跳过已在 MainFlutterWindow.awakeFromNib 中预设的不变属性调用,
|
||||
/// 避免 [NSWindow setBackgroundColor:] 与 Impeller SetupRenderPass 竞态
|
||||
/// ============================================================
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:macos_window_utils/macos_window_utils.dart';
|
||||
|
||||
import '../desktop_window_effect_service.dart';
|
||||
@@ -18,6 +22,10 @@ import 'package:xianyan/core/utils/logger.dart';
|
||||
/// - 标题栏融合(titlebarAppearsTransparent + fullSizeContentView)
|
||||
/// - 侧边栏毛玻璃(NSVisualEffectViewMaterial.sidebar)
|
||||
/// - 主题跟随(overrideMacOSBrightness)
|
||||
///
|
||||
/// 不变属性(isOpaque/backgroundColor/titlebarAppearsTransparent/fullSizeContentView/
|
||||
/// titleVisibility)已在 [MainFlutterWindow.awakeFromNib] 中预设,
|
||||
/// 此处不再通过 method channel 重复设置,避免与 Impeller 渲染线程竞态。
|
||||
class MacosWindowEffectService implements DesktopWindowEffectService {
|
||||
MacosWindowEffectService._();
|
||||
|
||||
@@ -29,6 +37,9 @@ class MacosWindowEffectService implements DesktopWindowEffectService {
|
||||
bool _initialized = false;
|
||||
int? _sidebarVisualEffectSubviewId;
|
||||
|
||||
/// 互斥锁:串行化 applyEffect 调用,防止并发导致原生视图层级竞争
|
||||
Completer<void>? _applyLock;
|
||||
|
||||
@override
|
||||
Future<void> initialize() async {
|
||||
if (!pu.isMacOS) return;
|
||||
@@ -50,26 +61,41 @@ class MacosWindowEffectService implements DesktopWindowEffectService {
|
||||
}) async {
|
||||
if (!pu.isMacOS || !_initialized) return;
|
||||
|
||||
try {
|
||||
// 1. 标题栏融合:透明标题栏 + 全尺寸内容视图
|
||||
await WindowManipulator.makeTitlebarTransparent();
|
||||
await WindowManipulator.enableFullSizeContentView();
|
||||
await WindowManipulator.hideTitle();
|
||||
// 串行化:若上一次 applyEffect 尚未完成,等待其结束后再执行
|
||||
while (_applyLock != null) {
|
||||
try {
|
||||
await _applyLock!.future;
|
||||
} catch (_) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_applyLock = Completer<void>();
|
||||
|
||||
// 2. 主题跟随:覆盖 macOS 亮度设置
|
||||
try {
|
||||
// 注意:以下属性已在 MainFlutterWindow.awakeFromNib 中预设,此处不再重复调用:
|
||||
// - makeTitlebarTransparent() → titlebarAppearsTransparent = true
|
||||
// - enableFullSizeContentView() → styleMask.insert(.fullSizeContentView)
|
||||
// - hideTitle() → titleVisibility = .hidden
|
||||
// - setWindowBackgroundColorToClear() → isOpaque=false + backgroundColor=clear
|
||||
//
|
||||
// 这些调用会触发 [NSWindow setBackgroundColor:] → NSThemeFrame._updateBackdropView
|
||||
// → removeFromSuperview,与 Impeller raster 线程的 SetupRenderPass 产生竞态,
|
||||
// 导致 EXC_BAD_ACCESS 空指针崩溃(Release 模式时序更紧更易触发)。
|
||||
|
||||
// 1. 主题跟随:覆盖 macOS 亮度设置(仅修改 appearance,不触发 _updateBackdropView)
|
||||
await WindowManipulator.overrideMacOSBrightness(dark: isDark);
|
||||
|
||||
// 3. 侧边栏毛玻璃
|
||||
// 2. 侧边栏毛玻璃(NSVisualEffectView 操作,不修改 NSWindow 背景)
|
||||
if (sidebarBlur) {
|
||||
await _applySidebarBlur();
|
||||
}
|
||||
|
||||
// 4. 窗口背景色设为透明(让 NSVisualEffectView 透出)
|
||||
await WindowManipulator.setWindowBackgroundColorToClear();
|
||||
|
||||
Log.i('MacosWindowEffectService 特效已应用 (isDark=$isDark, sidebarBlur=$sidebarBlur)');
|
||||
} catch (e) {
|
||||
Log.e('MacosWindowEffectService.applyEffect 失败: $e');
|
||||
} finally {
|
||||
_applyLock?.complete();
|
||||
_applyLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/// 闲言APP — macOS平台统一服务
|
||||
/// 创建时间: 2026-06-02
|
||||
/// 更新时间: 2026-06-24
|
||||
/// 作用: 集中管理所有macOS原生MethodChannel交互(主题同步/窗口管理/Touch Bar/共享/Dock徽章/菜单栏金句/Spotlight)
|
||||
/// 上次更新: 新增原生事件监听(onFullScreenExited),支持全屏退出后重新应用窗口特效
|
||||
/// 作用: 集中管理所有macOS原生MethodChannel交互(主题同步/窗口管理/Touch Bar/共享/Dock徽章/菜单栏金句/Spotlight/菜单语言)
|
||||
/// 上次更新: 新增 setMenuLanguage 方法,支持软件内切换语言后同步更新 macOS 系统菜单栏
|
||||
/// ============================================================
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -238,6 +238,31 @@ class MacosPlatformService {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 菜单栏语言切换
|
||||
// ============================================================
|
||||
|
||||
/// 通知原生侧切换 macOS 系统菜单栏语言
|
||||
///
|
||||
/// [languageId] 语言 ID,对应 macOS 本地化区域:
|
||||
/// - 'system' → 跟随系统语言
|
||||
/// - 'zh-CN' / 'zh-Hans' → 简体中文
|
||||
/// - 'zh-TW' / 'zh-Hant' → 繁体中文
|
||||
/// - 'en' → 英语
|
||||
/// - 'ja' → 日语
|
||||
/// - 'ko' → 韩语
|
||||
///
|
||||
/// 软件内切换语言后调用此方法,原生侧会重新加载对应语言的 MainMenu.strings
|
||||
/// 并更新 NSApp.mainMenu 的所有菜单项标题。
|
||||
static Future<void> setMenuLanguage(String languageId) async {
|
||||
if (!pu.isMacOS) return;
|
||||
try {
|
||||
await _channel.invokeMethod('setMenuLanguage', {'languageId': languageId});
|
||||
} catch (e) {
|
||||
Log.w('MacosPlatformService.setMenuLanguage失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 内部工具
|
||||
// ============================================================
|
||||
|
||||
Reference in New Issue
Block a user