在开发过程中,我们经常会用到图片上传,有的时候还要视频上传,那我们如何实现图片和视频上传呢?
这里我们要想实现这些涉及到几个插件
dio: 3.0.8
dio_cookie_manager: 1.0.0
fluttertoast: ^3.1.3
image_picker: ^0.6.3+1
permission_handler: ^5.0.1+1
添加完这几个插件我们需要 pub get 一下。注意:fluttertoast这个插件是一个提示框,如果不使用,不用引用也可以
pub get
因为图片上传我们使用的地方有很多,所以我这里对这个图片上传类进行了封装,类名:HttpFileUtils 。
下面是实现我们用到的插件dio、?dio_cookie_manager
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'dart:convert';
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:nursery_school_gardener/constant/Url.dart';
import 'package:nursery_school_gardener/data/base_requst.dart';
import 'package:nursery_school_gardener/util/Variable.dart';
//要查网络请求的日志可以使用过滤<net>
class HttpFileUtils {
static const String POST = "post";
//post请求
static void post(String url, Function callBack,
{FormData formData, Function errorCallBack}) async {
_request(url, callBack,
formData: formData, method: POST, errorCallBack: errorCallBack);
}
//具体的还是要看返回数据的基本结构
//公共代码部分
static void _request(String url, Function callBack,
{String method, FormData formData, Function errorCallBack}) async {
String errorMsg = "";
int statusCode;
// params['token'] = DataBase.TOKEN;
BaseOptions baseOptions;
try {
baseOptions = new BaseOptions(
baseUrl: Url.BASE_URL,
connectTimeout: 30000,
receiveTimeout: 30000,
responseType: ResponseType.plain,
contentType: "multipart/form-data; boundary=" + formData.boundary,
headers: {
"X-Access-Token": Variable.share().GARDENER_TOKEN,
"X-Request-Id": Variable.share().X_REQUEST_ID,
HttpHeaders.contentTypeHeader:
"multipart/form-data; boundary=" + formData.boundary,
});
} catch (exception) {
print(exception);
}
Dio dio = new Dio(baseOptions);
var cookieJar = CookieJar();
dio.interceptors.add(CookieManager(cookieJar));
//简单粗暴方式处理校验证书方法
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
client.badCertificateCallback =
(X509Certificate cert, String host, int port) {
return true;
};
};
Response response;
try {
if (method == POST) {
if (formData != null) {
response = await dio.post(
url,
data: formData,
);
} else {
response = await dio.post(url);
}
}
statusCode = response.statusCode;
//处理错误部分
if (statusCode < 0) {
errorMsg = "网络请求错误,状态码:" + statusCode.toString();
_handError(errorCallBack, errorMsg);
return;
}
if (callBack != null) {
var result = response.data.toString();
print("返回数据:" + result);
var data = json.decode(result);
BaseRequst baseData = BaseRequst.fromJson(data);
if (baseData.code == 200 || baseData.code == 0 ) {
callBack(data);
} else {
_handError(errorCallBack, baseData.message);
}
}
} catch (exception) {
String code = exception.message.toString();
String errorString = code.contains("timed out") ? "请求超时" : "服务异常";
_handError(errorCallBack, errorString);
}
}
//处理异常
static void _handError(Function errorCallback, String errorMsg) {
if (errorCallback != null) {
errorCallback(errorMsg);
}
print("<net> errorMsg :" + errorMsg);
}
}
到此图片上传类就完成了。
下面就是使用了,在使用之前我们需要获取相册的图片或者视频。这个时候我们就使用到了权限的申请permission_handler。
这里我为了方便使用权限这里对使用进行了封装,类名:PermissionUtils
完整内容
import 'package:permission_handler/permission_handler.dart';
class PermissionUtils {
/**
* 所有
*/
static Future requestAllPermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.camera,
Permission.photos,
Permission.speech,
Permission.storage,
Permission.location,
Permission.phone,
Permission.notification,
Permission.contacts
].request();
if (await Permission.camera.isGranted) {
print("相机权限申请通过");
} else {
print("相机权限申请失败");
}
if (await Permission.photos.isGranted) {
print("照片权限申请通过");
} else {
print("照片权限申请失败");
}
if (await Permission.speech.isGranted) {
print("语音权限申请通过");
} else {
print("语音权限申请失败");
}
if (await Permission.storage.isGranted) {
print("文件权限申请通过");
} else {
print("文件权限申请失败");
}
if (await Permission.location.isGranted) {
print("定位权限申请通过");
} else {
print("定位权限申请失败");
}
if (await Permission.phone.isGranted) {
print("手机权限申请通过");
} else {
print("手机权限申请失败");
}
if (await Permission.notification.isGranted) {
print("通知权限申请通过");
} else {
print("通知权限申请失败");
}
if (await Permission.contacts.isGranted) {
print("通讯录权限申请通过");
} else {
print("通讯录权限申请失败");
}
}
static Future<bool> requestCameraPermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.camera,
].request();
if (await Permission.camera.isGranted) {
print("相机权限申请通过");
return true;
} else {
print("相机权限申请失败");
return false;
}
}
static Future requestPhotosPermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.photos,
].request();
if (await Permission.photos.isGranted) {
print("照片权限申请通过");
} else {
print("照片权限申请失败");
}
}
static Future requestSpeechPermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.speech,
].request();
if (await Permission.speech.isGranted) {
print("语音权限申请通过");
} else {
print("语音权限申请失败");
}
}
static Future requestStoragePermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.storage,
].request();
if (await Permission.storage.isGranted) {
print("文件权限申请通过");
} else {
print("文件权限申请失败");
}
}
static Future requestLocationPermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.location,
].request();
if (await Permission.location.isGranted) {
print("定位权限申请通过");
} else {
print("定位权限申请失败");
}
}
static Future requestPhonePermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.phone,
].request();
if (await Permission.phone.isGranted) {
print("手机权限申请通过");
} else {
print("手机权限申请失败");
}
}
static Future requestNotificationPermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.notification,
].request();
if (await Permission.notification.isGranted) {
print("通知权限申请通过");
} else {
print("通知权限申请失败");
}
}
static Future requestContactsPermission() async {
Map<Permission, PermissionStatus> permission = await [
Permission.contacts,
].request();
if (await Permission.contacts.isGranted) {
print("通讯录权限申请通过");
} else {
print("通讯录权限申请失败");
}
}
}
到此就完成了app手机权限的封装,因为上传图片、视频要获取相册权限或者相机,所以我们要获取这几个权限。下面是使用
//申请相机、相册等权限
PermissionUtils.requestCameraPermission();
PermissionUtils.requestPhotosPermission();
PermissionUtils.requestStoragePermission();
这样就完成了获取
下面就是上传了,上传的过程中我们也要做一下权限的获取,如果未开启权限,要提示用户去打开权限。
if (!await Permission.camera.isGranted) {
Fluttertoast.showToast(msg: "相机权限已关闭");
return;
}
if (!await Permission.storage.isGranted) {
Fluttertoast.showToast(msg: "文件权限已关闭");
return;
}
if (!await Permission.photos.isGranted) {
Fluttertoast.showToast(msg: "相册权限已关闭");
return;
}
如果上述都符合要求,下面就是获取图片了,获取图片我们要使用的插件就是image_picker。
下面分别是图片和视频的获取方式
图片
File image = await ImagePicker.pickImage(
source: type == 0 ? ImageSource.camera : ImageSource.gallery); // 0 相机 1 相册
视频
File video = await ImagePicker.pickVideo(
source: type == 0 ? ImageSource.camera : ImageSource.gallery);// 1 相机 2 视频
其实图片和视频基本一致
这样子就完成了图片和视频的获取
下面就是上传了。下面是上传的所有代码
图片
/*
* 点击上传头像
* */
void _takePhoto(int type) async {
if (!await Permission.camera.isGranted) {
Fluttertoast.showToast(msg: "相机权限已关闭");
return;
}
if (!await Permission.storage.isGranted) {
Fluttertoast.showToast(msg: "文件权限已关闭");
return;
}
if (!await Permission.photos.isGranted) {
Fluttertoast.showToast(msg: "相册权限已关闭");
return;
}
File image = await ImagePicker.pickImage(
source: type == 0 ? ImageSource.camera : ImageSource.gallery);
if (image != null) {
String path = image.path;
var fileName = path.substring(path.lastIndexOf("/") + 1, path.length);
MultipartFile multipartFile =
MultipartFile.fromFileSync(path, filename: fileName);
FormData data = new FormData.fromMap({
"biz": "classReflect",// 和后台定一下上传的位置,不需要就为空
"file": multipartFile, // 上传的文件
});
HttpFileUtils.post(
Url.JF_API_FILE_UPLOAD,// 上传地址
(data) {
// 成功后返回的结果
},
formData: data,//上传的文件数据
errorCallBack: (errorMsg) { // 失败的报错信息
Fluttertoast.showToast(msg: errorMsg);
},
);
}
}
视频
void _takePhoto(int type) async {
if (!await Permission.camera.isGranted) {
Fluttertoast.showToast(msg: "相机权限已关闭");
return;
}
if (!await Permission.storage.isGranted) {
Fluttertoast.showToast(msg: "文件权限已关闭");
return;
}
if (!await Permission.photos.isGranted) {
Fluttertoast.showToast(msg: "相册权限已关闭");
return;
}
File video = await ImagePicker.pickVideo(
source: type == 0 ? ImageSource.camera : ImageSource.gallery);
print(video.lengthSync());
// 服务器要求图片最大为100M,所以这里app侧也要进行限制,不需要删除即可
if (video.lengthSync() > 104857600) {
Fluttertoast.showToast(msg: "当前视频文件过大,请编辑视频后再次上传");
return;
}
if (video != null) {
String path = video.path;
var fileName = path.substring(path.lastIndexOf("/") + 1, path.length);
MultipartFile multipartFile =
MultipartFile.fromFileSync(path, filename: fileName);
FormData data = new FormData.fromMap({
"biz": "group/" +
DateTime.now().year.toString() +
DateTime.now().month.toString(),//和图片一样,
"file": multipartFile,
});
HttpFileUtils.post(
Url.JF_API_FILE_UPLOAD,//上传接口
(data) {
// 返回结果
},
formData: data, // 视频文件
errorCallBack: (errorMsg) {
Fluttertoast.showToast(msg: errorMsg);
},
);
}
}
到此就完成了图片的上传
?
?
|