| // 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. | |
| import 'dart:io'; | |
| import 'package:pub_semver/pub_semver.dart'; | |
| import 'c_bindings_generated.dart' as c; | |
| /// Returns the current MacOS/iOS version. | |
| Version get osVersion => _osVersion; | |
| Version _osVersion = () { | |
| final ver = c.getOsVesion(); | |
| return Version(ver.major, ver.minor, ver.patch); | |
| }(); | |
| /// Returns whether the current MacOS/iOS version is greater than or equal to | |
| /// the given version. | |
| /// | |
| /// Designed to replace Objective-C's `@available` check. | |
| /// | |
| /// Each platform's version is optional, and the function returns false if | |
| /// no version is provided for the current platform. | |
| bool checkOSVersion({Version? iOS, Version? macOS}) { | |
| if (Platform.isIOS) return _checkOSVersionImpl(iOS); | |
| if (Platform.isMacOS) return _checkOSVersionImpl(macOS); | |
| throw UnsupportedError('Only supported on iOS and macOS'); | |
| } | |
| bool _checkOSVersionImpl(Version? version) { | |
| if (version == null) return false; | |
| return osVersion >= version; | |
| } | |
| final class OsVersionError implements Exception { | |
| final String apiName; | |
| final String message; | |
| OsVersionError(this.apiName, this.message); | |
| @override | |
| String toString() => '$runtimeType: $apiName $message.'; | |
| } | |
| typedef PlatformAvailability = (bool unavailable, (int, int, int)? introduced); | |
| /// Only for use by FFIgen bindings. | |
| void checkOsVersionInternal( | |
| String apiName, { | |
| PlatformAvailability? iOS, | |
| PlatformAvailability? macOS, | |
| }) { | |
| if (Platform.isIOS) _checkOsVersionInternalImpl(apiName, 'iOS', iOS); | |
| if (Platform.isMacOS) _checkOsVersionInternalImpl(apiName, 'macOS', macOS); | |
| } | |
| void _checkOsVersionInternalImpl( | |
| String apiName, | |
| String osName, | |
| PlatformAvailability? availability, | |
| ) { | |
| if (availability == null) return; | |
| final (bool unavailable, (int, int, int)? introduced) = availability; | |
| if (unavailable) { | |
| throw OsVersionError(apiName, 'is not supported on $osName'); | |
| } | |
| if (introduced != null && osVersion < _toVersion(introduced)) { | |
| throw OsVersionError( | |
| apiName, | |
| 'is not supported on $osName before version $introduced.' | |
| 'The current version is $osVersion', | |
| ); | |
| } | |
| } | |
| Version _toVersion((int, int, int) record) { | |
| final (int major, int minor, int patch) = record; | |
| return Version(major, minor, patch); | |
| } |