cupertino_ffi 0.2.0 cupertino_ffi: ^0.2.0 copied to clipboard
This package enables Dart developers to use various C APIs by Apple (Core Foundation, Security, etc.).
Overview #
This package enables Dart developers to use various C APIs by Apple. The package uses dart:ffi and the C APIs are generated with ffi_tool.
If you use this package, you must follow the correct reference counting patterns. The patterns are documented below.
If you want bindings for a large number of Objective-C libraries by Apple, see the package cupertino_ffi_generated.
Contributing #
C libraries in this package #
Core Foundation #
- Core classes such as CFString, CFDictionary, etc.
- Documentation: developer.apple.com
- Import:
package:cupertino_ffi/core_foundation.dart
- Note that Foundation types (NSString, etc.) and Core Foundation types (CFString,
etc.) are "toll-free" bridged types.
This means that
Pointer<CFString>
can be used asPointer<NSString>
and vice-versa.
Core Graphics #
- Documentation developer.apple.com
- Import:
package:cupertino_ffi/core_graphics.dart
Objective-C runtime #
- Documentation: developer.apple.com
- Import
package:cupertino_ffi/objective_c.dart
Security #
- Documentation: developer.apple.com
- Import
package:cupertino_ffi/objective_c.dart
Required #
Until dart:ffi supports garbage collection finalizers (Dart SDK issue #35770), you need to do memory management manually using the patterns described in this section
Calling APIs that return ARC pointers #
If you call any API that returns a reference-counter pointer, you need to call arcPush
and
arcPop
like in the following example:
String example() {
// Push a new ARC frame.
arcPush();
try {
final pointer = CFDictionary.fromDart({"key": "value"});
return "some return value";
} finally {
// Pop the topmost ARC frame.
arcPop();
}
}
Returning ARC pointers #
If you return a pointer to reference counted value, you must call function 'arcReturn', which inserts the pointer into caller's reference counting frame and increments the reference count (so it will 2 before 'arcPop').
Example:
Pointer<CFDictionary> example() {
arcPush();
try {
final result = CFDictionary.fromDart({"key": "value"});
return arcReturn(result);
} finally {
arcPop();
}
}
Storing ARC pointer #
You need to ensure that arcFieldGet
is invoked in the getter and arcFieldSet
is invoked in the
setter.
import 'package:cupertino_ffi/core_foundation.dart';
Pointer<CFString> _field;
Pointer<CFString> get field => arcFieldGet(_field);
set field(Pointer<CFString> newValue) {
_field = arcFieldSet(_field, newValue);
}
Generating Objective-C bindings yourself #
import 'package:ffi_tool/objective_c.dart';
void main() {
generateAll([
ObjcLibrary(
// Just for documentation purposes
productName: "Core ML",
uri: "https://developer.apple.com/documentation/coreml",
// For generated source code
libraryName: "example",
libraryPath: "/System/Library/Frameworks/CoreML.framework/Versions/Current/CoreML",
generatedPath: "core_ml.dart",
),
]);
}
Generating bindings for Objective-C libraries #
Objective-C supports reflection so we are able to generate APIs automatically. The generated libraries use cupertino_ffi for reference counting. Please make sure you understand the reference counting patterns that you need to follow when you use the generated library.
For example, our generator script looks like this:
import 'package:cupertino_ffi/objc_ffi_generator.dart';
void main() {
generateAll(ObjcBinding(
libraries: libraries,
packageName: "cupertino_ffi",
));
}
final libraries = [
ObjcLibraryBinding(
dynamicLibrary: DynamicLibraryInfo(
path: "/System/Library/Frameworks/CloudKit.framework/Versions/A/CloudKit",
name: "CloudKit",
url: "https://developer.apple.com/documentation/cloudkit?language=objc",
),
name: "cloudkit",
),
ObjcLibraryBinding(
dynamicLibrary: DynamicLibraryInfo(
path: "/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData",
name: "Core Data",
url: "https://developer.apple.com/documentation/coredata?language=objc",
),
name: "core_data",
),
// ...
];