Flutter云开发插件cloudbase_ce的使用
Flutter云开发插件cloudbase_ce的使用
介绍
cloudbase_ce
是腾讯云 CloudBase 的社区版 Flutter SDK。它完全兼容官方 SDK,并且支持 Dart 的空安全特性。
官方文档
特性对比
功能 | 官方 SDK | cloudbase_ce |
---|---|---|
完全兼容官方 SDK | 🚫 | ✅ |
支持空安全 | ❌ | ✅ |
修复已知 Bug | ❌ | ✅ |
支持手机认证 | ❌ | 🔜 |
Dart3 兼容性 | ❌ | ✅ |
删除过时的 API 调用 | ❌ | ✅ |
使用最新依赖版本 | ❌ | ✅ |
GitHub Actions CI/CD | ❌ | ✅ |
快速开始
1. 添加依赖
在 pubspec.yaml
文件中添加 cloudbase_ce
依赖:
dependencies:
flutter:
sdk: flutter
cloudbase_ce: ^2.x.x
2. 导入包
在 Dart 文件中导入 cloudbase_ce
包:
import 'package:cloudbase_ce/cloudbase_ce.dart';
3. 初始化 CloudBase
void main() async {
CloudBaseCore core = CloudBaseCore.init({
'env': 'your-env-id', // 替换为您的环境 ID
'appAccess': {
'key': 'your-app-access-key', // 替换为您的应用访问密钥
'version': 'your-app-access-version' // 替换为您的应用访问版本
},
'timeout': 3000 // 可选,请求超时时间(毫秒)
});
}
已迁移的包
包名称 | 版本 | 状态 |
---|---|---|
cloudbase_core | ✅ | |
cloudbase_auth | ✅ | |
cloudbase_database | ✅ | |
cloudbase_function | ✅ | |
cloudbase_storage | ✅ |
CI/CD
- ✅ 自动构建与测试
- ✅ 自动升级依赖(pub, github-actions)
- ✅ 自动质量控制
- ❌ 自动发布到
pub.dev
贡献者
示例代码
以下是一个完整的示例代码,展示了如何使用 cloudbase_ce
插件进行基本的操作。
import 'dart:developer' as dev;
import 'package:cloudbase_ce/cloudbase_ce.dart';
import 'package:cloudbase_ce/test_method_channel.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'case/interface_collection_p0.dart' as collection_p0;
import 'case/interface_command_p0.dart' as command_p0;
import 'case/intergace_geo_p0.dart' as geo_p0;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformTest = 'Unknown';
@override
void initState() {
super.initState();
initPlatformState();
}
// 平台消息异步初始化
Future<void> initPlatformState() async {
String platformTest;
try {
platformTest = await TestMethodChannel.platformTest ?? 'Unknown platform test';
} on PlatformException {
platformTest = 'Failed to get platform test.';
} on MissingPluginException {
platformTest = 'iOS platform test.';
}
if (!mounted) return;
setState(() {
_platformTest = platformTest;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('插件示例应用'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () async {
final CloudBaseCore core = await loginCloud();
await goTest(core);
},
child: Text('运行测试'),
),
Text(
_platformTest,
style: Theme.of(context).textTheme.headlineSmall,
)
],
),
),
),
);
}
Future<CloudBaseCore> loginCloud() async {
CloudBaseCore core = CloudBaseCore.init({
'env': 'your-tencent-cloud-env-id', // 在腾讯云控制台获取环境ID
'appAccess': {
'key': 'your-tencent-cloud-app-access-key', // 在腾讯云控制台获取应用访问密钥
'version': '1' // 应用访问版本
}
});
CloudBaseAuth auth = CloudBaseAuth(core);
CloudBaseAuthState? authState = await auth.getAuthState();
if (authState == null) {
authState = await auth.signInAnonymously();
}
return core;
}
Future<void> goTest(CloudBaseCore core) async {
logIndex = 0;
log("开始测试");
CloudBaseDatabase db = CloudBaseDatabase(core);
// collection p0用例
await test(collection_p0.casesData['name']!, () async {
List cases = collection_p0.casesData['cases'] as List;
for (var i = 0; i < cases.length; i++) {
await runCases(db, cases[i], collection_p0.casesData['name']!);
}
});
// command p0用例
await test(command_p0.casesData['name']!, () async {
List cases = command_p0.casesData['cases'] as List;
for (var i = 0; i < cases.length; i++) {
await runCases(db, cases[i], command_p0.casesData['name']!);
}
});
// geo command p0用例
await test(geo_p0.casesData['name']!, () async {
List cases = geo_p0.casesData['cases'] as List;
for (var i = 0; i < cases.length; i++) {
await runCases(db, cases[i], geo_p0.casesData['name']!);
}
});
// server date p0用例
await test('server_data p0用例', () async {
var collection = db.collection('doc_wcc');
var res = await collection
.add({'description': 'eat an apple', 'createTime': db.serverDate()});
testLog(res.code == null, 'server_data p0用例', res);
var res2 = await collection.doc(res.id).get();
testLog(res2.code == null, 'server_data p0用例', res2);
testLog(res2.data[0]['createTime'] is DateTime, 'server_data p0用例', res2);
});
// 实时推送 p0用例
await test(collection_p0.casesData['name']!, () async {
var collection = db.collection('tcb_hello_world');
var data = {
'_id': "f3db088f5e84cd1300409145374590bc", // 指定ID
'age': 18,
'name': 'hhxxn',
};
var res = await collection.add(data);
testLog(res.id == data['_id'], "添加一条数据 p0用例 - add测试", res);
// 单doc测试
RealtimeListener rl1 = collection
.doc('f3db088f5e84cd1300409145374590ba')
.watch(onChange: (Snapshot snapshot) {
testLog(
snapshot.docs.length == 1, "实时推送 p0用例 - 单doc测试 watch", snapshot);
}, onError: (error) {
testLog(error == null, "实时推送 p0用例 - 单doc测试 onError", error);
});
// query测试
RealtimeListener rl2 =
collection.where({'age': 18}).watch(onChange: (Snapshot snapshot) {
testLog(
snapshot.docs.length > 0, "实时推送 p0用例 - query测试 watch", snapshot);
}, onError: (error) {
testLog(error == null, "实时推送 p0用例 - query测试 onError", error);
});
// query + command 测试
RealtimeListener rl3 = collection.where({'age': db.command.gt(15)}).watch(
onChange: (Snapshot snapshot) {
testLog(snapshot.docs.length > 0, "实时推送 p0用例 - query测试 + command watch",
snapshot);
}, onError: (error) {
testLog(error == null, "实时推送 p0用例 - query + command 测试 onError", error);
});
// 等待10s, 让watch处理完
await Future.delayed(Duration(seconds: 10), () {
rl1.close();
rl2.close();
rl3.close();
});
});
}
int logIndex = 0;
void log(String val) {
dev.log("($logIndex) message: $val");
logIndex++;
}
Future<void> test(dynamic teatName, Function invoke) async {
dev.log("($logIndex) 测试: $teatName: ");
await invoke();
}
Future<dynamic> collectionOp(CloudBaseDatabase db, String cmd, dynamic event) async {
Query collection = db.collection(event['collection_name']);
switch (cmd) {
case 'collection_doc':
return (collection as Collection).doc(event['record_id']).get();
case 'collection_get':
if (event['skip'] != null) {
collection = collection.skip(event['skip']);
}
if (event['filter'] != null) {
collection = collection.where(event['filter']);
}
if (event['limit'] != null) {
collection = collection.limit(event['limit']);
}
if (event['order_key'] != null && event['order_type'] != null) {
collection =
collection.orderBy(event['order_key'], event['order_type']);
}
if (event['field'] != null) {
collection = collection.field(event['field']);
}
return collection.get();
case 'collection_search':
return collection
.where(event['filter'])
.skip(event['skip'])
.limit(event['limit'])
.orderBy(event['order_key'], event['order_type'])
.field(event['field'])
.get();
case 'collection_add':
return (collection as Collection).add(event['data']);
case 'collection_update':
return collection.where(event['filter']).update(event['data']);
case 'collection_remove':
return collection.where(event['filter']).remove();
case 'collection_count':
return collection.where({'_id': db.command.neq('undefined')}).count();
case 'collection_where':
return collection.where(event['filter']).get();
case 'collection_orderBy':
return collection
.orderBy(event['order_key'], event['order_type'])
.get();
case 'collection_limit':
return collection.limit(event['limit']).get();
case 'collection_skip':
return collection.where(event['filter']).skip(event['skip']).get();
case 'collection_field':
return collection.field(event['field']).get();
case 'collection_clean':
DbQueryResponse res = await collection.get();
List coll = res.data ?? [];
return Future.wait(coll.map((doc) {
return (collection as Collection).doc(doc['_id']).remove();
}));
default:
return null;
}
}
Future<dynamic> docOp(CloudBaseDatabase db, String cmd, dynamic event) async {
var doc = db.collection(event['collection_name']).doc(event['doc_id']);
switch (cmd) {
case 'doc_get':
return doc.get();
case 'doc_set':
return doc.set(event['data']);
case 'doc_update':
return doc.update(event['data']);
case 'doc_remove':
return doc.remove();
default:
}
}
Future<dynamic> commandOp(CloudBaseDatabase db, String cmd, dynamic event) async {
var collection = db.collection(event['collection_name']);
var _ = db.command;
switch (cmd) {
case 'command_eq':
return collection
.where({event['eq_key']: _.eq(event['eq_value'])}).get();
case 'command_neq':
return collection
.where({event['neq_key']: _.neq(event['neq_value'])}).get();
case 'command_lt':
return collection
.where({event['lt_key']: _.lt(event['lt_value'])}).get();
case 'command_lte':
return collection
.where({event['lte_key']: _.lte(event['lte_value'])}).get();
case 'command_gt':
return collection
.where({event['gt_key']: _.gt(event['gt_value'])}).get();
case 'command_gte':
return collection
.where({event['gte_key']: _.gte(event['gte_value'])}).get();
case 'command_in':
return collection
.where({event['in_key']: _.into(event['in_value'])}).get();
case 'command_nin':
return collection
.where({event['nin_key']: _.nin(event['nin_value'])}).get();
case 'command_and':
return collection.where({
event['and_key']:
_.and([_.gt(event['and_value0']), _.lt(event['and_value1'])])
}).get();
case 'command_or':
return collection.where({
event['or_key']:
_.or([_.gt(event['or_value0']), _.lt(event['or_value1'])])
}).get();
case 'command_set':
return collection
.doc(event['doc_id'])
.update({event['set_key']: _.set(event['set_value'])});
case 'command_remove':
return collection
.doc(event['doc_id'])
.update({event['remove_key']: _.remove()});
case 'command_inc':
return collection
.doc(event['doc_id'])
.update({event['inc_key']: _.inc(event['inc_value'])});
case 'command_mul':
return collection
.doc(event['doc_id'])
.update({event['mul_key']: _.mul(event['mul_value'])});
case 'command_push':
return collection
.doc(event['doc_id'])
.update({event['push_key']: _.push(event['push_value'])});
case 'command_pop':
return collection
.doc(event['doc_id'])
.update({event['pop_key']: _.pop()});
case 'command_shift':
return collection
.doc(event['doc_id'])
.update({event['shift_key']: _.shift()});
case 'command_unshift':
return collection
.doc(event['doc_id'])
.update({event['unshift_key']: _.unshift(event['unshift_value'])});
case 'command_geoNear':
return collection.where({
event['geoNear_key']: _.geoNear(
event['geoNear_value']['geometry'],
maxDistance: event['geoNear_value']['maxDistance'],
minDistance: event['geoNear_value']['minDistance'],
)
}).get();
case 'command_geoWithin':
return collection.where({
event['geoWithin_key']:
_.geoWithin(event['geoWithin_value']['geometry'])
}).get();
case 'command_geoIntersects':
return collection.where({
event['geoIntersects_key']:
_.geoIntersects(event['geoIntersects_value']['geometry'])
}).get();
default:
return null;
}
}
Future<void> runCases(db, element, testName) async {
var event = element['request'];
String cmd = event['cmd'];
print(element['desc']);
dynamic res;
if (cmd.startsWith('collection')) {
res = await collectionOp(db, cmd, event);
} else if (cmd.startsWith('doc')) {
res = await docOp(db, cmd, event);
} else if (cmd.startsWith('command')) {
res = await commandOp(db, cmd, event);
}
if (element['expect'] != null) {
final value = element['expect'](res);
testLog(value, element['desc'], res);
}
}
void testLog(res, testName, data) {
final result = "测试 [$testName] ${res ? 'SUCCESS' : 'FAIL'}";
print(res ? "" : data);
log("expect: [test result] -> $result");
}
}
注意事项
- 在运行测试前,需要先在腾讯云控制台创建两个集合
doc_wcc
和tcb_hello_world
。 - 为
doc_wcc
集合创建 6 个地理索引,具体步骤如下:- 打开 腾讯云数据库控制台
- 选择
索引管理
,点击新建索引
,依次创建如下 6 个索引:{'point_index': 'Point'} {'polygon_index': 'Polygon'} {'lineString_index': 'LineString'} {'multiPoint_index': 'MultiPoint'} {'multiPolygon_index': 'MultiPolygon'} {'multiLineString_index': 'MultiLineString'}
更多关于Flutter云开发插件cloudbase_ce的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter云开发插件cloudbase_ce的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用cloudbase_ce
插件进行云开发的代码示例。cloudbase_ce
是腾讯云开发(CloudBase)的一个Flutter插件,允许你在Flutter应用中轻松集成云功能,如数据库、云函数和文件存储等。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加cloudbase_ce
依赖:
dependencies:
flutter:
sdk: flutter
cloudbase_ce: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
2. 初始化CloudBase实例
在你的Flutter应用中,你需要初始化一个CloudBase实例。这通常在你的应用入口文件(如main.dart
)中进行。
import 'package:flutter/material.dart';
import 'package:cloudbase_ce/cloudbase_ce.dart';
void main() async {
// 初始化CloudBase实例
CloudBase cloudBase = CloudBase(
env: 'your-env-id', // 替换为你的云开发环境ID
);
// 将CloudBase实例传递给MaterialApp(或你的应用的其他部分)
runApp(MyApp(cloudBase: cloudBase));
}
class MyApp extends StatelessWidget {
final CloudBase cloudBase;
MyApp({required this.cloudBase});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter CloudBase Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(cloudBase: cloudBase),
);
}
}
3. 使用CloudBase功能
数据库操作
下面是一个简单的示例,展示如何使用CloudBase的数据库功能:
import 'package:flutter/material.dart';
import 'package:cloudbase_ce/cloudbase_ce.dart';
class MyHomePage extends StatefulWidget {
final CloudBase cloudBase;
MyHomePage({required this.cloudBase});
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late Database _database;
@override
void initState() {
super.initState();
// 获取数据库实例
_database = widget.cloudBase.database();
}
Future<void> addRecord() async {
try {
await _database
.collection('your-collection-name')
.add({
'name': 'John Doe',
'age': 30,
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Record added successfully')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to add record: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CloudBase Demo'),
),
body: Center(
child: ElevatedButton(
onPressed: addRecord,
child: Text('Add Record'),
),
),
);
}
}
云函数调用
下面是一个调用云函数的示例:
Future<void> callCloudFunction() async {
try {
var result = await widget.cloudBase.callFunction({
'name': 'your-cloud-function-name',
'data': {
'key': 'value',
},
});
print('Cloud function result: $result');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Cloud function called successfully')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to call cloud function: $e')),
);
}
}
你可以在按钮的onPressed
回调中使用这个函数来调用云函数。
文件存储操作
下面是一个上传文件的示例:
Future<void> uploadFile() async {
var filePickerResult = await FilePicker.platform.pickFiles();
if (filePickerResult != null && filePickerResult.files.isNotEmpty) {
var file = File(filePickerResult.files.first.path!);
try {
var cloudPath = 'your-directory/${file.path.split('/').last}';
await widget.cloudBase.storage().uploadFile(cloudPath, file);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('File uploaded successfully')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to upload file: $e')),
);
}
}
}
同样,你可以在按钮的onPressed
回调中使用这个函数来上传文件。
注意事项
- 确保你已经正确配置了腾讯云开发环境,并获取了环境ID。
- 在实际使用中,请处理异常和错误,以提供更好的用户体验。
- 根据你的应用需求,调整数据库集合名称、云函数名称和文件存储路径等参数。
希望这些代码示例能帮助你在Flutter项目中成功使用cloudbase_ce
插件进行云开发!