native
native copied to clipboard
WIP: Swiftgen prototype and example
This is a prototype of swiftgen, and an example program that uses the Swift AVAudioPlayer API to play some audio from Dart.
example/generate_code.dart uses swiftgen to generate Dart bindings like this:
await generate(Config(
target: Target(
triple: 'x86_64-apple-macosx14.0',
sdk: Uri.directory(
'/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'),
),
input: SwiftModuleInput(module: 'AVFAudio'),
tempDir: Uri.directory('temp'),
outputModule: 'AVFAudioWrapper',
objcSwiftFile: Uri.file('avf_audio_wrapper.swift'),
ffigen: FfiGenConfig(
output: Uri.file('avf_audio_bindings.dart'),
outputObjC: Uri.file('avf_audio_wrapper.m'),
externalVersions: ffigen.ExternalVersions(
ios: ffigen.Versions(min: Version(12, 0, 0)),
macos: ffigen.Versions(min: Version(10, 14, 0)),
),
objcInterfaces: ffigen.DeclarationFilters(
shouldInclude: (decl) => decl.originalName == 'AVAudioPlayerWrapper',
),
),
));
Then example/play_audio.dart uses the generated Dart bindings to play audio:
for (final file in args) {
final fileStr = NSString(file);
print('Loading $fileStr');
final fileUrl = NSURL.fileURLWithPath_(fileStr);
final player = AVAudioPlayerWrapper.alloc()
.initWithContentsOf_error_(fileUrl, nullptr);
if (player == null) {
print('Failed to load audio');
continue;
}
final durationSeconds = player.duration.ceil();
print('$durationSeconds sec');
final status = player.play();
if (status) {
print('Playing...');
await Future<void>.delayed(Duration(seconds: durationSeconds));
} else {
print('Failed to play audio.');
}
}
There are a few remaining hacks to iron out, due to https://github.com/dart-lang/native/issues/1775 and https://github.com/dart-lang/native/issues/1774.
PR Health
Breaking changes :heavy_check_mark:
| Package | Change | Current Version | New Version | Needed Version | Looking good? |
|---|
This check can be disabled by tagging the PR with skip-breaking-check.
Changelog Entry :heavy_check_mark:
| Package | Changed Files |
|---|
Changes to files need to be accounted for in their respective changelogs.
This check can be disabled by tagging the PR with skip-changelog-check.
API leaks :heavy_check_mark:
The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
| Package | Leaked API symbol | Leaking sources |
|---|
This check can be disabled by tagging the PR with skip-leaking-check.
License Headers :heavy_check_mark:
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
| Files |
|---|
| no missing headers |
All source files should start with a license header.
Unrelated files missing license headers
| Files |
|---|
| pkgs/objective_c/lib/src/ns_input_stream.dart |
This check can be disabled by tagging the PR with skip-license-check.
Hey there, would you be able to briefly explain how could I run this locally? Should I execute example/generate_code.dart?
@orestesgaolin Yeah, if you want to try the example you can run example/generate_code.dart to regenerate the bindings (avf_audio_bindings.dart etc) and example/play_audio.dart foo.mp3 to run the example.
Given we have a merged https://github.com/dart-lang/native/tree/main/pkgs/swiftgen, I presume this can be closed.
I don't see swiftgen updated on main... Is that something that needs to be synchronized with google's repos?
Oh, it's an empty directory, my bad! (I was in overzealous spring-cleaning-mode!)
coverage: 83.521%. remained the same when pulling 7f979f0e6362db51bf7ed005527a7b23ab0f81b9 on swiftgen2 into d7ab0d55e01c0eb3c35c5af9fefd84c53ef55215 on main.
https://github.com/dart-lang/native/pull/2585