[web] Use platform detection from Flutter web engine. (#147346)
> [!IMPORTANT] > Requires the following engine PR: > * https://github.com/flutter/engine/pull/52380 > ---- This PR refactors Flutter `foundation`'s library `platform` for the web with the same code we use to detect platforms in the engine. ## Issues * Fixes: https://github.com/flutter/flutter/issues/128943 ## Testing Demo app deployed here: * https://dit-browser-detect.web.app
This commit is contained in:
parent
f20c853d20
commit
d7656f2fcf
@ -4,7 +4,6 @@
|
||||
|
||||
import 'dart:ui_web' as ui_web;
|
||||
|
||||
import '../web.dart' as web;
|
||||
import 'platform.dart' as platform;
|
||||
|
||||
export 'platform.dart' show TargetPlatform;
|
||||
@ -19,46 +18,45 @@ platform.TargetPlatform get defaultTargetPlatform {
|
||||
_browserPlatform;
|
||||
}
|
||||
|
||||
final platform.TargetPlatform? _testPlatform = () {
|
||||
platform.TargetPlatform? result;
|
||||
// The TargetPlatform used on Web tests, unless overridden.
|
||||
//
|
||||
// Respects the `ui_web.browser.debugOperatingSystemOverride` value (when set).
|
||||
platform.TargetPlatform? get _testPlatform {
|
||||
platform.TargetPlatform? testPlatform;
|
||||
assert(() {
|
||||
if (ui_web.debugEmulateFlutterTesterEnvironment) {
|
||||
result = platform.TargetPlatform.android;
|
||||
// Return the overridden operatingSystem in tests, if any...
|
||||
if (ui_web.browser.debugOperatingSystemOverride != null) {
|
||||
testPlatform =
|
||||
_operatingSystemToTargetPlatform(ui_web.browser.operatingSystem);
|
||||
} else {
|
||||
// Fall back to `android` for tests.
|
||||
testPlatform = platform.TargetPlatform.android;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return result;
|
||||
}();
|
||||
return testPlatform;
|
||||
}
|
||||
|
||||
// Lazy-initialized and forever cached current browser platform.
|
||||
// Current browser platform.
|
||||
//
|
||||
// Computing the platform is expensive as it uses `window.matchMedia`, which
|
||||
// needs to parse and evaluate a CSS selector. On some devices this takes up to
|
||||
// 0.20ms. As `defaultTargetPlatform` is routinely called dozens of times per
|
||||
// frame this value should be cached.
|
||||
final platform.TargetPlatform _browserPlatform = () {
|
||||
final String navigatorPlatform = web.window.navigator.platform.toLowerCase();
|
||||
if (navigatorPlatform.startsWith('mac')) {
|
||||
return platform.TargetPlatform.macOS;
|
||||
}
|
||||
if (navigatorPlatform.startsWith('win')) {
|
||||
return platform.TargetPlatform.windows;
|
||||
}
|
||||
if (navigatorPlatform.contains('iphone') ||
|
||||
navigatorPlatform.contains('ipad') ||
|
||||
navigatorPlatform.contains('ipod')) {
|
||||
return platform.TargetPlatform.iOS;
|
||||
}
|
||||
if (navigatorPlatform.contains('android')) {
|
||||
return platform.TargetPlatform.android;
|
||||
}
|
||||
// Since some phones can report a window.navigator.platform as Linux, fall
|
||||
// back to use CSS to disambiguate Android vs Linux desktop. If the CSS
|
||||
// indicates that a device has a "fine pointer" (mouse) as the primary
|
||||
// pointing device, then we'll assume desktop linux, and otherwise we'll
|
||||
// assume Android.
|
||||
if (web.window.matchMedia('only screen and (pointer: fine)').matches) {
|
||||
return platform.TargetPlatform.linux;
|
||||
}
|
||||
return platform.TargetPlatform.android;
|
||||
}();
|
||||
// The computation of `operatingSystem` is cached in the ui_web package;
|
||||
// this getter may be called dozens of times per frame.
|
||||
//
|
||||
// _browserPlatform is lazily initialized, and cached forever.
|
||||
final platform.TargetPlatform _browserPlatform =
|
||||
_operatingSystemToTargetPlatform(ui_web.browser.operatingSystem);
|
||||
|
||||
// Converts an ui_web.OperatingSystem enum into a platform.TargetPlatform.
|
||||
platform.TargetPlatform _operatingSystemToTargetPlatform(ui_web.OperatingSystem os) {
|
||||
return switch (os) {
|
||||
ui_web.OperatingSystem.android => platform.TargetPlatform.android,
|
||||
ui_web.OperatingSystem.iOs => platform.TargetPlatform.iOS,
|
||||
ui_web.OperatingSystem.linux => platform.TargetPlatform.linux,
|
||||
ui_web.OperatingSystem.macOs => platform.TargetPlatform.macOS,
|
||||
ui_web.OperatingSystem.windows => platform.TargetPlatform.windows,
|
||||
// Resolve 'unknown' OS values to `android`.
|
||||
ui_web.OperatingSystem.unknown => platform.TargetPlatform.android,
|
||||
};
|
||||
}
|
||||
|
33
packages/flutter/test/foundation/platform_web_test.dart
Normal file
33
packages/flutter/test/foundation/platform_web_test.dart
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@TestOn('chrome')
|
||||
library;
|
||||
|
||||
import 'dart:ui_web' as ui_web;
|
||||
|
||||
import 'package:flutter/foundation.dart' show TargetPlatform, defaultTargetPlatform;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
tearDown(() {
|
||||
// Remove the `debugOperatingSystemOverride`.
|
||||
ui_web.browser.debugOperatingSystemOverride = null;
|
||||
});
|
||||
|
||||
group('defaultTargetPlatform', () {
|
||||
testWidgets('returns what ui_web says', (WidgetTester _) async {
|
||||
// Set the OS reported by web_ui to anything that is not linux.
|
||||
ui_web.browser.debugOperatingSystemOverride = ui_web.OperatingSystem.iOs;
|
||||
|
||||
expect(defaultTargetPlatform, TargetPlatform.iOS);
|
||||
});
|
||||
|
||||
testWidgets('defaults `unknown` to android', (WidgetTester _) async {
|
||||
ui_web.browser.debugOperatingSystemOverride = ui_web.OperatingSystem.unknown;
|
||||
|
||||
expect(defaultTargetPlatform, TargetPlatform.android);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user