You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[pigeon] Swift FFI wrapNumber serializes Objective-C CFBoolean / __NSCFBoolean inside Any as int instead of bool #193266
When using Pigeon's Swift FFI generator (createWithNativeInteropApi()), any Objective-C boolean (__NSCFBoolean / CFBoolean, a subclass of NSNumber) boxed inside a Swift Any or [String: Any] (such as values returned from UserDefaults.object(forKey:) or UserDefaults.persistentDomain(forName:)) is serialized across FFI to Dart as an int (1 or 0) instead of a bool (true or false).
Root Cause
In packages/pigeon/lib/src/swift/swift_generator.dart (around line 2321), the generated wrapNumber(number: Any) helper switches on number with case let value as Int: before case let value as Bool::
privatefunc wrapNumber(number:Any)->MessagesNumberWrapper{switch number {caseletvalue as Int:returnMessagesNumberWrapper(number:NSNumber(value: value), type:1)caseletvalue as Int64:returnMessagesNumberWrapper(number:NSNumber(value: value), type:1)caseletvalue as Double:returnMessagesNumberWrapper(number:NSNumber(value: value), type:2)caseletvalue as Float:returnMessagesNumberWrapper(number:NSNumber(value: value), type:2)caseletvalue as Bool:returnMessagesNumberWrapper(number:NSNumber(value: value), type:3)...
When Foundation is imported in Swift, an NSNumber (including __NSCFBoolean) boxed in Any succeeds when dynamically cast with as? Int (bridging true to 1 and false to 0). Because case let value as Int: is evaluated first, any CFBoolean instance matches as Int (type: 1) and never reaches case let value as Bool: (type: 3).
(By contrast, when using standard platform channels, FlutterStandardCodec checks CFGetTypeID((__bridge CFTypeRef)value) == CFBooleanGetTypeID() before treating an NSNumber as an integer or floating-point number.)
Steps to Reproduce
Define a Pigeon @HostApi() method returning Object? or Map<String, Object> (for example, UserDefaultsApi.getValue or UserDefaultsApi.getAll in shared_preferences_foundation).
In the Swift implementation, return a boolean value retrieved from an Objective-C API such as UserDefaults.standard.object(forKey:) or UserDefaults.standard.persistentDomain(forName:).
Call the API from Dart using the FFI client (createWithNativeInteropApi()).
Observe that Dart receives 1 (int) instead of true (bool).
Expected Results
Booleans backed by CFBoolean / __NSCFBoolean inside Any should be wrapped with type: 3 (Bool) and decoded as bool in Dart, matching the behavior of FlutterStandardCodec.
Suggested Fix
Check CFGetTypeID(number as CFTypeRef) == CFBooleanGetTypeID() at the beginning of wrapNumber(number: Any) (or before checking Int / Double) in packages/pigeon/lib/src/swift/swift_generator.dart:
ifCFGetTypeID(number asCFTypeRef)==CFBooleanGetTypeID(),let value = number as?Bool{returnMessagesNumberWrapper(number:NSNumber(value: value), type:3)}
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.
Activity
[pigeon] Fix NSnumber edge cases and null value bug (flutter#12997)
github-actions commentedon Oct 9, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.