注册

Flutter 鸿蒙化 在一起 就可以

相关阅读:


Flutter Love 鸿蒙 - 掘金 (juejin.cn)


不是鸿蒙 ArkUI 不会写,而是 Flutter 更有性价比 - 掘金 (juejin.cn)


前言


鸿蒙生态势如破竹,已有超4000应用加入,实现垂域全覆盖,商店里面的鸿蒙 app 也越来越多,就像余总说的一样,



在一起,就可以 !



OpenHarmony-SIG/flutter_flutter (gitee.com) 社区一直在致力于使用 Flutter 更加快速地适配鸿蒙平台。


而距离 不是鸿蒙 ArkUI 不会写,而是 Flutter 更有性价比 - 掘金 (juejin.cn) 已经有一段时间了,我们来看看 Flutter 鸿蒙化的进展如何了。



重要提示,Flutter 鸿蒙化,需要华为提供的真机和最新的SDK或者自己申请了开发者预览 Beta 招募,没有的,暂时不要尝试。



最近 华为纯血鸿蒙 HarmonyOS NEXT 开发者预览版首批 Beta 招募开启,支持 Mate 60 / Pro、X5 机型, 这给一些个人开发者提前体验鸿蒙 NEXT 的机会。



后续内容全部基于 OpenHarmony-SIG/flutter_flutter (gitee.com)OpenHarmony-SIG/flutter_engine (gitee.com)dev 分支。参考文档也以 dev 分支 的文档为准。另外最新支持的是 ohos api11



插件进度


现阶段 Flutter 适配工作主要集中在鸿蒙原生插件的适配。下面介绍一下已知完成适配的插件。


flutter_packages


OpenHarmony-SIG/flutter_packages (gitee.com) 是适配官方 flutter/packages: A collection of useful packages maintained by the Flutter team (github.com) 仓库。


引用方式例子如下:


dependencies:
path_provider:
git:
url: "https://gitee.com/openharmony-sig/flutter_packages.git"
path: "packages/path_provider/path_provider"

path_provider2.1.1官方库11月30日gitee.com/openharmony…
shared_preferences2.2.1官方库11月30日gitee.com/openharmony…
url_launcher6.1.11官方库11月30日gitee.com/openharmony…
image_picker1.0.4官方库12月30日gitee.com/openharmony…
local_auth2.1.6官方库12月30日gitee.com/openharmony…
pigeon11.0.1官方库12月30日gitee.com/openharmony…
webview_flutter4.2.4、4.4.4官方库12月30日gitee.com/openharmony…
video_player2.7.2官方库3月30日gitee.com/openharmony…
file_selector1.0.1官方库12月30日gitee.com/openharmony…
camera0.10.5官方库3月30日gitee.com/openharmony…

plus 插件


[Request]: support HarmonyOS · Issue #2480 · fluttercommunity/plus_plugins (github.com) 作者对于适配鸿蒙平台兴趣不大,所以这里决定 HarmonyCandies (github.com) 来维护。


wakelock_plus_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
wakelock_plus: 1.1.4
wakelock_plus_ohos: any

device_info_plus_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
device_info_plus: any
device_info_plus_ohos: any

注意,有 2uid 是系统级别的,需要应用单独申请。


  /// Requires permission: ohos.permission.sec.ACCESS_UDID (System permission, only open to system apps).
/// Device serial number.
/// 设备序列号。
final String serial;

/// Requires permission: ohos.permission.sec.ACCESS_UDID (System permission, only open to system apps).
/// Device Udid.
/// 设备Udid。
final String udid;

使用


import 'package:device_info_plus_ohos/device_info_plus_ohos.dart';

final DeviceInfoOhosPlugin deviceInfoOhosPlugin = DeviceInfoOhosPlugin();

OhosDeviceInfo deviceInfo = await deviceInfoOhosPlugin.ohosDeviceInfo;

// Requires permission: ohos.permission.sec.ACCESS_UDID (System permission, only open to system apps).
OhosAccessUDIDInfo accessUDIDInfo = await deviceInfoOhosPlugin.ohosAccessUDIDInfo;

network_info_plus_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
network_info_plus: any
network_info_plus_ohos: any

