Développer un plugin Flutter pour la plateforme HarmonyOS, implémenter une intégration mixte Flutter-HarmonyOS et gérer la communication inter-processus.
Côté Flutter : Configuration du MethodChannel
const MethodChannel _channel = MethodChannel('com.example.app/service');
/// Récupérer le jeton d'authentification
static Future<dynamic> fetchAuthToken() {
return _channel.invokeMethod("retrieveSetting", 'auth_token');
}
/// Enregistrer le jeton d'authentification
static Future<dynamic> storeAuthToken(String jeton) {
return _channel
.invokeMethod("saveSetting", {'cle': 'auth_token', 'valeur': jeton});
}
Ce code définit un canal de méthode et expose des fonctions pour stocker et récupérer des données via des appels de méthode.
Côté ArkTs : Implémentation native
Fichier EntryAbility.ets
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { PluginManager } from '../plugins/PluginManager';
import CustomBridgePlugin from './CustomBridgePlugin';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';
import { preferences } from '@kit.ArkData';
let localStore: preferences.Preferences | null = null;
export default class AppAbility extends FlutterAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
super.onWindowStageCreate(windowStage);
preferences.getPreferences(this.context, 'appDataStore', (err: BusinessError, prefs: preferences.Preferences) => {
if (err) {
console.error("Échec de l'initialisation des préférences. code=" + err.code);
return;
}
localStore = prefs;
console.info("Préférences chargées avec succès.");
})
}
setupFlutterEngine(flutterEngine: FlutterEngine) {
super.setupFlutterEngine(flutterEngine)
PluginManager.registerPlugins(flutterEngine)
this.registerPlugin(new CustomBridgePlugin());
}
}
export {localStore};
Ce fichier initialise le moteur Flutter, configure les plugins et charge le stockage local au démarrage de l'application.
Fichier CustomBridgePlugin.ets
import { MethodChannel, MethodCall, MethodResult, FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos';
import { localStore } from './AppAbility';
const LOG_TAG = "[HarmonyPlugin]";
export default class CustomBridgePlugin implements FlutterPlugin {
private methodChannel?: MethodChannel;
private storageService = new StorageOperations();
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.methodChannel = new MethodChannel(binding.getBinaryMessenger(), "com.example.app/service");
this.methodChannel.setMethodCallHandler({
onMethodCall : (call: MethodCall, result: MethodResult) => {
console.log(`${LOG_TAG} Méthode appelée: ${call.method}`);
switch (call.method) {
case "retrieveSetting":
this.storageService.readValue(String(call.args), result);
break;
case "saveSetting":
const key = String(call.argument("cle"));
const value = String(call.argument("valeur"));
this.storageService.writeValue(key, value);
break;
default:
result.notImplemented();
}
}
})
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.methodChannel?.setMethodCallHandler(null);
}
}
Classe StorageOperations
class StorageOperations {
readValue(key: string, callback: MethodResult) {
localStore?.get(key, '', (err: BusinessError, storedValue: preferences.ValueType) => {
if (err) {
console.error(`${LOG_TAG} Erreur de lecture pour la clé ${key}`);
callback.success('');
}
callback.success(storedValue);
})
}
writeValue(key: string, value: string) {
localStore?.put(key, value, (err: BusinessError) => {
if (!err) {
console.info(`${LOG_TAG} Valeur écrite pour la clé ${key}`);
}
})
}
removeValue(key: string) {
localStore?.delete(key, (err: BusinessError) => {
if (!err) {
console.info(`${LOG_TAG} Clé ${key} supprimée`);
}
})
}
}
Points d'attention
- Les noms des canaux de méthode doivent correspondre exactement entre les parties Flutter et native (ex: 'com.example.app/service').
- Les réponses natives sont asynchrones ; côté Dart, utilisez await ou des callbacks pour traiter les données.
- Seuls les types de données simples sont supportés nativement ; les objets complexes nécessitent une sérialisation.
- Les données reçues en Dart sont de type dynamic et nécessitent une conversion exlpicite.