Flutter Couchbase集成插件couchify的使用
Flutter Couchbase集成插件couchify的使用
Couchify 是一个为 Flutter 开发者提供的 Couchbase Lite API。其目标是让 Flutter 的 API 尽可能接近 Couchbase Lite 提供的官方 Android (Java) API,以便熟悉该 API 的用户可以轻松使用 Flutter API。该插件使用了 Couchbase Lite Android EE 2.8.5。目前,该插件仅支持 Android 平台,不支持 iOS。
开始使用
1. 添加依赖
在 pubspec.yaml 文件中添加 couchify 插件依赖:
dependencies:
couchify: ^0.1.0
2. 设置最小 SDK 版本
在应用级别的 build.gradle 文件(通常是 android/app/build.gradle)中将 minSdkVersion 设置为 19:
android {
...
defaultConfig {
...
minSdkVersion 19
...
}
...
}
3. 修改 AndroidManifest.xml
在 AndroidManifest.xml 文件中(通常位于 android/src/main/AndroidManifest.xml),添加 xmlns:tools 命名空间,并在 <application> 元素中添加 tools:replace 属性:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" <!-- 添加 xmlns:tools -->
package=...>
<application
android:label=...
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
tools:replace="android:label"> <!-- 添加 tools:replace -->
4. 导入模块
在需要使用的 Dart 文件中导入 couchify 模块:
import 'package:couchify/couchify.dart';
现在你已经准备好开始使用 Couchify 了!
示例用法
以下是一个完整的示例代码,展示了如何初始化 Couchbase Lite、创建数据库、保存文档、查询文档等操作:
// 初始化 Couchbase Lite
await CouchbaseLite.init();
// 创建数据库配置,默认目录为应用程序文件目录
// 如果需要自定义目录,可以使用 setDirectory 方法
DatabaseConfiguration configuration = DatabaseConfiguration();
// 打开或创建名为 "testDb" 的数据库
Database db = await Database.open("testDb", configuration);
// 打印数据库在设备上的路径
// 输出示例:/data/data/<package-name>/files/testDb.cblite2/
print(await db.getPath());
// 创建一个带有指定 ID 的可变文档,并设置键值对
MutableDocument doc =
MutableDocument.id("doc1").setString("key1", "value1");
// 创建一个可变数组并添加两个值,然后将其添加到文档中
MutableArray array = MutableArray().addString("value1").addInt(1234);
doc.setArray("an array", array);
// 创建一个可变字典并添加两个键值对,然后将其添加到文档中
MutableDictionary dictionary = MutableDictionary()
.setString("key1", "value1")
.setBoolean("key2", false);
doc.setDictionary("a dictionary", dictionary);
// 将文档保存到数据库中
await db.save(doc);
// 使用文档 ID 获取文档
Document? fetchedDoc = await db.getDocument("doc1");
if (fetchedDoc != null) {
// 将文档转换为可变文档并修改它
MutableDocument updatedDoc = fetchedDoc.toMutable();
updatedDoc.setString("key1", "new-value");
updatedDoc.setDate("current_date", DateTime.now());
updatedDoc.setValue("a null value", null);
// 将更新后的文档保存回数据库以更新现有文档
await db.save(updatedDoc);
// 使用 QueryBuilder API 构建查询(类似于官方 Couchbase Lite Android API)
Query query = QueryBuilder.select(
[SelectResult.expression(Meta.id), SelectResult.all()])
.from(DataSource.database(db));
// 执行查询以获取结果集
ResultSet rs = await query.execute();
// 遍历结果集并打印每个结果的内容作为 Map
await for (Result result in rs.getStream()) {
print(result.toMap());
}
}
支持的功能
该插件当前支持以下功能:
-
打开或创建本地数据库
- 可以指定默认目录或自定义目录。
-
CRUD 操作
- 创建、更新和保存可变文档。
- 根据 ID 获取文档。
- 删除文档。
-
删除数据库
-
同时打开多个不同的数据库
- 通过创建多个
Database对象实现。
- 通过创建多个
-
支持数组和字典类型
- 包括它们的可变版本。
-
文档支持的数据类型
num,bool,String,null,DateTime,Array,Dictionary,List,Map<String, dynamic>。- 最后两种类型必须只包含支持的类型。Blob 当前不支持。
-
部分支持查询
- 支持基本的
select,from,where和join子句。 - 支持数组函数、变量表达式和数组表达式。
- 不支持
group by,order by,limit子句和全文搜索。
- 支持基本的
以下是一个示例查询:
QueryBuilder.select([
SelectResult.expression(Expression.property("name").from("airline")),
SelectResult.expression(Expression.property("callsign").from("airline")),
SelectResult.expression(
Expression.property("destinationairport").from("route")),
SelectResult.expression(Expression.property("stops").from("route"))
]).from(DataSource.database(db).as("airline")).join([
Join.join(DataSource.database(db).as("route"))
]).where(Expression.property("type")
.from("route")
.equalTo(Expression.string("route"))
.and(Expression.property("type")
.from("airline")
.equalTo(Expression.string("airline")))
.and(Expression.property("sourceairport")
.from("route")
.equalTo(Expression.string("RIX"))));
路线图
以下功能目前尚未支持,但属于开发计划:
- 批量事务
- 数据库和文档更改监听器
- 同步网关和点对点同步支持
- 查询中的
order by,group by,limit子句 - 全文搜索
- 索引
完整示例 Demo
以下是一个完整的示例代码,展示了一个简单的待办事项列表应用,使用 Couchify 插件与 Couchbase Lite 进行交互:
import 'package:couchify_example/database_manager.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:couchify/couchify.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
static const String dbName = "todoListDb";
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(
home: TodoListViewer(dbName: dbName),
);
}
}
class TodoListViewer extends StatefulWidget {
final String dbName;
const TodoListViewer({Key? key, required this.dbName}) : super(key: key);
[@override](/user/override)
State<TodoListViewer> createState() => _TodoListViewerState();
}
class _TodoListViewerState extends State<TodoListViewer> {
bool _initialized = false;
DatabaseManager? _dbManager;
List<TodoListItem>? _todoList;
int _selectedItemsCount = 0;
bool _searchMode = false;
final _queryController = TextEditingController();
final _dateFormat = DateFormat(DateFormat.ABBR_MONTH_DAY);
[@override](/user/override)
void initState() {
super.initState();
CouchbaseLite.init().then((value) {
var configuration = DatabaseConfiguration();
return Database.open(widget.dbName, configuration);
}).then((database) {
_dbManager = DatabaseManager(database);
return _fetchTodoList();
}).then((value) {
setState(() {
_initialized = true;
});
});
}
Future _fetchTodoList() async {
var items = await _dbManager!.getItems();
setState(() {
_todoList = items;
_selectedItemsCount = 0;
});
}
Future _addItem(String title, String tags) async {
var item = TodoListItem(
title: title, tags: tags.split(","), created: DateTime.now());
await _dbManager?.addItem(item);
await _fetchTodoList();
print(_todoList);
}
Future _deleteItems() async {
await Future.forEach(_todoList!.where((item) => item.isSelected),
(TodoListItem item) async {
return _dbManager?.deleteItem(item);
});
if (_searchMode) {
await _queryItems(_queryController.text);
} else {
await _fetchTodoList();
}
}
Future _updateItem(TodoListItem item, String title, String tags) async {
item.title = title;
item.tags = tags.split(",");
await _dbManager?.updateItem(item);
await _fetchTodoList();
}
Future _queryItems(String query) async {
var items = await _dbManager!.queryByTitleOrTag(query);
setState(() {
_todoList = items;
_selectedItemsCount = 0;
});
}
void _showCreateTodoListItemModal() {
var titleController = TextEditingController();
var tagsController = TextEditingController();
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
height: 250,
color: Colors.amber,
child: Center(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'Create New Item',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 12.0,
),
TextField(
controller: titleController,
decoration: const InputDecoration(
hintText: "Title",
),
),
TextField(
controller: tagsController,
decoration: const InputDecoration(
hintText: "Tags (comma-separated)",
),
),
const SizedBox(
height: 12.0,
),
ElevatedButton(
child: const Text('Create'),
onPressed: () {
_addItem(titleController.text, tagsController.text);
Navigator.pop(context);
},
)
],
),
),
),
),
);
},
);
}
void _showEditTodoListItemModal(TodoListItem item) {
var titleController = TextEditingController(text: item.title!);
var tagsController = TextEditingController(text: item.tags!.join(','));
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
height: 250,
color: Colors.amber,
child: Center(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text(
'Edit Item',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 12.0,
),
TextField(
controller: titleController,
decoration: const InputDecoration(
hintText: "Title",
),
),
TextField(
controller: tagsController,
decoration: const InputDecoration(
hintText: "Tags (comma-separated)",
),
),
const SizedBox(
height: 12.0,
),
ElevatedButton(
child: const Text('Update'),
onPressed: () {
_updateItem(
item, titleController.text, tagsController.text);
Navigator.pop(context);
},
)
],
),
),
),
),
);
},
);
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: _searchMode
? AppBar(
title: TextField(
style: const TextStyle(color: Colors.white),
controller: _queryController,
cursorColor: Colors.white,
autofocus: true,
onChanged: (queryString) {
_queryItems(queryString);
},
decoration: const InputDecoration(
hintText: "Search by title or tag...",
hintStyle: TextStyle(color: Colors.white),
border: InputBorder.none,
),
),
leading: IconButton(
onPressed: () {
setState(() {
_searchMode = false;
_fetchTodoList();
});
},
icon: const Icon(Icons.arrow_back),
),
actions: _selectedItemsCount > 0
? <Widget>[
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
_deleteItems();
},
)
]
: null,
)
: AppBar(
title: const Text("To-do List App Example"),
actions: <Widget>[
_selectedItemsCount > 0
? IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
_deleteItems();
},
)
: IconButton(
onPressed: () {
_queryController.clear();
setState(() {
_searchMode = true;
});
},
icon: const Icon(Icons.search),
),
],
),
body: !_initialized
? const Center(child: CircularProgressIndicator())
: RefreshIndicator(
onRefresh: () async {
return;
},
child: ListView.builder(
itemBuilder: (context, index) {
return CheckboxListTile(
onChanged: (checked) {
setState(() {
_todoList![index].isSelected = checked ?? false;
_selectedItemsCount +=
_todoList![index].isSelected ? 1 : -1;
});
},
value: _todoList![index].isSelected,
controlAffinity: ListTileControlAffinity.leading,
secondary:
Text(_dateFormat.format(_todoList![index].created!)),
title: Text(_todoList![index].title!),
subtitle:
Text('Tags: ' + _todoList![index].tags!.join(', ')),
);
},
itemCount: _todoList!.length,
),
),
floatingActionButton: _initialized
? (_selectedItemsCount <= 1
? (_selectedItemsCount == 0
? FloatingActionButton(
onPressed: _showCreateTodoListItemModal,
child: const Icon(Icons.add))
: FloatingActionButton(
onPressed: () {
var item = _todoList!
.where((element) => element.isSelected)
.single;
_showEditTodoListItemModal(item);
},
child: const Icon(Icons.edit)))
: null)
: null,
);
}
}
class TodoListItem {
final String title;
final List<String> tags;
final DateTime created;
bool isSelected;
TodoListItem({
required this.title,
required this.tags,
required this.created,
this.isSelected = false,
});
}
更多关于Flutter Couchbase集成插件couchify的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Couchbase集成插件couchify的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
Couchbase Lite 是一个轻量级的、嵌入式的 NoSQL 数据库,适用于移动和桌面应用程序。Flutter 是一个流行的跨平台移动应用开发框架,而 couchify 是一个用于在 Flutter 应用中集成 Couchbase Lite 的插件。
以下是如何在 Flutter 项目中使用 couchify 插件的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml 文件中添加 couchify 插件的依赖。
dependencies:
flutter:
sdk: flutter
couchify: ^latest_version # 请替换为最新版本
然后运行 flutter pub get 来获取依赖。
2. 初始化 Couchbase Lite
在你的 Flutter 应用中,你需要初始化 Couchbase Lite 数据库。
import 'package:couchify/couchify.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化 Couchbase Lite
await Couchify.init();
runApp(MyApp());
}
3. 创建和打开数据库
你可以创建一个新的数据库或者打开一个已经存在的数据库。
Future<void> openDatabase() async {
final database = await Couchify.database("my_database");
await database.open();
}
4. 插入文档
你可以向数据库中插入文档。
Future<void> insertDocument(Database database) async {
final document = MutableDocument()
..setString("type", "user")
..setString("name", "John Doe")
..setInt("age", 30);
await database.saveDocument(document);
}
5. 查询文档
你可以使用查询来检索文档。
Future<void> queryDocuments(Database database) async {
final query = QueryBuilder.select([SelectResult.all()])
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string("user")));
final resultSet = await query.execute();
for (final result in resultSet.allResults()) {
print(result.toMap());
}
}
6. 更新文档
你可以更新现有的文档。
Future<void> updateDocument(Database database) async {
final document = await database.document("document_id");
if (document != null) {
final mutableDocument = document.toMutable()
..setString("name", "Jane Doe");
await database.saveDocument(mutableDocument);
}
}
7. 删除文档
你可以从数据库中删除文档。
Future<void> deleteDocument(Database database) async {
final document = await database.document("document_id");
if (document != null) {
await database.deleteDocument(document);
}
}
8. 关闭数据库
当你不再需要数据库时,可以关闭它。
Future<void> closeDatabase(Database database) async {
await database.close();
}
9. 处理同步(可选)
Couchbase Lite 支持与远程 Couchbase Server 进行数据同步。你可以配置同步器来实现数据的双向同步。
Future<void> startReplication(Database database) async {
final endpoint = URLEndpoint(Uri.parse("ws://localhost:4984/my_database"));
final replicatorConfig = ReplicatorConfiguration(
database: database,
target: endpoint,
replicatorType: ReplicatorType.pushAndPull,
);
final replicator = Replicator(replicatorConfig);
replicator.start();
}
10. 处理错误
在使用 Couchbase Lite 时,建议处理可能出现的错误。
try {
await database.saveDocument(document);
} catch (e) {
print("Error saving document: $e");
}
11. 清理资源
在应用退出时,确保清理 Couchbase Lite 资源。
@override
void dispose() {
database.close();
super.dispose();
}
12. 运行应用
现在你可以运行你的 Flutter 应用,并使用 couchify 插件来管理 Couchbase Lite 数据库。
flutter run