在你的项目的 module.json5 文件中增加以下权限设置。


    requestPermissions: [
{"name" : "ohos.permission.INTERNET"},
{"name" : "ohos.permission.GET_WIFI_INFO"},
],

sensors_plus_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
sensors_plus: 4.0.2
sensors_plus_ohos: any

在你的项目的 module.json5 文件中增加以下权限设置。


    requestPermissions: [
{"name" : "ohos.permission.ACCELEROMETER"},
{"name" : "ohos.permission.GYROSCOPE"},
],

connectivity_plus_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
connectivity_plus: 5.0.2
connectivity_plus_ohos: any

在你的项目的 module.json5 文件中增加以下权限设置。


    requestPermissions: [
{"name" : "ohos.permission.INTERNET"},
{"name" : "ohos.permission.GET_NETWORK_INFO"},
],

battery_plus_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
battery_plus: 5.0.3
battery_plus_ohos: any

package_info_plus_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
package_info_plus: 4.2.0
package_info_plus_ohos: any

糖果插件


flutter_image_compress


地址:github.com/fluttercand…


引用:


dependencies:
flutter_image_compress: ^2.2.0

FeatureAndroidiOSWebmacOSOpenHarmony
method: compressWithList
method: compressAssetImage
method: compressWithFile
method: compressAndGetFile
format: jpeg
format: png
format: webp[🌐][webp-compatibility]
format: heic
param: quality[🌐][webp-compatibility]
param: rotate
param: keepExif

flutter_image_editor


地址:github.com/fluttercand…


引用:


dependencies:
image_editor: ^2.2.0

FeatureAndroidiOSOpenHarmony
flip
crop
rotate
scale
matrix
mix image
merge multi image
draw point
draw line
draw rect
draw circle
draw path
draw Bezier
Gaussian blur

flutter_photo_manager


地址:github.com/fluttercand…


引用:


注意 photo_manager_image_provider 需要限制一下版本。


dependencies:
photo_manager: ^3.1.0
dependency_overrides:
photo_manager_image_provider: ^1.1.1

暂时支持下面的功能,目前鸿蒙只支持图片和视频 2 种资源类型。


FeatureOpenHarmony
getAssetPathList
getAssetCountFromPath
fetchPathProperties
getAssetCount
getAssetListPaged
getOriginBytes
getThumb
getAssetListRange
getAssetsByRange
deleteWithIds
getColumnNames
saveImage
saveImageWithPath
saveVideo
requestPermissionExtend
ignorePermissionCheck
log
notify

其他插件


permission_handler_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
permission_handler_ohos: any

权限列表来自: gitee.com/openharmony…


注意

由于 OpenHarmonyHarmonyOS 的权限差异以及鸿蒙版本的高速迭代,检查请求权限的 api 是传递的权限的字符串全称,如果你发现 PermissionOhos 枚举中没有某个权限,你可以直接传递权限的字符串全称。等鸿蒙版本稳定下来了,会再同步权限列表到枚举中。


权限枚举列表是由文档自动生成的。


// GENERATED CODE - DO NOT MODIFY MANUALLY
// **************************************************************************
// Auto generated by https://github.com/HarmonyCandies/permission_handler_ohos/bin/main.dart
// **************************************************************************
// https://gitee.com/openharmony/docs/blob/OpenHarmony-4.1-Release/zh-cn/application-dev/security/AccessToken/permissions-for-all.md
// ignore_for_file: constant_identifier_names,slash_for_doc_comments

/// The Permissions of OpenHarmony
/// total: 44
enum PermissionOhos {
/// ohos.permission.USE_BLUETOOTH
///
/// 允许应用查看蓝牙的配置。
///
/// 权限级别:normal
///
/// 授权方式:system_grant
///
/// ACL使能:true
///
/// 起始版本:8

use_bluetooth(
name: 'ohos.permission.USE_BLUETOOTH',
permissionLevel: 'normal',
grantType: 'system_grant',
aclEnabled: true,
startVersion: 8,
),

使用

请认真阅读官方关于权限的文档 gitee.com/openharmony…


在你的项目的 module.json5 文件中增加对应需要权限设置,比如:


    requestPermissions: [
{ name: "ohos.permission.READ_CALENDAR" },
{ name: "ohos.permission.WRITE_CALENDAR" },
],

例子

检查权限状态


import 'package:device_info_plus_ohos/device_info_plus_ohos.dart';

final PermissionStatusOhos status =
await PermissionHandlerOhos.checkPermissionStatus(
PermissionOhos.read_calendar.name);

请求单个权限


