uni-app跨平台选择非媒体文件(xlsx、pdf、docx等)解决方案

在实际开发中,我们经常遇到需要让用户选择各种类型的文件如PDF文档、Excel表格、Word文档等的需求。然而,由于各平台API的差异性,实现这一功能并非易事。本文将介绍如何在uni-app中实现跨平台选择非媒体文件的功能。

一、面临的问题

各平台文件选择面临以下差异:

App端:需调用原生API(如plus.io.chooseFile)H5端:支持uni.chooseFile,但浏览器兼容性存在限制微信小程序:需使用专用API(wx.chooseMessageFile)其他小程序:各平台API支持程度不一

二、解决方案概述

uni-app官方提供了
uni-file-picker
组件,但在实际项目中,对于特定格式文件的选择可能需要定制化处理。我们可以结合多种API来实现完整的跨平台方案。

三、具体实现

1. App端采用相应的文件选择方法:

  ①  Android 文件选择解决方案:

首先获取存储读取权限,防止获取的文件路径没有访问权限



// 判断是否是Android端 (plus.os.name == 'Android' 可以通过html5+ API获取)
 function equestAndroidPermission() {
		if (uni.getSystemInfoSync().platform == 'android') {
			return new Promise((resolve, reject) => {
             plus.android.requestPermissions(['android.permission.READ_EXTERNAL_STORAGE'], (e) => {
					if (e.granted.includes('android.permission.READ_EXTERNAL_STORAGE')) {
						resolve();
					} else {
						if (e.deniedAlways.length > 0) { //权限被永久拒绝
							uni.showModal({
								title: '提示',
								content: '文件读取权限被拒绝,是否前往开启权限',
								success: (res) => {
									if (res.confirm) {
										// 弹出提示框解释为何需要读写手机储存权限,引导用户打开设置页面开启
										var main = plus.android.runtimeMainActivity();
										var Intent = plus.android.importClass(
											"android.content.Intent");
										//直接进入应用列表的权限设置
										var mIntent = new Intent(
											'android.settings.APPLICATION_SETTINGS'
										);
										main.startActivity(mIntent);
									}
								}
							});
							reject("权限被拒绝了");
						}
						// 权限被临时拒绝
						if (e.deniedPresent.length > 0) {
							// 弹出提示框解释为何需要读写手机储存权限,可再次调用plus.android.requestPermissions申请权限
							plus.android.requestPermissions([
								'android.permission.READ_EXTERNAL_STORAGE'
							]);
							reject("权限被拒绝了");
						}
					}
				},(error) => {
					reject(error.message);
				});
			});
		}
	},

安卓系统通过Intent机制调用系统文件管理器(一定要调用equestAndroidPermission这个方法先获取读取文件权限)



// 调用原生Intent类调取文件系统管理器并选取文件获取文件地址
function PickFile(callback, errcallback, mimeTypes='*/*') {
    equestAndroidPermission().then(() => {
				// mimeTypes为你要查的文件类型"image/*","audio/*","video/*;image/*"  
                // 选择图片 intent.setType("image/*");
                // 选择音频 intent.setType("audio/*"); 
                //选择图片和视频 intent.setType("video/*;image/*");
                //选择视频 (mp4 3gp 是android支持的视频格式)
				const CODE_REQUEST = 1000;
				const main = plus.android.runtimeMainActivity();
				var Intent = plus.android.importClass('android.content.Intent');
				var intent = new Intent(Intent.ACTION_GET_CONTENT);
				intent.addCategory(Intent.CATEGORY_OPENABLE);
				if (mimeTypes) {
					intent.setType("*/*");
					intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
				} else {
					intent.setType("*/*");
				}
				let _this = pickFile;
				main.onActivityResult = function(requestCode, resultCode, data) {
					if (requestCode == CODE_REQUEST) {
						var uri = data.getData();
						plus.android.importClass(uri); ①
						var Build = plus.android.importClass('android.os.Build');
						var isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
				
						var DocumentsContract = plus.android.importClass('android.provider.DocumentsContract');
						// DocumentProvider
						if (isKitKat && DocumentsContract.isDocumentUri(main, uri)) {
							console.log("版本大于 4.4 ");
							// ExternalStorageProvider
							if ("com.android.externalstorage.documents" == uri.getAuthority()) {
								var docId = DocumentsContract.getDocumentId(uri);
								var split = docId.split(":");
								var type = split[0];
				
								if ("primary" == type) {
									var Environment = plus.android.importClass('android.os.Environment');
									callback(Environment.getExternalStorageDirectory() + "/" + split[1]);
								} else {
									var System = plus.android.importClass('java.lang.System');
									var sdPath = System.getenv("SECONDARY_STORAGE");
									if (sdPath) {
										callback(sdPath + "/" + split[1]);
									}
								}
							}
							// DownloadsProvider
							else if ("com.android.providers.downloads.documents" == uri.getAuthority()) {
								var id = DocumentsContract.getDocumentId(uri);
								var ContentUris = plus.android.importClass('android.content.ContentUris');
								var contentUri = ContentUris.withAppendedId(
									//    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
									Uri.parse("content://downloads/public_downloads"), id);
								callback(_this.getDataColumn(main, contentUri, null, null));
							}
							// MediaProvider
							else if ("com.android.providers.media.documents" == uri.getAuthority()) {
								var docId = DocumentsContract.getDocumentId(uri);
								var split = docId.split(":");
								var type = split[0];
				
								var MediaStore = plus.android.importClass('android.provider.MediaStore');
								if ("image" == type) {
									contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
								} else if ("video" == type) {
									contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
								} else if ("audio" == type) {
									contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
								} else {
									contentUri = MediaStore.Files.getContentUri("external");
								}
								console.log("版本大于 4.4 ", type);
				
								var selection = "_id=?";
								var selectionArgs = new Array();
								selectionArgs[0] = split[1];
				
								callback(_this.getDataColumn(main, contentUri, selection, selectionArgs));
							}
						}
						// MediaStore (and general)
						else if ("content" == uri.getScheme()) {
							callback(_this.getDataColumn(main, uri, null, null));
						}
						// File
						else if ("file" == uri.getScheme()) {
							callback(uri.getPath());
						}
					}
				}
				main.startActivityForResult(intent, CODE_REQUEST);
			}).catch((err) => {
				errcallback(err);
			})
}

