更新记录

1.0.0(2026-08-01) 下载此版本

  • 首次发布

平台兼容性

uni-app(5.0)

Vue2 Vue2插件版本 Vue3 Vue3插件版本 Chrome Safari app-vue app-vue插件版本 app-nvue Android iOS 鸿蒙
1.0.0 1.0.0 × × 1.0.0 - × ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

uni-app x(5.0)

Chrome Safari Android Android插件版本 iOS 鸿蒙 微信小程序
× × 1.0.0 × × ×

⬇️ Demo 应用下载

点击下载 Demo 应用(蓝奏云)

sn-ftp 插件 API 文档

sn-ftp 是 uni-app x 的 FTP/SFTP/FTPS 客户端 UTS 插件,支持连接管理、文件上传下载(带实时进度)、文件夹递归传输、目录操作、文件列表、多编码、日志管理、保存到相册、下载目录等。

兼容性 ?

Android iOS HarmonyOS Web 小程序
x x x x

错误规范:遵循 uni 错误规范,所有异步 API 通过 UniError 返回结果,errCode = 0 表示成功,非 0 表示失败(7 位规范码)。详见 错误码

目录


connect

连接 FTP / SFTP / FTPS 服务器。异步执行,在新线程完成连接后通过 callback 返回结果。若当前已存在连接,会先自动断开再建立新连接。

SFTP 连接默认启用 keepalive(每 5 秒心跳),避免用户选择文件夹等长时间无通信场景下被服务器 idle 超时断开;session 意外断开后,传输任务会自动使用保存的连接参数重连。

参数

名称 类型 必填 描述
options FtpConnectOptions 连接参数
callback FtpCallback 结果回调,errCode = 0 表示连接成功

类型

