在移动端应用开发中,图片上传是一个高频需求,而图片压缩则是提升上传效率、节省用户流量、降低服务器存储成本的关键环节。UniApp 作为跨端开发框架,需要同时兼顾小程序与 App 端的差异。本文将分享一套在 UniApp 中实现图片选择、压缩与上传的完整方案,并重点解决两端兼容性问题。
一、需求场景与技术选型
假设我们需要实现一个“用户头像上传”功能,要求:
- 用户可以从相册选择或相机拍摄图片;
- 图片大小限制在 2MB 以内,超出则自动压缩;
- 压缩后上传至服务器,并显示上传进度;
- 兼容微信小程序与 App(Android/iOS)。
UniApp 提供了 uni.chooseImage、uni.compressImage、uni.uploadFile 等 API,但不同平台的支持程度不同。例如,uni.compressImage 在微信小程序中支持较好,但在 App 端需要依赖原生插件或使用 plus.zip.compressImage。因此,我们需要封装一个统一的工具函数,根据平台调用不同的实现。
二、图片选择:统一入口
使用 uni.chooseImage 选择图片,它返回临时文件路径。注意:小程序返回的是 tempFilePaths,App 端返回的也是临时路径,但路径格式不同(如 _doc/ 或 file://)。我们只需关注后续处理。
function chooseImage() {
return new Promise((resolve, reject) => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'], // 小程序端优先压缩,App 端忽略
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0];
resolve(tempFilePath);
},
fail: reject
});
});
}
三、图片压缩:分平台实现
3.1 微信小程序端
小程序端可以直接使用 uni.compressImage,它底层调用 wx.compressImage。注意:该 API 仅支持压缩 JPG 格式,且压缩质量参数 quality 范围 0-100。
function compressImageMini(filePath, quality = 80) {
return new Promise((resolve, reject) => {
uni.compressImage({
src: filePath,
quality: quality,
success: (res) => {
resolve(res.tempFilePath);
},
fail: reject
});
});
}
3.2 App 端
App 端没有 uni.compressImage 的官方实现(HBuilderX 3.6+ 后部分支持,但兼容性不佳)。推荐使用 plus.zip.compressImage,它支持更丰富的参数,如宽度、高度、质量等。
function compressImageApp(filePath, quality = 80) {
return new Promise((resolve, reject) => {
plus.zip.compressImage({
src: filePath,
dst: '_doc/compressed_' + Date.now() + '.jpg',
quality: quality,
width: 'auto',
height: 'auto',
overwrite: true,
success: (res) => {
resolve(res.target);
},
fail: reject
});
});
}
3.3 统一压缩函数
根据当前平台判断调用哪个函数。可以通过 uni.getSystemInfoSync().platform 获取平台标识。
async function compressImage(filePath, quality = 80) {
const platform = uni.getSystemInfoSync().platform;
if (platform === 'android' || platform === 'ios') {
return compressImageApp(filePath, quality);
} else {
// 小程序端
return compressImageMini(filePath, quality);
}
}
注意:小程序端 uni.compressImage 可能因为图片过大而失败,建议先判断文件大小。如果小于 200KB,可以不压缩。
四、获取文件大小与条件压缩
在压缩前,我们需要知道图片大小。小程序端可以使用 uni.getFileInfo,App 端可以使用 plus.io.resolveLocalFileSystemURL 获取文件信息。
function getFileSize(filePath) {
return new Promise((resolve, reject) => {
const platform = uni.getSystemInfoSync().platform;
if (platform === 'android' || platform === 'ios') {
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
entry.getMetadata((metadata) => {
resolve(metadata.size);
}, reject);
}, reject);
} else {
uni.getFileInfo({
filePath: filePath,
success: (res) => {
resolve(res.size);
},
fail: reject
});
}
});
}
然后封装一个智能压缩函数:
async function smartCompress(filePath, maxSize = 2 * 1024 * 1024, quality = 80) {
const size = await getFileSize(filePath);
if (size <= maxSize) {
return filePath; // 无需压缩
}
return compressImage(filePath, quality);
}
五、图片上传:统一上传与进度处理
uni.uploadFile 在小程序与 App 端均可用,但需要注意:
- 小程序端需要配置合法域名;
- App 端可以直接使用
uni.uploadFile,但若需要更精细的控制(如分片上传),可使用plus.uploader。
这里使用 uni.uploadFile 实现基础上传,并监听进度。
function uploadFile(filePath, url, formData = {}) {
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: url,
filePath: filePath,
name: 'file',
formData: formData,
success: (res) => {
if (res.statusCode === 200) {
resolve(JSON.parse(res.data));
} else {
reject(new Error('上传失败:' + res.statusCode));
}
},
fail: reject
});
uploadTask.onProgressUpdate((res) => {
// 可以在这里更新进度条
console.log('上传进度:' + res.progress + '%');
});
});
}
六、完整流程示例
将上述步骤组合,实现一个完整的头像上传函数:
async function uploadAvatar() {
try {
// 1. 选择图片
const tempFilePath = await chooseImage();
// 2. 智能压缩
const compressedPath = await smartCompress(tempFilePath, 2 * 1024 * 1024, 80);
// 3. 上传
const result = await uploadFile(compressedPath, 'https://your-api.com/upload', {
userId: '12345'
});
uni.showToast({ title: '上传成功', icon: 'success' });
return result;
} catch (error) {
uni.showToast({ title: '上传失败', icon: 'none' });
console.error(error);
}
}
七、兼容性注意事项
- 小程序端:
uni.compressImage仅支持 JPG,若选择 PNG 图片,需先转换为 JPG 或使用 Canvas 压缩。另外,压缩后的临时文件在小程序重启后会失效,需及时上传。 - App 端:
plus.zip.compressImage的dst路径建议使用_doc/目录,避免权限问题。iOS 端需要注意相册权限和相机权限的配置。 - H5 端:本文未涉及,但可以使用 Canvas 进行压缩,上传则使用
uni.uploadFile或XMLHttpRequest。 - 性能优化:对于大图,建议先按最大边缩放(如 1080px)再压缩质量,避免内存溢出。小程序端可使用
uni.getImageInfo获取宽高。
八、总结
通过封装 chooseImage、compressImage、getFileSize、uploadFile 四个核心函数,我们实现了 UniApp 下兼容小程序与 App 的图片上传与压缩方案。关键点在于:
- 使用
uni.getSystemInfoSync().platform区分平台; - 小程序端调用
uni.compressImage,App 端调用plus.zip.compressImage; - 上传前先判断文件大小,避免不必要的压缩;
- 统一使用
uni.uploadFile处理上传,并利用onProgressUpdate实现进度反馈。
这套方案已在多个项目中验证,能够有效降低图片体积 60%-80%,同时保证两端体验一致。开发者可根据实际需求调整压缩质量与尺寸阈值。
未经允许不得转载:任鹏个人博客 » UniApp 图片上传与压缩:兼容小程序与 App 端的实践


朋友圈点赞图在线生成源码