1
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 267 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
@@ -0,0 +1,16 @@
|
||||
## 1.0.8(2025-08-17)
|
||||
* 兼容支持鸿蒙 Next
|
||||
## 1.0.4(2025-01-12)
|
||||
* 支持微信小程序
|
||||
## 1.0.3(2024-09-12)
|
||||
* 安卓更新了相关bug,另外使用方法改变以了有些方法类型变以了,更新时请注意比对demo方法.
|
||||
## 1.0.2(2024-08-14)
|
||||
* 新增属性超过指定文件大小,会被标注,并且三端会返回文件大小。
|
||||
## 1.0.1(2024-05-24)
|
||||
* 本次适配了IOS 11+(含),现在你可以在ios,安卓,web下选择文件上传了哦。
|
||||
* 请认真看说明文档使用,使用复杂了点,由于安卓,ios隐私等限制没办法抹平使用差异,请看仔细使用。如果不会用,请使用我tmui4.0x中的x-upload-file来进行文件上传。
|
||||
## 1.0.0(2024-04-13)
|
||||
* 原生文件选择器,支持安卓(不需要权限,也不需要打基座,标准基座即可)
|
||||
* web原生支持
|
||||
* ios待适配
|
||||
* tmui4.0种子用户,可免费赠送源码,无需购买
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"id": "x-file-s",
|
||||
"displayName": "tm-ui-4.0 安卓 IOS WEB 鸿蒙 文件选择器 通用无权限使用",
|
||||
"version": "1.0.8",
|
||||
"description": "安卓端不需要权限,web端,ios三端规格统一,抹平差异。",
|
||||
"keywords": [
|
||||
"安卓,web文件选择器,ios,鸿蒙"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.6.8",
|
||||
"uni-app": "",
|
||||
"uni-app-x": "^4.75"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "uts",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "99.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"darkmode": "x",
|
||||
"i18n": "x",
|
||||
"widescreen": "x"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "√",
|
||||
"aliyun": "√",
|
||||
"alipay": "√"
|
||||
},
|
||||
"client": {
|
||||
"uni-app": {
|
||||
"vue": {
|
||||
"vue2": "-",
|
||||
"vue3": "-"
|
||||
},
|
||||
"web": {
|
||||
"safari": "-",
|
||||
"chrome": "-"
|
||||
},
|
||||
"app": {
|
||||
"vue": "-",
|
||||
"nvue": "-",
|
||||
"android": "-",
|
||||
"ios": "-",
|
||||
"harmony": "-"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "-",
|
||||
"alipay": "-",
|
||||
"toutiao": "-",
|
||||
"baidu": "-",
|
||||
"kuaishou": "-",
|
||||
"jd": "-",
|
||||
"harmony": "-",
|
||||
"qq": "-",
|
||||
"lark": "-"
|
||||
},
|
||||
"quickapp": {
|
||||
"huawei": "-",
|
||||
"union": "-"
|
||||
}
|
||||
},
|
||||
"uni-app-x": {
|
||||
"web": {
|
||||
"safari": "√",
|
||||
"chrome": "√"
|
||||
},
|
||||
"app": {
|
||||
"android": {
|
||||
"extVersion": "",
|
||||
"minVersion": "21"
|
||||
},
|
||||
"ios": "√",
|
||||
"harmony": "√"
|
||||
},
|
||||
"mp": {
|
||||
"weixin": "√"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
# x-file-s
|
||||
### 开发文档
|
||||
[TMUI4.0文档](https://xui.tmui.design/)
|
||||
[TMUI4.0组件库](https://ext.dcloud.net.cn/plugin?id=16369)
|
||||
|
||||
**如果需要查看效果请[下载TMUI4.0组件库应用demo](https://ext.dcloud.net.cn/plugin?id=16369),导航到原生插件栏目体验。**
|
||||
|
||||
### 功能特色
|
||||
|
||||
** 本插件是API接口插件非组件,插件截图是我的TMUI4.0 x-upload-file基于此api接口封装的ui组件 **
|
||||
|
||||
- 支持安卓,无权限操作
|
||||
- 支持web选择文件上传
|
||||
- 支持多选,单选
|
||||
- 支持微信
|
||||
|
||||
### 功能说明
|
||||
|
||||
**请仔细看下面的使用方法,ios和web,安卓有区别注意条件编译进上传上传**
|
||||
|
||||
与官方 新 出的文件选择最大不同的是:
|
||||
1. 选择的文件不会有真实的文件,还要在上传时再执行内部 copy,因此理论上你选择 100 个文件上传,都是单个循环上传,不会造成崩溃
|
||||
除非你单个文件就非常大。(官方的是限制数量 100,默认选择后就给你一起复制到缓存了,而我是按需复制缓存文件。)
|
||||
2. 后缀不一样,可以任意标签的 miniType 格式如 application/msword等。
|
||||
|
||||
- 安卓端无需权限,返回系统的文件列表,但不包含真实文件地址。如果需要操作上传读取等,需要配置copyFileToPath方法,生成一个你自己的文件缓存目录。把文件复制到此位置。
|
||||
- 如果不要用了,要自己通过官方uni.getFileSystemManager来管理和清空缓存文件夹。不然应用随意使用的推移会增大。
|
||||
- web端直接选择上传没有上述问题
|
||||
- ios已支持从系统文件 管理器选择任意文件上传,它同安卓一样会在选择的时候copy一份文件到应用专属缓存文件中(不用担心变大,会自动清除),选择的文件只能当即临时上传
|
||||
时间长了会自动删除。返回的文件路径需要自行uni.env.CACHE_PATH + "/" + item.realFilePath组合路径进行上传
|
||||
|
||||
- 如果你不会使用,建议使用我的tmui4.0组件中的x-upload-file,它是基于此api接口封装的上传组件,啥都帮你配置好了,你只要提供个服务器的上传地址。
|
||||
|
||||
|
||||
### 兼容性
|
||||
|
||||
| Harmony | IOS | Android | WEB | 小程序 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 支持 | 支持 | 支持 | 支持 | 支持 |
|
||||
|
||||
### 说明
|
||||
这是tmui4.0|XUI的原生插件附赠插件。种子用户可免于购买。
|
||||
|
||||
非种子用户:
|
||||
|
||||
普通授权:99元
|
||||
源码授权:199元
|
||||
|
||||
### 使用
|
||||
如果你需要32位系统和模拟器x86上运行,需要自行配置打包cpu 支持类型,配置abis
|
||||
需要自定义基座运行,且安卓4.4+(含4.4)以上支持
|
||||
|
||||
```ts
|
||||
// 导入
|
||||
import {xFileSystem,fileListType} from "@/uni_modules/x-file-s"
|
||||
|
||||
/**
|
||||
* 新建文件管理对象,
|
||||
* typeFilter:string|null 文件过滤器例:"*/*",或者所有图片 "image/*"
|
||||
* tempmultiple:boolean|null 是否多选,默认是
|
||||
* maxSize:number|null 限制的文件大小,不是禁止用户选中,是返回的列表会标stauts=4,表示超过了大小。
|
||||
*/
|
||||
this.xfile = new xFileSystem(null,null)
|
||||
|
||||
// 打开文件夹选择文件
|
||||
this.xfile!.openDocument((list:any)=>{
|
||||
// 安卓是 list:fileListType[]是选中的文件列表,但这个文件列表是虚拟的,并非真实的文件地址。
|
||||
// web端list:fileListType[] 可以通过item.file访问文件对象即File
|
||||
// ios端是string
|
||||
|
||||
let list = [] as fileListType[];
|
||||
// #ifdef APP-IOS
|
||||
let templist = JSON.parseArray<string>(listtest)
|
||||
for(let i=0;i<templist.length;i++){
|
||||
let item = JSON.parse(templist[i])! as fileListType;
|
||||
list.push(item)
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-IOS
|
||||
list = listtest as fileListType[]
|
||||
// #endif
|
||||
|
||||
})
|
||||
|
||||
// 读取文件,为了抹平差异,web,安卓,ios编译在读取或者上传前调用以下函数获得上传的上传地址
|
||||
// 上传前需要一个临时存在的路径地址,这样文件会复制到你提供的目录缓存下。因此要选创建一个临时目录
|
||||
fileIsOnlyInSys( dir:string):Promise<string>{
|
||||
// #ifdef WEB
|
||||
return Promise.resolve("")
|
||||
// #endif
|
||||
//默认创建一个临时的 tmui4temp 目录
|
||||
let baseNamePath = dir==null?'tmui4temp':dir
|
||||
baseNamePath = uni.env.CACHE_PATH + "/" + baseNamePath
|
||||
const fileManager = uni.getFileSystemManager()
|
||||
return new Promise((res,rej)=>{
|
||||
fileManager.readdir({
|
||||
dirPath:baseNamePath,
|
||||
success(result:ReadDirSuccessResult){
|
||||
if(result==null){
|
||||
fileManager.mkdir({
|
||||
dirPath:baseNamePath,
|
||||
recursive:true,
|
||||
success(result:FileManagerSuccessResult){
|
||||
res(baseNamePath)
|
||||
},
|
||||
fail(er:UniError){
|
||||
console.log('创建目录失败',er)
|
||||
rej("")
|
||||
}
|
||||
} as MkDirOptions)
|
||||
}else{
|
||||
// 这个是目录路径
|
||||
res(baseNamePath)
|
||||
}
|
||||
},
|
||||
fail(ere:UniError){
|
||||
fileManager.mkdir({
|
||||
dirPath:baseNamePath,
|
||||
recursive:true,
|
||||
success(result:FileManagerSuccessResult){
|
||||
res(baseNamePath)
|
||||
},
|
||||
fail(er:UniError){
|
||||
console.log('创建目录失败',er)
|
||||
rej("")
|
||||
}
|
||||
} as MkDirOptions)
|
||||
}
|
||||
} as ReadDirOptions)
|
||||
})
|
||||
}
|
||||
|
||||
//调用上述方法,确保临时目录存在后通过Promise回调来复制文件路径
|
||||
// web,安卓如下执行读取真实路径给uploadfile来上传
|
||||
this.fileIsOnlyInSys('tmui4temp')
|
||||
.then((basedir:string)=>{
|
||||
_this.xfile!.copyFileToPath(item.id,basedir)
|
||||
.then((oreal:fileListType|null)=>{
|
||||
// oreal 这个对象包含了真实的上传地址
|
||||
// 在这里面你可以读取,上传文件了。
|
||||
})
|
||||
})
|
||||
// ios端不需要执行上面的步骤。
|
||||
// 直接就是前面的项目fileListType中的 uni.env.CACHE_PATH + "/" + item.realFilePath 组合路径进行上传
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
## 类型参考
|
||||
|
||||
```ts
|
||||
// api内部类型。
|
||||
type xFileSNameTYpe = {
|
||||
name:string,
|
||||
type:string,
|
||||
uri:Uri,
|
||||
id:string,
|
||||
realFilePath:string,
|
||||
cacheFilePath:string,
|
||||
size:number,
|
||||
status:number
|
||||
}
|
||||
// 你外部使用的文件对象类型
|
||||
export type xFileSListType = {
|
||||
name:string,
|
||||
type:string,
|
||||
id:string,
|
||||
/** web平台文件对象 */
|
||||
file?:any,
|
||||
/** 个人用户自定数据 */
|
||||
request?:any,
|
||||
/** 安卓机/ios机下面的真实sd路径 */
|
||||
realFilePath:string,
|
||||
/** uniapp应用协议文件路径,可用uni.getFileSystemManager进行删除或者查询到 */
|
||||
cacheFilePath:string,
|
||||
/** 文件大小 */
|
||||
size?:number
|
||||
/**
|
||||
* 0等待,1失败,2成功,3上传中,4超过大小。
|
||||
*/
|
||||
status?:0|1|2|3|4
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"minSdkVersion": "19"
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
import MediaStore from "android.provider.MediaStore"
|
||||
import Activity from 'android.app.Activity';
|
||||
import Bundle from 'android.os.Bundle';
|
||||
import Intent from 'android.content.Intent';
|
||||
import Uri from "android.net.Uri"
|
||||
import Context from 'android.content.Context'
|
||||
import ContentResolver from 'android.content.ContentResolver'
|
||||
import InputStream from 'java.io.InputStream'
|
||||
import FileOutputStream from 'java.io.FileOutputStream'
|
||||
import File from 'java.io.File'
|
||||
|
||||
import ByteArrayOutputStream from 'java.io.ByteArrayOutputStream'
|
||||
import MimeTypeMap from 'android.webkit.MimeTypeMap'
|
||||
import OpenableColumns from 'android.provider.OpenableColumns'
|
||||
import Build from 'android.os.Build'
|
||||
import ParcelFileDescriptor from 'android.os.ParcelFileDescriptor'
|
||||
|
||||
import { xFileSListType,fileListType } from "../interface.uts"
|
||||
|
||||
type xFileSNameTYpe = {
|
||||
name : string,
|
||||
type : string,
|
||||
uri : Uri,
|
||||
id : string,
|
||||
realFilePath : string,
|
||||
cacheFilePath : string,
|
||||
fileSize : number,
|
||||
status : number
|
||||
}
|
||||
type callReadBackFun = (byte : ByteArray) => void
|
||||
|
||||
type resumtype = (requestCode : Int, resultCode : Int, data : any) => void
|
||||
|
||||
const mimeTypes = new Map<string, string>([
|
||||
// 图片类型
|
||||
["jpg", "image/*"],
|
||||
["jpeg", "image/*"],
|
||||
["png", "image/*"],
|
||||
["gif", "image/*"],
|
||||
["bmp", "image/*"],
|
||||
["webp", "image/*"],
|
||||
["tiff", "image/*"],
|
||||
["svg", "image/*"],
|
||||
["ico", "image/*"],
|
||||
|
||||
// 视频类型
|
||||
["mp4", "video/*"],
|
||||
["webm", "video/*"],
|
||||
["ogv", "video/*"],
|
||||
["mov", "video/*"],
|
||||
["avi", "video/*"],
|
||||
["wmv", "video/*"],
|
||||
|
||||
// 音频类型
|
||||
["mp3", "audio/*"],
|
||||
["wav", "audio/*"],
|
||||
["ogg", "audio/*"],
|
||||
["flac", "audio/*"],
|
||||
["aac", "audio/*"],
|
||||
|
||||
// 文档类型
|
||||
["pdf", "application/*"],
|
||||
["doc", "application/*"],
|
||||
["docx", "application/*"],
|
||||
["xls", "application/*"],
|
||||
["xlsx", "application/*"],
|
||||
["ppt", "application/*"],
|
||||
["pptx", "application/*"],
|
||||
["odt", "application/*"],
|
||||
["ods", "application/*"],
|
||||
|
||||
// 文本类型
|
||||
["txt", "text/plain"],
|
||||
["html", "text/html"],
|
||||
["css", "text/css"],
|
||||
["js", "text/javascript"],
|
||||
["xml", "text/xml"],
|
||||
|
||||
// 其他类型
|
||||
["zip", "application/*"],
|
||||
["rar", "application/*"],
|
||||
["7z", "application/*"],
|
||||
["json", "application/*"]
|
||||
]);
|
||||
|
||||
|
||||
|
||||
function getMimeTypeFromUri(uri : Uri, max : number) : xFileSNameTYpe {
|
||||
let context = UTSAndroid.getAppContext() as Context
|
||||
let contentResolver = context.getContentResolver() as ContentResolver;
|
||||
let mime = MimeTypeMap.getSingleton() as MimeTypeMap;
|
||||
let gz = mime.getExtensionFromMimeType(contentResolver.getType(uri)) as string | null;
|
||||
let str = uri.getEncodedPath()
|
||||
let par = contentResolver.openFileDescriptor(uri, "r") as ParcelFileDescriptor
|
||||
let filesize = par.getStatSize()
|
||||
if (gz == null) {
|
||||
gz = str!.substring(str!.lastIndexOf(".") + 1)
|
||||
}
|
||||
let name = str!.substring(0, str!.lastIndexOf("/"))
|
||||
name = str!.substring(0, str!.lastIndexOf("."))
|
||||
///安卓10,api 29+需要遵循隐私策略获取名称。
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
|
||||
let cursor = contentResolver.query(uri, null, null, null, null)
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
let nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
if (nameIndex != -1) {
|
||||
name = cursor.getString(nameIndex);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
// 确保关闭游标
|
||||
if (cursor != null && !cursor.isClosed()) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
type: gz!,
|
||||
uri: uri,
|
||||
id: Math.floor(Math.random() * 1 * Math.floor(Math.random() * Date.now())).toString().substring(0, 10),
|
||||
realFilePath: "",
|
||||
cacheFilePath: "",
|
||||
fileSize: filesize,
|
||||
status: filesize > max ? 4 : 0
|
||||
|
||||
} as xFileSNameTYpe;
|
||||
}
|
||||
|
||||
function readFileToInputStrem(uri : Uri) : ByteArray {
|
||||
//读写块的大小。
|
||||
let sizeBlock = 1024
|
||||
let context = UTSAndroid.getAppContext() as Context
|
||||
let cover = context.getContentResolver() as ContentResolver
|
||||
let inputStream = cover.openInputStream(uri)
|
||||
let byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
// 文件的字节数组
|
||||
let buffer = new ByteArray(sizeBlock.toInt());
|
||||
let n = inputStream!.read(buffer)
|
||||
while (-1 != n) {
|
||||
byteArrayOutputStream.write(buffer, 0, n);
|
||||
n = inputStream!.read(buffer)
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
let filelistAll = [] as xFileSNameTYpe[]
|
||||
function isInfilelist(file : xFileSNameTYpe) : boolean {
|
||||
return filelistAll.some((el) : boolean => {
|
||||
return el.name == file.name && el.type == file.type
|
||||
})
|
||||
}
|
||||
let callFun = (list : fileListType[]) => { }
|
||||
let nowXFileSystem = null as null|xFileSystem;
|
||||
const activityResult = (requestCode : Int, resultCode : Int, data ?: Intent)=>{
|
||||
|
||||
let jgCode = 1;
|
||||
console.log(1)
|
||||
if (data != null && requestCode == jgCode.toInt()) {
|
||||
let fdata = data! as Intent
|
||||
let flistdata = fdata.getClipData();
|
||||
let flistdataOnly = data?.data
|
||||
//多选
|
||||
if (flistdata != null) {
|
||||
let count = flistdata.getItemCount();
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
let item = flistdata.getItemAt(i.toInt())
|
||||
let uri = item.getUri()
|
||||
|
||||
|
||||
let itemfile = getMimeTypeFromUri(uri, nowXFileSystem!.maxFileSize)
|
||||
if (!isInfilelist(itemfile)) {
|
||||
|
||||
filelistAll.push(itemfile)
|
||||
}
|
||||
|
||||
}
|
||||
//单选
|
||||
} else if (flistdataOnly != null) {
|
||||
let itemfile = getMimeTypeFromUri(flistdataOnly!, nowXFileSystem!.maxFileSize)
|
||||
if (!isInfilelist(itemfile)) {
|
||||
filelistAll.push(itemfile)
|
||||
}
|
||||
}
|
||||
let listfile = filelistAll.map((el) : fileListType => {
|
||||
return {
|
||||
name: el.name,
|
||||
type: el.type,
|
||||
id: el.id,
|
||||
uri: '',
|
||||
realFilePath: el.realFilePath,
|
||||
cacheFilePath: el.cacheFilePath,
|
||||
status: el.fileSize > nowXFileSystem!.maxFileSize ? 4 : 0,
|
||||
size: el.fileSize
|
||||
} as fileListType
|
||||
});
|
||||
|
||||
callFun(listfile)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 由于安卓隐私的问题。实际得到的所有文件 其实 都不是真实地址。因此你想要得到真实的地址,你就得复制到你的应用沙盒中。
|
||||
*/
|
||||
export class xFileSystem {
|
||||
mimeTypeFilter : string[] = [] as string[]
|
||||
filelist = [] as xFileSNameTYpe[]
|
||||
multiple : boolean = true;
|
||||
|
||||
maxFileSize = 30 * 1024 * 1024;
|
||||
|
||||
constructor(typeFilter : string[] | null, tempmultiple : boolean | null, maxSize : number | null) {
|
||||
if (typeFilter != null) {
|
||||
|
||||
let filter : string[] = [] as string[];
|
||||
let tms = typeFilter! as string[]
|
||||
for (let i = 0; i < tms.length; i++) {
|
||||
if (mimeTypes.get(tms[i]) != null) {
|
||||
filter.push(mimeTypes.get(tms[i])!)
|
||||
}
|
||||
}
|
||||
if (filter.length == 0) {
|
||||
filter.push("*/*")
|
||||
}
|
||||
|
||||
this.mimeTypeFilter = filter
|
||||
|
||||
}
|
||||
if (tempmultiple != null) {
|
||||
this.multiple = tempmultiple!
|
||||
}
|
||||
if (maxSize != null) {
|
||||
this.maxFileSize = maxSize!
|
||||
}
|
||||
nowXFileSystem = this;
|
||||
UTSAndroid.onAppActivityResult(activityResult);
|
||||
}
|
||||
|
||||
|
||||
|
||||
destory() {
|
||||
UTSAndroid.offAppActivityResult(activityResult)
|
||||
// filelistAll = [] as xFileSNameTYpe[]
|
||||
}
|
||||
openDocument(call : (list : fileListType[]) => void) {
|
||||
|
||||
let intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
|
||||
} else {
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
}
|
||||
|
||||
// intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
if (this.mimeTypeFilter.length == 0) {
|
||||
intent.type = "*/*"
|
||||
} else {
|
||||
let key = this.mimeTypeFilter[this.mimeTypeFilter.length - 1]
|
||||
let ftype = key;
|
||||
if (ftype != null) {
|
||||
intent.setType(ftype!);
|
||||
} else {
|
||||
intent.setType("*/*");
|
||||
}
|
||||
// console.log(this.mimeTypeFilter)
|
||||
// intent.putExtra(Intent.EXTRA_MIME_TYPES, []);
|
||||
|
||||
}
|
||||
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, this.multiple)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
let _this = this;
|
||||
callFun = call;
|
||||
|
||||
UTSAndroid.getUniActivity()!.startActivityForResult(intent, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个文件条目
|
||||
* @param {string} id - 文件id
|
||||
* @returns {fileListType[]} 最新的文件列表
|
||||
*/
|
||||
remove(id : string) : fileListType[] {
|
||||
|
||||
let index = -1;
|
||||
for (let i = 0; i < filelistAll.length; i++) {
|
||||
let item = filelistAll[i]
|
||||
if (item.id == id) {
|
||||
filelistAll.splice(i, 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return filelistAll.map((el) : fileListType => {
|
||||
|
||||
return {
|
||||
name: el.name,
|
||||
type: el.type,
|
||||
id: el.id,
|
||||
uri: '',
|
||||
realFilePath: el.realFilePath,
|
||||
cacheFilePath: el.cacheFilePath,
|
||||
size: el.fileSize,
|
||||
status: el.status
|
||||
} as fileListType
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 返回一个空文件列表数组
|
||||
*/
|
||||
clear() : fileListType[] {
|
||||
filelistAll = [] as xFileSNameTYpe[];
|
||||
this.filelist = [] as xFileSNameTYpe[];
|
||||
return [] as fileListType[]
|
||||
}
|
||||
/**
|
||||
* 读取文件
|
||||
* @description 提供这个函数是因为如果是大文件上传,你可能需要分块上传。由于安卓隐私问题,大文件超过16mb复制回用户区可能会卡或者其它意外事项。
|
||||
* @param {string} id - 文件id
|
||||
* @param {number} size - 读写块的大小,每次读取的大小
|
||||
* @param {Function<byte:ByteArray>} callBack - 读取文件时的回调。
|
||||
*/
|
||||
readFile(item : xFileSListType, size : number | null = null, callBack : null | callReadBackFun = null) : ByteArray {
|
||||
let index = -1;
|
||||
for (let i = 0; i < filelistAll.length; i++) {
|
||||
let item2 = filelistAll[i]
|
||||
if (item.id == item2.id) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
console.error("文件id不存在")
|
||||
return new ByteArray((0).toInt())
|
||||
}
|
||||
let file = filelistAll[index]
|
||||
// 1024
|
||||
|
||||
let sizeBlock = size == null ? 1024 : size!;
|
||||
let context = UTSAndroid.getAppContext() as Context
|
||||
let cover = context.getContentResolver() as ContentResolver
|
||||
let inputStream = cover.openInputStream(file.uri)
|
||||
let byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
// 文件的字节数组
|
||||
let buffer = new ByteArray(sizeBlock.toInt());
|
||||
let n = inputStream!.read(buffer)
|
||||
|
||||
while (-1 != n) {
|
||||
byteArrayOutputStream.write(buffer, 0, n);
|
||||
if (callBack != null) {
|
||||
let tempbuffer = new ByteArray(sizeBlock.toInt());
|
||||
byteArrayOutputStream.write(tempbuffer, 0, n);
|
||||
callBack(tempbuffer)!
|
||||
}
|
||||
n = inputStream!.read(buffer)
|
||||
}
|
||||
let ar = byteArrayOutputStream.toByteArray()
|
||||
try {
|
||||
byteArrayOutputStream.flush()
|
||||
} catch (e) {
|
||||
byteArrayOutputStream.close()
|
||||
}
|
||||
return ar
|
||||
}
|
||||
/**
|
||||
* 获取文件地址
|
||||
* @description 主要是用来你外部上传用,但记住这个内部会放到临时目录中,因此你的地址也是临时在用户中。
|
||||
* @returns {Promise<string>} 返回文件地址
|
||||
*/
|
||||
copyFileToPath(item : xFileSListType, path : string) : Promise<xFileSListType | null> {
|
||||
// let index = -1;
|
||||
// for(let i=0;i<this.filelist.length;i++){
|
||||
// let item = this.filelist[i]
|
||||
// if(item.id==id){
|
||||
// index = i;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if(index==-1){
|
||||
// console.error("文件id不存在")
|
||||
// uni.showToast({title:"文件id不存在",icon:'none'})
|
||||
// return Promise.resolve(null)
|
||||
// }
|
||||
|
||||
let file = item
|
||||
if (file.status == 4) {
|
||||
console.error("文件大小超了")
|
||||
// uni.showToast({title:"文件大小超了",icon:'none'})
|
||||
return Promise.resolve(item)
|
||||
}
|
||||
let fileData = this.readFile(item, 1024, null);
|
||||
let filepath = path + "/" + file.name
|
||||
|
||||
|
||||
let realfilepath = UTSAndroid.convert2AbsFullPath(filepath)
|
||||
// let outputFile = new File(filepath)
|
||||
uni.showLoading({ title: '...', mask: true })
|
||||
return new Promise((res, rej) => {
|
||||
try {
|
||||
let outputStream = new FileOutputStream(realfilepath)
|
||||
outputStream.write(fileData);
|
||||
outputStream.flush();
|
||||
uni.hideLoading()
|
||||
file.realFilePath = realfilepath
|
||||
file.cacheFilePath = filepath
|
||||
res({
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
id: file.id,
|
||||
realFilePath: file.realFilePath,
|
||||
cacheFilePath: file.cacheFilePath,
|
||||
status: file.status,
|
||||
size: file.size,
|
||||
uri: file.uri
|
||||
} as xFileSListType)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: "异常", icon: 'none' })
|
||||
rej("异常")
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"x_file_s": "./lib/x_file_s.har"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import { x_xFileSNameTYpe, x_xFileSystem } from "x_file_s"
|
||||
import { fileListType, xFileSListType } from "../interface"
|
||||
|
||||
let HxFilesSytem : x_xFileSystem | null = null;
|
||||
export class xFileSystem {
|
||||
mimeTypeFilter : string[] = []
|
||||
filelist = [] as fileListType[]
|
||||
multiple : boolean = true;
|
||||
maxFileSize = 30 * 1024 * 1024;
|
||||
constructor(typeFilter : string[] | null, tempmultiple : boolean | null, maxSize : number | null) {
|
||||
if (typeFilter != null) {
|
||||
let tms = typeFilter! as string[];
|
||||
this.mimeTypeFilter = tms;
|
||||
}
|
||||
if (tempmultiple != null) {
|
||||
let tm = tempmultiple as boolean;
|
||||
this.multiple = tm
|
||||
}
|
||||
if (maxSize != null) {
|
||||
this.maxFileSize = maxSize!
|
||||
}
|
||||
|
||||
if (HxFilesSytem == null) {
|
||||
HxFilesSytem = new x_xFileSystem(UTSHarmony.getCurrentWindow()!.getUIContext(), this.mimeTypeFilter, this.multiple, this.maxFileSize)
|
||||
} else {
|
||||
HxFilesSytem!.clear();
|
||||
}
|
||||
}
|
||||
destory() {
|
||||
HxFilesSytem = null;
|
||||
this.filelist = [] as fileListType[]
|
||||
}
|
||||
openDocument(callfun : (list : fileListType[]) => void) {
|
||||
if (HxFilesSytem != null) {
|
||||
HxFilesSytem!.openDocument((templist : x_xFileSNameTYpe[]) => {
|
||||
let listfile = templist.map((el) : fileListType => {
|
||||
return {
|
||||
name: el.name,
|
||||
type: el.type,
|
||||
id: el.id,
|
||||
uri: el.uri,
|
||||
realFilePath: el.realFilePath,
|
||||
cacheFilePath: el.cacheFilePath,
|
||||
status: el.status,
|
||||
size: el.fileSize
|
||||
} as fileListType
|
||||
});
|
||||
this.filelist = listfile
|
||||
callfun(listfile)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个文件条目
|
||||
* @param {string} id - 文件id
|
||||
* @returns {fileListType[]} 最新的文件列表
|
||||
*/
|
||||
remove(id : string) : fileListType[] {
|
||||
|
||||
const templist = HxFilesSytem!.remove(id)
|
||||
|
||||
let listfile = templist.map((el) : fileListType => {
|
||||
return {
|
||||
name: el.name,
|
||||
type: el.type,
|
||||
id: el.id,
|
||||
uri: el.uri,
|
||||
realFilePath: el.realFilePath,
|
||||
cacheFilePath: el.cacheFilePath,
|
||||
status: el.status,
|
||||
size: el.fileSize
|
||||
} as fileListType
|
||||
});
|
||||
this.filelist = listfile
|
||||
|
||||
return listfile
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个空文件列表数组
|
||||
*/
|
||||
clear() : fileListType[] {
|
||||
this.filelist = [] as fileListType[];
|
||||
HxFilesSytem!.clear();
|
||||
return [] as fileListType[]
|
||||
}
|
||||
|
||||
copyFileToPath(item : xFileSListType, path : string) : Promise<xFileSListType | null> {
|
||||
return Promise.resolve(item);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deploymentTarget": "11"
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
import { xFileSListType,fileListType } from "../interface"
|
||||
import { UIDocumentPickerViewController, UIDocumentPickerMode, UIDocumentPickerDelegate, UIViewController } from "UIKit"
|
||||
import { URL, URLResourceKey, URLResourceValues, Data, FileManager } from "Foundation"
|
||||
import { UTType } from "UniformTypeIdentifiers"
|
||||
import Swift from "Swift"
|
||||
|
||||
function getUid(rdix = 1, length = 12) : string {
|
||||
let ix = "";
|
||||
// #ifdef APP
|
||||
ix = Math.floor(Math.random() * rdix * Math.floor(Math.random() * Date.now())).toString().substring(0, length as Int);
|
||||
// #endif
|
||||
return ix;
|
||||
}
|
||||
let filelistAll = [] as fileListType[]
|
||||
export class xFileSystem {
|
||||
|
||||
mimeTypeFilter : string[] = []
|
||||
|
||||
filelist = [] as fileListType[]
|
||||
multiple : boolean = true;
|
||||
actionSeleCtedFiles : ActionsClass | null = null
|
||||
maxFileSize = 30 * 1024 * 1024;
|
||||
constructor(typeFilter : string[] | null, tempmultiple : boolean | null, maxSize : number | null) {
|
||||
if (typeFilter != null) {
|
||||
let tms = typeFilter! as string[];
|
||||
this.mimeTypeFilter = tms;
|
||||
|
||||
}
|
||||
if (tempmultiple != null) {
|
||||
let tm = tempmultiple as boolean;
|
||||
this.multiple = tm
|
||||
}
|
||||
if (maxSize != null) {
|
||||
this.maxFileSize = maxSize!
|
||||
}
|
||||
}
|
||||
destory(){
|
||||
|
||||
}
|
||||
openDocument(callfun : (list : any) => void) {
|
||||
let _this = this;;
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
_this.actionSeleCtedFiles = new ActionsClass((files : URL[]) => {
|
||||
let keysToFetch = new Swift.Set<URLResourceKey>();
|
||||
keysToFetch.insert(URLResourceKey.totalFileAllocatedSizeKey)
|
||||
// 获得当前用户的缓存目录路径主目录。
|
||||
let userDir = FileManager.default.urls(for = FileManager.SearchPathDirectory.cachesDirectory, in = FileManager.SearchPathDomainMask.userDomainMask).first!
|
||||
|
||||
for (let item in files) {
|
||||
let ditem = item;
|
||||
|
||||
try {
|
||||
let ds = UTSiOS.try(ditem.resourceValues(forKeys = keysToFetch), "?")
|
||||
|
||||
if (ds != null) {
|
||||
let fSize = ds?.totalFileAllocatedSize ?? 0
|
||||
let fName = ditem.lastPathComponent;
|
||||
let fPath = ditem.absoluteString;
|
||||
let fType = fName.substring((fName.lastIndexOf('.') + 1).toInt())
|
||||
let realFilePath = ''
|
||||
let cacheFilePath = fPath
|
||||
let status = 0
|
||||
let ifleid = getUid(1, 8);
|
||||
let tempath = UTSiOS.getDataPath() as string
|
||||
|
||||
let destinationFileName = ifleid + "." + fType
|
||||
let destinationURL = userDir.appendingPathComponent(destinationFileName)
|
||||
|
||||
let real = UTSiOS.try(FileManager.default.copyItem(at = ditem, to = destinationURL), "?");
|
||||
let itemobj = {
|
||||
name: fName,
|
||||
type: fType,
|
||||
id: ifleid,
|
||||
uri:"",
|
||||
realFilePath: destinationFileName,
|
||||
cacheFilePath: destinationFileName,
|
||||
size: fSize,
|
||||
status: fSize > _this.maxFileSize ? 4 : 0
|
||||
|
||||
} as fileListType;
|
||||
|
||||
if(!_this.isInfilelist(itemobj)){
|
||||
|
||||
_this.filelist.push(itemobj)
|
||||
filelistAll.push(itemobj)
|
||||
}
|
||||
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let list = [] as string[]
|
||||
for (file in _this.filelist) {
|
||||
list.push(JSON.stringify(file)!)
|
||||
}
|
||||
callfun(JSON.stringify(list))
|
||||
_this.filelist = [] as fileListType[]
|
||||
|
||||
})
|
||||
try {
|
||||
if (UTSiOS.available("iOS 14.0, *")) {
|
||||
let filter : UTType[] = [] as UTType[];
|
||||
for (let i = 0; i < _this.mimeTypeFilter.length; i++) {
|
||||
let contentType = new UTType(filenameExtension = _this.mimeTypeFilter[i])
|
||||
if (contentType != null) {
|
||||
filter.push(new UTType(filenameExtension = _this.mimeTypeFilter[i])!)
|
||||
}
|
||||
}
|
||||
if(filter.length==0){
|
||||
filter.push(UTType.item)
|
||||
}
|
||||
|
||||
let documentPickerController = new UIDocumentPickerViewController(forOpeningContentTypes = filter,asCopy = true)
|
||||
documentPickerController.delegate = _this.actionSeleCtedFiles
|
||||
documentPickerController.allowsMultipleSelection = _this.multiple // 是否允许选择多个文件
|
||||
UTSiOS.getCurrentViewController().present(documentPickerController, animated = true, completion = null)
|
||||
} else {
|
||||
let documentPickerController = new UIDocumentPickerViewController(documentTypes = ['public.data'], in = UIDocumentPickerMode.import)
|
||||
documentPickerController.delegate = _this.actionSeleCtedFiles
|
||||
documentPickerController.allowsMultipleSelection = _this.multiple // 是否允许选择多个文件
|
||||
UTSiOS.getCurrentViewController().present(documentPickerController, animated = true, completion = null)
|
||||
}
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
//读取文件
|
||||
copyFileToPath(item : xFileSListType, basedir : string) : string {
|
||||
// let filepath = ''
|
||||
// for (file in this.filelist) {
|
||||
// if (file.id == id) {
|
||||
// filepath = file.cacheFilePath
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
return item.cacheFilePath;
|
||||
}
|
||||
isInfilelist(file:fileListType):boolean{
|
||||
return filelistAll.some((el):boolean=>{
|
||||
return el.name==file.name&&el.type==file.type
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 返回一个空文件列表数组
|
||||
*/
|
||||
clear():fileListType[]{
|
||||
filelistAll = [] as fileListType[];
|
||||
this.filelist = [] as fileListType[];
|
||||
return [] as fileListType[]
|
||||
}
|
||||
// ios不作删除自行管理缓存文件。
|
||||
remove(id : string) : fileListType[] {
|
||||
let index = -1;
|
||||
for(let i=0;i<filelistAll.length;i++){
|
||||
let item = filelistAll[i]
|
||||
if(item.id==id){
|
||||
filelistAll.splice(i,1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filelistAll.map((el):fileListType=>{
|
||||
return {
|
||||
name:el.name,
|
||||
type:el.type,
|
||||
id:el.id,
|
||||
uri:'',
|
||||
realFilePath:el.realFilePath,
|
||||
cacheFilePath:el.cacheFilePath,
|
||||
size:el.size,
|
||||
status:el.status
|
||||
} as fileListType
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
class ActionsClass implements UIDocumentPickerDelegate {
|
||||
callSuccessFiles = (files : URL[]) => { }
|
||||
constructor(call : (files : URL[]) => void) {
|
||||
super()
|
||||
this.callSuccessFiles = call;
|
||||
}
|
||||
documentPicker(controller : UIDocumentPickerViewController, @argumentLabel("didPickDocumentsAt") urls : URL[]) {
|
||||
|
||||
this.callSuccessFiles(urls)
|
||||
}
|
||||
documentPickerWasCancelled(controller : UIDocumentPickerViewController) {
|
||||
console.log("User cancelled the document picker")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
export type xFileSListType = {
|
||||
name:string,
|
||||
type:string,
|
||||
id:string,
|
||||
uri:string,
|
||||
/** web平台文件对象 */
|
||||
file?:any,
|
||||
/** 个人用户自定数据 */
|
||||
request?:any,
|
||||
/** 安卓机/ios机下面的真实sd路径 */
|
||||
realFilePath:string,
|
||||
/** uniapp应用协议文件路径,可用uni.getFileSystemManager进行删除或者查询到 */
|
||||
cacheFilePath:string,
|
||||
/** 文件大小 */
|
||||
size?:number
|
||||
/**
|
||||
* 0等待,1失败,2成功,3上传中,4超过大小。
|
||||
*/
|
||||
status?:0|1|2|3|4
|
||||
}
|
||||
|
||||
// #ifndef MP
|
||||
export type fileListType = xFileSListType
|
||||
// #endif
|
||||
|
||||
// #ifdef MP
|
||||
export type fileListType = any
|
||||
// #endif
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
export { xFileSListType } from "../interface"
|
||||
export type fileListType = any;
|
||||
|
||||
type xFileSNameTYpe = {
|
||||
name:string,
|
||||
type:string,
|
||||
uri:string,
|
||||
id:string,
|
||||
file:any,
|
||||
size:number,
|
||||
status:number
|
||||
}
|
||||
// type callReadBackFun = (byte:ByteArray)=>void
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 由于安卓隐私的问题。实际得到的所有文件 其实 都不是真实地址。因此你想要得到真实的地址,你就得复制到你的应用沙盒中。
|
||||
*/
|
||||
export class xFileSystem {
|
||||
mimeTypeFilter = [] as string[];
|
||||
filelist = [] as xFileSNameTYpe[]
|
||||
inputDom:null|HTMLInputElement = null;
|
||||
multiple:boolean = true;
|
||||
maxFileSize:number = 30*1024*1024
|
||||
constructor(typeFilter:string|null,tempmultiple:boolean|null,maxSize:number|null){
|
||||
if(typeFilter!=null){
|
||||
|
||||
let filter : string[] = [] as string[];
|
||||
let tms = typeFilter! as string[]
|
||||
for (let i = 0; i < tms.length; i++) {
|
||||
filter.push("."+tms[i])
|
||||
}
|
||||
if(filter.length==0){
|
||||
filter.push("*/*")
|
||||
}
|
||||
|
||||
this.mimeTypeFilter = filter
|
||||
}
|
||||
if(tempmultiple!=null){
|
||||
this.multiple = tempmultiple!
|
||||
}
|
||||
if(maxSize!=null){
|
||||
this.maxFileSize = maxSize!
|
||||
}
|
||||
}
|
||||
isInfilelist(file:xFileSNameTYpe):boolean{
|
||||
return this.filelist.some((el):boolean=>{
|
||||
return el.name==file.name&&el.type==file.type
|
||||
})
|
||||
}
|
||||
destory(){
|
||||
|
||||
}
|
||||
openDocument(call:(list:xFileSListType[])=>void){
|
||||
|
||||
let _this = this;
|
||||
let filetype = this.mimeTypeFilter[0].split('/')[0]
|
||||
if(filetype=='*'){
|
||||
filetype = 'all'
|
||||
}
|
||||
|
||||
wx.chooseMessageFile({
|
||||
count:100,
|
||||
type:filetype,
|
||||
success(result) {
|
||||
let filelist = result.tempFiles
|
||||
for(let i=0;i<filelist.length;i++){
|
||||
let item = filelist[i];
|
||||
let fileitem = {
|
||||
name:item.name,
|
||||
type:item.type.substring(item.type.lastIndexOf("/")+1),
|
||||
uri:"",
|
||||
id:Math.floor(Math.random() * 1 * Math.floor(Math.random() * Date.now())).toString().substring(0, 10),
|
||||
file:item,
|
||||
size:item.size,
|
||||
status:item.size>_this.maxFileSize?4:0,
|
||||
} as xFileSNameTYpe
|
||||
if(!_this.isInfilelist(fileitem)){
|
||||
_this.filelist.push(fileitem)
|
||||
}
|
||||
}
|
||||
call(_this.filelist.map((el)=>{
|
||||
return {
|
||||
name:el.name,
|
||||
type:el.type,
|
||||
id:el.id,
|
||||
request:null,
|
||||
realFilePath:el.file.path,
|
||||
cacheFilePath:el.file.path,
|
||||
size:el.size,
|
||||
status:el.status
|
||||
}
|
||||
}))
|
||||
},
|
||||
fail(er) {
|
||||
console.error(er)
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 删除一个文件条目
|
||||
* @param {string} id - 文件id
|
||||
* @returns {fileListType[]} 最新的文件列表
|
||||
*/
|
||||
remove(id:string):xFileSListType[]{
|
||||
|
||||
return this.filelist.filter(el=>el.id!=id)
|
||||
|
||||
}
|
||||
/**
|
||||
* 返回一个空文件列表数组
|
||||
*/
|
||||
clear():xFileSListType[]{
|
||||
this.filelist = [] as xFileSNameTYpe[];
|
||||
return [] as xFileSListType[]
|
||||
}
|
||||
copyFileToPath(item:xFileSListType,path:string):Promise<xFileSListType|null>{
|
||||
return Promise.resolve(item)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
|
||||
export { xFileSListType } from "../interface"
|
||||
|
||||
export type fileListType = xFileSListType;
|
||||
|
||||
|
||||
type xFileSNameTYpe = {
|
||||
name:string,
|
||||
type:string,
|
||||
uri:string,
|
||||
id:string,
|
||||
file:any,
|
||||
size:number,
|
||||
status:number
|
||||
}
|
||||
// type callReadBackFun = (byte:ByteArray)=>void
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 由于安卓隐私的问题。实际得到的所有文件 其实 都不是真实地址。因此你想要得到真实的地址,你就得复制到你的应用沙盒中。
|
||||
*/
|
||||
export class xFileSystem {
|
||||
mimeTypeFilter = [] as string[];
|
||||
filelist = [] as xFileSNameTYpe[]
|
||||
inputDom:null|HTMLInputElement = null;
|
||||
multiple:boolean = true;
|
||||
maxFileSize:number = 30*1024*1024
|
||||
constructor(typeFilter:string|null,tempmultiple:boolean|null,maxSize:number|null){
|
||||
if(typeFilter!=null){
|
||||
|
||||
let filter : string[] = [] as string[];
|
||||
let tms = typeFilter! as string[]
|
||||
for (let i = 0; i < tms.length; i++) {
|
||||
filter.push("."+tms[i])
|
||||
}
|
||||
if(filter.length==0){
|
||||
filter.push("*/*")
|
||||
}
|
||||
|
||||
this.mimeTypeFilter = filter
|
||||
}
|
||||
if(tempmultiple!=null){
|
||||
this.multiple = tempmultiple!
|
||||
}
|
||||
if(maxSize!=null){
|
||||
this.maxFileSize = maxSize!
|
||||
}
|
||||
}
|
||||
isInfilelist(file:xFileSNameTYpe):boolean{
|
||||
return this.filelist.some((el):boolean=>{
|
||||
return el.name==file.name&&el.type==file.type
|
||||
})
|
||||
}
|
||||
destory(){
|
||||
|
||||
}
|
||||
openDocument(call:(list:fileListType[])=>void){
|
||||
if(this.inputDom!=null){
|
||||
this.inputDom!.remove()
|
||||
}
|
||||
let _this = this;
|
||||
let inputdom = document.createElement("input")
|
||||
inputdom.type = 'file';
|
||||
inputdom.accept = this.mimeTypeFilter.join(", ");
|
||||
inputdom.style.setProperty('position','absolute')
|
||||
inputdom.style.setProperty('left','-200%')
|
||||
inputdom.style.setProperty('top','-200%')
|
||||
inputdom.style.setProperty('opacity','0')
|
||||
if(this.multiple){
|
||||
inputdom.multiple = "multiple"
|
||||
}
|
||||
inputdom.onchange = function(evt){
|
||||
let filelist = inputdom.files||[] as File[];
|
||||
for(let i=0;i<filelist.length;i++){
|
||||
let item = filelist[i];
|
||||
|
||||
let fileitem = {
|
||||
name:item.name,
|
||||
type:item.type.substring(item.type.lastIndexOf("/")+1),
|
||||
uri:"",
|
||||
id:Math.floor(Math.random() * 1 * Math.floor(Math.random() * Date.now())).toString().substring(0, 10),
|
||||
file:item
|
||||
size:item.size,
|
||||
status:item.size>_this.maxFileSize?4:0
|
||||
} as xFileSNameTYpe
|
||||
if(!_this.isInfilelist(fileitem)){
|
||||
_this.filelist.push(fileitem)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
call(_this.filelist.map((el)=>{
|
||||
return {
|
||||
name:el.name,
|
||||
type:el.type,
|
||||
file:el.file,
|
||||
id:el.id,
|
||||
request:null,
|
||||
realFilePath:"",
|
||||
cacheFilePath:"",
|
||||
size:el.size,
|
||||
status:el.size>_this.maxFileSize?4:0
|
||||
}
|
||||
}))
|
||||
}
|
||||
inputdom.click()
|
||||
}
|
||||
/**
|
||||
* 删除一个文件条目
|
||||
* @param {string} id - 文件id
|
||||
* @returns {fileListType[]} 最新的文件列表
|
||||
*/
|
||||
remove(id:string):fileListType[]{
|
||||
return [] as fileListType[]
|
||||
}
|
||||
/**
|
||||
* 返回一个空文件列表数组
|
||||
*/
|
||||
clear():fileListType[]{
|
||||
this.filelist = [] as xFileSNameTYpe[];
|
||||
return [] as fileListType[]
|
||||
}
|
||||
copyFileToPath(item:fileListType,path:string):Promise<fileListType|null>{
|
||||
return Promise.resolve(item)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user