FtpConnectOptions
名称 类型 必备 默认值 描述
host string 服务器主机地址(IP 或域名),不可为空
port number 服务器端口,FTP 默认 21,SFTP 默认 22
username string 登录用户名,匿名登录填 "anonymous"
password string "" 登录密码;匿名登录填任意字符串(如 "anonymous");SFTP key 模式可填空字符串
type FtpType 连接类型:"ftp" / "sftp" / "ftps"
mode FtpMode 传输模式:"active""passive"(仅 FTP/FTPS 有效,SFTP 忽略)
encoding FtpEncoding 编码格式:"UTF-8" / "GBK" / "GB2312" / "ISO-8859-1"
timeout number 30000 连接超时时间(毫秒)
implicit boolean | null 条件必填 null 是否使用 implicit 模式。type == "ftps" 时必填false=explicit(端口 21 + AUTH TLS 升级),true=implicit(端口 990 隐式加密);type"ftp" / "sftp" 时忽略(填 null
authMethod FtpAuthMethod | null 条件必填 null SFTP 认证方式。type == "sftp" 时必填"password" 密码登录 / "key" 秘钥登录;type"ftp" / "ftps" 时忽略(填 null
privateKeyPath string | null 条件必填 null 秘钥文件路径或 content:// URI。type == "sftp"authMethod == "key" 时必填;其它情况填 null
passphrase string "" 秘钥密码。仅当私钥本身设置了密码时填写;私钥未加密时填空字符串 ""

connect 错误码

合法值 描述
9001701 参数无效(host 为空、ftps 未填 implicit、sftp 未填 authMethod 等)
9001702 网络错误(连接失败、超时、SSL 握手失败)
9001703 认证失败(密码错误、公钥被服务器拒绝)
9001707 协议错误(FTP 服务器拒绝连接)
9001712 秘钥错误(Ed25519 不支持、加密秘钥未提供 passphrase、文件格式错误)

示例

FTP 匿名登录:

import { connect } from '@/uni_modules/sn-ftp'

connect({
    host: '192.168.1.100',
    port: 21,
    username: 'anonymous',
    password: 'anonymous',
    type: 'ftp',
    mode: 'passive',
    encoding: 'UTF-8',
    timeout: 15000,
    implicit: null,
    authMethod: null,
    privateKeyPath: null,
    passphrase: ''
}, (err) => {
    if (err.errCode == 0) {
        console.log('连接成功')
    } else {
        console.error('连接失败:' + err.errMsg)
    }
})

SFTP 秘钥登录:

import { connect } from '@/uni_modules/sn-ftp'

connect({
    host: '192.168.1.100',
    port: 22,
    username: 'root',
    password: '',
    type: 'sftp',
    mode: 'passive',
    encoding: 'UTF-8',
    timeout: 15000,
    implicit: null,
    authMethod: 'key',
    privateKeyPath: '/storage/emulated/0/id_rsa',
    passphrase: ''
}, (err) => {
    console.log(err.errCode == 0 ? '连接成功' : '连接失败:' + err.errMsg)
})

disconnect

断开当前连接。异步执行,释放 FTP/SFTP 会话与通道资源。断开前会取消所有运行中的传输任务。

参数

名称 类型 必填 描述
callback FtpCallback 结果回调

disconnect 错误码

合法值 描述
9002708 状态错误(未连接)

示例

import { disconnect } from '@/uni_modules/sn-ftp'

disconnect((err) => {
    console.log(err.errCode == 0 ? '已断开连接' : '断开失败:' + err.errMsg)
})

upload

上传本地文件或文件夹到远端服务器。异步执行,传输过程在后台线程进行,按指定间隔触发进度回调。传输完成后触发一次最终进度回调(100%)。

每次上传会创建独立任务(UUID),可通过 pauseTask / resumeTask / cancelTask 控制。

插件自动检测 localPath 类型并分发处理:

  • 单文件上传(支持断点续传):localPath 为文件系统路径或 content:// 文件 URI
  • 文件夹上传(递归,仅支持暂停/取消,不支持断点续传):localPathcontent:// 树 URI(来自 chooseFolder

文件夹上传时,remotePath 为远端目标目录路径(插件自动递归创建);进度为整体进度(所有文件累计字节数 / 总字节数)。

参数

名称 类型 必填 描述
options FtpTransferOptions 传输参数
callback FtpCallback 完成回调
progressCallback FtpProgressCallback 进度回调

返回值

类型 描述
string 任务 ID(UUID),用于 pauseTask / resumeTask / cancelTask

类型

FtpTransferOptions

上传 / 下载通用的传输参数。

名称 类型 必备 默认值 描述
localPath string 本地源/目标路径。upload:本地文件路径、content:// 文件 URI 或 content:// 树 URI(文件夹);download:content:// 树 URI(目标目录)或空字符串(默认公共下载)或文件系统路径
remotePath string 远端路径(文件或目录的绝对路径)
progressInterval number | null 1000 进度回调间隔时间(毫秒),null 时使用默认值 1000,最小 100
FtpProgress

传输进度信息(upload / download 的 progressCallback 参数类型)。

名称 类型 必备 描述
bytesTransferred number 已传输字节数
totalBytes number 总字节数
percent number 进度百分比(0-100,整数)
speed number 当前速度(字节/秒)

upload 错误码

合法值 描述
9003701 参数无效(localPath 或 remotePath 为空)
9003704 本地文件/文件夹不存在
9003706 IO 错误(读取/写入失败、连接中断)
9003708 状态错误(未连接)
9003709 传输被取消(cancelTask 调用)

示例

单文件上传:

import { upload } from '@/uni_modules/sn-ftp'

const taskId = upload({
    localPath: '/sdcard/test.txt',
    remotePath: '/var/ftp/upload/test.txt',
    progressInterval: 500
}, (err) => {
    if (err.errCode == 0) {
        console.log('上传完成')
    } else {
        console.error('上传失败:' + err.errMsg)
    }
}, (p) => {
    console.log(`进度: ${p.percent}%  速度: ${p.speed} B/s`)
})
// taskId 可用于 pauseTask(taskId, cb) / cancelTask(taskId, cb)

文件夹上传(需配合 chooseFolder):

import { upload, chooseFolder } from '@/uni_modules/sn-ftp'
import type { ChooseFolderResult } from '@/uni_modules/sn-ftp'

chooseFolder((err) => {
    if (err.errCode != 0) {
        console.error('选择文件夹失败:' + err.errMsg)
        return
    }
    const result = err.data as ChooseFolderResult  // { uri, name }
    upload({
        localPath: result.uri,  // content:// 树 URI,插件自动识别为文件夹并递归上传
        remotePath: '/var/ftp/upload/' + result.name,
        progressInterval: 500
    }, (upErr) => {
        console.log(upErr.errCode == 0 ? '文件夹上传完成' : '文件夹上传失败:' + upErr.errMsg)
    }, (p) => {
        console.log(`整体进度: ${p.percent}%`)
    })
})

download

从远端服务器下载文件或文件夹到本地。异步执行,传输过程在后台线程进行,按指定间隔触发进度回调。传输完成后触发一次最终进度回调(100%)。

每次下载会创建独立任务(UUID),可通过 pauseTask / resumeTask / cancelTask 控制。

插件自动检测 remotePath 类型并分发处理:

  • 单文件下载localPath 为文件系统路径时支持断点续传):remotePath 为远端文件路径
  • 文件夹下载(递归,仅支持暂停/取消,不支持断点续传):remotePath 为远端目录路径

localPath 目标模式(自动检测):

localPath 传入 行为
content:// 树 URI(来自 chooseFolder 目标目录:源目录名/文件名作为子项保存到其下(文件夹 B → A/B/...
空字符串 "" 默认保存到公共"下载"目录 Download/sn_ftp/<源名>(MediaStore 实现,无需任何权限,文件管理器可见)
文件系统路径 现有行为(应用沙盒内,支持断点续传)

文件夹下载时,进度为整体进度(所有文件累计字节数 / 总字节数)。成功后 callbackdata 为实际保存位置字符串。

参数

名称 类型 必填 描述
options FtpTransferOptions 传输参数(localPath 为本地目标、remotePath 为远端源)
callback FtpCallback 完成回调,成功后 data 为实际保存位置字符串
progressCallback FtpProgressCallback 进度回调

返回值

类型 描述
string 任务 ID(UUID),用于 pauseTask / resumeTask / cancelTask

download 错误码

合法值 描述
9004701 参数无效(localPath 或 remotePath 为空)
9004704 远端文件/文件夹不存在
9004706 IO 错误(读取/写入失败、连接中断)
9004708 状态错误(未连接)
9004709 传输被取消(cancelTask 调用)

示例

单文件下载:

import { download } from '@/uni_modules/sn-ftp'

const taskId = download({
    localPath: '/sdcard/download/test.txt',
    remotePath: '/var/ftp/pub/test.txt',
    progressInterval: 500
}, (err) => {
    if (err.errCode == 0) {
        console.log('下载完成')
    } else {
        console.error('下载失败:' + err.errMsg)
    }
}, (p) => {
    console.log(`已下载 ${p.bytesTransferred}/${p.totalBytes} (${p.percent}%)`)
})

文件夹下载到用户选择的目录(文件夹 B 保存到所选目录 A 下,即 A/B/...):

import { download, chooseFolder } from '@/uni_modules/sn-ftp'
import type { ChooseFolderResult } from '@/uni_modules/sn-ftp'

chooseFolder((err) => {
    if (err.errCode != 0) {
        console.error('选择保存位置失败:' + err.errMsg)
        return
    }
    const result = err.data as ChooseFolderResult  // { uri, name }
    download({
        localPath: result.uri,              // content:// 树 URI:目标目录,文件夹保存到其下
        remotePath: '/var/ftp/pub/photos',   // 远端源目录
        progressInterval: 500
    }, (dlErr) => {
        if (dlErr.errCode == 0) {
            console.log('文件夹下载完成,保存位置: ' + dlErr.data)
        } else {
            console.error('文件夹下载失败:' + dlErr.errMsg)
        }
    }, (p) => {
        console.log(`整体进度: ${p.percent}%`)
    })
})

文件夹下载到默认公共目录(localPath 传空字符串,保存到 Download/sn_ftp/<源目录名>):

import { download } from '@/uni_modules/sn-ftp'

const taskId = download({
    localPath: '',                    // 空字符串 = 默认公共下载
    remotePath: '/var/ftp/pub/photos', // 远端源目录
    progressInterval: 500
}, (err) => {
    if (err.errCode == 0) {
        console.log('文件夹下载完成,保存位置: ' + err.data)
    } else {
        console.error('文件夹下载失败:' + err.errMsg)
    }
}, (p) => {
    console.log(`整体进度: ${p.percent}%`)
})

chooseFolder

调用 Android 系统文件夹选择器(ACTION_OPEN_DOCUMENT_TREE),让用户选择一个本地文件夹,返回 content:// 树 URI 及文件夹名。

返回的 uri 可直接作为 upload / downloadlocalPath 参数:

  • upload:插件自动识别为文件夹并递归上传
  • download:插件自动识别为目标目录,源目录名/文件名作为子项保存到其下

权限通过 takePersistableUriPermission 持久化,确保后续访问有效(即使应用重启)。无需在 AndroidManifest.xml 声明额外权限,系统文件夹选择器走 Storage Access Framework,不需要运行时权限申请。

参数

名称 类型 必填 描述
callback FtpCallback 结果回调,成功时 dataChooseFolderResult

类型

ChooseFolderResult
名称 类型 必备 描述
uri string 文件夹的 content:// 树 URI 字符串,可作为 upload / downloadlocalPath
name string 文件夹名称(用于构造远端目标路径)

chooseFolder 错误码

合法值 描述
9022704 URI 为空(系统选择器异常)
9022705 权限获取失败(takePersistableUriPermission 异常)
9022708 状态错误(Activity 为空)
9022709 用户取消选择

示例

import { chooseFolder } from '@/uni_modules/sn-ftp'
import type { ChooseFolderResult } from '@/uni_modules/sn-ftp'

chooseFolder((err) => {
    if (err.errCode == 0) {
        const result = err.data as ChooseFolderResult
        console.log('选中文件夹: ' + result.name)
        console.log('URI: ' + result.uri)
        // 将 result.uri 作为 upload / download 的 localPath
    } else if (err.errCode != 9022709) {
        // 9022709 是用户取消,不提示
        console.error('选择文件夹失败:' + err.errMsg)
    }
})

mkdir

在远端服务器创建目录。若目录已存在或父目录不存在,操作会失败。

参数

名称 类型 必填 描述
path string 目录绝对路径
callback FtpCallback 结果回调

mkdir 错误码

合法值 描述
9005701 参数无效(path 为空)
9005706 IO 错误(创建失败)
9005708 状态错误(未连接)

示例

import { mkdir } from '@/uni_modules/sn-ftp'

mkdir('/var/ftp/newdir', (err) => {
    console.log(err.errCode == 0 ? '目录已创建' : err.errMsg)
})

rmdir

删除远端目录。仅能删除空目录,若目录非空会失败。

参数

名称 类型 必填 描述
path string 目录绝对路径(仅能删除空目录)
callback FtpCallback 结果回调

rmdir 错误码

合法值 描述
9006701 参数无效(path 为空)
9006704 目录不存在
9006706 IO 错误(删除失败)
9006708 状态错误(未连接)

示例

import { rmdir } from '@/uni_modules/sn-ftp'

rmdir('/var/ftp/newdir', (err) => {
    console.log(err.errCode == 0 ? '目录已删除' : err.errMsg)
})

deleteFile

删除远端文件。

参数

名称 类型 必填 描述
path string 文件绝对路径
callback FtpCallback 结果回调

deleteFile 错误码

合法值 描述
9007701 参数无效(path 为空)
9007704 文件不存在
9007706 IO 错误(删除失败)
9007708 状态错误(未连接)

示例

import { deleteFile } from '@/uni_modules/sn-ftp'

deleteFile('/var/ftp/pub/old.txt', (err) => {
    console.log(err.errCode == 0 ? '文件已删除' : err.errMsg)
})

cd

切换远端工作目录。

参数

名称 类型 必填 描述
path string 目标目录绝对路径
callback FtpCallback 结果回调

cd 错误码

合法值 描述
9008701 参数无效(path 为空)
9008704 目录不存在
9008706 IO 错误(切换失败)
9008708 状态错误(未连接)

示例

import { cd } from '@/uni_modules/sn-ftp'

cd('/var/ftp/pub', (err) => {
    console.log(err.errCode == 0 ? '已切换目录' : err.errMsg)
})

list

获取远端目录下的文件列表(全量返回)。成功时 dataFtpFileInfo[]

参数

名称 类型 必填 描述
path string 目录绝对路径
callback FtpCallback 结果回调,成功时 dataFtpFileInfo[]

类型

FtpFileInfo

远端文件信息条目(list 返回的数组元素,页面展示时也使用)。

名称 类型 必备 描述
name string 文件/目录名
size number 字节数,目录固定为 0
isDirectory boolean 是否为目录
modifiedTime string 最后修改时间,格式 yyyy-MM-dd HH:mm:ss
permissions string 权限字符串,例如 rw-r--r--
path string 所在目录路径

list 错误码

合法值 描述
9009701 参数无效(path 为空)
9009706 IO 错误(列目录失败)
9009708 状态错误(未连接)

示例

import { list } from '@/uni_modules/sn-ftp'
import type { FtpFileInfo } from '@/uni_modules/sn-ftp'

list('/var/ftp/pub', (err) => {
    if (err.errCode == 0) {
        const files = err.data as FtpFileInfo[]
        files.forEach((f) => {
            console.log(`${f.isDirectory ? '[D]' : '[F]'} ${f.name}  ${f.size}`)
        })
    } else {
        console.error(err.errMsg)
    }
})

:插件仅提供全量列表接口。如需分页(大目录优化),请在业务层基于全量列表做本地切片(参考项目内 hooks/useFtpFileList.uts)。


logText

插件运行日志的只读响应式变量,通过 usePluginLog 组合式函数获取。数据源为 sn-ftp 插件内部日志缓冲区,每 300ms 自动同步,前端绑定到 <text> 组件即可实时显示,无需手动刷新。

特性

  • 只读:返回 readonly ref,外部代码不可修改,仅由插件内部日志驱动
  • 响应式setInterval 定时从插件同步,自动触发 UI 更新
  • 纯插件日志:仅包含插件层日志(连接、传输、错误等),不含应用层业务消息
  • 格式:按行拼接的纯文本,每行格式为 [yyyy-MM-dd HH:mm:ss.SSS] 消息内容

用法

import { usePluginLog } from '@/hooks/usePluginLog.uts'

const logText = usePluginLog(300)  // 300ms 刷新间隔
// 绑定到模板:<text>{{ logText }}</text>

示例

<template>
    <scroll-view direction="vertical" :scroll-top="scrollTop">
        <text>{{ logText }}</text>
    </scroll-view>
</template>

<script lang="uts" setup>
import { ref, watch } from 'vue'
import { usePluginLog } from '@/hooks/usePluginLog.uts'

const scrollTop = ref(0)
const logText = usePluginLog(300)
// 日志变化时自动滚动到底部
watch(logText, () => {
    setTimeout(() => { scrollTop.value += 10000 }, 50)
})
</script>

:日志内容由插件内部维护(连接、传输、错误等),应用层不应向日志写入业务消息。如需清空日志,调用 clearLogs


getLogTextSync

同步获取当前日志文本(按行拼接)。供 usePluginLog 组合式函数定时轮询使用,通常不需要直接调用。

返回值

类型 描述
string 日志文本(按行拼接,无条数限制)

示例

import { getLogTextSync } from '@/uni_modules/sn-ftp'

const text = getLogTextSync()
console.log(text)

getLogs

获取插件运行日志。日志由插件内部记录,包含连接、传输、错误等关键事件。

参数

名称 类型 必填 描述
callback FtpCallback 结果回调,成功时 data 为按行拼接的 string

示例

import { getLogs } from '@/uni_modules/sn-ftp'

getLogs((err) => {
    if (err.errCode == 0) {
        console.log(err.data as string)
    } else {
        console.error(err.errMsg)
    }
})

clearLogs

清空插件内部记录的运行日志。

参数

名称 类型 必填 描述
callback FtpCallback 结果回调

示例

import { clearLogs } from '@/uni_modules/sn-ftp'

clearLogs((err) => {
    console.log(err.errCode == 0 ? '日志已清空' : err.errMsg)
})

clearTempDir

清空临时目录(<cacheDir>/sn_ftp_temp/)下所有文件,释放存储空间。通常用于下载后立即打开的临时文件清理。

参数

名称 类型 必填 描述
callback FtpCallback 结果回调

clearTempDir 错误码

合法值 描述
9013706 IO 错误(删除失败)

示例

import { clearTempDir } from '@/uni_modules/sn-ftp'

clearTempDir((err) => {
    console.log(err.errCode == 0 ? '临时目录已清空' : err.errMsg)
})

saveMediaToGallery

保存图片或视频文件到系统相册。兼容 Android 10+ 使用 MediaStore(无需运行时权限),Android 9 及以下使用传统文件路径(需 WRITE_EXTERNAL_STORAGE 运行时权限)。

参数

名称 类型 必填 描述
srcPath string 源文件路径(应用沙盒内的临时文件)
isImage boolean true = 图片,false = 视频
callback FtpCallback 结果回调,成功时 data 为目标 Uri 字符串

saveMediaToGallery 错误码

合法值 描述
9014701 参数无效(srcPath 为空)
9014704 源文件不存在
9014705 权限不足(Android 9 及以下)
9014706 IO 错误(写入失败)

示例

import { saveMediaToGallery } from '@/uni_modules/sn-ftp'

saveMediaToGallery('/cache/sn_ftp_temp/photo.jpg', true, (err) => {
    if (err.errCode == 0) {
        console.log('已保存到相册:' + err.data)
    } else {
        console.error('保存失败:' + err.errMsg)
    }
})

saveFileToDownloads

保存任意类型文件到系统 Download 目录。兼容 Android 10+ 使用 MediaStore.Downloads,Android 9 及以下使用传统文件路径写入公共 Download 目录。

参数

名称 类型 必填 描述
srcPath string 源文件路径
callback FtpCallback 结果回调,成功时 data 为目标路径字符串

saveFileToDownloads 错误码

合法值 描述
9015701 参数无效(srcPath 为空)
9015704 源文件不存在
9015705 权限不足(Android 9 及以下)
9015706 IO 错误(写入失败)

示例

import { saveFileToDownloads } from '@/uni_modules/sn-ftp'

saveFileToDownloads('/cache/sn_ftp_temp/doc.pdf', (err) => {
    if (err.errCode == 0) {
        console.log('已保存到:' + err.data)
    } else {
        console.error('保存失败:' + err.errMsg)
    }
})

open

使用系统应用打开本地文件。基于 Android 原生 Intent + FileProvider 实现(不再使用 uni.openDocument),能正确处理应用私有目录(cacheDir)中的文件。

文件类型处理策略:

  • 视频(mp4/m4v/mkv 等)→ 系统播放器
  • 音频(mp3/aac/flac 等)→ 系统音乐播放器
  • 图片(jpg/png/gif/webp 等)→ 系统相册
  • 文档(pdf/doc/xls/ppt 等)→ 系统文档处理器
  • 其他/未知类型 → 系统弹出应用选择器,由用户选择

若精确 MIME 无对应应用,自动降级为 */* 兜底;仍无应用则返回错误。

参数

名称 类型 必填 描述
filePath string 本地文件绝对路径(应用沙盒内或已授权路径)
callback FtpCallback 结果回调,成功时 errCode = 0data = null

open 错误码

合法值 描述
9016701 参数无效(filePath 为空)
9016704 文件不存在
9016706 打开失败(IO 异常、FileProvider 配置错误)
9016710 无应用可打开此文件类型

示例

import { open } from '@/uni_modules/sn-ftp'

open('/cache/sn_ftp_temp/doc.pdf', (err) => {
    if (err.errCode == 0) {
        console.log('已打开文件')
    } else {
        console.error('打开失败:' + err.errMsg)
    }
})

配合下载使用的典型场景:

import { download, getTempFilePath, open } from '@/uni_modules/sn-ftp'

const localPath = getTempFilePath('report.pdf')
download({
    localPath: localPath,
    remotePath: '/var/ftp/pub/report.pdf',
    progressInterval: null
}, (err) => {
    if (err.errCode == 0) {
        // 下载完成后直接打开
        open(localPath, (openErr) => {
            console.log(openErr.errCode == 0 ? '已打开' : openErr.errMsg)
        })
    }
}, (p) => {
    console.log(`下载进度: ${p.percent}%`)
})

pauseTask

暂停传输任务。中断当前传输,记录已传输字节数,任务状态变为 "paused"。仅 "running" 状态的任务可暂停。暂停后可通过 resumeTask 从断点继续。

参数

名称 类型 必填 描述
taskId string 任务 ID(由 upload / download 返回)
callback FtpCallback 结果回调

pauseTask 错误码

合法值 描述
9017713 任务不存在
9017714 任务不可暂停(非 running 状态)

示例

import { pauseTask } from '@/uni_modules/sn-ftp'

pauseTask(taskId, (err) => {
    if (err.errCode == 0) {
        console.log('已暂停')
    } else {
        console.error('暂停失败:' + err.errMsg)
    }
})

resumeTask

继续已暂停的传输任务,从断点续传。仅 "paused" 状态的任务可继续。

  • FTP/FTPS:使用 REST 命令设置偏移量后 RETR
  • SFTP:使用 channel.getoffset 参数
  • 本地文件以 append 模式打开,新数据追加到已下载部分之后

续传的最终结果通过原 upload / download 的 callback 返回。

:文件夹任务(treeUri / mediaStore 目标模式)不支持断点续传,resume 时从头开始整个文件夹传输。

参数

名称 类型 必填 描述
taskId string 任务 ID
callback FtpCallback 结果回调(仅表示续传是否成功启动)

resumeTask 错误码

合法值 描述
9018713 任务不存在
9018715 任务不可继续(非 paused 状态)
9018708 状态错误(未连接)

示例

import { resumeTask } from '@/uni_modules/sn-ftp'

resumeTask(taskId, (err) => {
    if (err.errCode == 0) {
        console.log('已继续传输')
    } else {
        console.error('继续失败:' + err.errMsg)
    }
})

cancelTask

取消传输任务。中断传输并删除本地临时文件(下载时),任务状态变为 "canceled"。可对任意状态的任务执行取消。

参数

名称 类型 必填 描述
taskId string 任务 ID
callback FtpCallback 结果回调

cancelTask 错误码

合法值 描述
9019713 任务不存在

示例

import { cancelTask } from '@/uni_modules/sn-ftp'

cancelTask(taskId, (err) => {
    if (err.errCode == 0) {
        console.log('已取消任务')
    } else {
        console.error('取消失败:' + err.errMsg)
    }
})

getTaskStatus

查询任务状态(同步)。

参数

名称 类型 必填 描述
taskId string 任务 ID

返回值

类型 描述
TaskInfo | null 任务信息,任务不存在时返回 null

类型

TaskInfo

任务信息(getTaskStatus 返回值,任务列表也使用)。

名称 类型 必备 描述
taskId string 任务 ID(UUID)
kind string 任务类型:"download""upload"
status TaskStatus 当前任务状态
bytesTransferred number 已传输字节数
totalBytes number 总字节数(未知时为 0)
percent number 进度百分比(0-100)
localPath string 本地文件路径
remotePath string 远端文件路径
errMsg string 失败时的错误信息(status == "failed" 时有值)

示例

import { getTaskStatus } from '@/uni_modules/sn-ftp'

const info = getTaskStatus(taskId)
if (info != null) {
    console.log(`状态: ${info.status}  进度: ${info.percent}%`)
} else {
    console.log('任务不存在')
}

listTasks

列出所有任务 ID(同步)。

返回值

类型 描述
string[] 任务 ID 数组

示例

import { listTasks } from '@/uni_modules/sn-ftp'

const ids = listTasks()
console.log('当前任务数: ' + ids.length)

getTempDir

获取应用临时目录路径(同步)。用于下载后立即打开的临时文件存放,路径为 <cacheDir>/sn_ftp_temp/

返回值

类型 描述
string 临时目录绝对路径 <cacheDir>/sn_ftp_temp/

示例

import { getTempDir } from '@/uni_modules/sn-ftp'

const tempDir = getTempDir()
console.log('临时目录:' + tempDir)

getDownloadDir

获取应用下载目录路径(同步)。用于持久保存的下载文件,路径为 <externalFilesDir>/Downloads/sn_ftp/,应用卸载时清除。

:该目录位于应用沙盒内,用户无法直接通过文件管理器便捷访问。如需保存到公共"下载"目录,将 downloadlocalPath 传空字符串(默认公共下载)或使用 chooseFolder 选择目标目录。

返回值

类型 描述
string 下载目录绝对路径 <externalFilesDir>/Downloads/sn_ftp/

示例

import { getDownloadDir } from '@/uni_modules/sn-ftp'

const downloadDir = getDownloadDir()
console.log('下载目录:' + downloadDir)

isImageFile

判断文件名是否为图片类型(同步,按扩展名判断)。支持扩展名:jpg/jpeg/png/gif/bmp/webp/heic/heif

参数

名称 类型 必填 描述
filename string 文件名(含扩展名)

返回值

类型 描述
boolean true 表示是图片

示例

import { isImageFile } from '@/uni_modules/sn-ftp'

console.log(isImageFile('photo.jpg'))   // true
console.log(isImageFile('doc.pdf'))     // false

isVideoFile

判断文件名是否为视频类型(同步,按扩展名判断)。支持扩展名:mp4/avi/mov/wmv/flv/mkv/webm/3gp/m4v

参数

名称 类型 必填 描述
filename string 文件名(含扩展名)

返回值

类型 描述
boolean true 表示是视频

示例

import { isVideoFile } from '@/uni_modules/sn-ftp'

console.log(isVideoFile('movie.mp4'))   // true
console.log(isVideoFile('photo.jpg'))   // false

isTempFileExists

检查临时目录中是否存在指定文件(同步)。

参数

名称 类型 必填 描述
filename string 文件名

返回值

类型 描述
boolean true 表示存在

示例

import { isTempFileExists } from '@/uni_modules/sn-ftp'

if (isTempFileExists('cache.txt')) {
    console.log('临时文件已存在')
}

getTempFilePath

获取临时目录中指定文件的完整路径(同步)。会自动创建临时目录(若不存在)。

参数

名称 类型 必填 描述
filename string 文件名

返回值

类型 描述
string 文件绝对路径

示例

import { getTempFilePath } from '@/uni_modules/sn-ftp'

const path = getTempFilePath('cache.txt')
console.log('完整路径:' + path)

通用类型

通用类型用于放置那些并非某函数专用、很多地方都可以用或者可以暴露给用户使用的类型。

FtpType

连接类型枚举。

合法值 描述
"ftp" 标准 FTP 协议(基于 Apache Commons Net)
"sftp" SFTP 协议(基于 JSch,走 SSH 通道)
"ftps" FTP over SSL/TLS(基于 FTPSClient,支持 explicit/implicit 双模式)
FtpMode

传输模式枚举。仅 FTP/FTPS 有效,SFTP 忽略。

合法值 描述
"active" 主动模式,服务器主动连接客户端数据端口
"passive" 被动模式,客户端连接服务器数据端口(默认,穿越 NAT 友好)
FtpEncoding

编码格式枚举。

合法值 描述
"UTF-8" 默认推荐
"GBK" 中文服务器常见
"GB2312" 简体中文
"ISO-8859-1" 西欧编码(部分老服务器)
FtpAuthMethod

SFTP 认证方式枚举。仅 type == "sftp" 时有效。

合法值 描述
"password" 密码登录(默认)
"key" 秘钥登录(需提供 privateKeyPath
FtpCallback

通用结果回调类型。遵循 uni 错误规范,所有异步 API 通过 UniError 返回结果。

type FtpCallback = (err: UniError) => void
  • 成功:errCode = 0data 携带结果数据
  • 失败:errCode != 0errMsg 为错误描述,cause 为源错误

data 类型说明

API data 类型
connect / disconnect / mkdir / rmdir / deleteFile / cd / clearLogs / clearTempDir / open null
upload null(进度通过 progressCallback 返回)
download string(实际保存位置,进度通过 progressCallback 返回)
list FtpFileInfo[]
getLogs string(日志文本)
saveMediaToGallery / saveFileToDownloads string(目标路径)
chooseFolder ChooseFolderResult
FtpProgressCallback

传输进度回调类型(upload / download 的 progressCallback 参数)。

type FtpProgressCallback = (progress: FtpProgress) => void

progressFtpProgress 类型。

TaskStatus

任务状态枚举。

合法值 描述
"running" 传输中
"paused" 已暂停(可通过 resumeTask 继续)
"completed" 已完成
"failed" 失败
"canceled" 已取消

错误码

7 位错误码格式

格式:90XX7XX = ERR_BASE + ERR_API_XX + ERR_TYPE_XX

  • 1-2 位(90):sn-ftp 插件标识
  • 3-4 位(XX):API 编号
  • 5-7 位(7XX):具体错误(Android 用 7xx)

API 编号

API 编号 API 名称 错误码范围
01 connect 9001700-9001712
02 disconnect 9002700-9002708
03 upload 9003700-9003709
04 download 9004700-9004709
05 mkdir 9005700-9005708
06 rmdir 9006700-9006708
07 deleteFile 9007700-9007708
08 cd 9008700-9008708
09 list 9009700-9009708
11 getLogs 9011700-9011708
12 clearLogs 9012700-9012708
13 clearTempDir 9013700-9013708
14 saveMediaToGallery 9014700-9014708
15 saveFileToDownloads 9015700-9015708
16 open 9016700-9016708
17 pauseTask 9017700-9017715
18 resumeTask 9018700-9018715
19 cancelTask 9019700-9019715
20 getTaskStatus —(同步,不返回错误码)
21 listTasks —(同步,不返回错误码)
22 chooseFolder 9022700-9022709

错误类型后缀

后缀 含义
700 通用错误
701 参数无效
702 网络错误(连接失败、超时、断开)
703 认证失败
704 文件/目录不存在
705 权限不足
706 IO 错误
707 协议错误
708 状态错误(未连接、已连接等)
709 取消/中断
710 不支持的功能
711 路径错误
712 秘钥错误
713 任务不存在
714 任务不可暂停(非 running 状态)
715 任务不可继续(非 paused 状态)

完整错误码表

errCode 含义 触发场景
9001701 connect 参数无效 host 为空、ftps 未填 implicit、sftp 未填 authMethod
9001702 connect 网络错误 连接失败、超时、SSL 握手失败
9001703 connect 认证失败 密码错误、公钥被服务器拒绝
9001707 connect 协议错误 FTP 服务器拒绝连接
9001712 connect 秘钥错误 Ed25519 不支持、加密秘钥未提供 passphrase、文件格式错误
9002708 disconnect 状态错误 未连接
9003/4701 upload/download 参数无效 localPath 或 remotePath 为空
9003/4704 upload/download 文件不存在 本地/远端文件不存在
9003/4706 upload/download IO 错误 读取/写入失败、连接中断
9003/4708 upload/download 状态错误 未连接
9003/4709 upload/download 被取消 cancelTask 调用或断开连接
9005-9008 701 mkdir/rmdir/cd/delete 参数无效 path 为空
9005-9008 706 mkdir/rmdir/cd/delete IO 错误 操作失败
9005-9008 708 mkdir/rmdir/cd/delete 状态错误 未连接
9009 701 list 参数无效 path 为空
9009 706 list IO 错误 列目录失败
9009 708 list 状态错误 未连接
9014/15 701 saveMedia/saveFile 参数无效 srcPath 为空
9014/15 704 saveMedia/saveFile 文件不存在 源文件不存在
9014/15 706 saveMedia/saveFile IO 错误 写入失败
9016 701 open 参数无效 filePath 为空
9016 704 open 文件不存在 指定路径的文件不存在
9016 706 open 打开失败 IO 异常、FileProvider 配置错误
9016 710 open 无应用可用 系统无应用可打开此文件类型
9017713 pauseTask 任务不存在 taskId 不在任务 Map 中
9017714 pauseTask 不可暂停 任务非 running 状态
9018713 resumeTask 任务不存在 taskId 不在任务 Map 中
9018715 resumeTask 不可继续 任务非 paused 状态
9018708 resumeTask 状态错误 未连接
9019713 cancelTask 任务不存在 taskId 不在任务 Map 中
9022704 chooseFolder URI 为空 系统选择器返回的 URI 为空
9022705 chooseFolder 权限获取失败 takePersistableUriPermission 抛 SecurityException
9022708 chooseFolder 状态错误 Activity 为空
9022709 chooseFolder 用户取消 用户在系统选择器中点击返回/取消

注意事项

  1. 同一时刻只能维持一个连接。再次调用 connect 会先断开旧连接。
  2. 操作串行化。所有操作入队单线程执行,后入队的操作会等待前一个完成。
  3. 自动重连。SFTP session 意外断开(服务器 idle 超时、网络波动)后,传输任务会自动使用保存的连接参数重连;连接时默认启用 keepalive(每 5 秒心跳)从源头减少断开。
  4. 本地路径权限。Android 11+ 对 /sdcard 有 scoped storage 限制,建议使用应用沙盒目录、content:// 树 URI(SAF 授权)或公共目录(MediaStore)。
  5. 匿名 FTPusername"anonymous"password 填任意字符串即可(多数服务器不校验)。
  6. SFTP 跳过主机密钥校验。当前实现设置 StrictHostKeyChecking=no,生产环境若需安全校验请自行扩展。
  7. FTPS 证书校验。当前使用系统默认信任库严格校验。若服务器使用自签名证书会连接失败,需要自行将证书导入 Android 系统信任库,或在 FtpClient.kt 中扩展 FTPSClient.setTrustManager(...) 跳过校验(仅限调试环境)。
  8. FTPS 数据通道加密。连接后自动执行 PBSZ 0 + PROT P,保证数据通道也加密。如需明文数据通道(仅控制通道加密),修改 FtpClient.ktexecPROT("P")execPROT("C")
  9. 进度百分比。下载时若服务器不支持 SIZE 命令,totalBytes 可能为 0,percent 也为 0;上传时 totalBytes 始终使用本地文件大小。
  10. 文件夹传输upload / download 自动检测路径类型并递归处理文件夹:上传文件夹需先用 chooseFolder 获取 content:// 树 URI;文件夹传输仅支持暂停/取消,不支持断点续传,暂停后恢复会从头开始。
  11. 下载目标路径downloadlocalPath 支持三种模式:content:// 树 URI(保存到所选目录下)、空字符串(默认公共"下载"目录 Download/sn_ftp/<源名>,MediaStore 实现无需权限)、文件系统路径(应用沙盒内,支持断点续传)。
  12. 进度回调最小间隔 100ms。设置小于 100 的值会被强制提升到 100;填 null 使用默认值 1000ms。
  13. 日志无条数限制。插件日志缓冲区不设上限,全部保留在内存中;长时间运行日志量大会占用一定内存,可调用 clearLogs 手动清空。
  14. SFTP 秘钥格式。仅支持 OpenSSH 格式私钥(-----BEGIN OPENSSH PRIVATE KEY----- 或 PEM 格式)。PuTTY PPK 格式需先用 puttygen 转换。选择私钥文件而非公钥(公钥文件以 .pub 后缀结尾)。
  15. SFTP Ed25519 秘钥限制。JSch 0.2.20 在 Android 9+ 不支持 Ed25519/Ed448 秘钥签名(缺少 EdDSA 签名提供者)。请改用 RSA (ssh-keygen -t rsa -b 4096) 或 ECDSA (ssh-keygen -t ecdsa -b 256) 秘钥。
  16. SFTP 加密秘钥。若私钥生成时设置了 passphrase,必须在 passphrase 字段填写;否则认证会失败(USERAUTH fail)。可用 ssh-keygen -t rsa -b 4096 -f new_key -N "" 生成不带密码的秘钥。
  17. FTPS require_ssl_reuse。vsftpd 等服务器若启用 require_ssl_reuse=YES,插件已实现 SSL session 复用尝试,但 Android Conscrypt 实现可能不支持反射注入。若仍报 425 错误,需服务器端设置 require_ssl_reuse=NO,或改用 SFTP 协议。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。