first commit
This commit is contained in:
26
uni_modules/lime-choose-file/changelog.md
Normal file
26
uni_modules/lime-choose-file/changelog.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## 0.1.3(2025-09-16)
|
||||
- chore: 更新文档
|
||||
## 0.1.2(2025-06-07)
|
||||
- chore: 更新文档
|
||||
## 0.1.1(2025-06-02)
|
||||
- feat: 兼容鸿蒙next
|
||||
## 0.1.0(2025-04-04)
|
||||
- chore: 更新文档
|
||||
## 0.0.9(2025-03-11)
|
||||
- fix: 修复安卓报错的问题
|
||||
## 0.0.8(2025-03-11)
|
||||
- fix: 修复报错的问题
|
||||
## 0.0.7(2025-03-10)
|
||||
- feat: 增加重命名选项
|
||||
## 0.0.6(2025-02-28)
|
||||
- feat: 修复uniapp ios路径问题
|
||||
## 0.0.5(2024-10-31)
|
||||
- feat: 修复uniapp ios无法使用
|
||||
## 0.0.4(2024-10-26)
|
||||
- feat: 规范类型
|
||||
## 0.0.3(2024-07-10)
|
||||
- fext: 兼容ios
|
||||
## 0.0.2(2024-05-21)
|
||||
- fix: 修复uniapp找不到文件的错误
|
||||
## 0.0.1(2024-04-15)
|
||||
- init
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
2
uni_modules/lime-choose-file/encrypt
Normal file
2
uni_modules/lime-choose-file/encrypt
Normal 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><>#
|
||||
105
uni_modules/lime-choose-file/package.json
Normal file
105
uni_modules/lime-choose-file/package.json
Normal 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": "√"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
61
uni_modules/lime-choose-file/readme copy.md
Normal file
61
uni_modules/lime-choose-file/readme copy.md
Normal 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)文档来
|
||||
126
uni_modules/lime-choose-file/readme.md
Normal file
126
uni_modules/lime-choose-file/readme.md
Normal 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参数过滤文件类型
|
||||
|
||||
## 支持与赞赏
|
||||
|
||||
如果你觉得本插件解决了你的问题,可以考虑支持作者:
|
||||
|
||||
| 支付宝赞助 | 微信赞助 |
|
||||
|------------|------------|
|
||||
|  |  |
|
||||
@@ -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>
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"minSdkVersion": "21"
|
||||
}
|
||||
206
uni_modules/lime-choose-file/utssdk/app-android/index.uts
Normal file
206
uni_modules/lime-choose-file/utssdk/app-android/index.uts
Normal 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());
|
||||
}
|
||||
3
uni_modules/lime-choose-file/utssdk/app-ios/config.json
Normal file
3
uni_modules/lime-choose-file/utssdk/app-ios/config.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deploymentTarget": "9"
|
||||
}
|
||||
138
uni_modules/lime-choose-file/utssdk/app-ios/index.uts
Normal file
138
uni_modules/lime-choose-file/utssdk/app-ios/index.uts
Normal 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)
|
||||
}
|
||||
35
uni_modules/lime-choose-file/utssdk/index.uts
Normal file
35
uni_modules/lime-choose-file/utssdk/index.uts
Normal 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
|
||||
}
|
||||
108
uni_modules/lime-choose-file/utssdk/interface.uts
Normal file
108
uni_modules/lime-choose-file/utssdk/interface.uts
Normal 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
|
||||
}
|
||||
40
uni_modules/lime-choose-file/utssdk/unierror.uts
Normal file
40
uni_modules/lime-choose-file/utssdk/unierror.uts
Normal 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] ?? "";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user