前言:上传文件使用的是通过客户端直传的形式
1.引入相关库:
@ant-design/react-native ant风格UI库
expo-file-system 文件访问
expo-image-picker 图片/视频选择器
2.新建图片选择并上传的帮助类
import { Toast } from '@ant-design/react-native';
import * as FileSystem from "expo-file-system";
import * as ImagePicker from 'expo-image-picker';
import AppService from "../api/app";
import Loading from "../components/ui/Loading";
import LogUtil from "./log_util";
// 从后端api获取
export let ossUrl = 'https://oss-2008.oss-cn-hongkong.aliyuncs.com';
let ossConfig = null;
/**
* @desc 选择相册图片
*/
export const pickImage = async (mediaTypes = ImagePicker.MediaTypeOptions.Images) => {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: mediaTypes,
allowsEditing: true,
aspect: null,
quality: 0.5,
});
LogUtil.log('pick image result = ', result);
if (result.canceled) {
return null;
}
if (mediaTypes === ImagePicker.MediaTypeOptions.Images) {
if (result.assets[0]?.fileSize/(1024*1024) > 2) {
Toast.fail('图片不能超过2MB');
return null;
}
} else if (mediaTypes === ImagePicker.MediaTypeOptions.Videos) {
if (result.assets[0]?.fileSize/(1024*1024) > 10) {
Toast.fail('视频不能超过10MB');
return null;
}
} else {}
return result.assets[0].uri;
};
export const uploadImage = async (fileName, filePath, nav) => {
Loading.show();
// 从后端获取阿里云oss相关凭证
const res = await AppService.getAliyunOssToken({}, nav);
if (res.code === 200) {
/*
*
* host = obj['host']
policyBase64 = obj['policy']
accessid = obj['accessid']
signature = obj['signature']
expire = parseInt(obj['expire'])
callbackbody = obj['callback']
key = obj['dir']
*
* */
ossConfig = res.data;
ossUrl = ossConfig['host'];
} else {
Loading.hide();
Toast.info('获取oss token信息失败')
return null;
}
if (filePath && filePath.length > 0) {
const split = filePath.split('.');
let realFileName = (!fileName || fileName.length === 0) ? `${random_string()}.${split[split.length - 1]}` : `${fileName}.${split[split.length - 1]}`;
let key = `${ossConfig['dir']}${realFileName}`;
let imageServicePath = `${ossConfig['host']}/${key}`;
try {
LogUtil.log('ossUrl = ', ossUrl)
// 方式一 - 使用FileSystem.uploadAsync上传文件至阿里云oss
// const response = await FileSystem.uploadAsync(`${ossUrl}`, filePath, {
// fieldName: 'file',
// httpMethod: 'POST',
// uploadType: FileSystem.FileSystemUploadType.MULTIPART,
// parameters: {
// 'name': realFileName,
// 'key': key,
// 'policy': ossConfig['policy'],
// 'OSSAccessKeyId': ossConfig['accessid'],
// 'success_action_status': '200',
// 'callback': ossConfig['callback'],
// 'signature': ossConfig['signature']
// }
// })
// 方式二 - FileSystem.createUploadTask 可以感知到上传进度
// let uploadTask = FileSystem.createUploadTask(`${ossUrl}`, filePath, {
// fieldName: 'file',
// httpMethod: 'POST',
// uploadType: FileSystem.FileSystemUploadType.MULTIPART,
// parameters: {
// 'name': realFileName,
// 'key': key,
// 'policy': ossConfig['policy'],
// 'OSSAccessKeyId': ossConfig['accessid'],
// 'success_action_status': '200',
// 'callback': ossConfig['callback'],
// 'signature': ossConfig['signature']
// }
// }, (data) => {
// LogUtil.log('createUploadTask data', `${data?.totalBytesExpectedToSend / 1024 / 1024}MB, ${data?.totalBytesSent / 1024 / 1024}MB`, getCustomerLocalTime(Date.now(), 0));
// });
// const response = await uploadTask?.uploadAsync();
// 方式三 - fetch(自我吐槽:在公司项目中使用js原生api上传最稳定)
const formData = new FormData();
formData.append("name", realFileName);
formData.append("type", 'multipart/form-data');
formData.append("policy", ossConfig['policy']);
formData.append("OSSAccessKeyId", ossConfig['accessid']);
formData.append("success_action_status", "200");
formData.append("signature", ossConfig['signature']);
formData.append("key", key);
formData.append("file", {
uri: filePath,
});
const response = await fetch(`${ossUrl}`, { method: "POST", body: formData });
LogUtil.log('response', JSON.stringify(response), 'imageServicePath', imageServicePath)
Loading.hide();
if (response.status !== 200) {
return null;
}
return { imageServicePath, fileName: key };
} catch (error) {
LogUtil.error(error)
}
}
Loading.hide();
return null;
}
const random_string = (len) => {
len = len || 32;
let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
let maxPos = chars.length;
let pwd = '';
for (let i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
3.代码中调用:
3.1 只选择图片、视频后用于展示
pickImage(mediaTypes).then(uri => {
if (uri) {
// uri可直接使用ImageView组件展示
}
})
3.2 选择图片、视频再上传阿里云oss后展示
const ChatTypes = {
voice: 6,
image: 2,
video: 3,
text: 1,
systemTips: 4,
autoText: 5,
}
let imageSendValue = '';
let videoSendValue = '';
let imageUri = '';
let videoUri = '';
const pickAndUploadImage = (type) => {
let mediaTypes = type === ChatTypes.image ? ImagePicker.MediaTypeOptions.Images : ImagePicker.MediaTypeOptions.Videos;
pickImage(mediaTypes).then(uri => {
if (uri) {
uploadImage(null, uri, navigation).then(res => {
if (!res) {
Toast.info(i18n.t("Chat.UploadFail"));
return;
}
LogUtil.log('imageServicePath = ', res?.imageServicePath, 'fileName = ', res?.fileName)
switch (type) {
case ChatTypes.image:
imageSendValue = res?.fileName;
imageUri = uri;
// sendMessage(ChatTypes.image, imageSendValue, imageUri);
break;
case ChatTypes.video:
videoSendValue = res?.fileName;
videoUri = uri;
// sendMessage(ChatTypes.video, videoSendValue, videoUri);
break;
default:
break;
}
})
}
})
}