DEV Community

Cover image for HarmonyOS Flutter Practice: 06-Use ArkTs to Develop Flutter Harmony Plugins
shaohushuo
shaohushuo

Posted on

HarmonyOS Flutter Practice: 06-Use ArkTs to Develop Flutter Harmony Plugins

This article describes how to develop a Flutter Harmony plugin, how to achieve hybrid development of Flutter and Harmony, and two-way message communication.

Flutter side, write MethodChannel

const MethodChannel _methodChannel = MethodChannel('xxx.com/app');

/// Get token
static Future<dynamic> getToken() {
return _methodChannel.invokeMethod("getPrefs", 'token');
}

/// Set token
static Future<dynamic> setToken(String token) {
return _methodChannel
.invokeMethod("setPrefs", {'key': 'token', 'value': token});
}

Enter fullscreen mode Exit fullscreen mode

The code declares a methodChannel and implements the calling method of token storage error.

ArkTs side, implementation call

Write src/main/ets/entryability/EntryAbility.ets


import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
import ForestPlugin from './ForestPlugin';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';
import { preferences } from '@kit.ArkData';

let dataPreferences: preferences.Preferences | null = null;

export default class EntryAbility extends FlutterAbility { 

onWindowStageCreate(windowStage: window.WindowStage): void { super.onWindowStageCreate(windowStage); 
preferences.getPreferences(this.context, 'forestStore', (err: BusinessError, val: preferences.Preferences) => { 
if (err) { 
console.error("Failed to get preferences. code =" + err.code + ", message =" + err.message); 
return; 
} 
dataPreferences = val; 
console.info("Succeeded in getting preferences1."); 
}) 
} 

configureFlutterEngine(flutterEngine: FlutterEngine) { 
super.configureFlutterEngine(flutterEngine) 
GeneratedPluginRegistrant.registerWith(flutterEngine) 
this.addPlugin(new ForestPlugin()); 
}
}

export {dataPreferences};
Enter fullscreen mode Exit fullscreen mode

This file configures Flutter when the native page is loaded. Engine, register plugins. When Flutter is initialized, the preferences dataPreferences are also initialized for later use.

Write src/main/ets/entryability/ForestPlugin.ets

import { Any, BasicMessageChannel, EventChannel, FlutterManager, FlutterPlugin, Log, MethodCall, MethodChannel, StandardMessageCodec} from '@ohos/flutter_ohos';
import { FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin';
import { batteryInfo } from '@kit.BasicServicesKit';
import { MethodCallHandler, MethodResult } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel';
import { preferences } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';
import {dataPreferences} from './EntryAbility';
import router from '@ohos.router'
import { webviewRouterParams } from '../pages/Webview';

const TAG = "[flutter][plugin][forest]";

export default class ForestPlugin implements FlutterPlugin { 
private channel?: MethodChannel; 
private basicChannel?: BasicMessageChannel<Any>; 
private api = new ForestApi(); 
private dataPreferences: preferences.Preferences | null = null; 

onAttachedToEngine(binding: FlutterPluginBinding): void { 
this.channel = new MethodChannel(binding.getBinaryMessenger(), "xxx.com/app"); 
this.channel.setMethodCallHandler({ onMethodCall: (call: MethodCall, result: MethodResult) => { 
console.log(`${TAG}-->[${call.method}]: ${JSON.stringify(call.args)}`); 
switch (call.method) { 
case "getPrefs": 
this.api.getPrefs(String(call.args), result); 
break; 
case "setPrefs": 
let key = String(call.argument("key")); 
let value = String(call.argument("value")); 
this.api.setPrefs(key, value); 
default: 
result.notImplemented(); 
break; 
} 
} 
}) 
} 
//··· 
onDetachedFromEngine(binding: FlutterPluginBinding): void { 
Log.i(TAG, "onDetachedFromEngine"); this.channel?.setMethodCallHandler(null);
}

getUniqueClassName(): string {
return "ForestPlugin";
}
Enter fullscreen mode Exit fullscreen mode

The above code implements a plug-in class, the core of which implements the onAttachedToEngine method in FlutterPlugin, which is called after the Flutter engine is loaded successfully.

onMethodCall receives the message call from Flutter, and implements two callbacks, 'getPrefs' and 'setPrefs', respectively. Among them, getPrefs has a return value, which is returned asynchronously through result.success(val); (see below), and setPrefs has no return value.

The following is the specific implementation of ForestApi, which uses the preference API in HarmonyOS to set and read data.

class ForestApi { 
getPrefs(key: string, result: MethodResult) { 
dataPreferences?.get(key, '', (err: BusinessError, val: preferences.ValueType) => { 
if (err) { 
console.error(`${TAG} Failed to get value of ${key}. code =` + err.code + ", message =" + err.message); 
result.success(''); 
} 
console.info(`${TAG} Succeeded in getting value of ${key}:${val}.`); 
result.success(val); 
}) 

} 

setPrefs(key: string, value: string) { 
dataPreferences?.put(key, value, (err: BusinessError) => { 
if (err) { 
console.error(`${TAG} Failed to put value of ${key}. code =` + err.code + ", message =" + err.message); 
return; 
} 
console.info(`${TAG} Succeeded in putting value of ${key}.`); 
}) 
} 

clearPrefs(key: string) { 
dataPreferences?.delete(key, (err: BusinessError) => { 
if (err) { 
console.error("Failed to delete the key 'startup'. code =" + err.code + ", message =" + err.message);
return;
}
console.info(`Succeeded in deleting the key ${key}.`);
})
}
}

Enter fullscreen mode Exit fullscreen mode

Notes

  1. The name in the initialization methodChannel on both ends must be consistent, such as xxx.com/app.

  2. The arkTS side returns data through result.success(val), which is asynchronous, so you need to use await or callback function to get the value on the Dart side.

  3. Only basic data types are supported by default in communication, and complex types need to be serialized or encoded and decoded.

  4. The data received on the Dart side is of dymanic type, which requires data type conversion.

References

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.