Flutter多平台支持插件hycop_multi_platform的使用
Flutter多平台支持插件hycop_multi_platform的使用
特性
Hycop允许你使用以下由Firebase或AppWrite提供的6个服务:
- 数据库
- 实时
- 无服务器函数
- 账户
- 存储
- SocketIO
(SocketIO不是Firebase或AppWrite提供的服务,而是我们自己创建的服务。)
开始使用
示例程序将连接我们的演示服务器(Firebase或AppWrite)。你可以在example
文件夹中运行演示程序,例如:
% cd example
% flutter run -d chrome
使用说明
请参考以下示例页面:
- 数据库
example/app/database_example_page.dart
- 实时
example/app/real_example_page.dart
- 存储
example/app/storage_example_page.dart
- 无服务器函数
example/app/function_example_page.dart
- 账户
example/app/login_page.dart
example/app/register_page.dart
example/app/reset_password_confirm_page.dart
example/app/user_example_page.dart
- SocketIO
example/app/socketio_example_page.dart
- 配置
example/assets/hycop_config_example.json
示例程序将连接我们的演示服务器(Firebase或AppWrite)。如果你想要拥有自己的Firebase或AppWrite服务器,请按照以下步骤操作。
使用Firebase服务器的情况
在Firebase控制台中:
- 创建项目
- 注册你的应用
- 创建Firestore数据库
- 创建实时数据库
- 创建存储
- 创建函数
在源代码中:
- 在你的资源文件夹下创建一个
hycop_config.json
文件,并填充相应的值。 - 你可以参考
example/assets/hycop_config_example.json
文件,并在你的pubspec.yaml
文件中指定hycop_config.json
。
使用AppWrite服务器的情况
安装Docker
根据常见的方法安装Docker。Docker必须安装在至少有4GB内存的服务器上。只有具有域名的服务器才能使用HTTPS。
安装AppWrite
按照appwrite.io主页上的描述安装AppWrite。
AppWrite设置
如果你通过浏览器连接到AppWrite服务器的地址,可以访问AppWrite控制台。
- 第一次连接时,输入你的ID和密码。
- 创建项目
- 创建数据库
与Firebase不同,这里需要创建必要的集合。创建集合时,不要忘记给予适当的读写权限。
要使用实时服务,必须创建名为hycop_delta
的集合。
要使用账户服务,必须创建名为hycop_user
的集合。
hycop_user
和hycop_delta
的模式在example/assets/collection_hycop_delta.json
和example/assets/collection_hycop_user.json
文件中。
- 创建API密钥
- 创建函数 如果需要,可以按照AppWrite.io页面上的说明创建无服务器函数。
创建hycop_config.json
文件
你需要创建一个包含Firebase或AppWrite服务器信息的hycop_config.json
文件,并将其放在你的资源文件夹中。
hycop_config.json
文件可以通过参考example/assets/hycop_config_example.json
文件来创建。当然,你还需要在你的pubspec.yaml
文件中的assets
部分添加hycop_config.json
文件。
运行示例程序
cd example
flutter run -d chrome --web-renderer html
或者
flutter run -d chrome --web-renderer canvaskit
示例代码
以下是example/lib/main.dart
文件中的完整示例代码:
import 'package:creta_studio_model/model/frame_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:logging/logging.dart';
import 'package:hycop_multi_platform/hycop.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hycop Multi Platform',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Hycop Multi Platform'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _hycopInitResult = 'not initialize';
String _createAccountResult = '[empty]';
final String _loginAccountResult = '[empty]';
String _deleteAccountResult = '[empty]';
String _setDataResult = '[empty]';
String _getDataResult = '[empty]';
String _deleteDataResult = '[empty]';
String _uploadStorageResult = '[empty]';
String _downloadStorageResult = '[empty]';
Uint8List? _downloadUint8List;
FrameModel realtimeModel = FrameModel('', '');
bool _uploadToRealtime = false;
bool _downloadFromRealtime = false;
double _mouseX = 0;
double _mouseY = 0;
int _lastRealtime = DateTime.now().millisecondsSinceEpoch;
String _getNowString() {
return DateTime.now().toString();
}
Future<void> _hycopInit() async {
setupLogger();
Logger.root.level = Level.INFO;
HycopFactory.serverType = ServerType.firebase;
setState(() {
_hycopInitResult = '[${_getNowString()}] initializing...';
});
await HycopFactory.initAll();
setState(() {
_hycopInitResult = '[${_getNowString()}] initialized';
});
}
Future<void> _createAccount() async {
Map<String, dynamic> userData = {
'accountSignUpType': AccountSignUpType.hycop.index,
'password': '-507263a',
'email': 'HycopTestUser@nomail.com',
};
AccountManager.createAccount(userData).then((value) {
// 成功
setState(() {
_createAccountResult = '[${_getNowString()}] ${userData['email']} account created';
});
}).catchError(
(error, stackTrace) {
// 错误
setState(() {
_createAccountResult = '[${_getNowString()}] fail to create account !!!\n${error.toString()}';
});
},
);
}
Future<void> _loginAccount() async {
String password = '-507263a';
String email = 'HycopTestUser@nomail.com';
AccountManager.login(email, password).then((value) {
// 成功
setState(() {
_createAccountResult = '[${_getNowString()}] $email logined';
});
}).catchError(
(error, stackTrace) {
// 错误
setState(() {
_createAccountResult = '[${_getNowString()}] fail to login !!!\n${error.toString()}';
});
},
);
}
Future<void> _deleteAccount() async {
String email = AccountManager.currentLoginUser.email;
HycopFactory.account!.deleteAccount(deleteNow: true).then((value) {
// 成功
setState(() {
_deleteAccountResult = '[${_getNowString()}] $email account deleted';
});
}).catchError(
(error, stackTrace) {
// 错误
setState(() {
_deleteAccountResult = '[${_getNowString()}] fail to delete account !!!\n${error.toString()}';
});
},
);
}
Future<void> _getDataFromDB() async {
var userDataList = await HycopFactory.dataBase
?.queryData('hycop_users', where: {'email': 'test'}, orderBy: 'email');
if (userDataList?.isEmpty ?? true) {
setState(() {
_getDataResult = '[${_getNowString()}] no data';
});
return;
}
setState(() {
_getDataResult = '[${_getNowString()}] ';
for (var userData in userDataList!) {
_getDataResult += 'users=${userData['email']?.toString()},';
}
});
}
Future<void> _setDataToDB() async {
Map<String, dynamic> userData = {'userId': 'test', 'email': 'test', 'accountSignUpType': 0};
await HycopFactory.dataBase!.createData('hycop_users', 'user=test', userData).then((value) {
// 成功
setState(() {
_setDataResult = '[${_getNowString()}] create successfully';
});
}).catchError(
(error, stackTrace) {
// 错误
setState(() {
_setDataResult = '[${_getNowString()}] fail to create !!!\n${error.toString()}';
});
},
);
}
Future<void> _deleteDataFromDB() async {
await HycopFactory.dataBase!.removeData('hycop_users', 'user=test').then((value) {
// 成功
setState(() {
_deleteDataResult = '[${_getNowString()}] delete successfully';
});
}).catchError(
(error, stackTrace) {
// 错误
setState(() {
_deleteDataResult = '[${_getNowString()}] fail to delete !!!\n${error.toString()}';
});
},
);
}
Future<void> _downloadDataFromStorage() async {
HycopFactory.storage!.setBucket();
String fileId = 'HycopTest/content/image/a6de38b7f004ea361acfbc9ed98a447eHycopTestImage.png';
setState(() {
_downloadUint8List = null;
_downloadStorageResult = 'downloading...';
});
HycopFactory.storage!.getFileBytes(fileId).then((value) {
// 成功
setState(() {
_downloadUint8List = value;
if (_downloadUint8List == null) {
_downloadStorageResult = '[${_getNowString()}] fail to download !!!';
}
});
}).catchError(
(error, stackTrace) {
// 错误
setState(() {
_deleteDataResult = '[${_getNowString()}] fail to delete !!!\n${error.toString()}';
});
},
);
}
Future<void> _uploadDataToStorage() async {
setState(() {
_uploadStorageResult = 'uploading...';
});
HycopFactory.storage!.setBucket();
String fileName = 'HycopTestImage.png';
String fileType = 'image';
final ByteData bytes = await rootBundle.load('assets/logo.png');
final Uint8List fileBytes = bytes.buffer.asUint8List();
FileModel? fileModel = await HycopFactory.storage!.uploadFile(
fileName,
fileType,
fileBytes,
makeThumbnail: true,
bucketId: 'HycopTest',
);
setState(() {
_uploadStorageResult =
(fileModel == null) ? '[${_getNowString()}] fail to upload !!!' : fileModel.id;
});
}
void _updateLocation(PointerEvent details) {
if (_uploadToRealtime) {
int nowMilliseconds = DateTime.now().millisecondsSinceEpoch;
setState(() {
_mouseX = details.position.dx;
_mouseY = details.position.dy;
});
if (nowMilliseconds - _lastRealtime > 1000) {
_lastRealtime = nowMilliseconds;
realtimeModel.posX.set(details.position.dx,
save: false, noUndo: true, dontChangeBookTime: true, dontRealTime: true);
realtimeModel.posY.set(details.position.dy,
save: false, noUndo: true, dontChangeBookTime: true, dontRealTime: true);
HycopFactory.realtime!
.setDelta(directive: 'set', mid: realtimeModel.mid, delta: realtimeModel.toMap());
}
}
}
Future<void> _uploadDataToRealtime() async {
if (_uploadToRealtime == false && _downloadFromRealtime == false) {
_uploadToRealtime = true;
FrameModel tmpModel = FrameModel('page=hycoptest', 'book=hycoptest');
realtimeModel.copyFrom(tmpModel, newMid: 'frame=hycoptest', pMid: 'page=hycoptest');
HycopFactory.realtime!.startTemp(realtimeModel.mid);
//HycopFactory.realtime!.setPrefix('hycop'); // 不需要
}
}
void realTimeCallback(
String listenerId, String directive, String userId, Map<String, dynamic> dataMap) {
// logger.finest('realTimeCallback invoker($directive, $userId)');
if (directive == 'set') {
String mid = dataMap["mid"] ?? '';
if (mid.isEmpty) {
return;
}
if (realtimeModel.mid == mid) {
realtimeModel.fromMap(dataMap);
setState(() {
_mouseX = realtimeModel.posX.value;
_mouseY = realtimeModel.posY.value;
});
}
}
}
Future<void> _downloadDataFromRealtime() async {
if (_uploadToRealtime == false && _downloadFromRealtime == false) {
_downloadFromRealtime = true;
FrameModel tmpModel = FrameModel('page=hycoptest', 'book=hycoptest');
realtimeModel.copyFrom(tmpModel, newMid: 'frame=hycoptest', pMid: 'page=hycoptest');
HycopFactory.realtime!.start();
HycopFactory.realtime!.addListener("page=hycoptest", "hycop_frame", realTimeCallback);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: SingleChildScrollView(
child: MouseRegion(
onHover: _updateLocation,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 初始化Hycop
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _hycopInit();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('初始化Hycop'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_hycopInitResult),
),
// 创建账户
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _createAccount();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('创建账户'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_createAccountResult),
),
// 登录账户
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _loginAccount();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('登录账户'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_loginAccountResult),
),
// 删除账户
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _deleteAccount();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('删除账户'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_deleteAccountResult),
),
// 从数据库获取数据
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _getDataFromDB();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('从数据库获取数据'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_getDataResult),
),
// 设置数据库数据
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _setDataToDB();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('设置数据库数据'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_setDataResult),
),
// 从数据库删除数据
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _deleteDataFromDB();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('从数据库删除数据'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_deleteDataResult),
),
// 从存储下载数据
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _downloadDataFromStorage();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('从存储下载数据'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: _downloadUint8List == null
? Text(_downloadStorageResult)
: Container(
color: Colors.black,
child: Image.memory(
_downloadUint8List!,
width: 200,
)),
),
// 上传数据到存储
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _uploadDataToStorage();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('上传数据到存储'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(_uploadStorageResult),
),
// 上传数据到实时
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _uploadDataToRealtime();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('上传数据到实时'),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text('X:$_mouseX, Y:$_mouseY'),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: TextButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.grey[300])),
onPressed: () async {
await _downloadDataFromRealtime();
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text('从实时下载数据'),
),
),
),
],
),
),
),
),
);
}
}
更多关于Flutter多平台支持插件hycop_multi_platform的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter多平台支持插件hycop_multi_platform的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
hycop_multi_platform
是一个 Flutter 插件,旨在简化跨平台开发,允许开发者使用一套代码在多个平台上运行应用。以下是如何使用 hycop_multi_platform
插件的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 hycop_multi_platform
插件的依赖。
dependencies:
flutter:
sdk: flutter
hycop_multi_platform: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来获取依赖。
2. 导入插件
在需要使用插件的 Dart 文件中导入 hycop_multi_platform
:
import 'package:hycop_multi_platform/hycop_multi_platform.dart';
3. 使用插件功能
hycop_multi_platform
插件通常提供了一些跨平台的 API,你可以根据需求调用这些 API。
例如,假设插件提供了一个方法来获取当前平台的名称:
void getPlatformInfo() {
String platform = HycopMultiPlatform.getPlatformName();
print('Running on: $platform');
}
4. 平台特定代码
如果插件支持平台特定的代码,你可以在 android
、ios
、web
等目录下添加特定平台的实现。
例如,如果你需要在 Android 平台上进行一些特定的操作,你可以在 android/src/main/kotlin/com/example/your_app
目录下添加相应的 Kotlin 代码。
5. 运行和测试
在添加了插件代码后,你可以在不同的平台上运行和测试你的应用。
flutter run -d chrome # 在 Web 上运行
flutter run -d android # 在 Android 上运行
flutter run -d ios # 在 iOS 上运行
6. 调试和优化
根据不同的平台特性,你可能需要对代码进行一些调试和优化,以确保在所有平台上都能正常运行。
7. 发布
当你完成了开发和测试后,可以使用 Flutter 提供的命令来打包和发布你的应用。
flutter build apk # 打包 Android APK
flutter build ios # 打包 iOS
flutter build web # 打包 Web 应用