@wisdomgarden/cloak-plugin-file-transfer
v0.0.1
Published
A FileTransfer Plugin of Cloak framework(A Hybrid Development Framework for HarmonyOS)
Readme
FileTransfer 插件
用于在 Cloak 应用中下载、上传文件,过程中按需上报进度。落盘范围限于应用自己的沙箱,需要声明网络权限。
安装
ohpm install @wisdomgarden/cloak-plugin-file-transfer
# 可选,用于 TypeScript 类型
npm install @wisdomgarden/cloak-plugin-file-transfer在 entry/src/main/module.json5 中声明网络权限:
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:permission_internet_reason",
"usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
}
]在 EntryAbility.ets 中注册:
import { CloakPluginFileTransfer } from '@wisdomgarden/cloak-plugin-file-transfer';
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
const cloak = new Cloak(this);
cloak.addPlugins([
// ... 其他插件
new CloakPluginFileTransfer()
]);
}使用方法
const transfer = Cloak.plugins.FileTransfer;
// 落盘路径用 Filesystem 生成,两个插件都认 file:// 形态
const { uri } = await Cloak.plugins.Filesystem.getUri({ path: 'downloads/a.pdf', directory: 'DATA' });
// 订阅进度,payload 里的 id 用来区分是哪个任务
const handlerId = transfer.addEventListener('progress', (p) => {
if (!p.lengthComputable) {
console.log(p.id, `已传 ${p.bytes} 字节,总大小未知`);
return;
}
console.log(p.id, `${Math.floor((p.bytes / p.contentLength) * 100)}%`);
});
// id 是取消句柄,由调用方自己起名,用目标路径或自己的业务 id 都行。
// 多个任务同时跑就一定要传 id:进度事件靠它认领,abort 也靠它定位。
// 下载,不传 progress 就不发进度事件
const result = await transfer.downloadFile({
id: 'a.pdf',
url: 'https://example.com/a.pdf',
path: uri,
progress: true,
headers: { Authorization: 'Bearer ...' },
});
console.log(result.path); // file:///data/.../downloads/a.pdf
// 上传,默认 POST + multipart,文件字段名默认 file
const uploaded = await transfer.uploadFile({
id: 'report',
url: 'https://example.com/upload',
path: uri,
fileKey: 'attachment',
data: { courseId: '42' },
progress: true,
});
console.log(uploaded.responseCode, uploaded.response);
// 并发多个任务,进度事件靠 id 区分
await Promise.all([
transfer.downloadFile({ id: 'first', url: url1, path: path1, progress: true }),
transfer.downloadFile({ id: 'second', url: url2, path: path2, progress: true }),
]);
// 取消单个任务,被取消的那个 Promise 以 OS-PLUG-FLTR-0012 拒绝
await transfer.abort({ id: 'first' });
// 不传 id 则取消全部在传任务
await transfer.abort();
transfer.removeEventListener('progress', handlerId);
// 失败时 reject 一个带 code 的错误
try {
await transfer.downloadFile({ url: 'https://example.com/nope', path: uri });
} catch (e) {
console.error(e.code, e.httpStatus, e.body); // OS-PLUG-FLTR-0010 404 ...
}API
方法失败时 reject 的错误见错误码。
downloadFile
downloadFile(options: DownloadFileOptions): Promise<DownloadFileResult>;下载文件到指定路径,目标的父目录缺失时自动创建。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| options | DownloadFileOptions | 是 | 下载参数 |
返回值:Promise<DownloadFileResult>
uploadFile
uploadFile(options: UploadFileOptions): Promise<UploadFileResult>;以 multipart 表单上传文件,源文件必须已存在。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| options | UploadFileOptions | 是 | 上传参数 |
返回值:Promise<UploadFileResult>
abort
abort(options?: AbortOptions): Promise<void>;取消在传的任务。传 id 只取消那一个,不传则全部取消。被取消的任务各自以 OS-PLUG-FLTR-0012 拒绝。取消一个并不在传的任务不算错误。
下载和上传的"取消"含义不同:取消下载是干净的——写了一半的文件被删掉,目标路径上原有的文件不受影响,等同于这次下载没发生过。取消上传只是断开连接,已经发出去的那部分请求体,服务端留不留、算不算一次失败的提交,插件既不知道也无法回滚,更不会替你去调撤销接口。要做到"取消即无痕",需要服务端配合(分片上传 + 显式 commit,或者取消后自行调用删除接口)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| options | AbortOptions | 否 | 要取消的任务 |
返回值:Promise<void>
接口
DownloadFileOptions
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| url | string | 是 | — | 下载地址 |
| path | string | 是 | — | 落盘路径,file:// uri 与绝对沙箱路径都收。同一个 path 不能同时有两个下载在传,后来的直接失败 |
| id | string | 否 | — | 取消句柄,自己起名(目标路径、业务 id 都行)。进度事件回显它,abort 按它定位。不传则只能被 abort() 全量取消;同一个 id 还在传时再发起会失败 |
| progress | boolean | 否 | false | 是否上报进度 |
| method | string | 否 | 'GET' | 请求方法,只接受 GET / POST。HEAD 与 OPTIONS 按定义不返回响应体,会落一个空文件,所以直接拒绝 |
| params | Record<string, string | string[]> | 否 | — | 拼到 URL 查询串,数组值展开成重复的 key |
| headers | Record<string, string> | 否 | — | 请求头 |
| overwrite | boolean | 否 | true | 目标文件已存在时是否覆盖,关掉则改为失败 |
| connectTimeout | number | 否 | 60000 | 建立连接的超时,毫秒 |
| readTimeout | number | 否 | 60000 | 传输中等待下一段数据的超时,毫秒,每次收到数据后重新计时 |
| shouldEncodeUrlParams | boolean | 否 | true | 是否对 params 做百分号编码,值已编码过时关掉,避免二次编码 |
DownloadFileResult
| 字段 | 类型 | 说明 |
|---|---|---|
| path | string | 落盘文件的完整 uri,以 file:// 开头 |
UploadFileOptions
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| url | string | 是 | — | 上传地址 |
| path | string | 是 | — | 待上传的文件,file:// uri 与绝对沙箱路径都收,文件必须存在。同一个文件可以同时传给多个地址 |
| id | string | 否 | — | 取消句柄,规则同下载 |
| progress | boolean | 否 | false | 是否上报进度 |
| method | string | 否 | 'POST' | 请求方法,只接受 POST / PUT(S3 预签名、WebDAV 用 PUT)|
| params | Record<string, string | string[]> | 否 | — | 拼到 URL 查询串 |
| headers | Record<string, string> | 否 | — | 请求头。multipart 的 Content-Type 由插件生成,自己覆盖会破坏请求体 |
| fileKey | string | 否 | 'file' | 文件部分的表单字段名 |
| fileName | string | 否 | path 的最后一段 | 文件部分的文件名 |
| mimeType | string | 否 | — | 文件部分的类型,从文件名推断不出来时才用得上 |
| data | Record<string, string> | 否 | — | 同一个表单里附带的文本字段 |
| connectTimeout | number | 否 | 60000 | 建立连接的超时,毫秒 |
| readTimeout | number | 否 | 60000 | 传输中等待下一段数据的超时,毫秒,每次收到数据后重新计时 |
| shouldEncodeUrlParams | boolean | 否 | true | 是否对 params 做百分号编码 |
UploadFileResult
| 字段 | 类型 | 说明 |
|---|---|---|
| bytesSent | number | 实际上传的字节数 |
| responseCode | string | HTTP 状态码,字符串形式 |
| response | string | 响应体,服务端给了才有 |
| headers | Record<string, string> | 响应头,key 统一小写 |
AbortOptions
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string | 否 | 要取消的任务标识,不传则取消全部在传任务 |
ProgressStatus
progress 事件的 payload。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string | 否 | 发起时传的 id,没传就没有。多任务并发时靠它认领,别指望用其它字段替代 |
| type | 'download' \| 'upload' | 是 | 这条进度属于下载还是上传 |
| url | string | 是 | 传输涉及的地址 |
| path | string | 是 | 发起时传的 path,原样回显,不做归一化。主要用于展示"正在传哪个文件"(签名 url 通常没法看) |
| bytes | number | 是 | 已传字节数 |
| contentLength | number | 是 | 总字节数,服务端没给时为 0 |
| lengthComputable | boolean | 是 | contentLength 是否可信,服务端没给 Content-Length 时为 false |
FileTransferError
所有方法失败时 reject 的对象。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 是 | 见错误码 |
| message | string | 是 | 可读的失败原因 |
| source | string | 否 | 数据来源:下载是 url,上传是文件路径 |
| target | string | 否 | 数据去向:下载是文件路径,上传是 url |
| httpStatus | number | 否 | 服务端状态码,请求走到那一步才有 |
| headers | Record<string, string> | 否 | 响应头 |
| body | string | 否 | 错误响应体 |
| exception | string | 否 | 鸿蒙侧的原始错误信息 |
事件
用 addEventListener 订阅,返回的 handler id 可以传给 removeEventListener 精确移除;不传 id 则移除该事件的全部 handler。
| 事件 | payload | 说明 |
|---|---|---|
| progress | ProgressStatus | 只有 progress: true 的任务才发。每个任务各自 100ms 节流一次,完成时补发一次全量;多个任务并发时靠 payload 里的 id 区分,所以并发场景务必给每个任务传 id |
错误码
| code | 说明 |
|---|---|
| OS-PLUG-FLTR-0004 | 参数非法:缺 url/path,或 id 与在传任务重名,或下载的目标 path 已被在传任务占用 |
| OS-PLUG-FLTR-0005 | URL 为空或解析不了 |
| OS-PLUG-FLTR-0006 | 网络权限被拒,通常是没声明 ohos.permission.INTERNET |
| OS-PLUG-FLTR-0007 | 上传的源文件不存在 |
| OS-PLUG-FLTR-0008 | 连接不上服务器 |
| OS-PLUG-FLTR-0009 | 服务端返回 HTTP 304,检查与缓存相关的请求头 |
| OS-PLUG-FLTR-0010 | 其余 HTTP 错误,httpStatus / headers / body 里带响应详情 |
| OS-PLUG-FLTR-0011 | 其余失败,exception 里带鸿蒙原始错误 |
| OS-PLUG-FLTR-0012 | 任务被 abort 取消 |
| OS-PLUG-FLTR-0013 | 文件读写被拒(沙箱外的路径、或没有权限的目录),message 里带出错路径 |
关于 Cloak
Cloak 是专为 HarmonyOS 设计的混合开发框架,类似 Cordova 和 Capacitor,但具备 更轻量、更高性能 的特性。
该框架可将 Web 应用快速转换为原生应用,同时通过插件机制访问 HarmonyOS 原生能力。
核心特性
- 快速打包:将 H5 应用快速编译为 HarmonyOS 应用。
- 原生能力访问:通过插件机制调用原生接口。
- WebView 支持:提供高性能 WebView 容器,确保 H5 应用流畅运行。
- 插件开发:支持开发者自定义插件以扩展原生功能。
更多关于 Cloak 框架信息,请查看: https://github.com/WisdomGardenInc/Cloak
