flutter直接上傳文件到阿里云oss
代碼實(shí)現(xiàn)
以下是我寫的一個(gè)上傳oss的類,只需要替換ossAccessKeyId, ossAccessKeySecret, bucket, url, expiration這幾個(gè)參數(shù)就可以直接實(shí)現(xiàn)上傳
import 'dart:convert'; import 'dart:io'; import 'dart:math'; import 'package:crypto/crypto.dart'; import 'package:dio/dio.dart'; class UploadOss { static String ossAccessKeyId = 'ossAccessKeyId'; static String ossAccessKeySecret = 'ossAccessKeySecret'; // oss設(shè)置的bucket的名字 static String bucket = 'bucketName'; // 發(fā)送請(qǐng)求的url,根據(jù)你自己設(shè)置的是哪個(gè)城市的 static String url = 'https://$bucket.oss-cn-hangzhou.aliyuncs.com'; // 過期時(shí)間 static String expiration = '2025-01-01T12:00:00.000Z'; /** * @params file 要上傳的文件對(duì)象 * @params rootDir 阿里云oss設(shè)置的根目錄文件夾名字 * @param fileType 文件類型例如jpg,mp4等 * @param callback 回調(diào)函數(shù)我這里用于傳cancelToken,方便后期關(guān)閉請(qǐng)求 * @param onSendProgress 上傳的進(jìn)度事件 */ static Future<String> upload({ File file , String rootDir = 'moment', String fileType, Function callback, Function onSendProgress}) async { String policyText = '{"expiration": "$expiration","conditions": [{"bucket": "$bucket" },["content-length-range", 0, 1048576000]]}'; // 獲取簽名 String signature = getSignature(policyText); BaseOptions options = new BaseOptions(); options.responseType = ResponseType.plain; //創(chuàng)建dio對(duì)象 Dio dio = new Dio(options); // 生成oss的路徑和文件名我這里目前設(shè)置的是moment/20201229/test.mp4 String pathName = '$rootDir/${getDate()}/${getRandom(12)}.${fileType == null ? getFileType(file.path) : fileType}'; // 請(qǐng)求參數(shù)的form對(duì)象 FormData data = new FormData.fromMap({ 'key': pathName, 'policy': getSplicyBase64(policyText), 'OSSAccessKeyId': ossAccessKeyId, 'success_action_status': '200', //讓服務(wù)端返回200,不然,默認(rèn)會(huì)返回204 'signature': signature, 'contentType': 'multipart/form-data', 'file': MultipartFile.fromFileSync(file.path), }); Response response; CancelToken uploadCancelToken = CancelToken(); callback ?? callback(uploadCancelToken); try { // 發(fā)送請(qǐng)求 response = await dio.post(url, data: data, cancelToken: uploadCancelToken, onSendProgress: (int count, int data) { onSendProgress(count, data); }); // 成功后返回文件訪問路徑 return '$url/$pathName'; } catch(e) { throw(e.message); } } /* * 生成固定長(zhǎng)度的隨機(jī)字符串 * */ static String getRandom(int num) { String alphabet = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'; String left = ''; for (var i = 0; i < num; i++) { // right = right + (min + (Random().nextInt(max - min))).toString(); left = left + alphabet[Random().nextInt(alphabet.length)]; } return left; } /* * 根據(jù)圖片本地路徑獲取圖片名稱 * */ static String getImageNameByPath(String filePath) { // ignore: null_aware_before_operator return filePath?.substring(filePath?.lastIndexOf("/")+1,filePath?.length); } /** * 獲取文件類型 */ static String getFileType(String path) { print(path); List<String> array = path.split('.'); return array[array.length -1]; } /// 獲取日期 static String getDate() { DateTime now = DateTime.now(); return '${now.year}${now.month}${now.day}'; } // 獲取plice的base64 static getSplicyBase64(String policyText) { //進(jìn)行utf8編碼 List<int> policyText_utf8 = utf8.encode(policyText); //進(jìn)行base64編碼 String policy_base64 = base64.encode(policyText_utf8); return policy_base64; } /// 獲取簽名 static String getSignature(String policyText) { //進(jìn)行utf8編碼 List<int> policyText_utf8 = utf8.encode(policyText); //進(jìn)行base64編碼 String policy_base64 = base64.encode(policyText_utf8); //再次進(jìn)行utf8編碼 List<int> policy = utf8.encode(policy_base64); //進(jìn)行utf8 編碼 List<int> key = utf8.encode(ossAccessKeySecret); //通過hmac,使用sha1進(jìn)行加密 List<int> signature_pre = Hmac(sha1, key).convert(policy).bytes; //最后一步,將上述所得進(jìn)行base64 編碼 String signature = base64.encode(signature_pre); return signature; } }
調(diào)用上傳的例子
其他參事自己根據(jù)自己情況上傳
Future<String> uploadFile(File file, { Function onSendProgress, Function callback}) async { final String url = await UploadOss.upload(file: file, onSendProgress: onSendProgress, callback: callback); return url; }
另一種方法
目前阿里沒有針對(duì)Flutter有官方SDK可集成, 但是有人對(duì)Flutter的上傳有封裝庫https://pub.dev/packages/aly_oss#-example-tab-, 所以我們只能通過post提交PostObject的形式來上傳;
準(zhǔn)備工作:
1、獲取OSS憑證地址(your oss_sts_server), 通知get直接獲取static String ossServerUrl = 'http://.../sts-server/sts.php';
2、上傳的存儲(chǔ)地址(桶名):static String ossEndPointCdn = '<your endpointcdn>';
// 通過ossServerUrl直接get獲取到如下數(shù)據(jù) { "StatusCode": 200, "AccessKeyId": "STS.NSsrKZes4cqm.....", "AccessKeySecret": "7eGnLZaEFsRCGYJAnrtdE9n.....", "Expiration": "2020-04-08T03:44:21Z", "SecurityToken": "CAISlQJ1q6Ft5B2y....." } //表單需要的參數(shù): AccessKeyId、AccessKeySecret、SecurityToken; FormData formdata = new FormData.from({ //文件名,隨意 'Filename': OssUtil.instance.getImageName(filePath), //"可以填寫文件夾名(對(duì)應(yīng)于oss服務(wù)中的文件夾)/" + fileName 'key': uploadName,//上傳后的文件名 'policy': OssUtil.policy, //Bucket 擁有者的AccessKeyId。 'OSSAccessKeyId': data['AccessKeyId'], //讓服務(wù)端返回200,不然,默認(rèn)會(huì)返回204 'success_action_status': '200', 'signature': OssUtil.instance.getSignature(data['AccessKeySecret']), //臨時(shí)用戶授權(quán)時(shí)必須,需要攜帶后臺(tái)返回的security-token 'x-oss-security-token': data['SecurityToken'], 'file': new UploadFileInfo( file, OssUtil.instance.getImageNameByPath(filePath)) //必須放在參數(shù)最后 }); //然后通過存儲(chǔ)地址直接把表單(formdata)上傳上去; Dio dio=Dio(); dio.options.responseType=ResponseType.plain; Response response=awaitdio.post(<ossEndPointCdn>,data:formData); ......
tips: 上傳成功后圖片地址 imageUrl = ossEndPointCdn + '/' + uploadName;
給一個(gè)工具類
import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'dart:math'; class OssUtil { 獲取 //驗(yàn)證文本域 static String _policyText = '{"expiration": "2069-05-22T03:15:00.000Z","conditions": [["content-length-range", 0, 1048576000]]}';//UTC時(shí)間+8=北京時(shí)間 //進(jìn)行utf8編碼 // ignore: non_constant_identifier_names static List<int> _policyText_utf8 = utf8.encode(_policyText); //進(jìn)行base64編碼 static String policy= base64.encode(_policyText_utf8); //再次進(jìn)行utf8編碼 // ignore: non_constant_identifier_names static List<int> _policy_utf8 = utf8.encode(policy); // 工廠模式 factory OssUtil() => _getInstance(); static OssUtil get instance => _getInstance(); static OssUtil _instance; OssUtil._internal(); static OssUtil _getInstance() { if (_instance == null) { _instance = new OssUtil._internal(); } return _instance; } /* *獲取signature簽名參數(shù) */ String getSignature(String _accessKeySecret){ //進(jìn)行utf8 編碼 // ignore: non_constant_identifier_names List<int> AccessKeySecretUtf8 = utf8.encode(_accessKeySecret); //通過hmac,使用sha1進(jìn)行加密 List<int> signaturePre = new Hmac(sha1, AccessKeySecretUtf8).convert(_policy_utf8).bytes; //最后一步,將上述所得進(jìn)行base64 編碼 String signature = base64.encode(signaturePre); return signature; } // ignore: slash_for_doc_comments /** * 生成上傳上傳圖片的名稱 ,獲得的格式:photo/20171027175940_oCiobK * 可以定義上傳的路徑uploadPath(Oss中保存文件夾的名稱) * @param uploadPath 上傳的路徑 如:/photo * @return photo/20171027175940_oCiobK */ String getImageUploadName(String uploadPath,String filePath) { String imageMame = ""; var timestamp = new DateTime.now().millisecondsSinceEpoch; imageMame =timestamp.toString()+"_"+getRandom(6); if(uploadPath!=null&&uploadPath.isNotEmpty){ imageMame=uploadPath+"/"+imageMame; } String imageType=filePath?.substring(filePath?.lastIndexOf("."),filePath?.length); return imageMame+imageType; } String getImageName(String filePath) { String imageMame = ""; var timestamp = new DateTime.now().millisecondsSinceEpoch; imageMame =timestamp.toString()+"_"+getRandom(6); String imageType=filePath?.substring(filePath?.lastIndexOf("."),filePath?.length); return imageMame+imageType; } /* * 生成固定長(zhǎng)度的隨機(jī)字符串 * */ String getRandom(int num) { String alphabet = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'; String left = ''; for (var i = 0; i < num; i++) { // right = right + (min + (Random().nextInt(max - min))).toString(); left = left + alphabet[Random().nextInt(alphabet.length)]; } return left; } /* * 根據(jù)圖片本地路徑獲取圖片名稱 * */ String getImageNameByPath(String filePath) { // ignore: null_aware_before_operator return filePath?.substring(filePath?.lastIndexOf("/")+1,filePath?.length); } }
以上就是flutter直接上傳文件到阿里云oss的實(shí)現(xiàn)步驟的詳細(xì)內(nèi)容,更多關(guān)于flutter 上傳文件到阿里云oss的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Flutter中如何加載并預(yù)覽本地的html文件的方法
- 你必須掌握在Flutter中添加資源文件的方法
- flutter Container容器實(shí)現(xiàn)圓角邊框
- Flutter實(shí)現(xiàn)頁面切換后保持原頁面狀態(tài)的3種方法
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(一)
- Flutter 超實(shí)用簡(jiǎn)單菜單彈出框 PopupMenuButton功能
- Flutter中http請(qǐng)求抓包的完美解決方案
- 詳解Flutter WebView與JS互相調(diào)用簡(jiǎn)易指南
- Flutter持久化存儲(chǔ)之?dāng)?shù)據(jù)庫存儲(chǔ)(sqflite)詳解
相關(guān)文章
Android定時(shí)器實(shí)現(xiàn)定時(shí)執(zhí)行、重復(fù)執(zhí)行、定時(shí)重復(fù)執(zhí)行、定次數(shù)執(zhí)行的多種方式
今天小編就為大家分享一篇關(guān)于Android定時(shí)器實(shí)現(xiàn)定時(shí)執(zhí)行、重復(fù)執(zhí)行、定時(shí)重復(fù)執(zhí)行、定次數(shù)執(zhí)行的多種方式,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12RxJava和Retrofit2的統(tǒng)一處理單個(gè)請(qǐng)求示例詳解
這篇文章主要給大家介紹了關(guān)于RxJava和Retrofit2的統(tǒng)一處理單個(gè)請(qǐng)求的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11Android EditText輸入框?qū)崿F(xiàn)下拉且保存最近5個(gè)歷史記錄思路詳解
今天給大家介紹Android EditText輸入框?qū)崿F(xiàn)下拉且保存最近5個(gè)歷史記錄功能,android實(shí)現(xiàn)文本框下拉利用sharedpreferences來保存每次app啟動(dòng)和關(guān)閉時(shí)已經(jīng)填寫的數(shù)值,具體代碼跟隨小編一起看看吧2021-07-07基于Android studio3.6的JNI教程之ncnn之語義分割ENet
這篇文章主要介紹了基于Android studio3.6的JNI教程之ncnn之語義分割ENet的相關(guān)知識(shí),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2020-03-03從零開始使用gradle配置即可執(zhí)行的Hook庫詳解
這篇文章主要為大家介紹了從零開始使用gradle配置即可執(zhí)行的Hook庫詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Android 使用registerReceiver注冊(cè)BroadcastReceiver案例詳解
這篇文章主要介紹了Android 使用registerReceiver注冊(cè)BroadcastReceiver案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08Android開發(fā)之permission動(dòng)態(tài)權(quán)限獲取詳解
這篇文章主要為大家詳細(xì)介紹了Android開發(fā)之permission動(dòng)態(tài)權(quán)限獲取,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08