first commit

This commit is contained in:
2026-06-02 10:42:33 +08:00
commit dd4975fd2c
1084 changed files with 442416 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
## 0.1.32025-09-16
- chore: 更新文档
## 0.1.22025-06-07
- chore: 更新文档
## 0.1.12025-06-02
- feat: 兼容鸿蒙next
## 0.1.02025-04-04
- chore: 更新文档
## 0.0.92025-03-11
- fix: 修复安卓报错的问题
## 0.0.82025-03-11
- fix: 修复报错的问题
## 0.0.72025-03-10
- feat: 增加重命名选项
## 0.0.62025-02-28
- feat: 修复uniapp ios路径问题
## 0.0.52024-10-31
- feat: 修复uniapp ios无法使用
## 0.0.42024-10-26
- feat: 规范类型
## 0.0.32024-07-10
- fext: 兼容ios
## 0.0.22024-05-21
- fix: 修复uniapp找不到文件的错误
## 0.0.12024-04-15
- init

View File

@@ -0,0 +1,38 @@
<template>
<view @click="onClick">
<slot></slot>
</view>
</template>
<script>
import { chooseFile } from '@/uni_modules/lime-choose-file'
export default {
props: {
disabled: Boolean
},
emits: ['success', 'fail'],
data() {
return {
images: []
}
},
methods: {
onClick() {
if(this.disabled) return
chooseFile({
success:(res)=>{
this.$emit('success', res)
},
fail(err){
this.$emit('fail', err)
}
})
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,103 @@
<template>
<view class="demo-block">
<text class="demo-block__title-text ultra">ChooseFile 文件选择</text>
<text class="demo-block__desc-text">打开系统文件管理器选择文件。</text>
<view class="demo-block__body">
<view class="demo-block card">
<text class="demo-block__title-text large">基础使用</text>
<view class="demo-block__body row">
<button @click="onClick">选择图片</button>
<image v-for="(item, index) in images" :key="index" :src="item"></image>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { chooseFile, ChooseFileOption } from '@/uni_modules/lime-choose-file'
const images = ref<string[]>([])
const onClick = () => {
chooseFile({
// filename: 'xxx',
type: 'image',
success(res) {
images.value = res.tempFiles.map((item) : string => item.path)
console.log('res', res.tempFiles)
console.log('reserrMsg', res)
},
fail(err) {
console.log('err', err)
}
} as ChooseFileOption)
}
</script>
<style lang="scss">
.row {
flex-direction: row;
flex-wrap: wrap;
}
.btn {
margin-bottom: 20rpx;
margin-right: 20rpx;
}
.demo-block {
margin: 32px 10px 0;
// overflow: visible;
&.card {
background-color: white;
padding: 30rpx;
margin-bottom: 20rpx !important;
}
&__title {
margin: 0;
margin-top: 8px;
&-text {
color: rgba(0, 0, 0, 0.6);
font-weight: 400;
font-size: 14px;
line-height: 16px;
display: flex;
&.large {
color: rgba(0, 0, 0, 0.9);
font-size: 18px;
font-weight: 700;
line-height: 26px;
}
&.ultra {
color: rgba(0, 0, 0, 0.9);
font-size: 24px;
font-weight: 700;
line-height: 32px;
}
}
}
&__desc-text {
color: rgba(0, 0, 0, 0.6);
margin: 8px 16px 0 0;
font-size: 14px;
line-height: 22px;
}
&__body {
margin: 16px 0;
overflow: visible;
.demo-block {
// margin-top: 0px;
margin: 0;
}
}
}
</style>

View File

@@ -0,0 +1,36 @@
<template>
<view>
<button @click="onClick">选图</button>
<image v-for="(item, index) in images" :key="index" :src="item"></image>
</view>
</template>
<script>
import { chooseFile } from '@/uni_modules/lime-choose-file'
export default {
data() {
return {
images: []
}
},
methods: {
onClick() {
chooseFile({
type: 'image',
success:(res)=>{
this.images = res.tempFiles.map((item) => item.path)
console.log('res', res.tempFiles)
},
fail(err){
console.log('err', err)
}
})
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,2 @@
<EFBFBD>,<2C>P<EFBFBD><50>=<3D>[&<26>۸<>6<EFBFBD>
<1B>I<EFBFBD>T<EFBFBD> ]<5D><>r<EFBFBD><72><EFBFBD><EFBFBD>*<2A>I<EFBFBD>F<EFBFBD>܃<EFBFBD>C咺+<16><>E<>|<7C>q<EFBFBD>`(<28><><EFBFBD><EFBFBD>I_<49>+D<><16>Zs<5A>f<EFBFBD>V<EFBFBD><56><EFBFBD><EFBFBD>q<EFBFBD><71>gqݰ<71><DDB0><EFBFBD>IC*<2A>N<EFBFBD><4E>R<EFBFBD>W<EFBFBD>O<EFBFBD><17><>5<EFBFBD>@\7<>ta<74><61> `e<>7<EFBFBD><37><EFBFBD>H<EFBFBD><48>F:D<><44><EFBFBD>r<EFBFBD><72>|<7C><>#

View File

@@ -0,0 +1,105 @@
{
"id": "lime-choose-file",
"displayName": "lime-choose-file 文件选择",
"version": "0.1.3",
"description": "lime-choose-file 文件选择参考uni.chooseFile API实现的UTS API用法保持一致从本地选择文件。兼容uniapp/uniappX",
"keywords": [
"chooseFile",
"文件选择",
"uts"
],
"repository": "",
"engines": {
"HBuilderX": "^4.11",
"uni-app": "^4.61",
"uni-app-x": "^4.61"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": {
"price": "29.00"
},
"sourcecode": {
"price": "268.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": {
"extVersion": "",
"minVersion": "21"
},
"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": "√"
}
}
}
}
}
}

View File

@@ -0,0 +1,61 @@
# lime-choosefile 文件选择
文件选择UTS API系参考小程序chooseFile API实现的用法保持一致目前仅支持uniappX(web,ios,安卓,鸿蒙)
## 文档
🚀 [choose-file【站点1】](https://limex.qcoon.cn/native/choose-file.html)
🌍 [choose-file【站点2】](https://limeui.netlify.app/native/choose-file.html)
🔥 [choose-file【站点3】](https://limeui.familyzone.top/native/choose-file.html)
## 安装
插件市场导入APP需要在页面上引入然后自定义基座完成自定义基座后选择自定义基座运行
## 使用
### UNIAPPX
```js
import { chooseFile, type ChooseFileOption } from '@/uni_modules/lime-choose-file'
const images = ref<string[]>([])
const onClick = () => {
chooseFile({
filename: 'xxxx', // 可选 用于给文件重命名安卓、IOS
type: 'image',
success(res){
images.value = res.tempFiles.map((item):string => item.path)
console.log('res', res.tempFiles)
},
fail(err){
console.log('err', err)
}
} as ChooseFileOption)
}
```
### UNIAPP
```js
import { chooseFile } from '@/uni_modules/lime-choose-file'
const images = ref<string[]>([])
const onClick = () => {
chooseFile({
filename: 'xxxx', // 可选 用于给文件重命名安卓、IOS
type: 'image',
success(res){
images.value = res.tempFiles.map((item):string => item.path)
console.log('res', res.tempFiles)
},
fail(err){
console.log('err', err)
}
})
}
```
## 常见问题
- 1、IOS路径是中文时无法上传到服务器这时候需要设置`filename`给文件重命名
## API
因为直接参照小程序`chooseFile`API所以可以直接按[chooseFile](https://uniapp.dcloud.net.cn/api/media/file.html#choosefile)文档来

View File

@@ -0,0 +1,126 @@
# lime-choose-file 文件选择组件
一个基于UTS实现的文件选择插件参考小程序chooseFile API实现用法保持一致。支持安卓、iOS、鸿蒙和H5平台。提供了选择图片、视频和其他文件类型的功能。组件提供了简单易用的API使开发者能够方便地在应用中集成文件选择功能。
## 文档链接
📚 组件详细文档请访问以下站点:
- [文件选择组件文档 - 站点1](https://limex.qcoon.cn/native/choose-file.html)
- [文件选择组件文档 - 站点2](https://limeui.netlify.app/native/choose-file.html)
- [文件选择组件文档 - 站点3](https://limeui.familyzone.top/native/choose-file.html)
## 安装方法
1. 在uni-app插件市场中搜索并导入`lime-choose-file`
2. 导入后在页面引入相关方法
3. 需要自定义基座才能使用
4. 试用符合需求后才购买,插件无法退款
## 代码演示
### UNIAPPX 使用方式
```ts
import { chooseFile, type ChooseFileOption } from '@/uni_modules/lime-choose-file'
const images = ref<string[]>([])
const onClick = () => {
chooseFile({
filename: 'xxxx', // 可选 用于给文件重命名安卓、iOS
type: 'image',
success(res){
images.value = res.tempFiles.map((item):string => item.path)
console.log('选择结果:', res.tempFiles)
},
fail(err){
console.log('选择失败:', err)
}
} as ChooseFileOption)
}
```
### UNIAPP 使用方式
```ts
import { chooseFile } from '@/uni_modules/lime-choose-file'
const images = ref<string[]>([])
const onClick = () => {
chooseFile({
filename: 'xxxx', // 可选 用于给文件重命名安卓、iOS
type: 'image',
success(res){
images.value = res.tempFiles.map((item):string => item.path)
console.log('选择结果:', res.tempFiles)
},
fail(err){
console.log('选择失败:', err)
}
})
}
```
## API文档
### chooseFile 方法
| 参数 | 说明 | 类型 | 必填 |
| --- | --- | --- | --- |
| options | 文件选择选项 | _ChooseFileOption_ | 是 |
### ChooseFileOption 选项
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| filename | _string_ | 否 | 指定文件名用于给文件重命名安卓、iOS |
| count | _number_ | 否 | 最多可以选择的文件数量默认为100 |
| type | _string_ | 否 | 所选文件类型,默认为'all' |
| extension | _string[]_ | 否 | 根据文件拓展名过滤每一项都不能是空字符串。默认不过滤。仅H5支持 |
| success | _(result: ChooseFileSuccessCallbackResult) => void_ | 否 | 接口调用成功的回调函数 |
| fail | _(res: GeneralCallbackResult) => void_ | 否 | 接口调用失败的回调函数 |
| complete | _(res: GeneralCallbackResult) => void_ | 否 | 接口调用结束的回调函数 |
### ChooseFileSuccessCallbackResult 返回参数
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| tempFiles | _ChooseFile[]_ | 返回选择的文件的本地临时文件对象数组 |
| errMsg | _string_ | 错误信息 |
### ChooseFile 对象结构
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| name | _string_ | 选择的文件名称 |
| path | _string_ | 本地临时文件路径 (本地路径) |
| size | _number_ | 本地临时文件大小,单位 B |
| time | _number_ | 选择的文件的会话发送时间Unix时间戳 |
| type | _'video' \| 'image' \| 'file' \| 'all'_ | 选择的文件类型 |
### 文件类型说明
| 类型值 | 说明 |
| --- | --- |
| video | 视频文件 |
| image | 图片文件 |
| file | 除图片和视频外的其他文件 |
| all | 所有类型文件 |
## 功能特点
- 支持多种文件类型的选择,包括图片、视频和其他文件
- 支持文件重命名功能
- 兼容安卓、iOS、鸿蒙和H5平台
- 提供简单易用的API接口
- 支持指定最大选择数量
- 支持文件扩展名过滤H5平台
## 常见问题
- iOS路径是中文时无法上传到服务器这时候需要设置`filename`给文件重命名
- APP端需要自定义基座才能使用
- 文件选择后会返回临时文件路径,需要及时使用或保存
- H5端可以通过extension参数过滤文件类型
## 支持与赞赏
如果你觉得本插件解决了你的问题,可以考虑支持作者:
| 支付宝赞助 | 微信赞助 |
|------------|------------|
| ![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png) | ![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png) |

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.limeui.chooseFile">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>

View File

@@ -0,0 +1,3 @@
{
"minSdkVersion": "21"
}

View File

@@ -0,0 +1,206 @@
// @ts-nocheck
import Intent from 'android.content.Intent';
import ClipData from 'android.content.ClipData';
import Uri from 'android.net.Uri';
import InputStream from 'java.io.InputStream';
import OpenableColumns from 'android.provider.OpenableColumns';
import Cursor from 'android.database.Cursor';
import File from 'java.io.File';
import FileInputStream from 'java.io.FileInputStream';
import FileOutputStream from 'java.io.FileOutputStream';
import BufferedOutputStream from 'java.io.BufferedOutputStream';
import ByteArrayInputStream from 'java.io.ByteArrayInputStream';
import { ChooseFileOption, ChooseFile, ChooseFileSuccessCallbackResult } from '../interface'
import { GeneralCallbackResultImpl } from '../unierror'
const REQUEST_CODE_CHOOSE_FILE : Int = 42
let resultFunction : ((requestCode : Int, resultCode : Int, data ?: Intent) => void) | null = null
class ChooseFileImpl implements ChooseFile {
name : string = ''
path : string = ''
// private _path : string = ''
size : number = 0
time : number = 0
type : string = 'file'
// private uri : Uri
private options: ChooseFileOption
constructor(uri : Uri, options : ChooseFileOption) {
// this.uri = uri
this.options = options
this.time = Date.now()
this.type = this.getFileTypeFromUri(uri);
// this._path = uri.getPath() ?? ''
this.getFileInfoFromUri(uri)
if (this.isCache(options)) {
this.copyFileToCache(uri)
}
}
private isCache(options : ChooseFileOption) : boolean {
const extension = this.getFileExtension(this.name)
const extensions = options.extension
const type = options.type ?? 'all'
const hasExtension = extensions != null && extension != '' && extensions.includes(extension)
const isVideoOrImage = ['video', 'image'].includes(type)
const isFileAndNotVideoOrImage = type == 'file' && !['video', 'image'].includes(this.type);
if ((type == 'all' || isVideoOrImage || isFileAndNotVideoOrImage) && !hasExtension) {
return true
} else {
return false
}
}
private getFileExtension(fileName : string) : string {
const lastDotIndex = fileName.lastIndexOf(".");
if (lastDotIndex == -1) {
return "";
}
return fileName.substring(lastDotIndex + 1);
}
private copyFileToCache(uri : Uri) {
const cacheDir = UTSAndroid.getAppCachePath();
const context = UTSAndroid.getAppContext();
if(cacheDir != null) {
const path = new File(cacheDir);
if (!path.exists()) {
path.mkdir();
}
}
let fileName = this.name
if(this.options.filename != null) {
fileName = this.options.filename!;
if(this.options.count != null && this.options.count! > 1) {
fileName = `${fileName}_${Date.now()}`;
}
const extension = this.getFileExtension(this.name)
fileName = `${fileName}.${extension}`
}
const destFile = new File(cacheDir, fileName);
try {
const inputStream = context!.getContentResolver().openInputStream(uri)
const outputStream = new FileOutputStream(destFile)
if (inputStream != null) {
let buffer = ByteArray(1024);
let c = inputStream.read(buffer)
while (c > 0) {
outputStream.write(buffer, 0, c);
c = inputStream.read(buffer)
}
}
this.path = cacheDir + fileName//this.name
} catch (e) {
}
}
private getFileTypeFromUri(uri : Uri) : string {
const context = UTSAndroid.getAppContext();
let fileType = 'file'
let mimeType = context!.getContentResolver().getType(uri);
if (mimeType != null) {
if (mimeType.startsWith("video")) {
fileType = "video";
} else if (mimeType.startsWith("image")) {
fileType = "image";
}
}
return fileType;
}
private getFileInfoFromUri(uri : Uri) {
const context = UTSAndroid.getAppContext();
let cursor = context!.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
this.name = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
const fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(OpenableColumns.SIZE));
this.size = Number.from(fileSize)
cursor.close();
} else if ("file".equals(uri.getScheme())) {
this.name = uri.getLastPathSegment() ?? '';
const file = new File(uri.getPath() ?? '');
const fileSize = file.length();
this.size = Number.from(fileSize)
}
}
}
export function chooseFile(options : ChooseFileOption) {
if (resultFunction != null) {
UTSAndroid.offAppActivityResult(resultFunction!)
}
const type = options.type ?? 'all'
const intent = new Intent(Intent.ACTION_GET_CONTENT);
if (type.equals("all") || type.equals("file")) {
intent.setType("*/*");
} else if (type.equals("video")) {
intent.setType("video/*");
} else if (type.equals("image")) {
intent.setType("image/*");
}
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, options.count == 1 ? false : true); // 允许多选
resultFunction = (requestCode : Int, resultCode : Int, data ?: Intent) => {
if (requestCode == REQUEST_CODE_CHOOSE_FILE) {
UTSAndroid.offAppActivityResult(resultFunction!);
if (resultCode == -1 && data != null) {
const clipData = data.getClipData();
const tempFiles : ChooseFile[] = []
if (clipData != null) {
// 多选
// const itemCount = clipData.getItemCount();
// if (options.count != null && options.count! > itemCount) {
// const err = new GeneralCallbackResultImpl(9010002, `选中文件数量超过${options.count}`)
// options.fail?.(err)
// options.complete?.(err)
// return
// }
for (let i = 0; i < clipData.getItemCount(); i++) {
const uri = clipData.getItemAt(i.toInt()).getUri();
const chooseFile = new ChooseFileImpl(uri, options);
if(chooseFile.path !=''){
tempFiles.push(chooseFile)
}
}
} else {
// 单选
const uri = data.getData();
if (uri != null) {
const chooseFile = new ChooseFileImpl(uri, options)
if(chooseFile.path !='' ){
tempFiles.push(chooseFile)
}
}
}
const count = options.count ?? Integer.MAX_VALUE // Number.MAX_VALUE
if(tempFiles.length > 0 && count >= tempFiles.length){
options.success?.({
tempFiles,
errMsg: 'chooseFile:ok'
} as ChooseFileSuccessCallbackResult)
} else {
const err = new GeneralCallbackResultImpl(9010002, `没有可用的文件或文件超过设置数量`)
options.fail?.(err)
options.complete?.(err)
}
} else {
const err = new GeneralCallbackResultImpl(9010002, `没有可用的文件`)
options.fail?.(err)
options.complete?.(err)
}
} else {
const err = new GeneralCallbackResultImpl(9010002, `没有可用的文件`)
options.fail?.(err)
options.complete?.(err)
}
}
UTSAndroid.onAppActivityResult(resultFunction!)
UTSAndroid.getUniActivity()!.startActivityForResult(Intent.createChooser(intent, "选择文件"), REQUEST_CODE_CHOOSE_FILE)
// UTSAndroid.getUniActivity()!.overridePendingTransition((10).toInt(), (0).toInt());
}

View File

@@ -0,0 +1,3 @@
{
"deploymentTarget": "9"
}

View File

@@ -0,0 +1,138 @@
// @ts-nocheck
import { ChooseFileOption, ChooseFile, ChooseFileSuccessCallbackResult } from '../interface'
import { UIDocumentPickerDelegate, UIDocumentPickerMode } from "UIKit"
import { URL, FileManager } from 'Foundation';
import { GeneralCallbackResultImpl } from '../unierror'
import { DispatchQueue } from 'Dispatch';
const documentTypes : Map<string, string[]> = new Map([
["all", ["public.item"]],
["file", [
"public.text",
"public.zip-archive",
"public.data",
"com.adobe.pdf",
"com.microsoft.word.doc",
"com.microsoft.word.docx",
"com.microsoft.excel.xls",
"com.microsoft.excel.xlsx"
]
],
["video", ["public.movie"]],
["image", ["public.image"]],
])
class ChooseFileImpl {
name : string = ''
path : string = ''
size : number = 0
time : number = 0
type : string = 'file'
constructor(uri : URL, options : ChooseFileOption) {
try {
const originalFileName = uri.lastPathComponent;
const attributes = UTSiOS.try(FileManager.default.attributesOfItem(atPath = uri.path))
const fileSize = attributes[FileAttributeKey.size] as number
const pathExtension = `${uri.pathExtension}`
const imageFormats = ['jpeg', 'jpg', 'png', 'gif', 'bmp', 'tiff', 'svg']
const videoFormats = ['mov', 'm4v', 'mp4', 'avi']
let fileName = originalFileName
if(options.filename != null) {
fileName = options.filename!
if(options.count != null && options.count! > 1) {
fileName = `${fileName}_${Date.now()}`;
}
fileName = `${fileName}.${pathExtension}`
}
// #ifdef UNI-APP-X
const dataPath = UTSiOS.getDataPath()
// #endif
// #ifndef UNI-APP-X
const dataPath = UTSiOS.getDataPath().replace(/data$/, "doc");
// #endif
const file = new URL(fileURLWithPath = dataPath).appendingPathComponent(fileName)//.absoluteString
const fileData = FileManager.default.contents(atPath = uri.path);
UTSiOS.try(fileData?.write(to = file))
if (imageFormats.includes(pathExtension)) {
this.type = 'image'
} else if (videoFormats.includes(pathExtension)) {
this.type = 'video'
} else {
this.type = 'file'
}
this.name = `${originalFileName}`
this.size = fileSize
this.path = `${file.absoluteString}`
} catch (e) {
}
}
}
class FilePickerManager implements UIDocumentPickerDelegate {
options : ChooseFileOption = {}
constructor() { }
chooseFile(options : ChooseFileOption) {
DispatchQueue.main.async(execute = () : void => {
this.options = options
const type = options.type ?? 'all'
const count = options.count ?? 1
const types = (documentTypes.get(type) ?? documentTypes.get('all')) as string[]
let documentPicker = UIDocumentPickerViewController(
documentTypes = types,
in = UIDocumentPickerMode.import
)
documentPicker.delegate = this
// 多选要大于 ios11
if (UTSiOS.available("iOS 11.0, *")) {
documentPicker.allowsMultipleSelection = count > 1
}
UTSiOS.getCurrentViewController().present(documentPicker, animated = true)
})
}
documentPicker(controller : UIDocumentPickerViewController, @argumentLabel("didPickDocumentsAt") urls : URL[]) {
DispatchQueue.main.async(execute = () : void => {
const tempFiles : ChooseFile[] = []
for (let i = 0; i < urls.length; i++) {
const url = urls[i]
const chooseFile = new ChooseFileImpl(url, this.options);
// IOS -> js 无法传class?
const file : ChooseFile = {
name: chooseFile.name,
path: chooseFile.path,
size: chooseFile.size,
time: chooseFile.time,
type: chooseFile.type,
}
if (chooseFile.path != '') {
tempFiles.push(file)
}
}
const count = this.options.count ?? Number.from(Double.greatestFiniteMagnitude) //Number.from(Double.MAX_VALUE)
if (tempFiles.length > 0 && count >= tempFiles.length) {
const res : ChooseFileSuccessCallbackResult = {
tempFiles,
errMsg: 'chooseFile:ok'
}
this.options.success?.(res)
} else {
const err = new GeneralCallbackResultImpl(9010002, `没有可用的文件或文件超过设置数量`)
this.options.fail?.(err)
this.options.complete?.(err)
}
})
}
}
const fileManager = new FilePickerManager()
export function chooseFile(options : ChooseFileOption) {
fileManager.chooseFile(options)
}

View File

@@ -0,0 +1,35 @@
// @ts-nocheck
export * from './interface';
import { type ChooseFileOption } from './interface';
export function chooseFile(options: ChooseFileOption){
// #ifdef WEB || APP-HARMONY
uni.chooseFile({
count: options.count ?? 100,
type: options.type,
extension: options.extension,
success(res) {
options.success?.({
// tempFilePaths
errMsg : 'ok',
tempFiles: res.tempFiles
})
},
fail(err) {
options.fail?.({
errCode: err.errCode,
errSubject: 'lime-choose-file'
})
},
complete(res) {
// options.complete?.(res)
}
})
// #endif
// #ifdef MP-WEIXIN
uni.chooseMessageFile(options)
// #endif
// #ifndef WEB || MP-WEIXIN || APP-HARMONY
console.error('chooseFile 不支持该平台')
// #endif
}

View File

@@ -0,0 +1,108 @@
// @ts-nocheck
/**
* 错误码
* 根据uni错误码规范要求建议错误码以90开头以下是错误码示例
* - 9010001 错误信息1
* - 9010002 错误信息2
*/
export type ChooseFileErrorCode = 9010001 | 9010002 | 1101001 | 1101002 | 1101003 | 1101004 | 1101005 | 1101006 | 1101007 | 1101008 | 1101009 | 1101010;
/**
* myApi 的错误回调参数
*/
export interface GeneralCallbackResult extends IUniError {
errCode : ChooseFileErrorCode
};
/** 返回选择的文件的本地临时文件对象数组 */
// #ifdef APP-ANDROID
export interface ChooseFile {
/** 选择的文件名称 */
name : string
/** 本地临时文件路径 (本地路径) */
path : string
/** 本地临时文件大小,单位 B */
size : number
/** 选择的文件的会话发送时间Unix时间戳工具暂不支持此属性 */
time : number
/** 选择的文件类型
*
* 可选值:
* - 'video': 选择了视频文件;
* - 'image': 选择了图片文件;
* - 'file': 选择了除图片和视频的文件; */
type : 'video' | 'image' | 'file' | 'all'
}
// #endif
// #ifndef APP-ANDROID
export type ChooseFile = {
/** 选择的文件名称 */
name : string
/** 本地临时文件路径 (本地路径) */
path : string
/** 本地临时文件大小,单位 B */
size : number
/** 选择的文件的会话发送时间Unix时间戳工具暂不支持此属性 */
time : number
/** 选择的文件类型
*
* 可选值:
* - 'video': 选择了视频文件;
* - 'image': 选择了图片文件;
* - 'file': 选择了除图片和视频的文件; */
type : 'video' | 'image' | 'file' | 'all'
}
// #endif
export type ChooseFileSuccessCallbackResult = {
/** 返回选择的文件的本地临时文件对象数组 */
tempFiles : ChooseFile[],
errMsg : string
}
/** 接口调用成功的回调函数 */
export type ChooseFileSuccessCallback = (
result : ChooseFileSuccessCallbackResult
) => void
/** 接口调用失败的回调函数 */
export type ChooseFileFailCallback = (res : GeneralCallbackResult) => void
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
export type ChooseFileCompleteCallback = (
res : GeneralCallbackResult
) => void
export type ChooseFileOption = {
/**
* 指定文件名,如果是多选就在后面增加上时间
*/
filename?: string
/**
* 最多可以选择的文件数量。
* @defaultValue 100
*/
count ?: number | null,
/**
* 所选文件类型
* @defaultValue all
*/
type ?: string | null,
/**
* 根据文件拓展名过滤每一项都不能是空字符串。默认不过滤。仅H5支持
*/
extension ?: (string[]) | null,
/**
* 成功则返回图片的本地文件路径列表 tempFilePaths
*/
success ?: ChooseFileSuccessCallback | null,
/**
* 接口调用失败的回调函数
*/
fail ?: ChooseFileFailCallback | null,
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete ?: ChooseFileCompleteCallback | null
}

View File

@@ -0,0 +1,40 @@
// @ts-nocheck
/* 此规范为 uni 规范,可以按照自己的需要选择是否实现 */
import { ChooseFileErrorCode, GeneralCallbackResult } from "./interface.uts"
/**
* 错误主题
* 注意:错误主题一般为插件名称,每个组件不同,需要使用时请更改。
* [可选实现]
*/
export const UniErrorSubject = 'chooseFile"';
/**
* 错误信息
* @UniError
* [可选实现]
*/
export const UniErrors : Map<ChooseFileErrorCode, string> = new Map([
/**
* 错误码及对应的错误信息
*/
[9010001, 'chooseFile:ok'],
[9010002, 'ChooseFile:failed'],
]);
/**
* 错误对象实现
*/
export class GeneralCallbackResultImpl extends UniError implements GeneralCallbackResult {
/**
* 错误对象构造函数
*/
constructor(errCode : ChooseFileErrorCode, errMsg: string|null = null) {
super();
this.errSubject = UniErrorSubject;
this.errCode = errCode;
this.errMsg = errMsg ?? UniErrors[errCode] ?? "";
}
}

View File

@@ -0,0 +1 @@
"use strict";function t(t){for(var e=Object.create(null),n=t.attributes.length;n--;)e[t.attributes[n].name]=t.attributes[n].value;return e}function e(){a[1]&&(this.src=a[1],this.onerror=null),this.onclick=null,this.ontouchstart=null,uni.postMessage({data:{action:"onError",source:"img",attrs:t(this)}})}function n(){window.unloadimgs-=1,0===window.unloadimgs&&uni.postMessage({data:{action:"onReady"}})}function o(r,s,c){for(var d=0;d<r.length;d++)!function(){var u,l=r[d];if(l.type&&"node"!==l.type)u=document.createTextNode(l.text.replace(/&amp;/g,"&"));else{var g=l.name;"svg"===g&&(c="http://www.w3.org/2000/svg"),"html"!==g&&"body"!==g||(g="div"),u=c?document.createElementNS(c,g):document.createElement(g);for(var p in l.attrs)u.setAttribute(p,l.attrs[p]);if(l.children&&o(l.children,u,c),"img"===g){if(window.unloadimgs+=1,u.onload=n,u.onerror=n,!u.src&&u.getAttribute("data-src")&&(u.src=u.getAttribute("data-src")),l.attrs.ignore||(u.onclick=function(e){e.stopPropagation(),uni.postMessage({data:{action:"onImgTap",attrs:t(this)}})}),a[2]){var h=new Image;h.src=u.src,u.src=a[2],h.onload=function(){u.src=this.src},h.onerror=function(){u.onerror()}}u.onerror=e}else if("a"===g)u.addEventListener("click",function(e){e.stopPropagation(),e.preventDefault();var n,o=this.getAttribute("href");o&&"#"===o[0]&&(n=(document.getElementById(o.substr(1))||{}).offsetTop),uni.postMessage({data:{action:"onLinkTap",attrs:t(this),offset:n}})},!0);else if("video"===g||"audio"===g)i.push(u),l.attrs.autoplay||l.attrs.controls||u.setAttribute("controls","true"),u.onplay=function(){if(uni.postMessage({data:{action:"onPlay"}}),a[3])for(var t=0;t<i.length;t++)i[t]!==this&&i[t].pause()},u.onerror=function(){uni.postMessage({data:{action:"onError",source:g,attrs:t(this)}})};else if("table"===g&&a[4]&&!u.style.cssText.includes("inline")){var f=document.createElement("div");f.style.overflow="auto",f.appendChild(u),u=f}else"svg"===g&&(c=void 0)}s.appendChild(u)}()}document.addEventListener("UniAppJSBridgeReady",function(){document.body.onclick=function(){return uni.postMessage({data:{action:"onClick"}})},uni.postMessage({data:{action:"onJSBridgeReady"}})});var a,i=[];window.setContent=function(t,e,n){var r=document.getElementById("content");e[0]&&(document.body.style.cssText=e[0]),e[5]||(r.style.userSelect="none"),n||(r.innerHTML="",i=[]),a=e,window.unloadimgs=0;var s=document.createDocumentFragment();o(t,s),r.appendChild(s);var c=r.scrollHeight;uni.postMessage({data:{action:"onLoad",height:c}}),window.unloadimgs||uni.postMessage({data:{action:"onReady",height:c}}),clearInterval(window.timer),window.timer=setInterval(function(){r.scrollHeight!==c&&(c=r.scrollHeight,uni.postMessage({data:{action:"onHeightChange",height:c}}))},350)},window.onunload=function(){clearInterval(window.timer)};

View File

@@ -0,0 +1 @@
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function t(e,t){return n.call(e,t)}var i=[],a=function(e,n){var t={options:{timestamp:+new Date},name:e,arg:n};if(window.__dcloud_weex_postMessage||window.__dcloud_weex_){if("postMessage"===e){var a={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(a):window.__dcloud_weex_.postMessage(JSON.stringify(a))}var o={type:"WEB_INVOKE_APPSERVICE",args:{data:t,webviewIds:i}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(o):window.__dcloud_weex_.postMessageToService(JSON.stringify(o))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:t,pageId:""},"*");if(0===i.length){var r=plus.webview.currentWebview();if(!r)throw new Error("plus.webview.currentWebview() is undefined");var d=r.parent(),s="";s=d?d.id:r.id,i.push(s)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:t,webviewIds:i}},"__uniapp__service");else{var w=JSON.stringify(t);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(w,",").concat(JSON.stringify(i),");"))}},o={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;a("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;a("redirectTo",{url:encodeURI(n)})},getEnv:function(e){window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};a("postMessage",e.data||{})}},r=/uni-app/i.test(navigator.userAgent),d=/Html5Plus/i.test(navigator.userAgent),s=/complete|loaded|interactive/;var w=window.my&&navigator.userAgent.indexOf("AlipayClient")>-1;var u=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var c=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var g=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var v=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);for(var l,_=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},f=[function(e){if(r||d)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&s.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),o},function(e){if(v)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(c)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(w){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(u)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){return document.addEventListener("DOMContentLoaded",e),o}],m=0;m<f.length&&!(l=f[m](_));m++);l||(l={});var E="undefined"!=typeof uni?uni:{};if(!E.navigateTo)for(var b in l)t(l,b)&&(E[b]=l[b]);return E.webView=l,E}));

View File

@@ -0,0 +1 @@
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><style>body,html{width:100%;height:100%;overflow-x:scroll;overflow-y:hidden}body{margin:0}video{width:300px;height:225px}img{max-width:100%;-webkit-touch-callout:none}</style></head><body><div id="content" style="overflow:hidden"></div><script type="text/javascript" src="./js/uni.webview.min.js"></script><script type="text/javascript" src="./js/handler.js"></script></body>