Reputation: 70108
My goal is to import platform-specific code only on the respective platform. One use case is e.g. if the dart:html
package is used in the imported file which isn't available on iOS. Another example for platform-specific Dart code: XHR HTTP request (only available in browser) vs. other HTTP client implementation.
Previous, failed attempts:
1)
import 'specific_to_web.dart' if (dart.library.html) '';
2)
import 'package:flutter/foundation.dart' show kIsWeb;
import 'specific_to_web.dart' if (kIsWeb) '';
3)
In the file I'm importing:
export 'api_channel_grpc_web.dart'
if (dart.library.html) 'api_channel_grpc_raw.dart';
This is also mentioned in Flutter issue Dart SDK libraries and Flutter for web.
Upvotes: 5
Views: 3088
Reputation: 10214
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.
Upvotes: 4