Hooks
Execute scripts de build personalizados.
Este guia explica o que são hooks e como usá-los com um pacote.
Introdução
#Atualmente, você pode usar hooks para fazer coisas como compilar ou baixar native assets (código escrito em outras linguagens que é compilado para código de máquina) e depois chamar esses assets a partir do código Dart de um pacote.
Hooks são scripts Dart colocados no diretório hook/ do
seu pacote Dart. Eles têm um formato predefinido para
entrada e saída, o que permite ao Dart SDK:
- Descobrir os hooks.
- Executar os hooks com a entrada necessária.
- Consumir a saída produzida pelos hooks.
Exemplo de projeto com um build hook:
-
example_project/// Projeto com hooks.
hook/// Adicione os scripts de hook aqui.
- build.dart
lib/ // Use seus assets aqui.
- example.dart
src/ // Adicione os fontes nativos aqui.
- example_native_library.c
- example_native_library.h
test/// Teste seus assets aqui.
- example_test.dart
Hooks
#Atualmente, há build hooks e link hooks disponíveis. Para saber mais, veja o seguinte.
Build hooks
#Com build hooks, um pacote pode fazer coisas como compilar ou baixar native assets, como bibliotecas C ou Rust. Depois, esses assets podem ser chamados a partir do código Dart do pacote.
O build hook de um pacote é invocado automaticamente pelo Dart SDK em um momento apropriado do processo de build. Build hooks são executados em paralelo com a compilação Dart e podem fazer operações demoradas, como download ou chamada de um compilador nativo.
Use a função build
para analisar a
entrada do hook com BuildInput
e depois escrever a saída do hook
com BuildOutputBuilder. O hook deve colocar
os assets baixados e gerados em
BuildInput.sharedOutputDirectory.
Os assets produzidos para o seu pacote podem depender de
assets
ou metadata
produzidos pelos build hooks
dos pacotes nas dependências diretas do pubspec. Por isso,
build hooks são executados na ordem das dependências no pubspec, e dependências
cíclicas entre pacotes não são suportadas ao usar hooks.
Link hooks
#Com link hooks, um pacote pode filtrar, otimizar ou fazer tree-shaking dos code assets gerados pelos build hooks antes de empacotá-los em um aplicativo.
O Dart SDK invoca automaticamente o link hook de um pacote (hook/link.dart)
durante a fase de empacotamento do aplicativo. Diferentemente dos build hooks, que são executados para
cada pacote, os link hooks são executados com o contexto no nível do aplicativo, para que
possam inspecionar quais símbolos o aplicativo realmente usa.
Use a função link
para analisar a entrada do hook com LinkInput
e
escrever a saída do hook com LinkOutputBuilder.
Se o tree-shaking remover todos os símbolos de um asset, o link hook pode omitir
o asset por completo para não empacotá-lo com o aplicativo.
Variáveis de ambiente
#
Os hooks são executados em um ambiente semi-hermético.
Isso significa que Platform.environment não
expõe todas as variáveis de ambiente do processo pai.
Isso garante que as invocações de hooks sejam reproduzíveis e armazenáveis em cache, e
não dependam de variáveis de ambiente acidentais.
No entanto, algumas variáveis de ambiente são necessárias para localizar ferramentas (como compiladores) ou configurar o acesso à rede. As seguintes variáveis de ambiente são repassadas ao processo do hook:
-
Caminho e raízes do sistema:
-
PATH: Invocar ferramentas nativas. -
HOME,USERPROFILE: Encontrar ferramentas nos locais de instalação padrão. -
SYSTEMDRIVE,SYSTEMROOT,WINDIR: Invocações de processos e CMake no Windows. -
PROGRAMDATA: Para ovswhere.exeno Windows.
-
-
Diretórios temporários:
-
TEMP,TMP,TMPDIR: Diretórios temporários.
-
-
Proxies HTTP:
-
HTTP_PROXY,HTTPS_PROXY,NO_PROXY: Acesso à rede atrás de proxies.
-
-
Clang/LLVM:
-
LIBCLANG_PATH:bindgen+clang-sysdo Rust.
-
-
Android NDK:
-
ANDROID_HOME: Local padrão do Android SDK/NDK. -
ANDROID_NDK,ANDROID_NDK_HOME,ANDROID_NDK_LATEST_HOME,ANDROID_NDK_ROOT: Locais alternativos para o NDK.
-
- Nix:
- Qualquer variável que comece com
NIX_.
- Qualquer variável que comece com
Qualquer alteração nessas variáveis de ambiente invalida o cache dos hooks.
Todas as outras variáveis de ambiente são removidas.
Assets
#
Assets são os arquivos produzidos por um hook e depois
empacotados em um aplicativo Dart. Assets podem ser acessados
em tempo de execução pelo código Dart. Atualmente, o Dart SDK pode
usar o tipo CodeAsset, mas outros tipos de assets estão planejados.
Para saber mais, veja o seguinte.
Tipo CodeAsset
#
Um CodeAsset
representa um code asset. Um code asset é uma biblioteca dinâmica
compilada a partir de uma linguagem diferente de Dart, como C, C++, Rust ou Go.
CodeAsset faz parte do pacote code_assets. As APIs fornecidas por code assets
são acessadas em tempo de execução por meio de membros Dart externos correspondentes, anotados
com a anotação @Native
de dart:ffi.
Usar um hook
#Para adicionar assets ao seu projeto, use um hook. Para detalhes, veja as seções a seguir.
Adicionar dependências
#
Para usar um hook, primeiro você deve adicionar os pacotes auxiliares
hooks e code_assets às dependências do seu pubspec.yaml:
dart pub add hooks code_assets.
Se você precisar compilar fontes C, também precisará do pacote native_toolchain_c:
dart pub add native_toolchain_c.
Exemplo de dependências para um build hook:
name: native_add_library
description: Sums two numbers with native code.
version: 0.1.0
environment:
sdk: '^3.10.0'
dependencies:
# ...
code_assets: any
hooks: any
native_toolchain_c: any
dev_dependencies:
# ...
ffigen: ^18.0.0
Criar um build hook para gerar native assets
#
Se você quiser usar um build hook para compilar de forma transparente
native assets (como bibliotecas C ou Rust), que depois ficam disponíveis
para serem chamados a partir do código Dart de um pacote,
crie um script build.dart semelhante ao seguinte:
No seu projeto Dart, crie ou abra
hook/build.dart.-
No método
main, chame a funçãobuilddepackage:hooks/hooks.darte use a toolchain apropriada para compilar a biblioteca nativa. Por exemplo:hook/build.dartdartimport 'package:hooks/hooks.dart'; import 'package:native_toolchain_c/native_toolchain_c.dart'; void main(List<String> args) async { await build(args, (input, output) async { final packageName = input.packageName; final cLibrary = CLibrary( name: packageName, assetName: '$packageName.dart', sources: ['src/$packageName.c'], ); await cLibrary.build( input: input, output: output, ); }); }O segundo parâmetro de
buildespera uma função à qual ele passará dois argumentos:input: A entrada somente leitura do hook. Inclui informações para que o hook produza o tipo de asset correto (por exemplo, SO de destino, arquitetura de destino, diretório de saída e mais). Para detalhes, veja a classeBuildInput.output: O construtor somente escrita da saída do hook. Depois que o build hook lê a entrada, ele produz um asset e então fornece o que produziu como saída. Para detalhes, veja a classeBuildOutputBuilder.
Criar um link hook para fazer tree-shaking de native assets
#
Se o seu pacote gera native assets com um build hook (hook/build.dart),
você pode adicionar um link hook (hook/link.dart) para fazer tree-shaking dos code assets
não utilizados antes do empacotamento.
Durante a compilação, o compilador Dart registra quais símbolos @Native são
de fato referenciados pelo aplicativo e os disponibiliza aos link hooks por
meio de LinkInput.recordedUses.
Se input.recordedUses for null, o link hook desativa o tree-shaking e
mantém todos os símbolos.
No seu projeto Dart, crie ou abra
hook/link.dart.-
No método
main, chame a funçãolinkdepackage:hooks/hooks.darte passe as opções de tree-shaking paraCLibrary.link. Por exemplo:hook/link.dartdartimport 'package:hooks/hooks.dart'; import 'package:native_toolchain_c/native_toolchain_c.dart'; import 'package:record_use/record_use.dart'; import 'record_use_mapping.dart'; void main(List<String> args) async { await link(args, (input, output) async { final packageName = input.packageName; final cLibrary = CLibrary( name: packageName, assetName: '$packageName.dart', sources: ['src/$packageName.c'], ); final linkerOptions = LinkerOptions.treeshake( symbolsToKeep: input.recordedUses?.calls.keys .cast<Method>() .map((e) => recordUseMapping[e.name]!), ); await cLibrary.link( input: input, output: output, linkerOptions: linkerOptions, ); }); }
Os símbolos Dart em bindings gerados por ferramentas como ffigen nem sempre
correspondem um a um aos nomes de símbolos C nativos.
Ao gerar bindings FFI, o ffigen pode gerar automaticamente um mapeamento
(recordUseMapping) dos identificadores de métodos Dart para os símbolos nativos.
Mapeie cada chamada de método Dart registrada (input.recordedUses?.calls.keys)
usando recordUseMapping para passar os símbolos nativos correspondentes a
LinkerOptions.treeshake.
Quando symbolsToKeep é null (por exemplo, quando input.recordedUses
é
null), LinkerOptions.treeshake preserva todos os símbolos da biblioteca nativa.
Quando symbolsToKeep é uma lista vazia ([]), o que significa que o aplicativo não
referencia nenhum símbolo da biblioteca, CLibrary.link ignora automaticamente a
compilação e o empacotamento da biblioteca dinâmica.
Assets empacotados automaticamente
#
Os hooks são executados automaticamente ao invocar os comandos run, build ou
test.
Os assets resultantes são armazenados no diretório de saída especificado na
entrada do hook. Em seguida, o Dart SDK empacota automaticamente esses assets com
seu aplicativo Dart para que possam ser acessados em tempo de execução.
Usar assets
#
Assets são os arquivos que os hooks criam. Depois que um asset é
criado, você pode referenciá-lo no seu código e em tempo de execução
pelo seu asset ID (assetId). Asset IDs têm a estrutura
package:<package-name>/<asset-name>. Build hooks só podem
produzir assets no próprio pacote. O CLibrary no
build hook do exemplo anterior produz o asset ID
package:native_add_library/native_add_library.dart, com base no
packageName e no assetName.
O exemplo a seguir ilustra como vincular à
função C nativa add de native_add_library.c e chamá-la:
import 'dart:ffi';
@Native<Int32 Function(Int32, Int32)>()
external int add(int a, int b);
import 'package:my_package/my_package.dart';
void main() {
print(add(24, 18));
}
O asset ID em @Native é opcional e assume por padrão o
URI da biblioteca. No exemplo anterior, ele é
package:native_add_library/native_add_library.dart, que
é o mesmo asset ID produzido pelo build hook. Isso
permite que o Dart conecte um asset referenciado em tempo de execução ao
fornecido pelo hook durante o processo de build.
Testar assets
#Depois de escrever um hook que gera um asset e de usar esse asset no seu código Dart, considere escrever um teste para verificar se o hook e o asset gerado funcionam como esperado.
No exemplo a seguir, um teste é criado para
native_add_library.dart, um script que referencia uma
função C nativa chamada add:
import 'package:native_add_library/native_add_library.dart';
import 'package:test/test.dart';
void main() {
test('invoke native function', () {
expect(add(24, 18), 42);
});
}
Configuração de hooks
#
Passe parâmetros personalizados ou caminhos de arquivos locais para os build e link hooks
a partir do ambiente de build do seu projeto.
Configure esses parâmetros na chave hooks do seu arquivo pubspec.yaml.
Atualmente, esse bloco suporta apenas a opção user_defines.
Configurar user-defines
#
Configure os parâmetros personalizados no arquivo pubspec.yaml do pacote raiz,
ou no arquivo pubspec.yaml do workspace, se você usar workspace.
Somente os usuários finais—os autores do aplicativo ou pacote raiz que consome
as dependências—podem configurar user-defines.
As dependências não podem fornecer seus próprios user-defines padrão.
Os valores configurados em user_defines podem ser de qualquer tipo compatível com JSON,
como booleanos, strings, números, mapas aninhados ou listas.
Os user-defines são filtrados por pacote.
Um hook dentro de my_package só pode acessar as chaves configuradas em
hooks.user_defines.my_package.
Ele não pode acessar os user-defines de outros pacotes.
O exemplo a seguir passa dois user-defines
para os hooks do pacote my_package:
hooks:
user_defines:
my_package:
enable_experimental: true
custom_lib: assets/libnative.so
Acessar user-defines em um hook
#
Para acessar os user-defines configurados no seu script de hook
build.dart ou link.dart, use o objeto input.userDefines:
- Leia os valores brutos com o operador de colchetes, como
input.userDefines['key']. -
Resolva caminhos relativos para um
Uriusando o métodopath(), comoinput.userDefines.path('key'). Isso resolve o caminho relativo em relação ao diretório dopubspec.yamlonde os user-defines são declarados.
Se o hook ler um arquivo ou diretório resolvido,
registre-o como dependência usando
output.dependencies.add().
Isso garante que o sistema de build invalide o cache e
execute o hook novamente quando o arquivo mudar.
O exemplo a seguir é um script de hook que acessa os
user-defines enable_experimental e custom_lib:
import 'dart:io';
import 'package:hooks/hooks.dart';
void main(List<String> args) async {
await build(args, (input, output) async {
final experimental = input.userDefines['enable_experimental'];
if (experimental is! bool?) {
throw const FormatException(
'hooks.user_defines.my_package.enable_experimental must be a '
'boolean (or omitted)',
);
}
if (experimental ?? false) {
print('Experimental features enabled.');
}
final customLibUri = input.userDefines.path('custom_lib');
if (customLibUri != null) {
final file = File.fromUri(customLibUri);
output.dependencies.add(file.uri);
// Use the file...
}
});
}
Projetos de exemplo
#Há vários projetos de exemplo para ajudar você a começar com hooks e code assets:
| Projeto | Descrição |
|---|---|
sqlite
|
Um pacote que compila, empacota, faz tree-shaking e usa um mecanismo de banco de dados nativo. |
mini_audio
|
Um pacote que compila, empacota, faz tree-shaking e usa um reprodutor de áudio nativo. |
stb_image
|
Um pacote que compila, empacota, faz tree-shaking e usa uma biblioteca de imagens nativa. |
host_name
|
Um pacote que usa uma biblioteca nativa do sistema. |
native_add_library
|
Um pacote que compila, empacota e usa um código C simples. |
native_add_app
|
Um aplicativo CLI Dart que depende de native_add_library. |
download_asset
|
Um pacote que empacota e usa assets pré-compilados que são baixados no build hook. |
native_dynamic_linking
|
Um pacote que compila, empacota e usa três bibliotecas nativas que dependem umas das outras. |
use_dart_api
|
Um pacote que usa a API C da VM Dart. |
Mais informações
#Veja os links a seguir para mais informações:
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Página atualizada pela última vez em 2026-11-12. Ver código-fonte ou relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.