② ios 文件选择解决方案:

借助 5+App 的  
plus.io.chooseFile
  实现:


// 仅 App 端有效,需判断平台后使用
if (uni.getSystemInfoSync().platform === 'ios') {
  plus.io.chooseFile(
    {
      title: '选择文件', // 选择文件的标题提示
      filter: '*', // 筛选文件类型,* 表示所有,也可设 '.pdf,.docx' 等
      multiple: false // 是否多选
    },
    (res) => {
      const localPath = res.files[0]; // 获取选中的文件地址
      // 执行上传等操作
      ....
    },
    (err) => {
      console.error('选择文件失败:', err);
    }
  );
}

2. H5端采用相应的文件选择方法:

H5端可以使用uni-app 提供的   uni.chooseFile(OBJECT)   方法选择非媒体文件,此API只支持H5。

uni-app跨平台选择非媒体文件(xlsx、pdf、docx等)解决方案

uni-app跨平台选择非媒体文件(xlsx、pdf、docx等)解决方案uni-app跨平台选择非媒体文件(xlsx、pdf、docx等)解决方案

Tips: 

如果type属性和extension同时存在,例如 
{type:'image',extension:['.png','.jpg']}
,则会选择 
image/png,image/jpg
文件如果只配置extension属性,例如 
{extension:['.doc','.xlsx','.docx']}
 ,则会选择 
.doc,.xlsx,.docx
 文件,详情见accept属性在微信环境中,如果
type="all"
,则
extension
 属性失效



// 选择图片文件
uni.chooseFile({
  count: 10,
  type: 'image',
  success (res) {
    // tempFilePath可以作为img标签的src属性显示图片
    const tempFilePaths = res.tempFiles
  }
})

3. 微信小程序端采用相应的文件选择方法:

从微信聊天会话中选择文件,详见



// 微信小程序使用 wx.chooseMessageFile
let chooseFile = uni.chooseFile;
if (typeof wx !== 'undefined' && typeof wx.chooseMessageFile === 'function') {
  chooseFile = wx.chooseMessageFile;
}
 
chooseFile({
  type: 'all',
  count: 1,
  success(res) {
    // 处理选择的文件
  },
  fail(err) {
    console.error('选择文件失败', err);
  }
});

四、常见一些处理文件工具方法



 // 文件类型检查
 function isFileType(filename) {
      const fileExtensions = ['.pdf', '.doc', '.docx', '.xlsx', '.xls'];
      const extension = filename.slice(filename.lastIndexOf('.')).toLowerCase();
      return fileExtensions.includes(extension);
    }
 
 // 检查文件扩展名
 function  checkFileExt(path) {
      const reg = /.+./;
      let fileExt = path.replace(reg, "").toLowerCase();
      const allowedExts = ['pdf', 'doc', 'docx', 'xlsx', 'xls'];
      const isValid = allowedExts.some(ext => ext === fileExt);
      if (!isValid) {
        uni.showToast({
          title: `不允许选择${fileExt}格式的文件`,
          icon: 'none'
        });
      }
      return isValid;
 }
 
 // 获取文件扩展名(小写)
 function getFileExtension(filePath) {
    const ext = filePath.split('.').pop().toLowerCase();
	return ext;
 }
 
 // 判断文件后缀是否允许
 funbction checkFileExt(path) {
   const limitType = ['png', 'jpg', 'jpeg', 'mp4', 'pdf', 'doc', 'docx', 'xlsx', 'xls'];
   // 检查是否在允许的后缀中
   let noArrowExt = false;
   // 获取后缀名
   const reg = /.+./;
   let fileExt = path.replace(reg, "").toLowerCase();
   // 使用数组的some方法,只要符合limitType中的一个,就返回true
   noArrowExt = limitType .some(ext => {
       // 转为小写
       return ext.toLowerCase() === fileExt;
    })
	if (!noArrowExt) this.showToast(`不允许选择${fileExt}格式的文件`);
	return noArrowExt;
 }

五、注意事项

权限处理:Android平台需申请外部存储读取权限文件大小限制:应设置合理的文件大小限制,避免内存溢出文件预览:支持通过uni.openDocument接口预览选定文件错误处理:全面覆盖各类异常场景,优化用户使用体验

 通过以上方案,我们可以在uni-app中实现跨平台的非媒体文件选择功能。关键在于根据不同平台采用合适的API,并做好文件类型验证和错误处理。这样既能满足业务需求,又能保证良好的用户体验。

在实际项目中,还需要根据具体需求进行调整和完善,比如增加文件上传进度显示、批量文件选择等功能。

 

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...