    final PermissionStatusOhos status =
await PermissionHandlerOhos.requestPermission(
PermissionOhos.read_calendar.name,
);

请求多个权限


    final Map<String, PermissionStatusOhos> statusMap =
await PermissionHandlerOhos.requestPermissions([
PermissionOhos.read_calendar.name,
PermissionOhos.write_calendar.name,
]);

打开设置页面


   PermissionHandlerOhos.openAppSettings();

audio_streamer_ohos


地址:github.com/HarmonyCand…


引用:


dependencies:
audio_streamer: 4.1.1
audio_streamer_ohos: any

audio_streamer 在 OpenHarmony 平台上的实现


在 OpenHarmony 项目的 module.json 文件中添加 ohos.permission.MICROPHONE 权限


{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.MICROPHONE",
"reason": "Microphone permission is required to record audio."
}
]
}
}

geolocator


地址: HarmonyCandies/geolocator_ohos: The OpenHarmony implementation of geolocator. (github.com)


引用:


dependencies:
geolocator: any
geolocator_ohos: ^0.0.1

在你的项目的 module.json5 文件中增加以下权限设置。


    "requestPermissions": [
{"name" : "ohos.permission.KEEP_BACKGROUND_RUNNING"},
{
"name": "ohos.permission.LOCATION",
"reason": "$string:EntryAbility_label",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "$string:EntryAbility_label",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.LOCATION_IN_BACKGROUND",
"reason": "$string:EntryAbility_label",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
]

鸿蒙特有的方法


CountryCode? countryCode= await geolocatorOhos.getCountryCode();

(逆)地理编码转化


    final position = await geolocatorOhos.getCurrentPosition(
locationSettings: const CurrentLocationSettingsOhos(
priority: LocationRequestPriority.firstFix,
scenario: LocationRequestScenario.unset,
),
);

// ohos only
if (await geolocatorOhos.isGeocoderAvailable()) {
//
var addresses = await geolocatorOhos.getAddressesFromLocation(
ReverseGeoCodeRequest(
latitude: position.latitude,
longitude: position.longitude,
locale: 'zh',
maxItems: 1,
),
);

for (var address in addresses) {
if (kDebugMode) {
print('ReverseGeoCode address:$address');
}
var position = await geolocatorOhos.getAddressesFromLocationName(
GeoCodeRequest(description: address.placeName ?? ''),
);
if (kDebugMode) {
print('geoCode position:$position');
}
}
}

vibration


地址:flutter_vibration/vibration_ohos at master · benjamindean/flutter_vibration (github.com)


引用:


dependencies:
vibration: any
vibration_ohos: any

在你的项目的 module.json5 文件中增加以下权限设置。


    "requestPermissions": [
{"name" : "ohos.permission.VIBRATE"},
]

vibrateEffect and vibrateAttribute are only exist in VibrationOhos.


 (VibrationPlatform.instance as VibrationOhos).vibrate(
vibrateEffect: const VibratePreset(count: 100),
vibrateAttribute: const VibrateAttribute(
usage: 'alarm',
),
);

sqflite


地址:gitee.com/openharmony…


引用:


dependencies:
sqflite:
git:
url: "https://gitee.com/openharmony-sig/flutter_sqflite.git"
path: "sqflite"

fluttertoast


地址:gitee.com/openharmony…


引用:


dependencies:
fluttertoast:
git:
url: "https://gitee.com/openharmony-sig/flutter_fluttertoast.git"

audio_session


地址:gitee.com/openharmony…


引用:


dependencies:
audio_session:
git:
url: "https://gitee.com/openharmony-sig/flutter_audio_session.git"

flutter_sound


地址:gitee.com/openharmony…


引用:


dependencies:
flutter_sound:
git:
url: "https://gitee.com/openharmony-sig/flutter_sound.git"
path: "flutter_sound"

image_gallery_saver


地址:gitee.com/openharmony…


引用:


dependencies:
image_gallery_saver:
git:
url: "https://gitee.com/openharmony-sig/flutter_image_gallery_saver.git"

location


地址:gitee.com/openharmony…


引用:


dependencies:
location:
git:
url: "https://gitee.com/openharmony-sig/flutter_location.git"
path: "location"

power_image


地址:gitee.com/openharmony…


引用:


dependencies:
power_image:
git:
url: "https://gitee.com/openharmony-sig/flutter_power_image.git"

flutter_native_image


地址:gitee.com/openharmony…


引用:


dependencies:
flutter_native_image:
git:
url: "https://gitee.com/openharmony-sig/flutter_native_image.git"

audioplayers


地址:gitee.com/openharmony…


引用:


dependencies:
audioplayers:
git:
url: "https://gitee.com/openharmony-sig/flutter_audioplayers.git"

image_crop


地址:gitee.com/openharmony…


引用:


dependencies:
image_crop:
git:
url: "https://gitee.com/openharmony-sig/flutter_image_crop.git"

bitmap


地址:gitee.com/openharmony…


引用:


dependencies:
bitmap:
git:
url: "https://gitee.com/openharmony-sig/flutter_bitmap.git"

leak_detector


地址:gitee.com/openharmony…


引用:


dependencies:
leak_detector:
git:
url: "https://gitee.com/openharmony-sig/flutter_leak_detector.git"

flutter_contacts


地址:gitee.com/openharmony…


引用:


dependencies:
flutter_contacts:
git:
url: "https://gitee.com/openharmony-sig/flutter_contacts.git"

纯 Flutter 库


extended_text


dependencies:
extended_text: 10.0.1-ohos

extended_text_field


dependencies:
extended_text_field: 11.0.1-ohos

flutter_platform_utils


HarmonyCandies/flutter_platform_utils: A utility to check the platform for ohos (github.com)


如果您的库支持 OpenHarmony 平台,并且有 Platform.isOhos 的判断,那么建议换成 PlatformUtils.isOhos 避免对其他非鸿蒙用户在非鸿蒙分支编译的影响。


一些注意事项


关于鸿蒙的 context


在制作插件中,你可能需要用到 2context


ApplicationContex


你可以直接从 onAttachedToEngine 方法中获取。


  private context: Context | null = null;

onAttachedToEngine(binding: FlutterPluginBinding): void {
this.context = binding.getApplicationContext();
}

onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.context = null;
}

