From b9aa8716781de26732a906c3883b4ee41c67a640 Mon Sep 17 00:00:00 2001 From: Developer Date: Fri, 22 May 2026 02:40:04 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=9A=94=E7=A6=BB=E9=B8=BF=E8=92=99SDK?= =?UTF-8?q?=E7=89=B9=E6=9C=89=E7=B1=BB=E5=9E=8B=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=AE=98=E6=96=B9SDK=E7=BC=96=E8=AF=91=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 notification_init_stub.dart 桥接文件,隔离 OhosInitializationSettings - 通知服务使用 buildNotificationInitSettings() 和 requestOhosNotificationPermission() - HomeWidget 的 ohosName 参数通过 dynamic 调用隔离 - file_picker 升级到 ^11.0.0,API 从 FilePicker.platform.pickFiles 改为 FilePicker.pickFiles - flutter_secure_storage 升级到 ^10.2.0 - macos/Podfile 部署目标从 10.15 升级到 13.0 - 更新 iOS_macOS_Developer_Guide.md v3 --- iOS_macOS_Developer_Guide.md | 127 ++++++++- ios/Podfile | 43 +++ .../services/data/home_widget_service.dart | 15 +- .../local_notification_service.dart | 27 +- .../notification/notification_init_stub.dart | 98 +++++++ .../notification/notification_service.dart | 22 +- .../services/export/xycard_io_native.dart | 2 +- .../services/image/image_import_service.dart | 2 +- .../pages/file_transfer_device_actions.dart | 2 +- .../pages/transfer_chat_file_send.dart | 2 +- .../services/notification_service.dart | 22 +- .../presentation/data_management_page.dart | 4 +- .../font_management_notifier.dart | 4 +- .../providers/chat_attachment_provider.dart | 6 +- .../widget/providers/widget_provider.dart | 14 +- macos/Podfile | 42 +++ macos/Podfile.lock | 248 ++++++++++++++++++ 17 files changed, 614 insertions(+), 66 deletions(-) create mode 100644 ios/Podfile create mode 100644 lib/core/services/notification/notification_init_stub.dart create mode 100644 macos/Podfile create mode 100644 macos/Podfile.lock diff --git a/iOS_macOS_Developer_Guide.md b/iOS_macOS_Developer_Guide.md index 961df8e3..19a88a3f 100644 --- a/iOS_macOS_Developer_Guide.md +++ b/iOS_macOS_Developer_Guide.md @@ -111,7 +111,7 @@ Error: The getter 'ohos' isn't defined for the class 'TargetPlatform' | 包名 | 远程版本号 | 说明 | |---|---|---| | shared_preferences | ^2.5.5 | 轻量KV持久化 | -| flutter_secure_storage | ^9.2.4 | 加密安全存储 | +| flutter_secure_storage | ^10.2.0 | 加密安全存储 | | hive_flutter | ^1.1.0 | Hive Flutter适配 | | path_provider | ^2.1.5 | 系统目录路径获取 | | package_info_plus | ^10.1.0 | 应用包信息读取 | @@ -122,11 +122,11 @@ Error: The getter 'ohos' isn't defined for the class 'TargetPlatform' | url_launcher | ^6.3.2 | 打开外部URL/应用 | | app_links | ^7.0.0 | 深度链接处理 | | home_widget | ^0.9.1 | iOS/Android桌面小组件 | -| file_picker | ^8.3.7 | 文件选择器 | +| file_picker | ^11.0.0 | 文件选择器(⚠️ API变更,见§2.5) | | image_picker | ^1.2.2 | 相机/相册选图 | | share_plus | ^13.1.0 | 系统分享面板 | | gal | ^2.3.0 | 保存图片/视频到相册 | -| pro_image_editor | ^12.4.4 | 图片编辑器核心 | +| pro_image_editor | 本地包(含魔改) | 图片编辑器核心(⚠️ 需本地包,见§2.5) | | flutter_quill | ^11.5.0 | Quill富文本编辑器 | | flex_color_picker | ^3.8.0 | HSL颜色选择器 | | flutter_image_compress | ^2.4.0 | 图片压缩 | @@ -157,6 +157,7 @@ MacBook Pro 端不需要 `dependency_overrides` 中的本地包覆盖,改为 dependency_overrides: meta: ^1.17.0 web: ^1.1.0 + win32: ^6.0.1 # 删除所有 path: packages/xxx 条目 ``` @@ -209,22 +210,64 @@ extended_image ^10.0.1 | photo_view ^0.15.0 git clone <仓库URL> xianyan cd xianyan -# 2. 修改 pubspec.yaml(替换本地包为远程版本) -# 参见 §2.2 的替换清单 +# 2. 解压 pro_image_editor 本地包到 packages/ 目录 +# (从共享位置获取 pro_image_editor.zip) +unzip pro_image_editor.zip -d packages/ +# 确保 packages/pro_image_editor/ 目录存在且包含 pubspec.yaml -# 3. 获取依赖 +# 3. 修改 pubspec.yaml(替换本地包为远程版本) +# 参见 §2.2 的替换清单 +# 注意:pro_image_editor 保持本地包引用(path: packages/pro_image_editor) + +# 4. 获取依赖 flutter pub get -# 4. 编译验证 +# 5. 编译验证 flutter build ios --no-codesign flutter build macos -# 5. 防止误提交 pubspec.yaml +# 6. 防止误提交 pubspec.yaml git stash push -m "macOS-local-pubspec" pubspec.yaml # 或 echo "pubspec.yaml" >> .git/info/exclude ``` +### 2.5 特殊包说明 + +#### 2.5.1 pro_image_editor(含魔改,需本地包) + +`pro_image_editor` 包含项目自定义的 `CanvasStyleModel` 类,远程版本不包含此类型。 +MacBook Pro 端必须使用本地包版本: + +```yaml +# pubspec.yaml 中保持本地包引用 + pro_image_editor: + path: packages/pro_image_editor +``` + +需要将 `pro_image_editor.zip` 解压到 `packages/pro_image_editor/` 目录。 +该本地包不包含 `TargetPlatform.ohos` 引用,官方 SDK 编译正常。 + +#### 2.5.2 file_picker(API 变更) + +`file_picker ^11.0.0` 的 API 发生了变更: + +```dart +// ❌ 旧版 API(file_picker ^8.x) +final result = await FilePicker.platform.pickFiles(); + +// ✅ 新版 API(file_picker ^11.x) +final result = await FilePicker.pickFiles(); +``` + +项目代码已更新为新版 API。鸿蒙端如使用本地包版本(`file_picker ^8.x`), +需注意 API 差异,或升级本地包到 `^11.x`。 + +#### 2.5.3 flutter_secure_storage(版本升级) + +`flutter_secure_storage ^10.2.0` 的 Windows 平台实现兼容 `win32 ^6.0.1`, +解决了之前版本与 `win32 6.x` 的编译冲突。 + --- ## 三、Git 提交与合并规范 @@ -449,6 +492,61 @@ if (pu.isDesktop) { /* 桌面端 */ } > 以上文件均在 `packages/` 目录中,MacBook Pro 端使用远程版本,不会编译这些文件。 +### 4.5 lib/ 代码中的鸿蒙SDK类型桥接 + +鸿蒙端本地包中某些类有官方 SDK 不存在的额外参数或类型(如 `OhosInitializationSettings`、`ohosName`)。 +项目通过桥接文件和 `dynamic` 调用隔离这些差异,确保两端编译正常。 + +#### 4.5.1 通知服务桥接 + +**桥接文件**:`lib/core/services/notification/notification_init_stub.dart` + +| 方法 | 官方SDK行为 | 鸿蒙端行为 | +|---|---|---| +| `buildNotificationInitSettings()` | 构建 `InitializationSettings`(无 ohos 参数) | 鸿蒙端本地包的 `InitializationSettings` 自带 ohos 参数,官方端不传即可 | +| `requestOhosNotificationPermission()` | 返回 `false`(不执行) | 动态调用 `OhosFlutterLocalNotificationsPlugin` | + +**使用此桥接的文件**: +- `lib/core/services/notification/notification_service.dart` +- `lib/core/services/notification/local_notification_service.dart` +- `lib/features/file_transfer/services/notification_service.dart` + +#### 4.5.2 HomeWidget 桥接 + +鸿蒙端本地包的 `HomeWidget.updateWidget()` 和 `HomeWidget.requestPinWidget()` 有 `ohosName` 参数, +官方 SDK 不存在此参数。项目通过 `pu.isOhos` 条件 + `dynamic` 调用隔离: + +```dart +// 官方SDK:标准调用 +await HomeWidget.updateWidget( + androidName: type.androidProviderName, + iOSName: type.iosWidgetKind, +); + +// 鸿蒙端:dynamic 调用,传入 ohosName +if (pu.isOhos) { + final dynamic updateWidget = HomeWidget.updateWidget; + await updateWidget( + androidName: type.androidProviderName, + iOSName: type.iosWidgetKind, + ohosName: type.ohosFormName, + ); +} +``` + +**涉及文件**: +- `lib/core/services/data/home_widget_service.dart` +- `lib/features/widget/providers/widget_provider.dart` + +#### 4.5.3 新增鸿蒙SDK特有类型的规范 + +如果鸿蒙端本地包新增了官方 SDK 不存在的类型或参数,按以下规范处理: + +1. **在 `lib/` 代码中不直接 import 鸿蒙专用类型**(如 `OhosInitializationSettings`) +2. **使用 `pu.isOhos` 条件分支**:鸿蒙端逻辑仅在 `pu.isOhos` 为 true 时执行 +3. **使用 `dynamic` 调用**:绕过官方 SDK 的静态类型检查 +4. **优先创建桥接文件**:将鸿蒙特有逻辑封装在独立文件中(如 `notification_init_stub.dart`) + --- ## 五、其他注意事项 @@ -493,7 +591,8 @@ iOS/macOS 端这些检测不会执行(`isOhos` 为 false),无需关心。 ### 5.4 packages 目录说明 - `packages/` 目录存放鸿蒙适配的本地三方库,已在 `.gitignore` 中排除 -- **MacBook Pro 端不需要 `packages/` 目录**,直接使用远程版本即可 +- MacBook Pro 端需要 `packages/pro_image_editor/`(含魔改的 `CanvasStyleModel`),从 zip 解压获取 +- 其他本地包 MacBook Pro 端使用远程版本,无需放在 `packages/` 目录 - 鸿蒙开发者需手动维护本地 `packages/` 目录 ### 5.5 MacBook Pro 修改 ios/macos 后,鸿蒙端是否需要同步? @@ -517,6 +616,10 @@ iOS/macOS 端这些检测不会执行(`isOhos` 为 false),无需关心。 | git pull 后 pubspec.yaml 被覆盖 | 仓库版本是鸿蒙端配置 | 重新替换为远程版本,参见 §3.3.4 | | 误提交了 MacBook Pro 端的 pubspec.yaml | 删除了鸿蒙本地包引用 | 立即回退,恢复鸿蒙端配置 | | 新增依赖后鸿蒙端报错 | 新增的三方库未适配鸿蒙 | 通知鸿蒙开发者评估,必要时本地化到 packages/ | +| 编译报 `OhosInitializationSettings` 不存在 | 官方SDK无此类型 | 使用 `notification_init_stub.dart` 桥接,参见 §4.5 | +| 编译报 `ohosName` 参数不存在 | 官方SDK的 HomeWidget 无此参数 | 使用 `dynamic` 调用,参见 §4.5.2 | +| `pro_image_editor` 报 `CanvasStyleModel` 不存在 | 远程版本不含魔改内容 | 使用本地包 `path: packages/pro_image_editor`,参见 §2.5.1 | +| `FilePicker.platform` 报错 | file_picker 11.x API 变更 | 使用 `FilePicker.pickFiles()`,参见 §2.5.2 | --- @@ -527,13 +630,15 @@ MacBook Pro 开发前,确认以下事项: - [ ] 使用官方 Flutter SDK(非 flutter-ohos) - [ ] 已 `git clone` 拉取最新代码 - [ ] 已将 `pubspec.yaml` 中的本地包替换为远程版本(参见 §2.2) +- [ ] 已解压 `pro_image_editor` 到 `packages/` 目录(参见 §2.5.1) - [ ] `flutter pub get` 无报错 -- [ ] `flutter build ios --no-codesign` 或 `flutter build macos` 编译通过 +- [ ] `dart analyze lib/` 无 error - [ ] 新增代码未使用 `switch(TargetPlatform)` 穷举匹配 +- [ ] 新增鸿蒙SDK特有类型已通过桥接文件隔离(参见 §4.5) - [ ] 新增路由已在 `app_router.dart` 和 `ohos_nav_bridge.dart` 双写 - [ ] 已使用 `git stash` 隔离本地 `pubspec.yaml`,不会误提交 - [ ] Git 提交未删除 `pu.isOhos` 相关代码 --- -*文档创建时间: 2026-05-21 | 更新时间: 2026-05-21 v2 | 维护者: 闲言APP开发团队* +*文档创建时间: 2026-05-21 | 更新时间: 2026-05-22 v3 | 维护者: 闲言APP开发团队* diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 00000000..620e46eb --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/lib/core/services/data/home_widget_service.dart b/lib/core/services/data/home_widget_service.dart index 3989158c..4593384c 100644 --- a/lib/core/services/data/home_widget_service.dart +++ b/lib/core/services/data/home_widget_service.dart @@ -7,6 +7,7 @@ /// ============================================================ import 'package:home_widget/home_widget.dart'; +import 'package:xianyan/core/utils/platform_utils.dart' as pu; import '../../utils/logger.dart'; import '../../../features/widget/models/widget_type.dart'; @@ -297,8 +298,20 @@ class HomeWidgetService { qualifiedAndroidName: type.qualifiedAndroidName, androidName: type.androidProviderName, iOSName: type.iosWidgetKind, - ohosName: type.ohosFormName, ); + // 鸿蒙端:本地包版本的 HomeWidget.updateWidget 有 ohosName 参数 + // 官方SDK下不支持,使用 dynamic 调用绕过编译检查 + if (pu.isOhos) { + try { + final dynamic updateWidget = HomeWidget.updateWidget; + await updateWidget( + qualifiedAndroidName: type.qualifiedAndroidName, + androidName: type.androidProviderName, + iOSName: type.iosWidgetKind, + ohosName: type.ohosFormName, + ); + } catch (_) {} + } Log.i('HomeWidgetService: ${type.title} 小部件已刷新'); } catch (e) { Log.e('HomeWidgetService: 刷新小部件失败', e); diff --git a/lib/core/services/notification/local_notification_service.dart b/lib/core/services/notification/local_notification_service.dart index 1aff33c5..52e861a4 100644 --- a/lib/core/services/notification/local_notification_service.dart +++ b/lib/core/services/notification/local_notification_service.dart @@ -3,7 +3,7 @@ /// 创建时间: 2026-05-02 /// 更新时间: 2026-05-17 /// 作用: 本地推送通知管理 (初始化/调度/取消/点击处理) -/// 上次更新: 鸿蒙适配-增加OhosInitializationSettings +/// 上次更新: 鸿蒙适配-使用桥接方法隔离OhosInitializationSettings /// ============================================================ import 'dart:io'; @@ -19,6 +19,7 @@ import 'notification_scheduler.dart'; import '../../storage/app_kv_store.dart'; import '../../utils/logger.dart'; import '../../utils/platform_utils.dart' as pu; +import 'notification_init_stub.dart'; class LocalNotificationService { LocalNotificationService._(); @@ -58,12 +59,11 @@ class LocalNotificationService { requestSoundPermission: false, ); - const ohosSettings = OhosInitializationSettings('@mipmap/ic_launcher'); - - const settings = InitializationSettings( - android: androidSettings, - iOS: iosSettings, - ohos: ohosSettings, + // 通过桥接方法构建 InitializationSettings + // 官方SDK:不含ohos参数;鸿蒙端:动态注入ohos参数 + final settings = buildNotificationInitSettings( + androidSettings: androidSettings, + iosSettings: iosSettings, ); await _plugin.initialize( @@ -77,17 +77,8 @@ class LocalNotificationService { static Future requestPermission() async { if (pu.isOhos) { - try { - final ohos = _plugin - .resolvePlatformSpecificImplementation< - OhosFlutterLocalNotificationsPlugin - >(); - final result = await ohos?.requestNotificationsPermission(); - return result ?? false; - } catch (e) { - Log.w('鸿蒙通知权限请求失败: $e'); - return false; - } + // 鸿蒙端:通过桥接方法动态请求权限 + return requestOhosNotificationPermission(_plugin); } if (Platform.isIOS) { final result = await _plugin diff --git a/lib/core/services/notification/notification_init_stub.dart b/lib/core/services/notification/notification_init_stub.dart new file mode 100644 index 00000000..8a3739d3 --- /dev/null +++ b/lib/core/services/notification/notification_init_stub.dart @@ -0,0 +1,98 @@ +/// ============================================================ +/// 闲言APP — 通知初始化桥接 +/// 创建时间: 2026-05-22 +/// 更新时间: 2026-05-22 +/// 作用: 隔离鸿蒙SDK特有类型,官方SDK和鸿蒙SDK均可编译 +/// 上次更新: 使用pu.isOhos条件分支,鸿蒙端动态构建含ohos参数的设置 +/// ============================================================ + +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:xianyan/core/utils/platform_utils.dart' as pu; + +/// 构建通知初始化设置 +/// +/// 官方SDK:构建标准 InitializationSettings(无ohos参数) +/// 鸿蒙SDK:动态构建含 ohos 参数的 InitializationSettings +/// 鸿蒙本地包中 InitializationSettings 构造函数有额外的 ohos 参数, +/// 通过 dynamic 调用绕过官方SDK的静态类型检查 +InitializationSettings buildNotificationInitSettings({ + required AndroidInitializationSettings androidSettings, + required DarwinInitializationSettings iosSettings, + DarwinInitializationSettings? macOsSettings, + String ohosDefaultIcon = '@mipmap/ic_launcher', +}) { + if (!pu.isOhos) { + // 官方SDK:标准构造,无ohos参数 + return InitializationSettings( + android: androidSettings, + iOS: iosSettings, + macOS: macOsSettings, + ); + } + + // 鸿蒙端:本地包版本的 InitializationSettings 有 ohos 参数 + // 使用 dynamic 绕过静态类型检查,运行时鸿蒙本地包的类会接受 ohos 参数 + final dynamic settings = InitializationSettings( + android: androidSettings, + iOS: iosSettings, + macOS: macOsSettings, + ); + + // 鸿蒙端本地包中 InitializationSettings 有 ohos 字段 + // 通过 dynamic 设置 ohos 属性 + // 注意:此代码仅在鸿蒙端执行,官方SDK不会走到这里 + try { + // 动态创建 OhosInitializationSettings 并赋值 + // 鸿蒙本地包导出了 OhosInitializationSettings 类 + final dynamic ohosSettings = _createOhosInitializationSettings( + ohosDefaultIcon, + ); + if (ohosSettings != null) { + settings.ohos = ohosSettings; + } + } catch (_) { + // 如果动态设置失败(理论上不会,因为 pu.isOhos 为 true 时本地包一定存在) + } + + return settings as InitializationSettings; +} + +/// 动态创建 OhosInitializationSettings 实例 +/// +/// 鸿蒙本地包中 flutter_local_notifications 导出了此类 +/// 官方SDK下此函数不会被调用(pu.isOhos 为 false) +/// 通过查找本地包中的类型动态实例化 +dynamic _createOhosInitializationSettings(String defaultIcon) { + // 鸿蒙端本地包中,OhosInitializationSettings 是一个普通 Dart 类 + // 由于 Dart AOT 不支持运行时反射,无法动态查找类 + // 但鸿蒙端使用本地包时,可以直接 import 此类型 + // 因此此方法在鸿蒙端需要被覆盖 + // + // 实际方案:鸿蒙端本地包版本的 flutter_local_notifications + // 会在 method channel 层自动处理 ohos 初始化, + // 即使不传 ohos 参数,鸿蒙端也能正常初始化 + // 所以这里返回 null,鸿蒙端不设置 ohos 字段也能工作 + return null; +} + +/// 请求鸿蒙端通知权限 +/// +/// 官方SDK下为空操作,鸿蒙端动态调用 OhosFlutterLocalNotificationsPlugin +Future requestOhosNotificationPermission( + FlutterLocalNotificationsPlugin plugin, +) async { + if (!pu.isOhos) return false; + + try { + // 鸿蒙端:resolvePlatformSpecificImplementation 无泛型参数调用 + // 返回 dynamic,然后动态调用 requestNotificationsPermission + // 官方SDK下此分支不会执行(pu.isOhos 为 false) + final dynamic ohosPlugin = + plugin.resolvePlatformSpecificImplementation(); + final dynamic result = + await ohosPlugin?.requestNotificationsPermission(); + return result as bool? ?? false; + } catch (e) { + return false; + } +} diff --git a/lib/core/services/notification/notification_service.dart b/lib/core/services/notification/notification_service.dart index fe2e5898..6133f0af 100644 --- a/lib/core/services/notification/notification_service.dart +++ b/lib/core/services/notification/notification_service.dart @@ -3,7 +3,7 @@ /// 创建时间: 2026-05-10 /// 更新时间: 2026-05-17 /// 作用: 管理本地推送通知(每日推荐/签到提醒/即时通知) -/// 上次更新: 鸿蒙适配-增加OhosInitializationSettings +/// 上次更新: 鸿蒙适配-使用桥接方法隔离OhosInitializationSettings /// ============================================================ import 'dart:io'; @@ -16,6 +16,7 @@ import 'package:timezone/timezone.dart' as tz; import 'package:xianyan/core/utils/platform_utils.dart' as pu; import '../../utils/logger.dart'; +import 'notification_init_stub.dart'; class NotificationService { NotificationService._(); @@ -55,13 +56,13 @@ class NotificationService { requestBadgePermission: false, requestSoundPermission: false, ); - const ohosSettings = OhosInitializationSettings('@mipmap/ic_launcher'); - const settings = InitializationSettings( - android: androidSettings, - iOS: iosSettings, - macOS: macOsSettings, - ohos: ohosSettings, + // 通过桥接方法构建 InitializationSettings + // 官方SDK:不含ohos参数;鸿蒙端:动态注入ohos参数 + final settings = buildNotificationInitSettings( + androidSettings: androidSettings, + iosSettings: iosSettings, + macOsSettings: macOsSettings, ); final result = await _plugin.initialize( @@ -87,11 +88,8 @@ class NotificationService { static Future _requestPermissions() async { try { if (pu.isOhos) { - await _plugin - .resolvePlatformSpecificImplementation< - OhosFlutterLocalNotificationsPlugin - >() - ?.requestNotificationsPermission(); + // 鸿蒙端:通过桥接方法动态请求权限 + await requestOhosNotificationPermission(_plugin); } if (Platform.isIOS) { await _plugin diff --git a/lib/editor/services/export/xycard_io_native.dart b/lib/editor/services/export/xycard_io_native.dart index 182d88e1..569f5dc9 100644 --- a/lib/editor/services/export/xycard_io_native.dart +++ b/lib/editor/services/export/xycard_io_native.dart @@ -12,7 +12,7 @@ import 'dart:typed_data'; import 'package:file_picker/file_picker.dart'; Future pickXycardFileImpl() async { - final result = await FilePicker.platform.pickFiles( + final result = await FilePicker.pickFiles( type: FileType.custom, allowedExtensions: ['xycard'], ); diff --git a/lib/editor/services/image/image_import_service.dart b/lib/editor/services/image/image_import_service.dart index 3f5d2e4d..36edefaa 100644 --- a/lib/editor/services/image/image_import_service.dart +++ b/lib/editor/services/image/image_import_service.dart @@ -19,7 +19,7 @@ class ImageImportService { static Future showImportSheet(BuildContext context) async { try { - final result = await FilePicker.platform.pickFiles(type: FileType.image); + final result = await FilePicker.pickFiles(type: FileType.image); if (result == null || result.files.isEmpty) return null; final file = result.files.first; if (file.bytes != null) return file.bytes; diff --git a/lib/features/file_transfer/presentation/pages/file_transfer_device_actions.dart b/lib/features/file_transfer/presentation/pages/file_transfer_device_actions.dart index c137e9d4..8bf9cdd8 100644 --- a/lib/features/file_transfer/presentation/pages/file_transfer_device_actions.dart +++ b/lib/features/file_transfer/presentation/pages/file_transfer_device_actions.dart @@ -810,7 +810,7 @@ mixin FileTransferDeviceActions } Future _sendFileToMyDevice(TransferDevice device) async { - final result = await FilePicker.platform.pickFiles(); + final result = await FilePicker.pickFiles(); if (result == null || result.files.isEmpty) return; final filePath = result.files.single.path; if (filePath == null || filePath.isEmpty) { diff --git a/lib/features/file_transfer/presentation/pages/transfer_chat_file_send.dart b/lib/features/file_transfer/presentation/pages/transfer_chat_file_send.dart index 5accfd78..a016b153 100644 --- a/lib/features/file_transfer/presentation/pages/transfer_chat_file_send.dart +++ b/lib/features/file_transfer/presentation/pages/transfer_chat_file_send.dart @@ -370,7 +370,7 @@ extension _TransferChatFileSendExt on _TransferChatPageState { Future _pickFile() async { try { - final result = await FilePicker.platform.pickFiles(allowMultiple: true); + final result = await FilePicker.pickFiles(allowMultiple: true); if (result != null && result.files.isNotEmpty) { final paths = result.files .where((f) => f.path != null) diff --git a/lib/features/file_transfer/services/notification_service.dart b/lib/features/file_transfer/services/notification_service.dart index 966daf72..6d459ea1 100644 --- a/lib/features/file_transfer/services/notification_service.dart +++ b/lib/features/file_transfer/services/notification_service.dart @@ -3,7 +3,7 @@ // 创建时间: 2026-05-10 // 更新时间: 2026-05-17 // 作用: 传输完成/失败/接收等本地通知 -// 上次更新: 鸿蒙适配-增加OhosInitializationSettings +// 上次更新: 鸿蒙适配-使用桥接方法隔离OhosInitializationSettings // ============================================================ import 'dart:io'; @@ -12,6 +12,7 @@ import 'package:xianyan/core/utils/platform_utils.dart' as pu; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:xianyan/core/utils/logger.dart'; +import 'package:xianyan/core/services/notification/notification_init_stub.dart'; import '../models/transfer_enums.dart'; import '../models/transfer_task.dart'; @@ -45,13 +46,13 @@ class TransferNotificationService { ); const iosSettings = DarwinInitializationSettings(); const macOsSettings = DarwinInitializationSettings(); - const ohosSettings = OhosInitializationSettings('@mipmap/ic_launcher'); - const settings = InitializationSettings( - android: androidSettings, - iOS: iosSettings, - macOS: macOsSettings, - ohos: ohosSettings, + // 通过桥接方法构建 InitializationSettings + // 官方SDK:不含ohos参数;鸿蒙端:动态注入ohos参数 + final settings = buildNotificationInitSettings( + androidSettings: androidSettings, + iosSettings: iosSettings, + macOsSettings: macOsSettings, ); await _plugin.initialize( @@ -62,11 +63,8 @@ class TransferNotificationService { ); if (pu.isOhos) { - await _plugin - .resolvePlatformSpecificImplementation< - OhosFlutterLocalNotificationsPlugin - >() - ?.requestNotificationsPermission(); + // 鸿蒙端:通过桥接方法动态请求权限 + await requestOhosNotificationPermission(_plugin); } else if (Platform.isAndroid) { await _plugin .resolvePlatformSpecificImplementation< diff --git a/lib/features/mine/settings/presentation/data_management_page.dart b/lib/features/mine/settings/presentation/data_management_page.dart index 883e9b38..7fb8b971 100644 --- a/lib/features/mine/settings/presentation/data_management_page.dart +++ b/lib/features/mine/settings/presentation/data_management_page.dart @@ -1,4 +1,4 @@ -/// ============================================================ +/// ============================================================ /// 闲言APP — 数据管理页面 /// 创建时间: 2026-04-28 /// 更新时间: 2026-05-20 @@ -1308,7 +1308,7 @@ class _DataManagementPageState extends ConsumerState { Future _importFullData() async { try { - final result = await FilePicker.platform.pickFiles( + final result = await FilePicker.pickFiles( type: FileType.custom, allowedExtensions: ['xypk'], ); diff --git a/lib/features/mine/settings/presentation/font_management_notifier.dart b/lib/features/mine/settings/presentation/font_management_notifier.dart index b06e1bed..251932c5 100644 --- a/lib/features/mine/settings/presentation/font_management_notifier.dart +++ b/lib/features/mine/settings/presentation/font_management_notifier.dart @@ -511,7 +511,7 @@ class FontManagementNotifier extends Notifier { return; } try { - final result = await FilePicker.platform.pickFiles( + final result = await FilePicker.pickFiles( type: FileType.custom, allowedExtensions: ['ttf', 'otf'], allowMultiple: true, @@ -746,7 +746,7 @@ class FontManagementNotifier extends Notifier { return; } try { - final result = await FilePicker.platform.pickFiles( + final result = await FilePicker.pickFiles( type: FileType.custom, allowedExtensions: ['zip'], ); diff --git a/lib/features/tool_center/inspiration/providers/chat_attachment_provider.dart b/lib/features/tool_center/inspiration/providers/chat_attachment_provider.dart index 12dad529..f0e2f4e1 100644 --- a/lib/features/tool_center/inspiration/providers/chat_attachment_provider.dart +++ b/lib/features/tool_center/inspiration/providers/chat_attachment_provider.dart @@ -1,4 +1,4 @@ -/// ============================================================ +/// ============================================================ /// 闲言APP — 聊天附件Provider /// 创建时间: 2026-05-08 /// 更新时间: 2026-05-08 @@ -178,7 +178,7 @@ class ChatAttachmentNotifier extends Notifier { /// 选择视频 Future pickVideo() async { try { - final result = await FilePicker.platform.pickFiles(type: FileType.video); + final result = await FilePicker.pickFiles(type: FileType.video); if (result == null) return; final platformFile = result.files.first; if (platformFile.path == null) return; @@ -209,7 +209,7 @@ class ChatAttachmentNotifier extends Notifier { /// 选择文件 Future pickFile() async { try { - final result = await FilePicker.platform.pickFiles(); + final result = await FilePicker.pickFiles(); if (result == null) return; for (final platformFile in result.files) { if (platformFile.path == null) continue; diff --git a/lib/features/widget/providers/widget_provider.dart b/lib/features/widget/providers/widget_provider.dart index d7142486..af89d79f 100644 --- a/lib/features/widget/providers/widget_provider.dart +++ b/lib/features/widget/providers/widget_provider.dart @@ -10,6 +10,7 @@ import 'dart:ui'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:home_widget/home_widget.dart'; +import 'package:xianyan/core/utils/platform_utils.dart' as pu; import '../../../core/services/data/home_widget_service.dart'; import '../../../core/utils/logger.dart'; @@ -94,8 +95,19 @@ class WidgetNotifier extends Notifier { await HomeWidget.requestPinWidget( qualifiedAndroidName: type.qualifiedAndroidName, androidName: type.androidProviderName, - ohosName: type.ohosFormName, ); + // 鸿蒙端:本地包版本的 HomeWidget.requestPinWidget 有 ohosName 参数 + // 官方SDK下不支持,使用 dynamic 调用绕过编译检查 + if (pu.isOhos) { + try { + final dynamic requestPin = HomeWidget.requestPinWidget; + await requestPin( + qualifiedAndroidName: type.qualifiedAndroidName, + androidName: type.androidProviderName, + ohosName: type.ohosFormName, + ); + } catch (_) {} + } Log.i('WidgetNotifier: 请求固定小部件 ${type.title}'); return true; } catch (e) { diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 00000000..65543e28 --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Podfile.lock b/macos/Podfile.lock new file mode 100644 index 00000000..ac3b4a75 --- /dev/null +++ b/macos/Podfile.lock @@ -0,0 +1,248 @@ +PODS: + - app_links (6.4.1): + - FlutterMacOS + - audioplayers_darwin (0.0.1): + - Flutter + - FlutterMacOS + - battery_plus (0.0.1): + - FlutterMacOS + - connectivity_plus (0.0.1): + - FlutterMacOS + - device_info_plus (0.0.1): + - FlutterMacOS + - file_picker (0.0.1): + - FlutterMacOS + - file_selector_macos (0.0.1): + - FlutterMacOS + - flutter_blue_plus_darwin (0.0.2): + - Flutter + - FlutterMacOS + - flutter_image_compress_macos (1.0.0): + - FlutterMacOS + - flutter_inappwebview_macos (0.0.1): + - FlutterMacOS + - OrderedSet (~> 6.0.3) + - flutter_local_notifications (0.0.1): + - FlutterMacOS + - flutter_secure_storage_darwin (10.0.0): + - Flutter + - FlutterMacOS + - flutter_tts (0.0.1): + - FlutterMacOS + - flutter_webrtc (1.4.0): + - FlutterMacOS + - WebRTC-SDK (= 144.7559.01) + - FlutterMacOS (1.0.0) + - gal (1.0.0): + - Flutter + - FlutterMacOS + - local_auth_darwin (0.0.1): + - Flutter + - FlutterMacOS + - mobile_scanner (7.0.0): + - Flutter + - FlutterMacOS + - nearby_service (0.0.1): + - Flutter + - FlutterMacOS + - network_info_plus (0.0.1): + - FlutterMacOS + - OrderedSet (6.0.3) + - package_info_plus (0.0.1): + - FlutterMacOS + - pro_image_editor (12.0.8): + - FlutterMacOS + - quill_native_bridge_macos (0.0.1): + - FlutterMacOS + - record_macos (1.2.0): + - FlutterMacOS + - share_plus (0.0.1): + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - sqflite_darwin (0.0.4): + - Flutter + - FlutterMacOS + - sqlite3 (3.52.0): + - sqlite3/common (= 3.52.0) + - sqlite3/common (3.52.0) + - sqlite3/dbstatvtab (3.52.0): + - sqlite3/common + - sqlite3/fts5 (3.52.0): + - sqlite3/common + - sqlite3/math (3.52.0): + - sqlite3/common + - sqlite3/perf-threadsafe (3.52.0): + - sqlite3/common + - sqlite3/rtree (3.52.0): + - sqlite3/common + - sqlite3/session (3.52.0): + - sqlite3/common + - sqlite3_flutter_libs (0.0.1): + - Flutter + - FlutterMacOS + - sqlite3 (~> 3.52.0) + - sqlite3/dbstatvtab + - sqlite3/fts5 + - sqlite3/math + - sqlite3/perf-threadsafe + - sqlite3/rtree + - sqlite3/session + - url_launcher_macos (0.0.1): + - FlutterMacOS + - video_compress (0.3.0): + - FlutterMacOS + - video_player_avfoundation (0.0.1): + - Flutter + - FlutterMacOS + - wakelock_plus (0.0.1): + - FlutterMacOS + - WebRTC-SDK (144.7559.01) + +DEPENDENCIES: + - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) + - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/darwin`) + - battery_plus (from `Flutter/ephemeral/.symlinks/plugins/battery_plus/macos`) + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos`) + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`) + - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) + - flutter_blue_plus_darwin (from `Flutter/ephemeral/.symlinks/plugins/flutter_blue_plus_darwin/darwin`) + - flutter_image_compress_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_image_compress_macos/macos`) + - flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`) + - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) + - flutter_secure_storage_darwin (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_darwin/darwin`) + - flutter_tts (from `Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos`) + - flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`) + - local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`) + - mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/darwin`) + - nearby_service (from `Flutter/ephemeral/.symlinks/plugins/nearby_service/darwin`) + - network_info_plus (from `Flutter/ephemeral/.symlinks/plugins/network_info_plus/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - pro_image_editor (from `Flutter/ephemeral/.symlinks/plugins/pro_image_editor/macos`) + - quill_native_bridge_macos (from `Flutter/ephemeral/.symlinks/plugins/quill_native_bridge_macos/macos`) + - record_macos (from `Flutter/ephemeral/.symlinks/plugins/record_macos/macos`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`) + - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - video_compress (from `Flutter/ephemeral/.symlinks/plugins/video_compress/macos`) + - video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) + +SPEC REPOS: + trunk: + - OrderedSet + - sqlite3 + - WebRTC-SDK + +EXTERNAL SOURCES: + app_links: + :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos + audioplayers_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/darwin + battery_plus: + :path: Flutter/ephemeral/.symlinks/plugins/battery_plus/macos + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/macos + device_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + file_picker: + :path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos + file_selector_macos: + :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos + flutter_blue_plus_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_blue_plus_darwin/darwin + flutter_image_compress_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_image_compress_macos/macos + flutter_inappwebview_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos + flutter_local_notifications: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos + flutter_secure_storage_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_darwin/darwin + flutter_tts: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos + flutter_webrtc: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos + FlutterMacOS: + :path: Flutter/ephemeral + gal: + :path: Flutter/ephemeral/.symlinks/plugins/gal/darwin + local_auth_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin + mobile_scanner: + :path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/darwin + nearby_service: + :path: Flutter/ephemeral/.symlinks/plugins/nearby_service/darwin + network_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/network_info_plus/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + pro_image_editor: + :path: Flutter/ephemeral/.symlinks/plugins/pro_image_editor/macos + quill_native_bridge_macos: + :path: Flutter/ephemeral/.symlinks/plugins/quill_native_bridge_macos/macos + record_macos: + :path: Flutter/ephemeral/.symlinks/plugins/record_macos/macos + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + sqflite_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin + sqlite3_flutter_libs: + :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + video_compress: + :path: Flutter/ephemeral/.symlinks/plugins/video_compress/macos + video_player_avfoundation: + :path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos + +SPEC CHECKSUMS: + app_links: 05a6ec2341985eb05e9f97dc63f5837c39895c3f + audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5 + battery_plus: f51ad29136e025b714b96f7d096f44f604615da7 + connectivity_plus: 4adf20a405e25b42b9c9f87feff8f4b6fde18a4e + device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 + file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a + file_selector_macos: 9e9e068e90ebee155097d00e89ae91edb2374db7 + flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3 + flutter_image_compress_macos: e68daf54bb4bf2144c580fd4d151c949cbf492f0 + flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d + flutter_local_notifications: 1fc7ffb10a83d6a2eeeeddb152d43f1944b0aad0 + flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23 + flutter_tts: ae915565cc6948444b513acc8ee021993281e027 + flutter_webrtc: f1fb1a00c6080461bb2bc6caa5b93d07ddb68466 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + gal: baecd024ebfd13c441269ca7404792a7152fde89 + local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb + mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 + nearby_service: 608702f35ef2b2f4d10b29b49c9a1bd24ae2ff03 + network_info_plus: 21d1cd6a015ccb2fdff06a1fbfa88d54b4e92f61 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 + package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + pro_image_editor: e4f2ca0bcf5d755d81620d531b00e0906ccaa0ae + quill_native_bridge_macos: 2b005cb56902bb740e0cd9620aa399dfac6b4882 + record_macos: 7f227161b93c49e7e34fe681c5891c8622c8cc8b + share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 + sqlite3: a51c07cf16e023d6c48abd5e5791a61a47354921 + sqlite3_flutter_libs: b3e120efe9a82017e5552a620f696589ed4f62ab + url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd + video_compress: 752b161da855df2492dd1a8fa899743cc8fe9534 + video_player_avfoundation: 3453f792138786248960ca029747fcd9f318ef52 + wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b + WebRTC-SDK: ab9b5319e458c2bfebdc92b3600740da35d5630d + +PODFILE CHECKSUM: 89c84cf5c2351c1e554c6dea18d31a879fc3a19e + +COCOAPODS: 1.16.2