Refrain the Use of Platform.isAndroid in Flutter — Runtime Platform Detection Made Right
Yes, you read it right! Platform.isAndroid and Platform.isIOS are not the first choice when it comes to detecting runtime platforms for Flutter apps. Turns out, there are other better ways to detect which platform your app is currently running on —
Why Platform Class is Not The First Choice
Even though all the articles and YouTube tutorials show the use of Platform class for checking if platform is Android/iOS/Others, it is not recommended. Here are the reasons:
- Platform.isAndroid and Platform.isIOS return false in a test environment. Hence, platform branching (platform if checks) code will fail for the test case.
- Platform class is not mockable when writing Widget Tests. You cannot stub the behavior for underlying platform enums which makes it hard to test platform specific logic, if any.
Hence, Platform class is easy and goto choice for beginner, non widget test projects. However, if you are planning to write tests you should use one of the methods below.
1. Using Theme Data
As we get text theme, screen and orientation data, in the same way, we can make use of platform property from Theme
final isAndroid = Theme.of(context).platform == TargetPlatform.android;
Arghh! Don’t tell I need to pass context everywhere through my nested code just to get the platform😶🌫️.
No, this is recommended way for widgets residing in the UI layer. For other business layers,
2. defaultTargetPlatform top-level property
Flutter directly provides a top-level property for accessing platform where context cannot reach (or extra effort). This is accessible from ‘package:flutter/foundation.dart’ package.
import 'package:flutter/foundation.dart';
if (defaultTargetPlatform == TargetPlatform.android) {
// android code
} else if(defaultTargetPlatform == TargetPlatform.iOS) {
// iOS code
} else if(kIsWeb) {
// web
} else {
// other platforms
// TargetPlatform.fuchsia
// TargetPlatform.linux
// TargetPlatform.macOS
// TargetPlatform.windows
}
3. Stub Platform in Unit/Widget Tests
Flutter provides a top-level field debugDefaultTargetPlatformOverride
for stubbing platform behavior. It’s very simple to use:
testWidgets('test name',(WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
// target platform is now iOS
// test code
// ...
// ...
debugDefaultTargetPlatformOverride = null;
});
Remember, default platform is Android for defaultTargetPlatform
field in widget tests.
Notice, how at the end of the test case, the override field is made null. This is important because testWidgets() calls function debugAssertAllFoundationVarsUnset() that will check whether debugDefaultTargetPlatformOverride
is null to make sure you didn’t forget to reset it to the default value. This must be done because debugDefaultTargetPlatformOverride
is a top-level variable that persists across tests.
Note : You might want to make
debugDefaultTargetPlatformOverride = null
in thetearDown()
, but it won't work sincedebugAssertAllFoundationVarsUnset()
is called beforetearDown()
.
That’s it. I hope this article was helpful in some way or the other. Do comment if I have made any mistakes or better solution available.
Happy Coding…
Utterly Flutterly Declious!
Follow me on LinkedIn — Utkarsh Kore