The really clean and sustainable solution is to write a federated plugin. Plugins are not just for external use, for other people to consume as a library, you can easily put a plugin inside your own project to separate out platform specific code.
If you really don't want to do that because you only need a few items inside your own code, just set up the usual interface-implementation approach. You write an abstract class with the interface you want to use, you write two (or more) implementations and you include the one you need conditionally. An extract from one of my apps:
The interface:
// interface.dart import 'worker.dart' // if (dart.library.io) 'worker_io.dart' if (dart.library.html) 'worker_async.dart'; abstract class BackgroundWorker { factory BackgroundWorker() => getWorker(); void sendTo(dynamic message); }
The base implementation:
// worker.dart BackgroundWorker getWorker() => throw UnimplementedError('getWorker');
The mobile implementation:
// worker_io.dart BackgroundWorker getWorker() => BackgroundWorkerIo(); class BackgroundWorkerIo implements BackgroundWorker { @override void sendTo(dynamic message) { } }
The web implementation:
// worker_web.dart BackgroundWorker getWorker() => BackgroundWorkerWeb(); class BackgroundWorkerWeb implements BackgroundWorker { @override void sendTo(dynamic message) { } }
To use it, you simply call getWorker(), that will return the actual implementation needed, and you call its methods, functions, fields, whatever.
Oh, and while I didn't need it in this code of mine but if the implementations are not that lightweight and you want to avoid instantiating them again and again with every call to getWorker(), return a singleton instead.