鸿蒙 Next 实战:打造全能文件管理器应用
SameX
Posted on November 28, 2024
本文旨在深入探讨华为鸿蒙HarmonyOS Next系统(截止目前 API12)在开发多语言电商平台方面的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。
在当今数字化时代,文件管理器成为了人们管理本地文件和媒体文件的重要工具。今天,我们将基于鸿蒙 Next 系统,深入探讨如何开发一个功能强大的文件管理器应用,涵盖从基础架构设计到核心功能实现的全过程,让你全面掌握鸿蒙 Next 在文件管理领域的应用开发技巧。
一、应用架构设计:MVC 架构的应用
(一)MVC 架构概述
MVC(Model-View-Controller)架构是一种经典的软件设计模式,它将应用程序分为三个主要部分:模型(Model)、视图(View)和控制器(Controller)。在我们的文件管理器应用中,这种架构的应用将使代码结构更加清晰,易于维护和扩展。
(二)模型(Model)层
模型层负责处理数据的存储、检索和更新。在文件管理器应用中,它主要涉及文件和目录的操作,如文件读取、写入、删除、复制、移动等。我们将使用鸿蒙 Next 的系统 API 来实现这些操作。例如,使用fileIo
模块来进行文件的读写操作,directoryIo
模块来处理目录相关操作。
(三)视图(View)层
视图层负责呈现用户界面,展示文件和目录列表,以及提供操作按钮等交互元素。我们将使用 ArkUI 框架来构建用户界面,通过组件化的方式,如List
组件展示文件列表,Button
组件实现操作按钮,确保界面简洁、美观且易于操作。
(四)控制器(Controller)层
控制器层充当模型和视图之间的桥梁,负责处理用户输入事件,并根据业务逻辑调用模型层的相应方法。例如,当用户点击文件上传按钮时,控制器将获取用户选择的文件路径,调用模型层的上传方法将文件上传到指定位置。
(五)使用系统 Picker 实现文件选择和保存
为了遵循鸿蒙 Next 的安全原则,避免直接访问用户文件系统,我们将广泛使用系统 Picker 来实现文件选择和保存功能。当用户需要打开文件时,通过文件选择器(FilePicker)让用户选择文件,应用获取用户选择的文件路径后进行后续操作。同样,在保存文件时,使用系统提供的保存路径选择器,确保文件保存到正确的位置。
二、权限申请与管理
(一)权限机制回顾
在鸿蒙 Next 系统中,权限分为 system_grant(系统授权)和 user_grant(用户授权)两种类型。系统授权权限在应用安装时自动授予,而用户授权权限则需要在应用运行时向用户请求授权。
(二)应用所需权限及申请方式
-
读取文件权限(user_grant)
应用需要读取用户本地文件时,需申请
ohos.permission.READ_EXTERNAL_STORAGE
权限(假设为读取外部存储文件权限,实际根据系统定义)。在应用启动时,通过requestPermissionsFromUser()
接口向用户请求授权。例如:
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
const readPermission: Permissions = 'ohos.permission.READ_EXTERNAL_STORAGE';
async function checkReadPermissionGrant(): Promise<abilityAccessCtrl.GrantStatus> {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
// 获取应用程序的 accessTokenID
let tokenId: number = 0;
try {
let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
tokenId = appInfo.accessTokenId;
} catch (error) {
const err: BusinessError = error as BusinessError;
console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
}
// 校验应用是否被授予权限
try {
grantStatus = await atManager.checkAccessToken(tokenId, readPermission);
} catch (error) {
const err: BusinessError = error as BusinessError;
console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`);
}
return grantStatus;
}
async function requestReadPermission(): Promise<void> {
let grantStatus: abilityAccessCtrl.GrantStatus = await checkReadPermissionGrant();
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
// 已获得读取权限,可以进行文件读取操作
console.log('已获得读取文件权限,可以继续操作。');
} else {
// 申请读取文件权限
const permissions: Array<Permissions> = [readPermission];
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(globalThis.context as common.UIAbilityContext, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
console.log('用户已授权读取文件权限,可以继续操作。');
} else {
// 用户拒绝授权,提示用户必须授权才能访问相关功能,并引导用户到系统设置中打开相应权限
console.log('用户拒绝授权读取文件权限,请前往系统设置中手动授予权限。');
return;
}
}
// 授权成功
}).catch((err: BusinessError) => {
console.error(`Failed to request read permission from user. Code is ${err.code}, message is ${err.message}`);
});
}
}
// 在应用启动或需要读取文件时调用 requestReadPermission() 函数
requestReadPermission();
写入文件权限(user_grant)
当应用需要保存文件或修改文件内容时,需申请ohos.permission.WRITE_EXTERNAL_STORAGE
权限。申请方式与读取文件权限类似,同样需要先检查权限状态,未授权时向用户请求授权。访问网络权限(system_grant)
文件上传和下载功能需要访问网络,应用需申请ohos.permission.INTERNET
权限。此权限为系统授权类型,在应用的配置文件(如module.json5
)中声明即可,系统会在安装时自动授予。
(三)受限开放权限与 ACL 申请(以读取媒体文件为例)
如果应用需要读取用户媒体文件,如图片、音频、视频等,可能涉及受限开放权限。假设读取媒体文件权限为ohos.permission.READ_MEDIA_FILES
(实际根据系统定义),且该权限属于受限开放权限。
AGC 申请 Profile 文件
首先,开发者需要在应用市场(AppGallery Connect,AGC)申请 Profile 文件,并在申请过程中明确申请使用读取媒体文件权限。提供详细的应用使用场景说明,如文件管理器需要读取媒体文件以实现预览、分类管理等功能。代码工程中声明权限
在 AGC 侧申请成功后,在代码工程的配置文件(module.json5
)中声明该权限:
{
"module": {
"requestPermissions":[
{
"name": "ohos.permission.READ_MEDIA_FILES",
"reason": "$string:reason_for_read_media_files",
"usedScene": {
"abilities": [
"MainAbility"
],
"when":"inuse"
}
}
]
}
}
同时,在应用运行时,按照用户授权的流程,通过requestPermissionsFromUser()
接口向用户请求授权(如果该权限属于 user_grant 类型),并处理用户的授权结果。
三、核心功能实现
(一)文件操作功能
-
文件读取
使用
fileIo
模块的open()
方法打开文件,获取文件描述符,然后通过read()
方法读取文件内容。例如:
import { fileIo } from '@kit.CoreFileKit';
async function readFile(filePath: string): Promise<string> {
let file = await fileIo.open(filePath, fileIo.OpenMode.READ_ONLY);
let buffer = new ArrayBuffer(fileIo.statSync(filePath).size);
await fileIo.read(file.fd, buffer);
await fileIo.close(file.fd);
return new TextDecoder().decode(buffer);
}
-
文件写入
通过
fileIo
模块的open()
方法以写入模式打开文件,使用write()
方法将数据写入文件。例如:
async function writeFile(filePath: string, content: string): Promise<void> {
let file = await fileIo.open(filePath, fileIo.OpenMode.WRITE_ONLY | fileIo.OpenMode.CREATE);
await fileIo.write(file.fd, new TextEncoder().encode(content));
await fileIo.close(file.fd);
}
-
文件删除、复制和移动
利用
fileIo
和directoryIo
模块的相关方法实现文件的删除、复制和移动操作。例如,文件删除可以使用unlink()
方法,文件复制可以先读取源文件内容,再写入到目标文件,文件移动可以通过先复制再删除源文件的方式实现(需考虑原子性操作以确保数据完整性)。
(二)网络操作功能
-
文件上传
使用
http
或https
模块(假设鸿蒙 Next 提供类似网络请求模块)实现文件上传功能。首先创建一个HttpRequest
对象,设置请求方法为POST
,上传地址等参数,然后将文件内容作为请求体发送。例如:
import { http } from '@kit.NetworkKit';
async function uploadFile(filePath: string, uploadUrl: string): Promise<void> {
let fileContent = await readFile(filePath);
let request = http.createHttpRequest();
request.method = 'POST';
request.url = uploadUrl;
request.headers = { 'Content-Type': 'application/octet-stream' };
request.requestBody = new Uint8Array(new TextEncoder().encode(fileContent));
try {
await request.send();
if (request.responseCode === 200) {
console.log('文件上传成功。');
} else {
console.error('文件上传失败,错误码:', request.responseCode);
}
} catch (error) {
console.error('文件上传过程中出错:', error);
}
}
-
文件下载
类似地,使用网络请求模块实现文件下载功能。创建
HttpRequest
对象,设置请求方法为GET
,下载地址等参数,然后接收服务器返回的文件内容并保存到本地。例如:
async function downloadFile(downloadUrl: string, savePath: string): Promise<void> {
let request = http.createHttpRequest();
request.method = 'GET';
request.url = downloadUrl;
try {
await request.send();
if (request.responseCode === 200) {
await writeFile(savePath, request.responseData.toString());
console.log('文件下载成功,保存路径:', savePath);
} else {
console.error('文件下载失败,错误码:', request.responseCode);
}
} catch (error) {
console.error('文件下载过程中出错:', error);
}
}
(三)分享功能
分享方式选择
提供多种分享方式,如通过邮件、短信、社交媒体等分享文件。在用户选择分享文件后,弹出分享方式选择界面,让用户选择合适的分享渠道。分享实现
根据用户选择的分享方式,使用相应的系统 API 实现分享操作。例如,通过邮件分享文件时,使用邮件客户端的分享接口,将文件作为附件添加到邮件中。假设鸿蒙 Next 提供了share
模块来实现分享功能,以下是一个简单的邮件分享示例(实际接口可能不同):
import { share } from '@kit.ShareKit';
async function shareFileByEmail(filePath: string, recipient: string): Promise<void> {
let fileContent = await readFile(filePath);
let shareData = {
type:'message/email',
subject: '文件分享',
body: '这是一个通过文件管理器分享的文件。',
attachments: [
{
name: filePath.split('/').pop(),
data: fileContent
}
]
};
try {
await share.share(shareData, { recipients: [recipient] });
console.log('文件通过邮件分享成功。');
} catch (error) {
console.error('文件分享失败:', error);
}
}
四、总结与展望
通过本次实战,我们成功构建了一个基于鸿蒙 Next 系统的文件管理器应用,涵盖了文件浏览、管理、上传、下载和分享等核心功能。在开发过程中,我们深入应用了鸿蒙 Next 的应用沙箱与权限机制、系统授权与用户授权、受限开放权限与 ACL 申请、系统 Picker 等关键技术,确保了应用的安全性、稳定性和功能性。
展望未来,随着鸿蒙 Next 系统的不断发展和完善,我们可以进一步优化文件管理器的性能,如提升大文件操作的效率、增强文件搜索功能等。同时,结合分布式技术,实现跨设备的文件管理和共享,为用户提供更加便捷、高效的文件管理体验。希望本文能够为鸿蒙 Next 同行者提供有益的参考和借鉴,激发更多创新应用的开发。
Posted on November 28, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024
November 29, 2024
November 29, 2024
November 29, 2024