Indeed, I also got this error. However, none of the previous solutions helped me. I spent hours and finally I understood that I was doing native imports in the context of the web.
The application I made compiles on Android and on the Web. How did I do it?
Step 1: My dependency for both web and Android in my pubsec
#SQLITE with moore for all platforms
moor: ^4.6.0+1
moor_flutter: ^4.0.0
ffi: ^1.1.2
# for sqlite on android
sqlite3_flutter_libs:
Step 2: injecting my db object depending of the Platform.
My service_locator.dart is the file I use to inject all my dependencies in my project (Database, Rest Api Clients, etc.); your own may have another name.
This is the content of my service_locator.dart:
export 'unsupported.dart'
if (dart.library.ffi) 'service_locator_native.dart'
if (dart.library.html) 'service_locator_web.dart';
As you can see, if the platform is android it will import native code otherwise if it's web it will import library for the web.
This is the sample of service_locator_web.dart:
import 'dart:async';
import 'package:get_it/get_it.dart';
import 'package:my_app/src/dao/chat_channel_dao.dart';//database class
import 'package:drift/web.dart';//only for the web
final GetIt serviceLocator = GetIt.instance;
initLocator() {
...
//Environment Settings
...
//DAO Injection
serviceLocator.registerLazySingleton<ChatContactDao>(() => ChatChannelDao(WebDatabase('db_chat_channels')));
...
}
//to fake the interpreter to see service_locator like an getIt Instance
T get<T extends Object>() {
return serviceLocator.get<T>();
}
registerLazySingleton<T extends Object>(T Function() function){
serviceLocator.registerLazySingleton<T>(function);
}
FutureOr unregister<T extends Object>({
Object? instance,
String? instanceName,
FutureOr Function(T)? disposingFunction,
}){
return serviceLocator.unregister<T>();
}
This is the sample of service_locator_native.dart:
import 'dart:async';
import 'package:get_it/get_it.dart';
import 'package:my_app/src/dao/chat_channel_dao.dart';//database class
import 'package:drift/native.dart';//only for the native platform
final GetIt serviceLocator = GetIt.instance;
initLocator() {
...
//Environment Settings
...
//DAO Injection
serviceLocator.registerLazySingleton<ChatContactDao>(
() => ChatChannelDao(makeLazyDb('db_chat_channels.sqlite')));//here for native DB
...
}
//to fake the interpreter to see service_locator like an getIt Instance
T get<T extends Object>() {
return serviceLocator.get<T>();
}
registerLazySingleton<T extends Object>(T Function() function){
serviceLocator.registerLazySingleton<T>(function);
}
// to call native Db Builder
LazyDatabase makeLazyDb(String dbName){
final db = LazyDatabase(() async {
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, dbName));
return NativeDatabase(file);
});
return db;
}
For unsupported platform this is the code of unsupported.dart:
import 'dart:async';
T get<T extends Object>() => throw UnimplementedError();
initLocator() => throw UnimplementedError();
registerLazySingleton<T extends Object>(T Function() function)=> throw UnimplementedError();
FutureOr unregister<T extends Object>() => throw UnimplementedError();
Step 3: calling my DB class
import 'package:my_app/src/service/service_locator.dart' as serviceLocator;
class my_sample_ui{
my_sample_method(EntityChatChannel myEntity) async{
var ticketDao = serviceLocator.get<TicketDao>();
await chatChannelDao?.createNew(myEntity);
}
//implements your own methods
}
Conclusion:
This is simply a design pattern to assist you all, which can be adapted based on your code structure. In this example, I am using GetIt for dependency injection between classes. Flutter is an exceptional multi-platform framework, but we need to write multi-platform code to ensure it works in all environments.
sqlite3
and it is not supported in web - pub.dev/packages/sqlite3 – Parchmentsqlite3
? – Parchment