Flutter阿里云OSS存储插件flutter_oss_aliyun的使用
Flutter阿里云OSS存储插件flutter_oss_aliyun的使用
简介
flutter_oss_aliyun
是一个用于访问阿里云OSS(对象存储服务)的Flutter库,支持STS临时访问凭证,并且涵盖了阿里云OSS SDK的大部分功能。它可以帮助开发者轻松地在Flutter应用中集成OSS文件上传、下载、删除等操作。
- 官方文档: https://pub.dev/packages/flutter_oss_aliyun
- STS文档: https://help.aliyun.com/document_detail/100624.html
初始化Client
添加依赖
在pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter_oss_aliyun: ^6.4.2
初始化oss client
1. 提供sts server地址
通过后端API获取STS临时凭证来初始化Client:
Client.init(
stsUrl: "server url get sts token",
ossEndpoint: "oss-cn-beijing.aliyuncs.com",
bucketName: "bucket name",
);
后端API返回的数据格式如下:
{
"AccessKeyId": "AccessKeyId",
"AccessKeySecret": "AccessKeySecret",
"SecurityToken": "SecurityToken",
"Expiration": "2022-03-22T11:33:06Z"
}
2. 自定义authGetter得到Auth
通过自定义认证函数来初始化Client:
Client.init(
ossEndpoint: "oss-cn-beijing.aliyuncs.com",
bucketName: "bucketName",
authGetter: _authGetter
);
Auth _authGetter() {
return Auth(
accessKey: "accessKey",
accessSecret: 'accessSecret',
expire: '2023-02-23T14:02:46Z',
secureToken: 'token',
);
}
集成get_it
可以与get_it
一起使用以实现依赖注入:
@module
abstract class OssProvider {
@singleton
Client client() {
return Client.init(
stsUrl: Env.stsUrl,
ossEndpoint: Env.endpointUrl,
bucketName: Env.bucketName,
);
}
}
使用自定义Dio
可以在初始化时传入自定义的Dio实例:
Client.init(
stsUrl: "server url get sts token",
ossEndpoint: "oss-cn-beijing.aliyuncs.com",
bucketName: "bucket name",
dio: Dio(BaseOptions(connectTimeout: 9000)),
);
使用示例
文件上传
final bytes = "file bytes".codeUnits;
await Client().putObject(
bytes,
"test.txt",
option: PutRequestOption(
onSendProgress: (count, total) {
print("send: count = $count, and total = $total");
},
onReceiveProgress: (count, total) {
print("receive: count = $count, and total = $total");
},
override: false,
aclModel: AclMode.publicRead,
storageType: StorageType.ia,
headers: {"cache-control": "no-cache"},
callback: Callback(
callbackUrl: "callback url",
callbackBody: "{\"mimeType\":\${mimeType}, \"filepath\":\${object},\"size\":\${size},\"bucket\":\${bucket},\"phone\":\${x:phone}}",
callbackVar: {"x:phone": "android"},
calbackBodyType: CalbackBodyType.json,
),
),
);
追加文件上传
final Response<dynamic> resp = await Client().appendObject(
Uint8List.fromList(utf8.encode("Hello World")),
"test_append.txt",
);
final Response<dynamic> resp2 = await Client().appendObject(
position: int.parse(resp.headers["x-oss-next-append-position"]?[0]),
Uint8List.fromList(utf8.encode(", Fluter.")),
"test_append.txt",
);
跨bucket复制文件
final Response<dynamic> resp = await Client().copyObject(
const CopyRequestOption(
sourceFileKey: 'test.csv',
targetFileKey: "test_copy.csv",
targetBucketName: "bucket_2"
),
);
取消文件上传
final CancelToken cancelToken = CancelToken();
final bytes = ("long long bytes" * 1000).codeUnits;
Client().putObject(
Uint8List.fromList(utf8.encode(string)),
"cancel_token_test.txt",
cancelToken: cancelToken,
option: PutRequestOption(
onSendProgress: (count, total) {
if (kDebugMode) {
print("send: count = $count, and total = $total");
}
if (count > 56) {
cancelToken.cancel("cancel the uploading.");
}
},
),
).then((response) {
// success
print("upload success = ${response.statusCode}");
}).catchError((err) {
if (CancelToken.isCancel(err)) {
print("error message = ${err.message}");
} else {
// handle other errors
}
});
批量文件上传
await Client().putObjects([
AssetEntity(
filename: "filename1.txt",
bytes: "files1".codeUnits,
option: PutRequestOption(
onSendProgress: (count, total) {
print("send: count = $count, and total = $total");
},
onReceiveProgress: (count, total) {
print("receive: count = $count, and total = $total");
},
aclModel: AclMode.private,
),
),
AssetEntity(filename: "filename2.txt", bytes: "files2".codeUnits),
]);
本地文件上传
final Response<dynamic> resp = await Client().putObjectFile(
"/Users/aaa.pdf",
fileKey: "aaa.png",
option: PutRequestOption(
onSendProgress: (count, total) {
print("send: count = $count, and total = $total");
},
onReceiveProgress: (count, total) {
print("receive: count = $count, and total = $total");
},
aclModel: AclMode.private,
callback: Callback(
callbackUrl: callbackUrl,
callbackBody:
"{\"mimeType\":\${mimeType}, \"filepath\":\${object},\"size\":\${size},\"bucket\":\${bucket},\"phone\":\${x:phone}}",
callbackVar: {"x:phone": "android"},
calbackBodyType: CalbackBodyType.json,
),
),
);
批量本地文件上传
final List<Response<dynamic>> resp = await Client().putObjectFiles(
[
AssetFileEntity(
filepath: "//Users/private.txt",
option: PutRequestOption(
onSendProgress: (count, total) {
print("send: count = $count, and total = $total");
},
onReceiveProgress: (count, total) {
print("receive: count = $count, and total = $total");
},
override: false,
aclModel: AclMode.private,
),
),
AssetFileEntity(
filepath: "//Users/splash.png",
filename: "aaa.png",
option: PutRequestOption(
onSendProgress: (count, total) {
print("send: count = $count, and total = $total");
},
onReceiveProgress: (count, total) {
print("receive: count = $count, and total = $total");
},
override: true,
),
),
],
);
文件下载
await Client().getObject(
"test.txt",
onReceiveProgress: (count, total) {
debugPrint("received = $count, total = $total");
},
);
查询文件是否存在
final bool isExisted = await Client().doesObjectExist(
"aaa.jpg",
);
文件下载并保存
await Client().downloadObject(
"test.txt",
"./example/test.txt",
onReceiveProgress: (count, total) {
debugPrint("received = $count, total = $total");
},
);
文件删除
await Client().deleteObject("test.txt");
批量文件删除
await Client().deleteObjects(["filename1.txt", "filename2.txt"]);
获取已签名的文件url
final String url = await Client().getSignedUrl(
"test.jpg",
params: {"x-oss-process": "image/resize,w_10/quality,q_90"},
);
获取多个已签名的文件url
final Map<String, String> result = await Client().getSignedUrls(["test.txt", "filename1.txt"]);
列举所有的存储空间
final Response<dynamic> resp = await Client().listBuckets({"max-keys": 2});
列举存储空间中所有文件
final Response<dynamic> resp = await Client().listFiles({});
获取bucket信息
final Response<dynamic> resp = await Client().getBucketInfo();
获取bucket的储容量以及文件数量
final Response<dynamic> resp = await Client().getBucketStat();
获取文件元信息
final Response<dynamic> resp = await Client().getObjectMeta("huhx.csv");
查询所有regions
final Response<dynamic> resp = await Client().getAllRegions();
查询特定region
final Response<dynamic> resp = await Client().getRegion("oss-ap-northeast-1");
查询bucket acl
final Response<dynamic> resp = await Client().getBucketAcl(
bucketName: "bucket-name",
);
更新bucket acl
final Response<dynamic> resp = await Client().putBucketAcl(
AciMode.publicRead,
bucketName: "bucket-name",
);
查询bucket policy
final Response<dynamic> resp = await Client().getBucketPolicy(
bucketName: "bucket-name",
);
更新bucket policy
final Response<dynamic> resp = await Client().putBucketPolicy(
{},
bucketName: "bucket-name",
);
删除bucket policy
final Response<dynamic> resp = await Client().deleteBucketPolicy(
bucketName: "bucket-name",
);
完整示例Demo
// ignore: depend_on_referenced_packages
import 'package:flutter/material.dart';
import 'package:flutter_oss_aliyun/flutter_oss_aliyun.dart';
void main() {
runApp(
const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomeScreen(),
),
);
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
Client.init(
stsUrl: "server sts url",
ossEndpoint: "oss-cn-beijing.aliyuncs.com",
bucketName: "bucket name",
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Flutter aliyun oss example"),
),
body: Container(
alignment: Alignment.center,
child: Column(
children: [
TextButton(
onPressed: () async {
final bytes = "Hello World".codeUnits;
await Client().putObject(
bytes,
"filename.txt",
option: PutRequestOption(
onSendProgress: (count, total) {
if (kDebugMode) {
print("send: count = $count, and total = $total");
}
},
onReceiveProgress: (count, total) {
if (kDebugMode) {
print("receive: count = $count, and total = $total");
}
},
override: false,
aclModel: AclMode.private,
storageType: StorageType.standard,
callback: const Callback(
callbackUrl: "callbackUrl",
callbackBody:
"{\"mimeType\":\${mimeType}, \"filepath\":\${object},\"size\":\${size},\"bucket\":\${bucket},\"phone\":\${x:phone}}",
callbackVar: {"x:phone": "android"},
calbackBodyType: CalbackBodyType.json,
),
),
);
},
child: const Text("Upload object"),
),
TextButton(
onPressed: () async {
await Client().getObject(
"filename.txt",
onReceiveProgress: (count, total) {
debugPrint("received = $count, total = $total");
},
);
},
child: const Text("Get object"),
),
TextButton(
onPressed: () async {
await Client().downloadObject(
"filename.txt",
"./example/savePath.txt",
onReceiveProgress: (count, total) {
debugPrint("received = $count, total = $total");
},
);
},
child: const Text("Download object"),
),
TextButton(
onPressed: () async {
await Client().deleteObject("filename.txt");
},
child: const Text("Delete object"),
),
TextButton(
onPressed: () async {
await Client().putObjects(
[
AssetEntity(
filename: "filename1.txt",
bytes: "files1".codeUnits,
option: PutRequestOption(
onSendProgress: (count, total) {
if (kDebugMode) {
print("send: count = $count, and total = $total");
}
},
onReceiveProgress: (count, total) {
if (kDebugMode) {
print(
"receive: count = $count, and total = $total");
}
},
override: true,
aclModel: AclMode.inherited,
),
),
AssetEntity(
filename: "filename2.txt", bytes: "files2".codeUnits),
],
);
},
child: const Text("Batch upload object"),
),
TextButton(
onPressed: () async {
await Client()
.deleteObjects(["filename1.txt", "filename2.txt"]);
},
child: const Text("Batch delete object"),
),
],
),
),
);
}
}
如果你觉得这个插件对你有帮助,请给它一个⭐。
更多关于Flutter阿里云OSS存储插件flutter_oss_aliyun的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter阿里云OSS存储插件flutter_oss_aliyun的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用 flutter_oss_aliyun
插件在 Flutter 应用中上传文件到阿里云 OSS(对象存储服务)的示例代码。
首先,确保你已经在 pubspec.yaml
文件中添加了 flutter_oss_aliyun
依赖:
dependencies:
flutter:
sdk: flutter
flutter_oss_aliyun: ^版本号 # 请替换为实际的最新版本号
然后运行 flutter pub get
来获取依赖。
接下来,你需要进行一些初始化配置,包括设置阿里云 OSS 的 endpoint
、accessKeyId
、accessKeySecret
以及 bucketName
等信息。在实际应用中,这些信息通常不应该硬编码在客户端,而是通过安全的方式(例如后端服务)获取。
以下是一个完整的示例代码,展示了如何使用 flutter_oss_aliyun
插件上传文件到阿里云 OSS:
import 'package:flutter/material.dart';
import 'package:flutter_oss_aliyun/flutter_oss_aliyun.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Aliyun OSS Upload Example'),
),
body: Center(
child: UploadButton(),
),
),
);
}
}
class UploadButton extends StatefulWidget {
@override
_UploadButtonState createState() => _UploadButtonState();
}
class _UploadButtonState extends State<UploadButton> {
final AliyunOssFlutter aliyunOssFlutter = AliyunOssFlutter();
@override
void initState() {
super.initState();
// 初始化配置,这里为了示例直接硬编码,实际应用中应从安全的地方获取
aliyunOssFlutter.init(
endpoint: 'https://oss-cn-hangzhou.aliyuncs.com', // 替换为你的OSS endpoint
accessKeyId: 'yourAccessKeyId', // 替换为你的AccessKeyId
accessKeySecret: 'yourAccessKeySecret', // 替换为你的AccessKeySecret
bucketName: 'yourBucketName', // 替换为你的BucketName
region: 'oss-cn-hangzhou', // 替换为你的Region
);
}
void _uploadFile() async {
String localFilePath = 'path/to/your/local/file.jpg'; // 替换为你的本地文件路径
String ossObjectName = 'folder/yourFileName.jpg'; // 替换为你希望存储在OSS上的文件名
try {
bool result = await aliyunOssFlutter.uploadFile(
localFilePath,
ossObjectName,
);
if (result) {
print('File uploaded successfully!');
} else {
print('File upload failed!');
}
} catch (e) {
print('Error uploading file: $e');
}
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _uploadFile,
child: Text('Upload File to OSS'),
);
}
}
在这个示例中:
MyApp
是主应用组件,包含一个Scaffold
和一个居中的UploadButton
。UploadButton
是一个有状态的组件,用于处理文件上传的逻辑。- 在
initState
方法中,我们初始化了AliyunOssFlutter
插件,并设置了必要的配置信息。 _uploadFile
方法是实际执行文件上传的地方,它接收本地文件路径和 OSS 对象名称作为参数,并调用aliyunOssFlutter.uploadFile
方法上传文件。
请注意,在实际应用中,你应该采取安全措施来保护你的 accessKeyId
和 accessKeySecret
,避免直接在客户端代码中暴露这些信息。通常,你可以在后端生成一个临时的 STS(Security Token Service)令牌,并在客户端使用这个令牌进行身份验证和授权。