Configuração do ambiente Flutter para HarmonyOS
Utilize uma versão do Flutter oficialmente compatível com HarmonyOS. A versão recomendada é 3.22.1-ohos-1.0.4, que inclui suporte nativo ao runtime OHOS. Atualize o pubspec.yaml:
environment:
sdk: '3.4.0'
flutter: "3.22.1-ohos-1.0.4"
Atualização de dependências
Substitua os pacotes padrão por versões adaptadas ao HarmonyOS, priorizando forks mantidos pela comunidade OpenHarmony SIG:
dependencies:
em_chat_uikit:
path: ../em_chat_uikit-2.2.0
im_flutter_sdk_ohos:
git:
url: https://github.com/easemob/im_flutter_sdk_oh.git
ref: 1.5.3
dependency_overrides:
record:
git:
url: https://gitcode.com/openharmony-sig/fluttertpc_record.git
path: record
ref: d40e26bd4052362d505ef8c2c600ac69aa5a967a
shared_preferences:
git:
url: https://gitcode.com/openharmony-sig/flutter_packages.git
path: packages/shared_preferences/shared_preferences
image_picker:
git:
url: https://gitcode.com/openharmony-sig/flutter_packages.git
path: packages/image_picker/image_picker
audioplayers:
git:
url: https://gitcode.com/openharmony-sig/flutter_audioplayers.git
path: packages/audioplayers
video_player:
git:
url: https://gitcode.com/openharmony-sig/flutter_packages.git
path: packages/video_player/video_player
flutter_localization:
git:
url: https://gitcode.com/openharmony-sig/flutter_localization.git
sqflite:
git:
url: https://gitcode.com/OpenHarmony-SIG/flutter_sqflite.git
ref: 'github.com/tekartik/sqflite.git/v2.3.3+1'
path: sqflite
Otimizações de interface para HarmonyOS
O compoennte ChatUIKitPopupMenu foi reestruturado para evitar estouro visual em telas com densidade variável. As principais mudanças incluem:
- Substituição de
ContainerporSizedBoxpara eliminar padding vertical indesejado; - Redução do espaçamento entre ícone e rótulo de
4pxpara2px; - Uso explícito de
TextScaler.noScalingpara garantir consistência tipográfica.
Exemplo revisado:
@override
Widget build(BuildContext context) {
return Wrap(
direction: Axis.horizontal,
children: widget.actions.map((action) {
return InkWell(
onTap: () {
widget.close?.call();
action.onTap?.call();
},
child: SizedBox(
width: 72,
height: 64,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (action.icon != null)
SizedBox(height: 28, width: 28, child: action.icon!),
const SizedBox(height: 2),
Text(
action.label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textScaler: TextScaler.noScaling,
style: TextStyle(
color: widget.style.foregroundColor,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
}).toList(),
);
}
Tratamento de funcionalidades não suportadas
Recursos como *threads*, tradução e denúncia não possuem implementação nativa no SDK HarmonyOS. Desative-os via configuração centralizada:
// Desativa threads de mensagens
ChatUIKitSettings.enableMessageThread = false;
// Remove opções de menu longo
ChatUIKitSettings.msgItemLongPressActions
..remove(ChatUIKitActionType.translate)
..remove(ChatUIKitActionType.report);
Gerenciamento de permissões de áudio
No arquivo ohos/entry/src/main/module.json5, adicione a permissão de microfone:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:permission_microphone_reason",
"usedScene": {
"when": "always",
"abilities": ["EntryAbility"]
}
}
]
}
}
E defina a string localizada em ohos/AppScope/resources/base/element/string.json:
{
"string": [
{
"name": "permission_microphone_reason",
"value": "Permite gravar mensagens de voz e participar de chamadas de áudio/vídeo"
}
]
}
Na lógica de gravação, substitua lançamentos de exceção por notificações amigáveis ao usuário:
Future<void> startRecording() async {
if (!await record.hasPermission()) {
ChatUIKit.instance.sendChatUIKitEvent(
ChatUIKitEvent.noMicrophonePermission
);
_showPermissionAlert();
return;
}
try {
final timestamp = DateTime.now().millisecondsSinceEpoch;
final fileName = '$timestamp.$extensionName';
await record.start(recordConfig, path: '${_directory!.path}/$fileName');
_state?.switchRecordType(RecordBarRecordType.recording);
} on RecordException catch (e) {
debugPrint('Gravação falhou: $e');
}
}
void _showPermissionAlert() {
final ctx = _state?.context;
if (ctx == null || !ctx.mounted) return;
showChatUIKitDialog(
context: ctx,
title: ChatUIKitLocal.microphonePermissionDeniedTitle.localString(ctx),
content: ChatUIKitLocal.microphonePermissionDeniedContent.localString(ctx),
actionItems: [
ChatUIKitDialogAction.confirm(
label: ChatUIKitLocal.confirm.localString(ctx),
onTap: () => Navigator.of(ctx).pop(),
),
],
);
}
Substituição de plugins incompatíveis
O plugin open_file não oferece suporte a HarmonyOS. Substitua-o por open_filex, aplicando codificação URI aos caminhos de arquivos para evitar falhas com caracteres especiais (como # em app keys):
final encodedPath = Uri.encodeComponent('/data/storage/el1/base/haps/entry/files/downloads/file.pdf');
final fileUri = Uri.parse('file://$encodedPath');
await OpenFilex.open(fileUri.toString());
Atualização dinâmica de reações
Para garantir que a lista de mensagens reflita alterações em reações em tempo real, implemente um mecanismo de atualização explícito no controlador de mensagens:
Future<void> updateReaction(
String msgId,
String emoji,
bool isAdding,
) async {
try {
await ChatUIKit.instance.updateMessageReaction(
messageId: msgId,
reaction: emoji,
isAdd: isAdding,
);
await refreshMessageReaction(msgId); // Atualiza UI imediatamente
} catch (e) {
chatPrint('Falha ao atualizar reação: $e');
}
}
Future<void> refreshMessageReaction(String msgId) async {
final idx = msgModelList.indexWhere((m) => m.message.msgId == msgId);
if (idx == -1) return;
final msg = await ChatUIKit.instance.loadMessage(messageId: msgId);
if (msg == null) return;
final reactions = await msg.reactionList();
msgModelList[idx] = msgModelList[idx].copyWith(
message: msg,
reactions: reactions,
);
notifyListeners();
}
Integre esse comportamento ao componente de visualização de reações via callback onReactionChanged, disparado ao adicionar/remover uma reação — acionando assim a atualização da lista pai.