主要解决问题
-
Flutter中如何把数据传递到原生侧再传递给服务卡片
FormKit?(这篇) -
如何响应服务卡片的一些特定指令如快捷跳转到特定的Flutter界面?(第二篇)
-
Flutter应用内如何将服务卡片添加到桌面?(第二篇)
如果你也有相关的困惑,可以看这篇文章哦!
一、什么是服务卡片
如下图,服务卡片就是下面的展示出来的小组件,鸿蒙官方的名称是服务卡片。
二、创建服务卡片
对着鸿蒙项目的目录下的entry/src/ets单击右键,选择 Service Widget 中的 Dynamic Widget(见下两张图)。
三、新增的主要文件介绍
resource/base/profile/form_config.json:这是服务卡片的配置文件,设置服务卡片的名字,对外显示的名字等。具体说明见下,更详细的介绍可见官方文档:developer.huawei.com/consumer/cn…
{
"forms": [
{
"name": "anniversary", //卡片名字,用于代码等开发操作
"displayName": "$string:anniversary_display_name", // 对用户显示的名字
"description": "$string:anniversary_desc", // 对用户显示的卡片描述
"src": "./ets/anniversary/pages/AnniversaryCard.ets", // 界面文件
"uiSyntax": "arkts", //开发的语言
"window": {
"designWidth": 720,
"autoDesignWidth": true
},
"formConfigAbility": "ability://EntryAbility", // 配置卡片的ability,主要就是用户在桌面长按卡片的时候可以长按进行编辑卡片
"colorMode": "auto",
"isDynamic": true,
"isDefault": true,
"updateEnabled": false,
"scheduledUpdateTime": "00:00",
"updateDuration": 1,
"defaultDimension": "2*2",
"supportDimensions": [
"2*2"
]
}
]
}
\ets\anniversary\pages\AnniversaryCard.ets 界面文件,编写服务卡片的UI
\ets\EntryFormAbility.ets 服务卡片的管理类,所有服务卡片的逻辑处理都在这一个文件中编写逻辑,不管你不同类型的卡片有多少个。
四、Flutter 怎么把数据传递给服务卡片?
4.1 Flutter端
编写一个工具类,主要负责创建Flutter与鸿蒙原生之间的通信。
class HomeWidgetUtils {
static pinCard(context, String name, String date, String image) async {
const String channelPath =
"plugins.flutter.io/home_widget"; //这儿要与MethodChannel(flutterEngine?.dartExecutor, CHANNEL)中CHANNEL名称一致
const MethodChannel channel = MethodChannel(channelPath);
Map map = {
"name": name,
"date": date,
"image": image
};
await channel
.invokeMethod("setPin", {"card": map}); //TODO 这里传数据有问题
printLog("已发送到桌面");
}
}
4.2 鸿蒙端
主要就是要写一下channel的代码,然后在EntryAbility.ets那里注册一下。
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
this.registerWith(flutterEngine)
}
// 加入自己的引擎
registerWith(flutterEngine: FlutterEngine) {
try {
flutterEngine.getPlugins()?.add(new HomeWidgetPlugin());
} catch (e) {
}
}
export class HomeWidgetPlugin implements FlutterPlugin, AbilityAware {
private methodChannel: MethodChannel | null = null
private methodCallHandler: HomeWidgetHandlerImpl | null = null
private context: common.UIAbilityContext | null = null
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.setUpMethodChannel(binding.getBinaryMessenger(), binding.getApplicationContext());
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.teardownMethodChannel();
}
onAttachedToAbility(binding: AbilityPluginBinding): void {
this.context = binding.getAbility().context
this.methodCallHandler?.setContext(this.context)
}
onDetachedFromAbility(): void {
this.methodCallHandler?.setContext(null)
}
getUniqueClassName(): string {
return TAG
}
setUpMethodChannel(messenger: BinaryMessenger, context: common.Context) {
this.methodChannel = new MethodChannel(messenger, "plugins.flutter.io/home_widget");
this.methodCallHandler =
new HomeWidgetHandlerImpl(context, this.methodChannel);
this.methodChannel.setMethodCallHandler(this.methodCallHandler);
}
teardownMethodChannel() {
this.methodChannel?.setMethodCallHandler(null);
this.methodChannel = null;
this.methodCallHandler = null;
this.context = null;
}
}
值得注意的是,这里是要把拿到的数据用鸿蒙端的Sharepreference存起来。以供\ets\EntryFormAbility.ets 服务卡片的管理类使用。
export class HomeWidgetHandlerImpl implements MethodCallHandler {
private context: common.UIAbilityContext | null = null
private methodChannel: MethodChannel
constructor(context: common.Context, methodChannel: MethodChannel) {
this.methodChannel = methodChannel
}
setContext(context: common.UIAbilityContext | null) {
this.context = context
}
async onMethodCall(call: MethodCall, result: MethodResult): Promise<void> {
switch (call.method) {
case "setPin": // 这里的名字要与Flutter端调用的对应
await preferenceUtils.loadPreference(this.context,'pin')
let pinDeed: Map<string, string> = call.argument('card') // 这里获取参数名以获得参数
await preferenceUtils.delPreferenceValue('pin', 'name')
await preferenceUtils.delPreferenceValue('pin', 'date')
await preferenceUtils.delPreferenceValue('pin', 'image')
await preferenceUtils.putPreferenceValue('pin', 'name', pinDeed.get('name'))
await preferenceUtils.putPreferenceValue('pin', 'date', pinDeed.get('date'))
await preferenceUtils.putPreferenceValue('pin', 'image', pinDeed.get('image'))
result.success(null);
break;
default:
result.notImplemented();
}
}
}
在管理类所在的EntryFormAbility.ets文件中的几个重要函数 onUpdateForm,onFormEvent, onAddForm 中获取刚刚的数据data并填入到formData = formBindingData.createFormBindingData(data)中。示例代码如下:
async onUpdateForm(formId: string): Promise<void> {
// 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm formId: ' + formId);
let formData: formBindingData.FormBindingData
let data = await this.getPinData(formId) // 这里就是从sharepreference中获取数据
formData = formBindingData.createFormBindingData(data)
formProvider.updateForm(formId, formData).catch((error: BusinessError) => {
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] updateForm, error:' + JSON.stringify(error));
});
}