cloudbase_flutter 1.0.6
cloudbase_flutter: ^1.0.6 copied to clipboard
Tencent CloudBase Flutter SDK for authentication, cloud functions, cloud run, and API gateway integration.
CloudBase Flutter SDK #
Tencent CloudBase Flutter SDK, providing authentication, cloud functions, cloud run, and API gateway capabilities.
Features #
- Authentication - Support email/phone password login, OTP login, anonymous login, OAuth login and more
- Cloud Functions - Invoke cloud functions, supporting regular functions and HTTP triggers
- Cloud Run - Call cloud run services
- API Gateway - Call HTTP APIs
- MySQL Database - Query, insert, update, delete with filters, pagination, joins, and upsert
- Data Model - CRUD operations on CloudBase data models with filter, select, orderBy, upsert, batch operations, and raw MySQL commands
- DataSource Query - Query aggregate/basic datasource lists, details, schemas, and table names
- Captcha - Built-in captcha support with automatic challenge handling
- Session Management - Automatic session management with persistent storage
Supported Platforms #
- Android
- iOS
- Web
- macOS
- Linux
- Windows
Installation #
Add dependency in pubspec.yaml:
dependencies:
cloudbase_flutter: ^1.0.0
Then run:
flutter pub get
Quick Start #
Initialization #
import 'package:cloudbase_flutter/cloudbase_flutter.dart';
// Initialize CloudBase app
final app = await CloudBase.init(
env: 'your-env-id', // TCB environment ID (required)
region: 'ap-shanghai', // Region, default ap-shanghai
accessKey: 'your-key', // Optional, Publishable Key
);
Authentication #
Email/Phone Password Sign-in
// Email sign-in
final result = await app.auth.signInWithPassword(
SignInWithPasswordReq(
email: 'user@example.com',
password: 'your-password',
),
);
print('Signed in: ${result.data?.user?.email}');
// Phone sign-in (automatically adds +86 prefix)
final result = await app.auth.signInWithPassword(
SignInWithPasswordReq(
phone: '13800138000',
password: 'your-password',
),
);
// Username sign-in
final result = await app.auth.signInWithPassword(
SignInWithPasswordReq(
username: 'myusername',
password: 'your-password',
),
);
OTP Sign-in
// 1. Initiate OTP sign-in, get verifyOtp callback
final otpResult = await app.auth.signInWithOtp(
SignInWithOtpReq(email: 'user@example.com'),
// Or use phone: SignInWithOtpReq(phone: '13800138000'),
);
// 2. After user receives the code, call verifyOtp to complete sign-in
final session = await otpResult.data!.verifyOtp(
VerifyOtpParams(token: '123456'),
);
Anonymous Sign-in
final result = await app.auth.signInAnonymously();
print('Anonymous user: ${result.data?.user?.uid}');
OAuth Third-party Sign-in
// 1. Get OAuth authorization URL
final oauthResult = await app.auth.signInWithOAuth(
SignInWithOAuthReq(
provider: 'wechat', // WeChat, QQ, GitHub, etc.
options: SignInWithOAuthOptions(
redirectTo: 'https://your-app.com/callback',
),
),
);
// 2. Redirect to authorization page
// launchUrl(Uri.parse(oauthResult.data!.url));
// 3. Verify OAuth after callback
final verifyResult = await app.auth.verifyOAuth(
VerifyOAuthReq(code: 'auth-code', state: 'state'),
);
Custom Ticket Sign-in
final result = await app.auth.signInWithCustomTicket(() async {
// Get custom ticket from your server
return 'your-custom-ticket';
});
User Registration
// 1. Initiate registration, get verifyOtp callback
final signUpResult = await app.auth.signUp(
SignUpReq(
email: 'newuser@example.com',
password: 'your-password',
nickname: 'Nickname',
// Optional fields: username, avatarUrl, gender
),
);
// 2. After user receives the code, call verifyOtp to complete registration
final session = await signUpResult.data!.verifyOtp(
VerifyOtpParams(token: '123456'),
);
Session Management
// Get current session
final sessionResult = await app.auth.getSession();
if (sessionResult.data?.session != null) {
print('Logged in: ${sessionResult.data?.user?.id}');
}
// Refresh session
await app.auth.refreshSession();
// Sign out
await app.auth.signOut();
User Information
// Get current user
final userResult = await app.auth.getUser();
if (userResult.data?.user != null) {
print('Current user: ${userResult.data!.user!.email ?? userResult.data!.user!.phone ?? userResult.data!.user!.id}');
}
// Update user information
final updateResult = await app.auth.updateUser(
UpdateUserReq(
nickname: 'New Nickname',
avatarUrl: 'https://example.com/avatar.png',
// Updating email/phone requires verification code
),
);
// Refresh user information
await app.auth.refreshUser();
Password Management
// Reset password via email/phone
final resetResult = await app.auth.resetPasswordForEmail('user@example.com');
// After receiving the verification code
await resetResult.data!.updateUser(
UpdateUserAttributes(nonce: '123456', password: 'new-password'),
);
// Reset password with old password
await app.auth.resetPasswordForOld(
ResetPasswordForOldReq(
oldPassword: 'old-password',
newPassword: 'new-password',
),
);
Identity Provider Management
// Get user's linked identity providers
final identities = await app.auth.getUserIdentities();
// Link new identity provider
await app.auth.linkIdentity(LinkIdentityReq(provider: 'github'));
// Unlink identity provider
await app.auth.unlinkIdentity(UnlinkIdentityReq(provider: 'github'));
Listen to Auth State Changes
final result = app.auth.onAuthStateChange((event, session, info) {
switch (event) {
case AuthStateChangeEvent.signedIn:
print('User signed in');
break;
case AuthStateChangeEvent.signedOut:
print('User signed out');
break;
case AuthStateChangeEvent.tokenRefreshed:
print('Token refreshed');
break;
case AuthStateChangeEvent.userUpdated:
print('User info updated');
break;
default:
break;
}
});
// Unsubscribe
result.data?.subscription.unsubscribe();
Call Cloud Functions #
// Regular cloud function
final result = await app.callFunction(
name: 'myFunction',
data: {'key': 'value'},
);
print('Result: ${result.data}');
// HTTP trigger
final httpResult = await app.callFunction(
name: 'myHttpFunction',
type: FunctionType.httpTrigger,
method: HttpMethod.post,
path: '/api/users',
data: {'name': 'test'},
);
Call Cloud Run #
final response = await app.callContainer(
name: 'my-service',
path: '/api/hello',
method: HttpMethod.get,
);
print('Response: ${response.result}');
// POST request
final postResponse = await app.callContainer(
name: 'my-service',
path: '/api/users',
method: HttpMethod.post,
data: {'name': 'test', 'age': 18},
);
Call API Gateway #
// GET request
final result = await app.apis['myApi'].get(
query: {'page': '1', 'limit': '10'},
);
// POST request
final postResult = await app.apis['myApi'].post(
body: {'title': 'Hello', 'content': 'World'},
);
// With path parameters
final userResult = await app.apis['users'].get(
path: '/123',
);
MySQL Database #
// Query all records
final allUsers = await app.mysql.query(table: 'users');
// Query with filters, pagination, sorting, and field selection
final pagedUsers = await app.mysql.query(
table: 'users',
options: MySqlQueryOptions(
select: 'id,name,email,age',
filters: {'age': 'gt.18', 'name': 'like.%test%'},
limit: 10,
offset: 0,
order: 'id.desc',
withCount: true,
),
);
print('Users: ${pagedUsers.data}, Total: ${pagedUsers.total}');
// Join query (foreign key relation)
final students = await app.mysql.query(
table: 'students',
options: MySqlQueryOptions(
select: '*,class_id(grade,class_number)',
),
);
// Insert a single record
final insertResult = await app.mysql.insert(
table: 'users',
data: {'name': 'Alice', 'age': 25, 'email': 'alice@example.com'},
);
// Batch insert
final batchResult = await app.mysql.insert(
table: 'users',
data: [
{'name': 'Bob', 'age': 30},
{'name': 'Charlie', 'age': 28},
],
);
// Upsert (insert or update on conflict)
final upsertResult = await app.mysql.insert(
table: 'users',
data: {'id': 1, 'name': 'Alice', 'age': 26},
upsert: true,
onConflict: 'id',
);
// Update records
final updateResult = await app.mysql.update(
table: 'users',
data: {'age': 26},
filters: {'name': 'eq.Alice'},
);
// Delete records
final deleteResult = await app.mysql.delete(
table: 'users',
filters: {'name': 'eq.Alice'},
);
// Count records
final totalCount = await app.mysql.count(table: 'users');
final adultCount = await app.mysql.count(
table: 'users',
filters: {'age': 'gt.18'},
);
Data Model #
// Get a single record by ID
final item = await app.models.getById(
modelName: 'user',
recordId: '6801234567890abcdef12345',
);
print('Record: ${item.record}');
// Get a single record by filter
final found = await app.models.get(
modelName: 'user',
filter: {'where': {'_id': {'\$eq': '123'}}},
select: {'\$master': true},
);
// List records with filter, select, orderBy, and pagination
final list = await app.models.list(
modelName: 'user',
filter: {'where': {'age': {'\$gt': 18}}},
select: {'name': true, 'age': true},
pageSize: 10,
pageNumber: 1,
getCount: true,
orderBy: [{'createdAt': 'desc'}],
);
print('Total: ${list.total}, Records: ${list.records.length}');
// Simple list (GET, pagination only)
final simpleList = await app.models.listSimple(
modelName: 'user',
pageSize: 20,
pageNumber: 1,
getCount: true,
);
// Create a single record
final created = await app.models.create(
modelName: 'user',
data: {'name': 'Alice', 'age': 25},
);
print('Created ID: ${created.id}');
// Batch create
final batchCreated = await app.models.createMany(
modelName: 'user',
data: [
{'name': 'Bob', 'age': 30},
{'name': 'Charlie', 'age': 28},
],
);
print('Created IDs: ${batchCreated.idList}');
// Update a single record
final updated = await app.models.update(
modelName: 'user',
filter: {'where': {'_id': {'\$eq': created.id}}},
data: {'age': 26},
);
// Batch update
final batchUpdated = await app.models.updateMany(
modelName: 'user',
filter: {'where': {'age': {'\$lt': 18}}},
data: {'status': 'minor'},
);
// Upsert (create or update)
final upserted = await app.models.upsert(
modelName: 'user',
filter: {'where': {'email': {'\$eq': 'test@example.com'}}},
create: {'email': 'test@example.com', 'name': 'New User'},
update: {'name': 'Existing User'},
);
// Delete by ID
final deleted = await app.models.deleteById(
modelName: 'user',
recordId: '6801234567890abcdef12345',
);
// Delete by filter
final deletedByFilter = await app.models.deleteRecord(
modelName: 'user',
filter: {'where': {'name': {'\$eq': 'Alice'}}},
);
// Batch delete
final batchDeleted = await app.models.deleteMany(
modelName: 'user',
filter: {'where': {'status': {'\$eq': 'inactive'}}},
);
// Execute raw MySQL command with parameters
final sqlResult = await app.models.mysqlCommand(
sqlTemplate: 'SELECT * FROM `users` WHERE _id = {{ _id }}',
parameter: [
ModelMysqlParameter(key: '_id', type: 'STRING', value: '123'),
],
config: ModelMysqlConfig(timeout: 10, preparedStatements: true),
);
print('SQL result: ${sqlResult.executeResultList}');
DataSource Query #
// Query aggregate datasource list
final aggregateList = await app.models.getAggregateDataSourceList(
pageSize: 10,
pageIndex: 0,
);
if (aggregateList.isSuccess) {
print('Count: ${aggregateList.count}');
for (final ds in aggregateList.rows) {
print('${ds.name}: ${ds.title} (type: ${ds.type})');
}
}
// Query aggregate datasource detail
final detail = await app.models.getDataSourceAggregateDetail(
dataSourceName: 'user',
);
print('Schema: ${detail.dataSource?.schema}');
// Query datasource schema by table name
final tableSchemas = await app.models.getDataSourceByTableName(
tableNames: ['user_table', 'order_table'],
);
for (final info in tableSchemas.dataSourceTableInfos) {
print('Table: ${info.tableName}, Name: ${info.name}');
}
// Query basic datasource list (POST with filters)
final basicList = await app.models.getBasicDataSourceList(
pageSize: 10,
pageNum: 1,
queryFilterList: [
DataSourceQueryFilter(name: 'Type', values: ['database']),
],
);
print('Total: ${basicList.total}');
// Query basic datasource info
final basicDetail = await app.models.getBasicDataSource(
dataSourceName: 'user',
);
print('DataSource: ${basicDetail.dataSource?.name}');
// Query all datasource schemas
final schemaList = await app.models.getSchemaList(
dataSourceNameList: ['user', 'order'],
);
for (final rel in schemaList.dataSourceRelationInfoList) {
print('${rel.name}: ${rel.title}');
}
// Query table name by datasource name
final tableName = await app.models.getTableName(
dataSourceName: 'user',
);
print('Table: ${tableName.tableName}, DB: ${tableName.dbType}');
Configuration Options #
CloudBase.init Parameters #
| Parameter | Type | Required | Description |
|---|---|---|---|
env |
String | Yes | TCB environment ID |
region |
String | No | Region, default ap-shanghai, options: ap-guangzhou, ap-singapore |
lang |
String | No | Language, default zh-CN, options: en-US |
accessKey |
String | No | Publishable Key for anonymous access |
authConfig |
AuthConfig | No | Authentication configuration |
captchaConfig |
CaptchaConfig | No | Captcha configuration |
Captcha Configuration #
To use the built-in captcha dialog, configure navigatorKey:
final navigatorKey = GlobalKey<NavigatorState>();
final app = await CloudBase.init(
env: 'your-env-id',
captchaConfig: CaptchaConfig(
navigatorKey: navigatorKey,
),
);
// Use in MaterialApp
MaterialApp(
navigatorKey: navigatorKey,
// ...
);
Screenshots #
For CloudBase Flutter examples, please refer to Example Code
Error Handling #
The SDK throws CloudBaseException:
try {
await app.auth.signInWithPassword(
SignInWithPasswordReq(
email: 'user@example.com',
password: 'wrong-password',
),
);
} on CloudBaseException catch (e) {
print('Error code: ${e.code}');
print('Error message: ${e.message}');
}
Related Links #
License #
MIT License - See LICENSE file for details