Dart
Codegen
Write code generation with build_runner.
Codegen
Now we add code generation. We will define a NativeBinding annotation class and a BindingGenerator class. This is a simplified model of the build_runner + source_gen approach.
NativeBinding marks a class as having a native binding. BindingGenerator produces binding code for the marked class. In reality build_runner does this automatically; here we call it manually.
In this lesson gen.generate('NativeMathService') returns the generated binding code as a String. This String represents the code that would be written to a .g.dart file.
The annotation class
In Dart annotations are classes with a const constructor. class NativeBinding { final String name; const NativeBinding(this.name); } allows @NativeBinding('native_add') usage.
BindingGenerator takes a class name and produces binding code: String generate(String className) => '// generated binding for $className';. In reality this would be a full class wrapping FFI calls.
This model mirrors source_gen's GeneratorForAnnotation approach. Annotation-marked classes are found automatically and code is generated. Here we call it manually but the mechanism is the same.
Exercise Add NativeBinding and BindingGenerator
The NativeMathService is already defined below. Now define a class NativeBinding with final String name; const NativeBinding(this.name);. Define a class BindingGenerator with String generate(String className) => '// generated binding for $className';. In main create final gen = BindingGenerator(); and add print(gen.generate('NativeMathService'));.
Show example solution
import 'dart:ffi';
abstract class MathService {
int add(int a, int b);
}
typedef NativeAdd = Int32 Function(Int32 a, Int32 b);
typedef DartAdd = int Function(int a, int b);
class NativeMathService implements MathService {
final String bindingName;
NativeMathService(this.bindingName);
@override
int add(int a, int b) => a + b;
String describe() => 'native: $bindingName';
}
class NativeBinding {
final String name;
const NativeBinding(this.name);
}
class BindingGenerator {
String generate(String className) => '// generated binding for $className';
}
void main() {
print('service ready');
final svc = NativeMathService('native_add');
print(svc.describe());
print('result: ${svc.add(2, 3)}');
final gen = BindingGenerator();
print(gen.generate('NativeMathService'));
}
Test yourself
-
What does BindingGenerator produce?
- Test code
- Binding code
- UI widgets
- Database table
Show answer
Binding code — BindingGenerator produces native binding code.
-
The const constructor
class NativeBinding {
final String name;
____ NativeBinding(this.name);
}
Show answer
class NativeBinding {
final String name;
const NativeBinding(this.name);
}
-
Match the codegen parts
- NativeBinding
- Annotation
- BindingGenerator
- Generator class
- generate(...)
- Generation method
- .g.dart
- Generated file
Next lesson: Architecture