手把手教你用 HarmonyOS 文件分享 API,实现应用间文件安全共享
本文介绍了HarmonyOS文件分享API的核心功能和使用方法。该API提供了安全便捷的文件共享机制,主要功能包括权限授权、权限控制和安全验证。
今天咱们来聊聊 HarmonyOS 里一个非常实用的功能 —— 文件分享 API。不管你是开发社交软件、办公应用还是文件管理器,这套 API 都能帮你实现应用之间安全便捷的文件共享。我会用最通俗的话来讲,每个知识点都配上代码示例,保证你看完就能上手写!
一、文件分享 API 能干啥?先搞懂核心能力
简单来说,这个 API 就像一个 "文件通行证" 管理系统,主要解决两个问题:
- 安全授权:让一个应用能把文件权限(比如读、写)临时或长期授权给另一个应用
- 权限管理:能激活、停用、撤销这些授权,就像管理钥匙一样灵活
举个例子:你在相册应用里选了一张照片想分享到聊天软件,相册应用就通过这个 API 给聊天软件发一个 "读文件通行证",聊天软件拿到后才能读取这张照片。而且这个通行证还能设置有效期、权限范围,非常安全。
重点总结:文件分享 = 权限授权 + 权限控制 + 安全验证
// 先导入核心模块,这是所有操作的基础
import fileShare from '@ohos.fileshare';
二、核心概念:权限模式和策略信息
在开始写代码前,得先认识几个关键概念,就像开车前要认识油门刹车一样:
1. OperationMode:权限的 "钥匙类型"
这是个枚举,定义了不同的文件操作权限,就像不同钥匙开不同锁:
- READ_MODE(0b1):读文件的权限,只能看不能改
- WRITE_MODE(0b10):写文件的权限,可以修改内容
- CREATE_MODE(0b100):创建文件 / 文件夹的权限
- DELETE_MODE(0b1000):删除文件 / 文件夹的权限
- RENAME_MODE(0b10000):重命名文件 / 文件夹的权限
重点代码:权限模式的使用
// 组合多种权限,比如同时给读和写权限
const readWriteMode = fileShare.OperationMode.READ_MODE | fileShare.OperationMode.WRITE_MODE;
console.log(`读写权限组合值:${readWriteMode}`); // 输出3(0b11)
2. PolicyInfo:权限策略的 "通行证信息"
每个权限授权都需要这个对象,包含两个必填项:
- uri:要授权的文件或目录的 URI 地址
- operationMode:上面说的权限模式
重点代码:创建权限策略
// 创建一个读权限的策略
const policy: fileShare.PolicyInfo = {
uri: "file://docs/storage/Users/me/important.txt",
operationMode: fileShare.OperationMode.READ_MODE
};
3. PolicyErrorResult:错误处理的 "诊断书"
当授权操作失败时,会返回这个对象,告诉你哪里出错了,包含:
- uri:失败的文件 URI
- code:错误码(比如 1 是禁止持久化,2 是无效模式)
- message:错误原因描述
三、核心流程:从授权到撤销的完整操作
现在进入最关键的部分,咱们一步步看怎么实现文件分享的完整流程。
1. 持久化授权:发一张长期有效的 "通行证"
persistPermission 接口就像发一张长期有效的通行证,让其他应用可以长期访问文件。注意:不支持媒体类 URI 和远端 URI 哦。
重点代码:文件持久化授权
import { BusinessError } from '@ohos.base';
import picker from '@ohos.file.picker';
async function persistPermissionDemo() {
try {
// 1. 用文件选择器让用户选文件
const selectOptions = new picker.DocumentSelectOptions();
const picker = new picker.DocumentViewPicker();
const uris = await picker.select(selectOptions);
if (!uris || uris.length === 0) {
console.log('用户未选择文件');
return;
}
// 2. 创建权限策略(给第一个文件读权限)
const policyInfo: fileShare.PolicyInfo = {
uri: uris[0],
operationMode: fileShare.OperationMode.READ_MODE
};
// 3. 发起持久化授权(数组最多500个策略)
await fileShare.persistPermission([policyInfo]);
console.log('持久化授权成功');
} catch (error) {
const err = error as BusinessError<Array<fileShare.PolicyErrorResult>>;
console.error(`授权失败,错误码:${err.code},信息:${err.message}`);
// 处理批量授权失败的情况
if (err.code === 13900001 && err.data) {
console.error('以下文件授权失败:');
err.data.forEach((item, index) => {
console.error(`第${index+1}个文件URI:${item.uri}`);
console.error(`错误码:${item.code},原因:${item.message}`);
// 根据不同错误码给用户提示
if (item.code === fileShare.PolicyErrorCode.INVALID_PATH) {
console.error('请检查文件路径是否正确');
} else if (item.code === fileShare.PolicyErrorCode.INVALID_MODE) {
console.error('权限模式无效,比如不能单独给创建权限而不给写权限');
}
});
}
}
}
2. 撤销授权:收回发出去的 "通行证"
revokePermission 接口用于收回已经发出的持久化授权,就像把钥匙收回来。
重点代码:撤销文件授权
async function revokePermissionDemo() {
try {
// 假设这个URI是之前授权过的
const uri = "file://docs/storage/Users/me/authorized.txt";
const policyInfo: fileShare.PolicyInfo = {
uri,
operationMode: fileShare.OperationMode.READ_MODE
};
// 发起撤销授权
await fileShare.revokePermission([policyInfo]);
console.log('撤销授权成功');
} catch (error) {
const err = error as BusinessError<Array<fileShare.PolicyErrorResult>>;
console.error(`撤销失败,错误码:${err.code},信息:${err.message}`);
// 特别处理权限未持久化的情况
if (err.code === 13900001 && err.data) {
const firstError = err.data[0];
if (firstError.code === fileShare.PolicyErrorCode.PERMISSION_NOT_PERSISTED) {
console.error('该URI未被持久化授权,无法撤销');
}
}
}
}
3. 激活 / 停用权限:临时开关 "通行证"
有时候我们不想彻底收回钥匙,只是临时禁用,这时候就用 activatePermission 和 deactivatePermission:
- activate:激活已持久化的权限(打开开关)
- deactivate:停用已持久化的权限(关闭开关)
重点代码:激活和停用权限
async function activateAndDeactivateDemo() {
try {
const uri = "file://docs/storage/Users/me/temp.txt";
const policyInfo: fileShare.PolicyInfo = {
uri,
operationMode: fileShare.OperationMode.READ_MODE
};
// 1. 先激活权限
await fileShare.activatePermission([policyInfo]);
console.log('权限已激活,其他应用可以访问');
// 模拟使用文件...
// 2. 用完后停用权限
await fileShare.deactivatePermission([policyInfo]);
console.log('权限已停用,暂时无法访问');
} catch (error) {
const err = error as BusinessError<Array<fileShare.PolicyErrorResult>>;
console.error(`操作失败,错误码:${err.code},信息:${err.message}`);
// 处理激活时权限未持久化的情况
if (err.code === 13900001 && err.data) {
const firstError = err.data[0];
if (firstError.code === fileShare.PolicyErrorCode.PERMISSION_NOT_PERSISTED) {
console.log('先进行持久化授权');
// 先持久化再激活
await fileShare.persistPermission([policyInfo]);
await fileShare.activatePermission([policyInfo]);
}
}
}
}
4. 检查权限:看看 "通行证" 还在不在
checkPersistentPermission 用于检查某个 URI 是否有持久化授权,返回布尔数组,对应每个策略的授权状态。
重点代码:检查权限状态
async function checkPermissionDemo() {
try {
// 假设这两个URI是之前授权过的
const uris = [
"file://docs/storage/Users/me/authorized1.txt",
"file://docs/storage/Users/me/authorized2.txt"
];
const policies: fileShare.PolicyInfo[] = uris.map(uri => ({
uri,
operationMode: fileShare.OperationMode.READ_MODE
}));
// 检查权限
const results = await fileShare.checkPersistentPermission(policies);
// 处理结果
results.forEach((hasPermission, index) => {
const uri = uris[index];
if (hasPermission) {
console.log(`URI ${uri} 有持久化授权`);
} else {
console.log(`URI ${uri} 没有持久化授权,重新授权`);
// 没有授权的话,重新发起授权
fileShare.persistPermission([policies[index]]);
}
});
} catch (error) {
const err = error as BusinessError;
console.error(`检查失败,错误码:${err.code},信息:${err.message}`);
}
}
四、错误处理:遇到问题怎么办?
在使用文件分享 API 时,难免会遇到各种错误,咱们挑几个常见的说说:
-
13900001 - 操作不允许:最常见的错误,可能是:
- URI 格式不对(比如媒体类 URI 不支持持久化)
- 权限模式组合错误(比如只给 CREATE_MODE 却没给 WRITE_MODE)
- 没有申请 ohos.permission.FILE_ACCESS_PERSIST 权限
-
401 - 参数错误:检查参数是否必填,类型是否正确,比如 policies 数组不能超过 500 个
-
201 - 权限验证失败:应用没有获取到足够的权限,检查配置文件和动态申请权限流程
-
801 - 功能不支持:设备不支持该功能,比如某些老型号设备可能没有相关系统能力
重点代码:统一错误处理
// 封装一个错误处理函数
function handleFileShareError(error: any, operation: string) {
console.error(`[${operation}] 操作出错`, error);
if (error.code) {
switch (error.code) {
case 13900001:
console.log('操作不允许,可能是URI或权限模式有问题');
if (error.data && error.data.length > 0) {
const firstError = error.data[0];
if (firstError.code === fileShare.PolicyErrorCode.INVALID_PATH) {
console.log('建议操作:检查URI是否为有效文件路径,且不是媒体类或远端URI');
} else if (firstError.code === fileShare.PolicyErrorCode.INVALID_MODE) {
console.log('建议操作:检查权限模式是否正确,比如创建文件需要WRITE_MODE+CREATE_MODE');
}
}
break;
case 401:
console.log('参数错误,检查是否有必填参数缺失或类型错误');
break;
case 201:
console.log('权限验证失败,检查是否申请了file.access.persist权限');
break;
case 801:
console.log('设备不支持该功能,检查设备系统版本');
break;
default:
console.log(`错误码 ${error.code},详细信息:${error.message}`);
}
} else {
console.log('未知错误:', error.message);
}
}
// 使用示例
fileShare.persistPermission(policies).then(...).catch((err) => {
handleFileShareError(err, '持久化授权');
});
五、实际应用场景:文件分享功能实战
现在把前面的知识点串起来,看看怎么在实际应用中实现一个完整的文件分享功能,比如一个简单的文件管理器应用:
1. 场景需求:
- 用户选择文件后,可以分享给其他应用
- 分享时可以选择权限(只读、读写等)
- 能查看已授权的文件列表
- 可以撤销不需要的授权
2. 核心流程:
import { BusinessError } from '@ohos.base';
import picker from '@ohos.file.picker';
import fileShare from '@ohos.fileshare';
export default class FileSharingApp {
private authorizedUris: string[] = []; // 存储已授权的URI
// 启动应用时检查已授权的文件
async init() {
await this.checkAllAuthorizedPermissions();
console.log('应用初始化完成,已授权文件数:', this.authorizedUris.length);
}
// 文件选择与授权
async shareFile() {
try {
// 1. 打开文件选择器
const selectOptions = new picker.DocumentSelectOptions();
selectOptions.multiple = true; // 支持多选
const picker = new picker.DocumentViewPicker();
const uris = await picker.select(selectOptions);
if (!uris || uris.length === 0) {
console.log('用户未选择文件');
return;
}
// 2. 显示权限选择界面(这里简化处理,实际应用中会有UI交互)
const operationMode = await this.showPermissionDialog(); // 假设返回选择的权限模式
// 3. 发起持久化授权
const policies = uris.map(uri => ({
uri,
operationMode
}));
await fileShare.persistPermission(policies);
console.log('授权成功,文件已分享');
// 4. 更新已授权列表
this.authorizedUris = [...this.authorizedUris, ...uris];
// 5. 通知其他应用可以访问这些文件(实际应用中通过Intent或其他方式通知)
this.notifyOtherApps(uris);
} catch (error) {
handleFileShareError(error, '文件分享');
}
}
// 显示权限选择对话框(模拟函数)
private showPermissionDialog(): Promise<number> {
return new Promise(resolve => {
// 实际应用中这里会有UI对话框让用户选择权限
// 这里简化返回读权限
resolve(fileShare.OperationMode.READ_MODE);
});
}
// 通知其他应用(模拟函数)
private notifyOtherApps(uris: string[]) {
console.log('通知其他应用可以访问这些URI:', uris);
// 实际应用中可能通过系统广播或自定义接口通知
}
// 检查所有已授权的权限
async checkAllAuthorizedPermissions() {
if (this.authorizedUris.length === 0) return;
const policies = this.authorizedUris.map(uri => ({
uri,
operationMode: fileShare.OperationMode.READ_MODE // 任意模式都可以,只检查是否授权
}));
try {
const results = await fileShare.checkPersistentPermission(policies);
// 过滤掉未授权的URI
this.authorizedUris = this.authorizedUris.filter((_, index) => results[index]);
console.log('已授权文件数更新为:', this.authorizedUris.length);
} catch (error) {
handleFileShareError(error, '检查所有授权');
}
}
// 显示已授权文件列表
showAuthorizedFiles() {
if (this.authorizedUris.length === 0) {
console.log('当前没有已授权的文件');
return;
}
console.log('===== 已授权文件列表 =====');
this.authorizedUris.forEach((uri, index) => {
console.log(`${index+1}. ${uri}`);
});
}
// 撤销单个文件授权
async revokeSinglePermission(uri: string) {
try {
const policyInfo: fileShare.PolicyInfo = {
uri,
operationMode: fileShare.OperationMode.READ_MODE
};
await fileShare.revokePermission([policyInfo]);
console.log(`已撤销URI ${uri} 的授权`);
// 更新列表
this.authorizedUris = this.authorizedUris.filter(u => u !== uri);
} catch (error) {
handleFileShareError(error, '撤销单个授权');
}
}
// 批量撤销授权
async revokeMultiplePermissions(uris: string[]) {
try {
const policies = uris.map(uri => ({
uri,
operationMode: fileShare.OperationMode.READ_MODE
}));
await fileShare.revokePermission(policies);
console.log(`已撤销 ${uris.length} 个文件的授权`);
// 更新列表
this.authorizedUris = this.authorizedUris.filter(u => !uris.includes(u));
} catch (error) {
handleFileShareError(error, '撤销多个授权');
}
}
}
// 使用示例
const fileSharing = new FileSharingApp();
fileSharing.init();
// 模拟用户点击分享按钮
fileSharing.shareFile();
// 显示已授权列表
fileSharing.showAuthorizedFiles();
// 撤销某个文件授权
fileSharing.revokeSinglePermission("file://docs/storage/Users/me/oldfile.txt");
六、高级技巧:权限组合与批量操作
1. 权限组合使用
有时候需要同时给多个权限,比如读写 + 创建,这时候可以用按位或操作:
// 组合读写和创建权限
const complexMode =
fileShare.OperationMode.READ_MODE |
fileShare.OperationMode.WRITE_MODE |
fileShare.OperationMode.CREATE_MODE;
console.log(`复杂权限模式值:${complexMode}`); // 输出7(0b111)
2. 批量授权与错误处理
当需要授权多个文件时,要特别注意错误处理,因为只要有一个文件授权失败,整个操作就会抛出异常:
async function batchAuthorize(uris: string[], operationMode: number) {
try {
const policies = uris.map(uri => ({ uri, operationMode }));
await fileShare.persistPermission(policies);
console.log(`成功授权 ${uris.length} 个文件`);
} catch (error) {
const err = error as BusinessError<Array<fileShare.PolicyErrorResult>>;
console.error(`批量授权失败,错误码:${err.code}`);
if (err.data) {
const successCount = uris.length - err.data.length;
console.log(`成功授权 ${successCount} 个文件,以下 ${err.data.length} 个失败:`);
err.data.forEach((item, index) => {
console.error(`第${index+1}个失败文件:${item.uri}`);
console.error(`错误码:${item.code},原因:${item.message}`);
});
}
}
}
七、总结:文件分享 API 的三大优势和使用建议
1. 三大核心优势
- 安全可控:通过权限模式和持久化管理,精确控制其他应用的文件访问范围
- 灵活方便:支持激活 / 停用权限,就像开关一样灵活,不需要彻底撤销
- 批量操作:支持一次授权 / 撤销多个文件,提高批量处理效率
2. 开发建议
- 先小后大:先实现单个文件的授权撤销,再扩展到批量操作
- 完善错误处理:线上应用一定要处理各种错误情况,给用户清晰的提示
- 权限最小化:授权时只给必要的权限,比如只读就不要给写权限
- 定期检查:应用启动时检查已授权的文件,清理无效或过期的授权
通过这套文件分享 API,我们可以在 HarmonyOS 应用中实现安全、灵活的文件共享功能,无论是相册分享、文档协作还是文件传输,都能轻松搞定。赶紧动手试试吧,有问题咱们可以一起讨论!
更多推荐



所有评论(0)