context 可以用于获取 applicationInfo 等属性。


let applicationInfo = this.context.applicationInfo;


UIAbilityContext


插件继承 AbilityAware 并且在 onAttachedToAbility 方法中获取。



export default class XXXPlugin implements FlutterPlugin, MethodCallHandler, AbilityAware {
private _uiContext: common.UIAbilityContext | null = null;

onAttachedToAbility(binding: AbilityPluginBinding): void {
this._uiContext = binding.getAbility().context;
}

onDetachedFromAbility(): void {
this._uiContext = null;
}
}

uiContext 可以用于获取 applicationInfo 等属性。


photoAccessHelper.getPhotoAccessHelper(PhotoManagerPlugin.uiContext);


关于插件参数传递


按照以前的习惯,dart 端传递 map 参数,原生端根据 map 解析参数。


但由于 ts 支持将字符串直接转换成对应的 interface ,那么我们可以将 dart 的端的参数。


参数定义


比如 geolocator_ohos 中的 CurrentLocationSettingsOhosdart 端的实现为如下:


  Map<String, dynamic> toMap() {
return {
if (priority != null) 'priority': priority?.toInt(),
if (scenario != null) 'scenario': scenario?.toInt(),
if (maxAccuracy != null) 'maxAccuracy': maxAccuracy,
if (timeoutMs != null) 'timeoutMs': timeoutMs,
};
}

@override
String toString() {
return jsonEncode(toMap());
}

而在鸿蒙原生端,对于的 interfaceCurrentLocationRequest


export interface CurrentLocationRequest {
priority?: LocationRequestPriority;
scenario?: LocationRequestScenario;
maxAccuracy?: number;
timeoutMs?: number;
}

值得注意的是,如果参数为 null,不要传递过去,比如 'priority': null , 如果传递过去,鸿蒙原生端会解析错误。不传递过去的话,会解析为 undefined,这也对应了 priority?: LocationRequestPriority 可选的意思。



可以使用 chatgpt 直接将鸿蒙的 interface 转换成 dart 的类,并且增加 toMapfromMap,和注释。



