├── .gitignore ├── AUTHORS ├── CHANGELOG.md ├── pubspec.yaml ├── lib ├── override.dart ├── src │ ├── osid_html.dart │ ├── osid_unknown.dart │ ├── osid_io.dart │ ├── os_kind.dart │ └── os_override.dart └── os_detect.dart ├── .github ├── dependabot.yml └── workflows │ └── test-package.yml ├── analysis_options.yaml ├── example ├── tree_shaking.dart └── example.dart ├── bin └── os_detect.dart ├── LICENSE ├── README.md └── test └── osid_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool/ 2 | .packages 3 | pubspec.lock 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people and organizations that have contributed 2 | # to the Dart project. Names should be added to the list like so: 3 | # 4 | # Name/Organization 5 | 6 | Google LLC 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.0.2-wip 2 | 3 | - Require Dart 3.0 4 | - Make work with VM's platform-constants. 5 | 6 | ## 2.0.1 7 | 8 | - Populate the pubspec `repository` field. 9 | 10 | ## 2.0.0 11 | 12 | - Stable null safety release. 13 | 14 | ## 1.0.0 15 | 16 | - Initial release 17 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: os_detect 2 | version: 2.0.2-wip 3 | description: Platform independent OS detection. 4 | repository: https://github.com/dart-lang/os_detect 5 | 6 | environment: 7 | sdk: ^3.0.0 8 | 9 | dependencies: 10 | meta: ^1.9.0 11 | 12 | dev_dependencies: 13 | dart_flutter_team_lints: ^2.0.0 14 | test: ^1.24.0 15 | -------------------------------------------------------------------------------- /lib/override.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | /// Functionality to override information about the current platform. 6 | library; 7 | 8 | export 'src/os_override.dart' show OperatingSystem, overrideOperatingSystem; 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Set update schedule for GitHub Actions 2 | # See https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/keeping-your-actions-up-to-date-with-dependabot 3 | 4 | version: 2 5 | updates: 6 | 7 | - package-ecosystem: github-actions 8 | directory: / 9 | schedule: 10 | interval: monthly 11 | labels: 12 | - autosubmit 13 | groups: 14 | github-actions: 15 | patterns: 16 | - "*" 17 | -------------------------------------------------------------------------------- /lib/src/osid_html.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:html'; 6 | 7 | import 'os_kind.dart' show BrowserOS; 8 | import 'os_override.dart'; 9 | 10 | String get _osVersion => window.navigator.appVersion; 11 | 12 | final OperatingSystem platformOS = 13 | OperatingSystemInternal(const BrowserOS(), _osVersion); 14 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # https://dart.dev/tools/analysis#the-analysis-options-file 2 | include: package:dart_flutter_team_lints/analysis_options.yaml 3 | 4 | analyzer: 5 | language: 6 | strict-casts: true 7 | strict-inference: true 8 | strict-raw-types: true 9 | 10 | linter: 11 | rules: 12 | - avoid_bool_literals_in_conditional_expressions 13 | - avoid_classes_with_only_static_members 14 | - avoid_private_typedef_functions 15 | - avoid_redundant_argument_values 16 | - avoid_returning_this 17 | - avoid_unused_constructor_parameters 18 | - avoid_void_async 19 | - literal_only_boolean_expressions 20 | - missing_whitespace_between_adjacent_strings 21 | - no_adjacent_strings_in_list 22 | - no_runtimeType_toString 23 | - package_api_docs 24 | - prefer_const_declarations 25 | - use_raw_strings 26 | 27 | 28 | -------------------------------------------------------------------------------- /example/tree_shaking.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | // Try compiling this example with (if on Linux): 6 | // 7 | // dart compile exe --target-os=linux tree_shaking.dart 8 | // 9 | // then check that "SOMETHING ELSE" does not occur in the 10 | // output `tree_shaking.exe` program, e.g.: 11 | // 12 | // strings tree_shaking.exe | grep SOMETHING 13 | // 14 | // which shows no matches. 15 | 16 | import 'package:os_detect/os_detect.dart' as platform; 17 | 18 | void main() { 19 | if (platform.isLinux) { 20 | print('Is Linux'); 21 | } else { 22 | print('SOMETHING ELSE'); 23 | } 24 | if (platform.operatingSystem == 'linux') { 25 | print('Is Linux'); 26 | } else { 27 | print('SOMETHING ELSE'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /example/example.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'package:os_detect/os_detect.dart' as os_detect; 6 | 7 | void main() { 8 | print(''' 9 | OS ID: ${os_detect.operatingSystem} 10 | OS Version: ${os_detect.operatingSystemVersion}'''); 11 | if (os_detect.isAndroid) { 12 | print(' OS Type: Android'); 13 | } else if (os_detect.isBrowser) { 14 | print(' OS Type: Browser'); 15 | } else if (os_detect.isFuchsia) { 16 | print(' OS Type: Fuchsia'); 17 | } else if (os_detect.isIOS) { 18 | print(' OS Type: iOS'); 19 | } else if (os_detect.isLinux) { 20 | print(' OS Type: Linux'); 21 | } else if (os_detect.isMacOS) { 22 | print(' OS Type: MacOS'); 23 | } else if (os_detect.isWindows) { 24 | print(' OS Type: Windows'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bin/os_detect.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | /// Prints the operating system detected by the current compilation environment. 6 | library pkg.os_detect.run; 7 | 8 | import 'package:os_detect/os_detect.dart' as os_detect; 9 | 10 | void main() { 11 | final knownName = knownOSName(); 12 | print('OS name : ${os_detect.operatingSystem} ' 13 | '${knownName != null ? '($knownName)' : ''}'); 14 | print('OS version : ${os_detect.operatingSystemVersion}'); 15 | } 16 | 17 | String? knownOSName() { 18 | if (os_detect.isAndroid) { 19 | return 'Android'; 20 | } 21 | if (os_detect.isBrowser) { 22 | return 'Browser'; 23 | } 24 | if (os_detect.isFuchsia) { 25 | return 'Fuchsia'; 26 | } 27 | if (os_detect.isIOS) { 28 | return 'iOS'; 29 | } 30 | if (os_detect.isLinux) { 31 | return 'Linux'; 32 | } 33 | if (os_detect.isMacOS) { 34 | return 'MacOS'; 35 | } 36 | if (os_detect.isWindows) { 37 | return 'Windows'; 38 | } 39 | return null; 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/osid_unknown.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'os_kind.dart'; 6 | import 'os_override.dart'; 7 | 8 | @pragma('vm:platform-const') 9 | const String _os = 10 | String.fromEnvironment('dart.os.name', defaultValue: 'unknown'); 11 | const String _osVersion = String.fromEnvironment('dart.os.version'); 12 | 13 | const OperatingSystem platformOS = OperatingSystemInternal( 14 | _os == RecognizedOS.linuxId 15 | ? LinuxOS() 16 | : _os == RecognizedOS.macOSId 17 | ? MacOS() 18 | : _os == RecognizedOS.windowsId 19 | ? WindowsOS() 20 | : _os == RecognizedOS.androidId 21 | ? AndroidOS() 22 | : _os == RecognizedOS.iOSId 23 | ? IOS() 24 | : _os == RecognizedOS.fuchsiaId 25 | ? FuchsiaOS() 26 | : _os == RecognizedOS.browserId 27 | ? BrowserOS() 28 | : UnknownOS(_os), 29 | _osVersion); 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020, the Dart project authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following 11 | disclaimer in the documentation and/or other materials provided 12 | with the distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /lib/src/osid_io.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:io'; 6 | 7 | import 'os_kind.dart'; 8 | import 'os_override.dart'; 9 | 10 | // Uses VM platform-constant functionality to constant fold this expression 11 | // when `Platform.operatingSystem` is known at compile-time. 12 | // Uses a valid "potentially constant" expression for this, instead of, e.g., 13 | // a `switch` expression. 14 | @pragma('vm:platform-const') 15 | final RecognizedOS? _osType = Platform.operatingSystem == RecognizedOS.linuxId 16 | ? const LinuxOS() 17 | : Platform.operatingSystem == RecognizedOS.macOSId 18 | ? const MacOS() 19 | : Platform.operatingSystem == RecognizedOS.windowsId 20 | ? const WindowsOS() 21 | : Platform.operatingSystem == RecognizedOS.androidId 22 | ? const AndroidOS() 23 | : Platform.operatingSystem == RecognizedOS.iOSId 24 | ? const IOS() 25 | : Platform.operatingSystem == RecognizedOS.fuchsiaId 26 | ? const FuchsiaOS() 27 | : Platform.operatingSystem == RecognizedOS.browserId 28 | ? const BrowserOS() 29 | : null; 30 | 31 | final OperatingSystem platformOS = OperatingSystemInternal( 32 | _osType ?? UnknownOS(Platform.operatingSystem), 33 | Platform.operatingSystemVersion); 34 | -------------------------------------------------------------------------------- /.github/workflows/test-package.yml: -------------------------------------------------------------------------------- 1 | name: Dart CI 2 | 3 | on: 4 | # Run on PRs and pushes to the default branch. 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | schedule: 10 | - cron: "0 0 * * 0" 11 | 12 | env: 13 | PUB_ENVIRONMENT: bot.github 14 | 15 | jobs: 16 | # Check code formatting and static analysis on a single OS (linux) 17 | # against Dart dev. 18 | analyze: 19 | runs-on: ubuntu-latest 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | sdk: [dev] 24 | steps: 25 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 26 | - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 27 | with: 28 | sdk: ${{ matrix.sdk }} 29 | - id: install 30 | name: Install dependencies 31 | run: dart pub get 32 | - name: Check formatting 33 | run: dart format --output=none --set-exit-if-changed . 34 | if: always() && steps.install.outcome == 'success' 35 | - name: Analyze code 36 | run: dart analyze --fatal-infos 37 | if: always() && steps.install.outcome == 'success' 38 | 39 | # Run tests on a matrix consisting of two dimensions: 40 | # 1. OS: ubuntu-latest, (macos-latest, windows-latest) 41 | # 2. release channel: dev 42 | test: 43 | needs: analyze 44 | runs-on: ${{ matrix.os }} 45 | strategy: 46 | fail-fast: false 47 | matrix: 48 | # Add macos-latest and/or windows-latest if relevant for this package. 49 | os: [ubuntu-latest, windows-latest, macos-latest] 50 | sdk: [3.0.0, dev] 51 | steps: 52 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 53 | - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 54 | with: 55 | sdk: ${{ matrix.sdk }} 56 | - id: install 57 | name: Install dependencies 58 | run: dart pub get 59 | - name: Run VM tests 60 | run: dart test --platform vm 61 | if: always() && steps.install.outcome == 'success' 62 | - name: Run Chrome tests 63 | run: dart test --platform chrome 64 | if: always() && steps.install.outcome == 'success' 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > This repo has moved to https://github.com/dart-lang/core/tree/main/pkgs/os_detect 3 | 4 | [![Build Status](https://github.com/dart-lang/os_detect/workflows/Dart%20CI/badge.svg)](https://github.com/dart-lang/os_detect/actions?query=workflow%3A"Dart+CI"+branch%3Amaster) 5 | [![pub package](https://img.shields.io/pub/v/os_detect.svg)](https://pub.dev/packages/os_detect) 6 | [![package publisher](https://img.shields.io/pub/publisher/os_detect.svg)](https://pub.dev/packages/os_detect/publisher) 7 | 8 | Platform independent access to information about the current operating system. 9 | 10 | ## Querying the current OS 11 | 12 | Exposes `operatingSystem` and `operatingSystemVersion` strings similar to those 13 | of the `Platform` class in `dart:io`, but also works on the web. The 14 | `operatingSystem` of a browser is the string "browser". Also exposes convenience 15 | getters like `isLinux`, `isAndroid` and `isBrowser` based on the 16 | `operatingSystem` string. 17 | 18 | To use this package instead of `dart:io`, replace the import of `dart:io` with: 19 | 20 | ```dart 21 | import 'package:os_detect/os_detect.dart' as os_detect; 22 | ``` 23 | 24 | That should keep the code working if the only functionality used from `dart:io` 25 | is operating system detection. You should then use your IDE to rename the import 26 | prefix from `Platform` to something lower-cased which follows the style guide 27 | for import prefixes. 28 | 29 | Any new platform which supports neither `dart:io` nor `dart:html` can make 30 | itself recognizable by configuring the `dart.os.name` and `dart.os.version` 31 | environment settings, so that `const String.fromEnvironment` can access them. 32 | 33 | ## Overriding the current OS string 34 | 35 | It's possible to override the current operating system string, as exposed by 36 | `operatingSystem` and `operatingSystemVersion` in 37 | `package:os_detect/os_detect.dart`. To do so, import the 38 | `package:os_detect/override.dart` library and use the `overrideOperatingSystem` 39 | function to run code in a zone where the operating system and version values are 40 | set to whatever values are desired. 41 | 42 | The class `OperatingSystemID` can also be used directly to abstract over the 43 | operating system name and version. The `OperatingSystemID.current` defaults to 44 | the values provided by the platform when not overridden using 45 | `overrideOperatingSystem`. 46 | -------------------------------------------------------------------------------- /test/osid_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | 7 | import 'package:os_detect/os_detect.dart'; 8 | import 'package:os_detect/override.dart'; 9 | import 'package:test/test.dart'; 10 | 11 | void main() { 12 | test('Exists and is consistent', () { 13 | expect(operatingSystem, isNotNull); 14 | expect(operatingSystemVersion, isNotNull); 15 | 16 | expect(isLinux, operatingSystem == OperatingSystem.linuxId); 17 | expect(isAndroid, operatingSystem == OperatingSystem.androidId); 18 | expect(isMacOS, operatingSystem == OperatingSystem.macOSId); 19 | expect(isWindows, operatingSystem == OperatingSystem.windowsId); 20 | expect(isIOS, operatingSystem == OperatingSystem.iOSId); 21 | expect(isFuchsia, operatingSystem == OperatingSystem.fuchsiaId); 22 | expect(isBrowser, operatingSystem == OperatingSystem.browserId); 23 | }); 24 | 25 | test('Override', () { 26 | const overrideName = 'argle-bargle'; 27 | const overrideVersion = 'glop-glyf'; 28 | final overrideOS = OperatingSystem(overrideName, overrideVersion); 29 | Zone? overrideZone; 30 | 31 | final originalName = operatingSystem; 32 | final originalVersion = operatingSystemVersion; 33 | final originalID = OperatingSystem.current; 34 | final originalZone = Zone.current; 35 | expect(originalName, isNot(overrideName)); 36 | expect(originalVersion, isNot(overrideVersion)); 37 | 38 | // Override OS ID. 39 | overrideOperatingSystem(overrideOS, () { 40 | overrideZone = Zone.current; 41 | expect(operatingSystem, overrideName); 42 | expect(operatingSystemVersion, overrideVersion); 43 | expect(OperatingSystem.current, same(overrideOS)); 44 | // Nested override. 45 | overrideOperatingSystem(originalID, () { 46 | expect(operatingSystem, originalName); 47 | expect(operatingSystemVersion, originalVersion); 48 | expect(OperatingSystem.current, same(originalID)); 49 | }); 50 | expect(operatingSystem, overrideName); 51 | expect(operatingSystemVersion, overrideVersion); 52 | expect(OperatingSystem.current, same(overrideOS)); 53 | // Captured parent zone does not have override. 54 | originalZone.run(() { 55 | expect(operatingSystem, originalName); 56 | expect(operatingSystemVersion, originalVersion); 57 | }); 58 | expect(operatingSystem, overrideName); 59 | expect(operatingSystemVersion, overrideVersion); 60 | expect(OperatingSystem.current, same(overrideOS)); 61 | }); 62 | 63 | expect(operatingSystem, originalName); 64 | expect(operatingSystemVersion, originalVersion); 65 | 66 | // A captured override zone retains the override. 67 | overrideZone!.run(() { 68 | expect(operatingSystem, overrideName); 69 | expect(operatingSystemVersion, overrideVersion); 70 | expect(OperatingSystem.current, same(overrideOS)); 71 | }); 72 | }); 73 | } 74 | -------------------------------------------------------------------------------- /lib/src/os_kind.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | /// Shared constants and classes used to represent a recongized OS type 6 | /// 7 | /// Not exported in the public API, but used to communicate between 8 | /// `override.dart` and the conditionally imported `osid_X.dart` files. 9 | /// 10 | /// When the platform is statically known, all but one of the subclasses 11 | /// should be tree-shaken, so an `os is AndroidOS` can be resolved to 12 | /// a constant true/false depending on whether the class is the retained one 13 | /// or not. 14 | library; 15 | 16 | /// Operating identity object. 17 | /// 18 | /// By only instantiating these subtypes guarded by target-OS guarded 19 | /// checks, unless using the "for testing" `OperatingSystem` constructor, 20 | /// all but one of the subclasses should be tree-shaken, 21 | /// and, e.g., the `_isId is IOS` test above should become tree-shakable 22 | /// on all other platforms. 23 | sealed class RecognizedOS { 24 | // The recognized OS identifier strings recognized. 25 | static const androidId = 'android'; 26 | static const browserId = 'browser'; 27 | static const fuchsiaId = 'fuchsia'; 28 | static const iOSId = 'ios'; 29 | static const linuxId = 'linux'; 30 | static const macOSId = 'macos'; 31 | static const windowsId = 'windows'; 32 | 33 | abstract final String id; 34 | const RecognizedOS(); 35 | } 36 | 37 | /// Operations system object for Android. 38 | class AndroidOS extends RecognizedOS { 39 | @override 40 | final String id = RecognizedOS.androidId; 41 | const AndroidOS(); 42 | } 43 | 44 | /// Operations system object for browsers. 45 | class BrowserOS extends RecognizedOS { 46 | @override 47 | final String id = RecognizedOS.browserId; 48 | const BrowserOS(); 49 | } 50 | 51 | /// Operations system object for Fuchsia. 52 | class FuchsiaOS extends RecognizedOS { 53 | @override 54 | final String id = RecognizedOS.fuchsiaId; 55 | const FuchsiaOS(); 56 | } 57 | 58 | /// Operations system object for iOS. 59 | class IOS extends RecognizedOS { 60 | @override 61 | final String id = RecognizedOS.iOSId; 62 | const IOS(); 63 | } 64 | 65 | /// Operations system object for Linux. 66 | class LinuxOS extends RecognizedOS { 67 | @override 68 | final String id = RecognizedOS.linuxId; 69 | const LinuxOS(); 70 | } 71 | 72 | /// Operations system object for MacOS. 73 | class MacOS extends RecognizedOS { 74 | @override 75 | final String id = RecognizedOS.macOSId; 76 | const MacOS(); 77 | } 78 | 79 | /// Operations system object for Windows. 80 | class WindowsOS extends RecognizedOS { 81 | @override 82 | final String id = RecognizedOS.windowsId; 83 | const WindowsOS(); 84 | } 85 | 86 | /// Fallback to represent unknown operating system. 87 | /// 88 | /// Do not use for one of the recognized operating 89 | /// systems 90 | class UnknownOS extends RecognizedOS { 91 | @override 92 | final String id; 93 | const UnknownOS(this.id) 94 | : assert(id != RecognizedOS.linuxId), 95 | assert(id != RecognizedOS.macOSId), 96 | assert(id != RecognizedOS.windowsId), 97 | assert(id != RecognizedOS.androidId), 98 | assert(id != RecognizedOS.iOSId), 99 | assert(id != RecognizedOS.fuchsiaId), 100 | assert(id != RecognizedOS.browserId); 101 | } 102 | -------------------------------------------------------------------------------- /lib/os_detect.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | /// Information about the current operating system. 6 | library pkg.os_detect; 7 | 8 | import 'src/os_override.dart'; 9 | 10 | /// Identification of the current operating system or platform. 11 | /// 12 | /// Specific known operating systems are reported by a unique known string, 13 | /// and all the `is` values are computed by comparing the 14 | /// [operatingSystem] string against those known strings. 15 | /// That means that *at most* one of those value can be `true`, 16 | /// and usually precisely one will be `true`. 17 | /// 18 | /// **Notice:** Programs running in a browser will report their 19 | /// operating system as `"browser"`, not the operating system 20 | /// that browser is running on. See [isBrowser]. 21 | String get operatingSystem => OperatingSystem.current.id; 22 | 23 | /// Representation of the version of the current operating system or platform. 24 | /// 25 | /// May be empty if no version is known or available. 26 | String get operatingSystemVersion => OperatingSystem.current.version; 27 | 28 | /// Whether the current operating system is a version of 29 | /// [Linux](https://en.wikipedia.org/wiki/Linux). 30 | /// 31 | /// Identified by [operatingSystem] being the string `linux`. 32 | /// 33 | /// This value is `false` if the operating system is a specialized 34 | /// version of Linux that identifies itself by a different name, 35 | /// for example Android (see [isAndroid]), 36 | /// or if the code is running inside a browser (see [isBrowser]). 37 | @pragma('vm:prefer-inline') 38 | bool get isLinux => OperatingSystem.current.isLinux; 39 | 40 | /// Whether the current operating system is a version of 41 | /// [macOS](https://en.wikipedia.org/wiki/MacOS). 42 | /// 43 | /// Identified by [operatingSystem] being the string `macos`. 44 | /// 45 | /// The value is `false` if the code is running inside a browser, 46 | /// even if that browser is running on MacOS (see [isBrowser]). 47 | @pragma('vm:prefer-inline') 48 | bool get isMacOS => OperatingSystem.current.isMacOS; 49 | 50 | /// Whether the current operating system is a version of 51 | /// [Microsoft Windows](https://en.wikipedia.org/wiki/Microsoft_Windows). 52 | /// 53 | /// Identified by [operatingSystem] being the string `windows`. 54 | /// 55 | /// The value is `false` if the code is running inside a browser, 56 | /// even if that browser is running on Windows (see [isBrowser]). 57 | @pragma('vm:prefer-inline') 58 | bool get isWindows => OperatingSystem.current.isWindows; 59 | 60 | /// Whether the current operating system is a version of 61 | /// [Android](https://en.wikipedia.org/wiki/Android_%28operating_system%29). 62 | /// 63 | /// Identified by [operatingSystem] being the string `android`. 64 | /// 65 | /// The value is `false` if the code is running inside a browser, 66 | /// even if that browser is running on Android (see [isBrowser]). 67 | @pragma('vm:prefer-inline') 68 | bool get isAndroid => OperatingSystem.current.isAndroid; 69 | 70 | /// Whether the current operating system is a version of 71 | /// [iOS](https://en.wikipedia.org/wiki/IOS). 72 | /// 73 | /// Identified by [operatingSystem] being the string `ios`. 74 | /// 75 | /// The value is `false` if the code is running inside a browser, 76 | /// even if that browser is running on iOS (see [isBrowser]). 77 | @pragma('vm:prefer-inline') 78 | bool get isIOS => OperatingSystem.current.isIOS; 79 | 80 | /// Whether the current operating system is a version of 81 | /// [Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia). 82 | /// 83 | /// Identified by [operatingSystem] being the string `fuchsia`. 84 | /// 85 | /// The value is `false` if the code is running inside a browser, 86 | /// even if that browser is running on Fuchsia (see [isBrowser]). 87 | @pragma('vm:prefer-inline') 88 | bool get isFuchsia => OperatingSystem.current.isFuchsia; 89 | 90 | /// Whether running in a web browser. 91 | /// 92 | /// Identified by [operatingSystem] being the string `browser`. 93 | /// 94 | /// If so, the [operatingSystemVersion] is the string made available 95 | /// through `window.navigator.appVersion`. 96 | /// 97 | /// The value is `true` when the code is running inside a browser, 98 | /// no matter which operating system the browser is itself running on. 99 | /// No attempt is made to detect the underlying operating system. 100 | /// That information *may* be derived from [operatingSystemVersion], 101 | /// but browsers are able to lie in the app-version/user-agent 102 | /// string. 103 | @pragma('vm:prefer-inline') 104 | bool get isBrowser => OperatingSystem.current.isBrowser; 105 | -------------------------------------------------------------------------------- /lib/src/os_override.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async' show Zone, runZoned; 6 | 7 | import 'package:meta/meta.dart'; 8 | 9 | import 'os_kind.dart'; 10 | import 'osid_unknown.dart' 11 | if (dart.library.io) 'osid_io.dart' 12 | if (dart.library.html) 'osid_html.dart'; 13 | 14 | /// The name and version of an operating system. 15 | final class OperatingSystem { 16 | // The recognized OS identifier strings. 17 | 18 | /// The operating system ID string for Linux. 19 | /// 20 | /// Compare against [id] or the `operatingSystem` of `os_detect.dart`, 21 | /// or use as argument to [OperatingSystem.new]. 22 | static const androidId = RecognizedOS.androidId; 23 | 24 | /// The operating system ID string for browsers. 25 | /// 26 | /// Compare against [id] or the `operatingSystem` of `os_detect.dart`, 27 | /// or use as argument to [OperatingSystem.new]. 28 | static const browserId = RecognizedOS.browserId; 29 | 30 | /// The operating system ID string for Fuchsia. 31 | /// 32 | /// Compare against [id] or the `operatingSystem` of `os_detect.dart`, 33 | /// or use as argument to [OperatingSystem.new]. 34 | static const fuchsiaId = RecognizedOS.fuchsiaId; 35 | 36 | /// The operating system ID string for iOS. 37 | /// 38 | /// Compare against [id] or the `operatingSystem` of `os_detect.dart`, 39 | /// or use as argument to [OperatingSystem.new]. 40 | static const iOSId = RecognizedOS.iOSId; 41 | 42 | /// The operating system ID string for Linux. 43 | /// 44 | /// Compare against [id] or the `operatingSystem` of `os_detect.dart`, 45 | /// or use as argument to [OperatingSystem.new]. 46 | static const linuxId = RecognizedOS.linuxId; 47 | 48 | /// The operating system ID string for macOS. 49 | /// 50 | /// Compare against [id] or the `operatingSystem` of `os_detect.dart`, 51 | /// or use as argument to [OperatingSystem.new]. 52 | static const macOSId = RecognizedOS.macOSId; 53 | 54 | /// The operating system ID string for Windows. 55 | /// 56 | /// Compare against [id] or the `operatingSystem` of `os_detect.dart`, 57 | /// or use as argument to [OperatingSystem.new]. 58 | static const windowsId = RecognizedOS.windowsId; 59 | 60 | /// The current operating system ID. 61 | /// 62 | /// Defaults to what information is available 63 | /// from known platform specific libraries, 64 | /// but can be overridden using functionality from the 65 | /// `osid_override.dart` library. 66 | @pragma('vm:try-inline') 67 | static OperatingSystem get current => 68 | Zone.current[#_os] as OperatingSystem? ?? platformOS; 69 | 70 | /// A string representing the operating system or platform. 71 | String get id => _osId.id; 72 | 73 | // Operating system ID object. 74 | final RecognizedOS _osId; 75 | 76 | /// A string representing the version of the operating system or platform. 77 | /// 78 | /// May be empty if no version is known or available. 79 | final String version; 80 | 81 | /// Creates a new operating system object for testing. 82 | /// 83 | /// Can be used with [overrideOperatingSystem] to selectively 84 | /// change the value returned by [current]. 85 | /// 86 | /// **Notice:** Using this constructor may reduce the efficiency 87 | /// of compilers recognizing code that isn't needed when compiling 88 | /// for a particular platform (aka. "tree-shaking" of unreachable code). 89 | // Uses chained conditionals to allow back-ends to constant fold when they 90 | // know what `id` is, which they'd usually know for a specific operation. 91 | // That can avoid retaining *all* the subclasses of `OS`. 92 | @visibleForTesting 93 | @pragma('vm:prefer-inline') 94 | OperatingSystem(String id, String version) 95 | : this._( 96 | id == linuxId 97 | ? const LinuxOS() 98 | : id == macOSId 99 | ? const MacOS() 100 | : id == windowsId 101 | ? const WindowsOS() 102 | : id == androidId 103 | ? const AndroidOS() 104 | : id == iOSId 105 | ? const IOS() 106 | : id == fuchsiaId 107 | ? const FuchsiaOS() 108 | : id == browserId 109 | ? const BrowserOS() 110 | : UnknownOS(id), 111 | version); 112 | 113 | /// Used by platforms which know the ID object. 114 | const OperatingSystem._(this._osId, this.version); 115 | 116 | /// Whether the operating system is a version of 117 | /// [Linux](https://en.wikipedia.org/wiki/Linux). 118 | /// 119 | /// Identified by [id] being the string `linux`. 120 | /// 121 | /// This value is `false` if the operating system is a specialized 122 | /// version of Linux that identifies itself by a different name, 123 | /// for example Android (see [isAndroid]). 124 | bool get isLinux => _osId is LinuxOS; 125 | 126 | /// Whether the operating system is a version of 127 | /// [macOS](https://en.wikipedia.org/wiki/MacOS). 128 | /// 129 | /// Identified by [id] being the string `macos`. 130 | bool get isMacOS => _osId is MacOS; 131 | 132 | /// Whether the operating system is a version of 133 | /// [Microsoft Windows](https://en.wikipedia.org/wiki/Microsoft_Windows). 134 | /// 135 | /// Identified by [id] being the string `windows`. 136 | bool get isWindows => _osId is WindowsOS; 137 | 138 | /// Whether the operating system is a version of 139 | /// [Android](https://en.wikipedia.org/wiki/Android_%28operating_system%29). 140 | /// 141 | /// Identified by [id] being the string `android`. 142 | bool get isAndroid => _osId is AndroidOS; 143 | 144 | /// Whether the operating system is a version of 145 | /// [iOS](https://en.wikipedia.org/wiki/IOS). 146 | /// 147 | /// Identified by [id] being the string `ios`. 148 | bool get isIOS => _osId is IOS; 149 | 150 | /// Whether the operating system is a version of 151 | /// [Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia). 152 | /// 153 | /// Identified by [id] being the string `fuchsia`. 154 | bool get isFuchsia => _osId is FuchsiaOS; 155 | 156 | /// Whether running in a web browser. 157 | /// 158 | /// Identified by [id] being the string `browser`. 159 | /// 160 | /// If so, the [version] is the string made available 161 | /// through `window.navigator.appVersion`. 162 | bool get isBrowser => _osId is BrowserOS; 163 | } 164 | 165 | /// Run [body] in a zone with platform overrides. 166 | /// 167 | /// Overrides [OperatingSystem.current] with the supplied [operatingSystem] 168 | /// value while running in a new zone, and then runs [body] in that zone. 169 | /// 170 | /// This override affects the `operatingSystem` and `version` 171 | /// exported by `package:osid/osid.dart`. 172 | R overrideOperatingSystem( 173 | OperatingSystem operatingSystem, R Function() body) => 174 | runZoned(body, zoneValues: {#_os: operatingSystem}); 175 | 176 | // Exposes the `OperatingSystem._` constructor to the conditionally imported 177 | // libraries. Not exported by `../override.dart'. 178 | final class OperatingSystemInternal extends OperatingSystem { 179 | const OperatingSystemInternal(super.id, super.version) : super._(); 180 | } 181 | --------------------------------------------------------------------------------