I am working on a Flutter app and I am testing on both Android and iOS devices. My app works perfectly on a physical Android device and it works on an iOS device with iOS 13. The problem is that since I updated the iOS device to iOS 14.3, I cannot insert into the database with SQFlite.
What does work
- Android devices
- iOS devices with iOS older than 14
- Reading from the database (meaning items that were inserted into the database when the phone was on iOS 13 can successfully be retrieved after updating to iOS 14.3)
What does not work
- Inserting into the database on iOS 14.3.
await db.transaction((txn) async {
return await txn.insert(TodoList.TABLENAME, TodoList.toMap(todoList),
conflictAlgorithm: ConflictAlgorithm.replace);
});
The app does not provide any error logs and it also does not crash; I can continue to interact with the app. It behaves as if it just disregards the database insert. I've tried a few different things to get it to work but I am at a loss. I appreciate any advice!
This is the first thing I tried: Flutter sqflite app does not working on real ios device
I also tried a workaround mentioned here (although it may not be relevant to my issue): Modify schema structure fails on iOS 14
Relevant Code
Dependencies (Edit: Issue occurs on any SQFlite version, even 1.3.2+2):
sqflite: ^1.3.0
path_provider: ^0.4.1
Database Class:
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:todo_list/data/todo_list.dart';
class DatabaseHelper {
//Create a private constructor
DatabaseHelper._();
static const databaseName = 'todos_database.db';
static final DatabaseHelper instance = DatabaseHelper._();
static Database _database;
Future<Database> get database async {
if (_database == null) {
return await initializeDatabase();
}
return _database;
}
initializeDatabase() async {
return await openDatabase(join(await getDatabasesPath(), databaseName),
version: 1, onCreate: (Database db, int version) async {
// Possible fix for iOS issue (did not work)
if (Platform.isIOS) {
await db.execute('PRAGMA sqflite -- db_config_defensive_off');
}
await db.execute(
"CREATE TABLE todos(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, listName TEXT, items TEXT, completed TEXT, count INTEGER, color INTEGER, ordering INTEGER)");
});
}
Future<List<TodoList>> retrieveTodos() async {
final Database db = await database;
final List<Map<String, dynamic>> maps = await db.query(TodoList.TABLENAME);
return List.generate(maps.length, (i) {
return TodoList(
id: maps[i]["id"],
listName: maps[i]["listName"],
items: maps[i]["items"],
completed: maps[i]["completed"],
count: maps[i]["count"],
color: maps[i]["color"],
ordering: maps[i]["ordering"],
);
});
}
insertTodo(TodoList todoList) async {
final db = await database;
await db.transaction((txn) async {
return await txn.insert(TodoList.TABLENAME, TodoList.toMap(todoList),
conflictAlgorithm: ConflictAlgorithm.replace);
});
//return res;
}
updateTodo(TodoList todoList) async {
final db = await database;
await db.update(TodoList.TABLENAME, TodoList.toMap(todoList),
where: "id = ?",
whereArgs: [todoList.id],
conflictAlgorithm: ConflictAlgorithm.replace);
}
deleteTodo(int id) async {
var db = await database;
db.delete(TodoList.TABLENAME, where: "id = ?", whereArgs: [id]);
}
}
Call to insertToDo:
await DatabaseHelper.instance.insertTodo(TodoList(
listName: listName,
items: encodedTodo,
completed: encodedDone,
count: 0,
color: _mainColor.value,
ordering: order));
UPDATE
Attempted raw SQL query. No change, works fine on Android but not on iOS 14.3.
Insert function with raw query:
insertTodo(TodoList todoList) async {
final db = await database;
await db.transaction((txn) async {
return await txn.rawInsert(
'INSERT INTO todos(listName, items, completed, count, color, ordering) VALUES(?, ?, ?, ?, ?, ?)',
[
todoList.listName,
todoList.items,
todoList.completed,
todoList.count,
todoList.color,
todoList.ordering
]);
/*await txn.insert(TodoList.TABLENAME, TodoList.toMap(todoList),
conflictAlgorithm: ConflictAlgorithm.replace);*/
});
//return res;
}
Note, I've also tried insert without transaction
.
insertTodo(TodoList todoList) async {
final db = await database;
return await db.insert(TodoList.TABLENAME, TodoList.toMap(todoList),
conflictAlgorithm: ConflictAlgorithm.replace);
}