插件传递


dart 端,将参数类以字符串的方式传递过去,并且用字符串的方式接受返回值。


  @override
Future<Position> getCurrentPosition({
LocationSettings? locationSettings,
String? requestId,
}) async {
assert(
locationSettings == null ||
locationSettings is CurrentLocationSettingsOhos,
'locationSettings should be CurrentLocationSettingsOhos',
);

try {
final Duration? timeLimit = locationSettings?.timeLimit;

Future<dynamic> positionFuture =
GeolocatorOhos._methodChannel.invokeMethod(
'getCurrentPosition',
locationSettings?.toString(),
);

if (timeLimit != null) {
positionFuture = positionFuture.timeout(timeLimit);
}

return PositionOhos.fromString(await positionFuture);
}
}

在鸿蒙端, 将字符串直接转换成鸿蒙对应的 interface


let request: geoLocationManager.CurrentLocationRequest = JSON.parse(args);


并且将要返回的 interface 转换成字符串。


result.success(JSON.stringify(location));


当然了,这样有个问题,就是如果鸿蒙端修改了 interface 的属性名字,插件很难感知到(当然会报错)。


关于做 Flutter 鸿蒙化的一些环境要求



重要提示,Flutter 鸿蒙化,需要华为提供的真机和最新的SDK或者自己申请了开发者预览 Beta 招募,没有的,暂时不要尝试。



Xcode15


如果你的电脑升级了 Xcode15,在做编译引擎的时候,也许会遇到下面的错误。


/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:657:37: error: use of undeclared identifier 'NSIntegerMax'
static const NSInteger NSNotFound = NSIntegerMax;

或者


../../third_party/dart/runtime/bin/security_context_macos.cc:188:17: error: use of undeclared identifier 'noErr'
if (status != noErr) {
^
../../third_party/dart/runtime/bin/security_context_macos.cc:196:19: error: use of undeclared identifier 'noErr'
if (status != noErr) {
^
../../third_party/dart/runtime/bin/security_context_macos.cc:205:17: error: use of undeclared identifier 'noErr'
if (status != noErr) {
^
../../third_party/dart/runtime/bin/security_context_macos.cc:303:21: error: use of undeclared identifier 'noErr'
OSStatus status = noErr;
^
../../third_party/dart/runtime/bin/security_context_macos.cc:319:23: error: use of undeclared identifier 'noErr'
status == noErr && (trust_result == kSecTrustResultProceed ||
^

解决办法是从下面地址选择 13.3 sdk 中的 TargetConditionals.h


macos-sdk/MacOSX13.3.sdk/usr/include/TargetConditionals.h at main · alexey-lysiuk/macos-sdk (github.com)


替换掉你本地的,注意做备份。


/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/TargetConditionals.h


说点其他


关于 Google 裁员


QQ图片20240504115445.jpg


最近很多人都在问,传着传着就变成 Google 要解散 Flutter 团队。不管是哪个公司都会有裁员的哪一天,与其犹豫不决,还不如笃定前行。


总有人年轻


没有人永远年轻,但总有人年轻。最近 NBA 季后赛,你不得不承认,他们都老了。过年的时候出去玩,把娃放肩膀上面驮着,脖子肩膀酸痛了,2天才恢复。有那么一刻,确实感觉自己也不再年轻了。
尽管时间会在我们身上留下痕迹,但当我们投身于自己热爱的事业或兴趣时,心态和精神永远年轻。



扶我起来,我还能写代码。那你,是什么时候发现自己不再年轻的?



结语


跟当年 Flutter 社区一样,我们也是从一点点慢慢变好的。5年前,Flutter Candies 一桶天下 - 掘金 (juejin.cn),社区开始慢慢壮大。现在我们也将继续在新的领域汇集在一起 不是鸿蒙 ArkUI 不会写,而是 Flutter 更有性价比 - 掘金 (juejin.cn)



如果你是喜欢分享的,请加入我们;如果你需要分享的,也请加入我们。



鸿蒙,爱糖果,欢迎加入Harmony Candies,一起生产可爱的鸿蒙小糖果QQ群:981630644


harmony_candies.png


作者:法的空间
来源:juejin.cn/post/7364698043910930443

0 个评论

要回复文章请先登录注册