Если вы хоть раз делали приложение и для Web, и для мобильных платформ, то точно сталкивались с конфликтами библиотек dart:io и dart:html (а точнее, уже dart:web) или других платформенно-специфичных пакетов. Вы могли увидеть примерно такое сообщение в консоли:
Failed to build iOS app
Error (Xcode): lib/main.dart:7:8: Error: Dart library 'dart:html' is not available on this platform.
или, например:
Running Gradle task 'assembleDebug'...
../lib/web_widgets/url_functions_web.dart:19:31: Error: Type 'ui.HashUrlStrategy' not found.
class UrlPathStrategy extends ui.HashUrlStrategy {
^^^^^^^^^^^^^^^^^^
........
И это объяснимо, ведь мы используем пакет, который не поддерживается в мобильном устройстве, все просто и понятно.
Давайте по порядку!
◾️ dart:io — библиотека для работы с файлами, сокетами и прочим «системным» API. Он поддерживается только на мобильных и desktop устройствах.
◾️ dart:html(dart:web) — библиотека для работы с DOM и Web API. Поддерживается только в браузере.
Соответственно, если мы подключаем dart:io в вебе или dart:web на мобильных устройствах, компилятор выдаст ошибку.
Чтобы решить эту проблему, можно:
1. Использовать сторонние кроссплатформенные библиотеки:
Например, cross_file.
Этот пакет предоставляет абстракцию XFile, которая позволяет работать с файлами на всех платформах (Web, Desktop, Mobile).
При помощи cross_file, например, вы можете сделать файловый пикер:
Future<XFile?> showFilePicker({List<String>? extensions}) {
return FilePicker.platform.pickFiles(
allowedExtensions: extensions,
type: extensions?.isNotEmpty ?? false ? FileType.custom : FileType.any,
).then((result) {
return result?.xFiles.firstOrNull;
});
}2. Делать условные импорты
Если подходящей библиотеки нет, можно подключать разные реализации под разные платформы. Например, для настройки ClientChannelBase для grpc. Подробнее о grpc можете прочитать здесь.
export 'grpc_stub.dart'
if (dart.library.io) 'grpc_io.dart'
if (dart.library.js_interop) 'grpc_web.dart';
При использовании этого файла (импорте его в ваш виджет) Dart сам подставит нужную реализацию в зависимости от платформы:
✔️ если это мобильные или desktop → grpc_io.dart
✔️ если это Web → grpc_web.dart
✔️ а если ни одна из библиотек не доступна → grpc_stub.dart
grpc_stub.dart (заглушка):
import 'package:grpc/grpc_connection_interface.dart';
ClientChannelBase setupChannel(String url) =>
throw UnimplementedError();
grpc_io.dart (Mobile/Desktop):
import 'package:grpc/grpc.dart';
import 'package:grpc/grpc_connection_interface.dart';
ClientChannelBase setupChannel(String url) {
return ClientChannel(
uri.host,
port: uri.port,
options: ChannelOptions(credentials: credentials),
);
}
grpc_web.dart (Web):
import 'package:grpc/grpc_connection_interface.dart';
import 'package:grpc/grpc_web.dart';
ClientChannelBase setupChannel(String url) {
return GrpcWebClientChannel.xhr(uri);
}
А в коде используем :
late final ClientChannelBase channel = setupChannel(baseUrl);
Вот и все! Делитесь в комментах вашими лайфхаками при работе с кроссплатформой!
