嗨~我是小L!在鸿蒙开发中,文件分享就像「数字高速公路」——URI和FD两种方式各有优势。今天带你掌握安全高效的分享技巧,让应用间数据交换更流畅~
一、两种分享方式:URI vs FD🚗
核心差异对比表
| 维度 | URI分享 | FD分享 |
|----------------|---------------------------|---------------------------|
| 操作难度 | 简单(系统自动管理权限) | 复杂(需手动管理文件句柄)|
| 分享单位 | 单个文件 | 单个文件或目录 |
| 权限时效 | 临时授权(接收方退出即失效)| 永久授权(FD关闭后失效) |
| 典型场景 | 文本、图片临时分享 | 大文件、目录批量传输 |
适用场景选择
- 选URI:聊天App发图片、邮件附件分享
- 选FD:文件管理器传输文件夹、音视频应用批量导入
二、URI分享:「即点即走」的轻量级方案✨
1. 分享端实现(以图片为例)
import { fileUri, wantConstant } from '@ohos.fileUri';
import { UIAbility, Want } from '@ohos.app.ability';
export default class ShareAbility extends UIAbility {
onWindowStageCreate() {
// 1. 获取文件URI
const imagePath = `${this.context.filesDir}/poster.jpg`;
const uri = fileUri.getUriFromPath(imagePath);
// 2. 创建分享意图(授予读写权限)
const want: Want = {
action: wantConstant.Action.SEND_DATA,
uri: uri,
type: 'image/jpeg',
flags: wantConstant.Flag.AUTH_READ_URI_PERMISSION |
wantConstant.Flag.AUTH_WRITE_URI_PERMISSION
};
// 3. 发起分享
this.context.startAbility(want).then(() => {
console.log('图片分享成功');
});
}
}
2. 接收端处理(保存文件到沙箱)
export default class ReceiveAbility extends UIAbility {
onNewWant(want: Want) {
if (want.uri) {
const sourceUri = want.uri;
const destPath = `${this.context.filesDir}/received_${Date.now()}.jpg`;
// 读取URI文件并写入本地
fileIo.copySync(sourceUri, destPath);
console.log('文件已保存至:', destPath);
}
}
}
3. 权限配置(module.json5)
{
"abilities": [
{
"name": ".ShareAbility",
"skills": [
{
"actions": ["ohos.arkui.intent.action.SEND_DATA"],
"uris": [
{
"scheme": "file",
"host": "*",
"path": "/data/storage/el1/*" // 允许分享的路径范围
}
]
}
]
}
]
}
三、FD分享:「大文件专用」的高效通道🚚
1. 分享目录示例(如文档文件夹)
import { fileIO as fs } from '@ohos.fileIO';
import { FileDescriptor } from '@ohos.fs';
function shareDirectory(sourceDir: string) {
// 1. 打开目录获取FD
const fd: FileDescriptor = fs.openSync(sourceDir, fs.OpenMode.READ);
// 2. 创建FD分享数据
const shareData = {
fd: fd,
type: 'directory',
metadata: {
name: 'ProjectFiles',
size: fs.statSync(sourceDir).size
}
};
// 3. 通过自定义通道传递FD(如IPC)
ipc.send('SHARE_FD', shareData);
}
2. 接收端处理FD(读取目录内容)
function handleReceivedFD(fd: FileDescriptor) {
// 1. 读取目录下所有文件
const entries = fs.readdirSync(fd);
// 2. 遍历处理文件
entries.forEach((entry) => {
if (entry.isFile()) {
const fileFd = fs.openSync(`${fd.path}/${entry.name}`, fs.OpenMode.READ);
const content = fs.readFileSync(fileFd, 'utf8');
fs.closeSync(fileFd);
}
});
// 3. 关闭FD释放资源
fs.closeSync(fd);
}
3. 安全注意事项
- FD生命周期:接收方必须在FD关闭前完成操作,否则会导致文件不可访问
- 权限控制:仅允许分享已授权的目录(如应用沙箱内的
files/
目录)
四、安全控制:数据交换的「交通规则」🛑
1. 权限最小化原则
仅授予必要权限:
// 仅授予读权限(避免接收方篡改文件) flags: wantConstant.Flag.AUTH_READ_URI_PERMISSION
2. 敏感数据加密
// 分享前加密文件
import { crypto } from '@ohos.security';
async function encryptAndShare(filePath: string) {
const key = crypto.generateKey('AES', 256);
const encryptedData = await crypto.encryptFile(filePath, key);
const uri = fileUri.getUriFromPath(encryptedData.path);
// 分享加密后的URI
shareUri(uri);
}
3. 临时权限管理
- URI分享自动回收权限:接收方应用退出后,URI自动失效
FD分享需手动关闭:
// 接收方使用完FD后立即关闭 fs.closeSync(fd);
五、实战场景:跨设备批量文件传输📱→💻
场景描述
用户通过鸿蒙「一碰传」将手机中的文件夹快速分享到平板:
手机端(分享方):
- 选择目标文件夹,生成FD
- 通过分布式软总线传输FD和元数据
平板端(接收方):
- 接收FD,验证目录权限
- 遍历FD读取文件,保存至本地
核心代码(简化版)
// 手机端:通过软总线发送FD
import { distributedBus } from '@ohos.distributedBus';
const bus = distributedBus.create('file_share_channel');
bus.on('receive_fd', (fdData) => {
// 平板端接收FD后处理
handleReceivedFD(fdData.fd);
});
// 平板端:接收并处理FD
function handleReceivedFD(fd: FileDescriptor) {
// 检查是否为允许的分享目录
if (!isAuthorized(fd.path)) {
fs.closeSync(fd);
throw new Error('非法目录');
}
// 执行文件复制逻辑
}
六、避坑指南⚠️
1. URI分享常见问题
- 权限不足:未在
module.json5
声明SEND_DATA
动作,导致分享失败 - 文件路径错误:使用绝对路径而非沙箱路径,例如
/sdcard/
可能无权访问
2. FD分享注意事项
FD泄漏:忘记关闭FD会导致文件句柄耗尽,需在
finally
块中关闭try { const fd = fs.openSync(...); // 使用FD } finally { fs.closeSync(fd); }
- 跨进程问题:FD仅在当前进程有效,跨进程传递需通过
dup()
复制
3. 测试要点
- 模拟低权限场景:验证未授权文件是否无法访问
- 压力测试:同时分享多个大文件,观察系统资源占用
总结:分享方案「三选法则」
- 轻量临时:选URI(如社交分享、单文件传输)
- 大量持久:选FD(如文件管理、目录迁移)
- 敏感数据:必加密+临时权限(防止数据泄露)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。