鸿蒙5文件存储解决方案:AGC云存储集成教程

前言
在HarmonyOS 5应用开发中,文件存储是常见需求。AppGallery Connect(AGC)云存储服务提供了安全可靠的文件存储解决方案,支持多种文件类型,具备权限管理和自动扩展能力。本文将详细介绍如何在HarmonyOS 5应用中集成AGC云存储服务。

第一部分:环境准备
1.1 创建HarmonyOS 5项目
打开DevEco Studio 5.0,创建新项目:
模板:Empty Ability
语言:ArkTS
API版本:HarmonyOS 5.0
配置项目基本信息:
{
"projectName": "CloudStorageDemo",
"bundleName": "com.example.cloudstorage",
"deviceTypes": ["phone", "tablet"]
}
1.2 在AGC控制台启用云存储
登录AppGallery Connect
选择你的项目,进入"构建" → "云存储"
点击"立即启用",选择存储区域(如中国区)
配置安全规则(可先使用默认规则)
第二部分:集成AGC云存储SDK
2.1 添加依赖
修改oh-package.json5文件:

{
"dependencies": {
"@hw-agconnect/api-ohos": "^1.8.0",
"@hw-agconnect/core-ohos": "^1.8.0",
"@hw-agconnect/storage-ohos": "^1.8.0"
}
}
运行依赖安装:

ohpm install
2.2 配置AGC服务
从AGC控制台下载agconnect-services.json
放入项目entry/src/main/resources/rawfile/目录
第三部分:实现文件上传功能
3.1 初始化云存储
创建entry/src/main/ets/utils/CloudStorageUtil.ets:

import { agconnect } from '@hw-agconnect/api-ohos';
import { AGCStorage, StorageReference, StorageTask, StorageError } from '@hw-agconnect/storage-ohos';

export class CloudStorageUtil {
private static instance: CloudStorageUtil = new CloudStorageUtil();
private storage: AGCStorage;

private constructor() {
agconnect.instance().init(globalThis.abilityContext);
this.storage = AGCStorage.getInstance();
}

public static get(): CloudStorageUtil {
return this.instance;
}

// 获取存储引用
public getRef(path: string): StorageReference {
return this.storage.reference().child(path);
}

// 上传文件
public async uploadFile(
localPath: string,
remotePath: string,
onProgress?: (progress: number) => void
): Promise {
const ref = this.getRef(remotePath);
const task = ref.putFile(localPath);

if (onProgress) {
  task.on('progress', (snapshot) => {
    const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
    onProgress(progress);
  });
}

try {
  await task;
  return await ref.getDownloadURL();
} catch (error) {
  if (error instanceof StorageError) {
    throw new Error(`上传失败: ${error.message}`);
  }
  throw error;
}

}
}
3.2 创建文件上传页面
创建entry/src/main/ets/pages/UploadPage.ets:

import { CloudStorageUtil } from '../utils/CloudStorageUtil';
import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';

@Entry
@Component
struct UploadPage {
@State selectedFile: string = '';
@State uploadProgress: number = 0;
@State downloadUrl: string = '';
@State isUploading: boolean = false;

// 选择文件
async selectFile() {
try {
const context = getContext(this) as common.UIAbilityContext;
const result = await context.startAbilityForResult({
bundleName: 'com.example.filepicker',
abilityName: 'FilePickerAbility'
});

  if (result?.resultCode === 0 && result.want?.parameters?.fileUri) {
    this.selectedFile = result.want.parameters.fileUri;
  }
} catch (error) {
  console.error('选择文件失败:', error);
}

}

// 上传文件
async uploadFile() {
if (!this.selectedFile) return;

this.isUploading = true;
this.uploadProgress = 0;
this.downloadUrl = '';

try {
  // 获取文件名
  const fileName = this.selectedFile.split('/').pop() || `file_${new Date().getTime()}`;
  
  // 上传到云存储
  const downloadUrl = await CloudStorageUtil.get().uploadFile(
    this.selectedFile,
    `uploads/${fileName}`,
    (progress) => {
      this.uploadProgress = progress;
    }
  );
  
  this.downloadUrl = downloadUrl;
  console.log('文件上传成功,下载URL:', downloadUrl);
} catch (error) {
  console.error('上传失败:', error);
} finally {
  this.isUploading = false;
}

}

build() {
Column() {
Text('文件上传')
.fontSize(25)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 })

  // 文件选择区域
  Row() {
    Button('选择文件')
      .width(150)
      .height(50)
      .onClick(() => this.selectFile())
    
    Text(this.selectedFile || '未选择文件')
      .margin({ left: 10 })
      .maxLines(1)
      .textOverflow({ overflow: TextOverflow.Ellipsis })
  }
  .width('90%')
  .margin({ bottom: 20 })
  
  // 上传按钮
  Button(this.isUploading ? '上传中...' : '上传文件')
    .width(200)
    .height(50)
    .margin({ bottom: 20 })
    .enabled(!this.isUploading && !!this.selectedFile)
    .onClick(() => this.uploadFile())
  
  // 进度条
  if (this.isUploading) {
    Column() {
      Text(`上传进度: ${this.uploadProgress.toFixed(1)}%`)
        .margin({ bottom: 10 })
      
      Progress({
        value: this.uploadProgress,
        total: 100,
        type: ProgressType.Linear
      })
      .width('90%')
      .height(20)
    }
    .width('100%')
    .margin({ bottom: 20 })
  }
  
  // 下载链接
  if (this.downloadUrl) {
    Column() {
      Text('上传成功!下载链接:')
        .margin({ bottom: 10 })
      
      Text(this.downloadUrl)
        .fontColor(Color.Blue)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
        .maxLines(1)
        .onClick(() => {
          // 实现打开链接的逻辑
        })
    }
    .width('90%')
    .margin({ top: 20 })
  }
}
.width('100%')
.height('100%')
.padding(20)

}
}
第四部分:实现文件下载功能
4.1 扩展CloudStorageUtil
在CloudStorageUtil.ets中添加下载方法:

// 添加至CloudStorageUtil类
public async downloadFile(
remotePath: string,
localPath: string,
onProgress?: (progress: number) => void
): Promise {
const ref = this.getRef(remotePath);
const task = ref.getFile(localPath);

if (onProgress) {
task.on('progress', (snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
onProgress(progress);
});
}

try {
await task;
} catch (error) {
if (error instanceof StorageError) {
throw new Error(下载失败: ${error.message});
}
throw error;
}
}

// 获取文件列表
public async listFiles(path: string): Promise<Array> {
const ref = this.getRef(path);
const result = await ref.listAll();

return result.items.map(item => item.fullPath);
}
4.2 创建文件下载页面
创建entry/src/main/ets/pages/DownloadPage.ets:

import { CloudStorageUtil } from '../utils/CloudStorageUtil';
import { fileIo } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct DownloadPage {
@State fileList: Array = [];
@State downloadProgress: number = 0;
@State isDownloading: boolean = false;
@State downloadPath: string = '';

onPageShow() {
this.loadFileList();
}

// 加载文件列表
async loadFileList() {
try {
this.fileList = await CloudStorageUtil.get().listFiles('uploads/');
} catch (error) {
console.error('获取文件列表失败:', error);
}
}

// 下载文件
async downloadFile(remotePath: string) {
const context = getContext(this) as common.UIAbilityContext;
const fileName = remotePath.split('/').pop() || download_${new Date().getTime()};
const localPath = ${context.filesDir}/${fileName};

this.isDownloading = true;
this.downloadProgress = 0;
this.downloadPath = '';

try {
  await CloudStorageUtil.get().downloadFile(
    remotePath,
    localPath,
    (progress) => {
      this.downloadProgress = progress;
    }
  );
  
  this.downloadPath = localPath;
  console.log('文件下载成功,保存路径:', localPath);
} catch (error) {
  console.error('下载失败:', error);
} finally {
  this.isDownloading = false;
}

}

build() {
Column() {
Text('文件下载')
.fontSize(25)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 })

  // 文件列表
  List({ space: 10 }) {
    ForEach(this.fileList, (filePath) => {
      ListItem() {
        Row() {
          Text(filePath)
            .fontSize(16)
            .layoutWeight(1)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .maxLines(1)
          
          Button('下载')
            .width(80)
            .height(40)
            .enabled(!this.isDownloading)
            .onClick(() => this.downloadFile(filePath))
        }
        .width('100%')
        .padding(10)
      }
    }, (filePath) => filePath)
  }
  .width('100%')
  .layoutWeight(1)
  
  // 下载进度
  if (this.isDownloading) {
    Column() {
      Text(`下载进度: ${this.downloadProgress.toFixed(1)}%`)
        .margin({ bottom: 10 })
      
      Progress({
        value: this.downloadProgress,
        total: 100,
        type: ProgressType.Linear
      })
      .width('90%')
      .height(20)
    }
    .width('100%')
    .margin({ top: 20 })
  }
  
  // 下载完成提示
  if (this.downloadPath) {
    Text(`文件已保存到: ${this.downloadPath}`)
      .fontSize(14)
      .margin({ top: 20 })
  }
}
.width('100%')
.height('100%')
.padding(20)

}
}
第五部分:实现文件管理功能
5.1 扩展CloudStorageUtil
添加文件管理相关方法:

// 添加至CloudStorageUtil类
public async deleteFile(path: string): Promise {
const ref = this.getRef(path);
try {
await ref.delete();
} catch (error) {
if (error instanceof StorageError) {
throw new Error(删除失败: ${error.message});
}
throw error;
}
}

public async getFileMetadata(path: string): Promise<{
name: string;
size: number;
contentType: string;
updated: string;
}> {
const ref = this.getRef(path);
const metadata = await ref.getMetadata();

return {
name: metadata.name,
size: metadata.size,
contentType: metadata.contentType,
updated: new Date(metadata.updated).toLocaleString()
};
}
5.2 创建文件管理页面
创建entry/src/main/ets/pages/FileManagerPage.ets:

import { CloudStorageUtil } from '../utils/CloudStorageUtil';

@Entry
@Component
struct FileManagerPage {
@State fileList: Array = [];
@State currentFile: string = '';
@State fileMetadata: {
name: string;
size: string;
contentType: string;
updated: string;
} | null = null;

onPageShow() {
this.loadFileList();
}

async loadFileList() {
try {
this.fileList = await CloudStorageUtil.get().listFiles('uploads/');
} catch (error) {
console.error('获取文件列表失败:', error);
}
}

async showFileDetails(filePath: string) {
this.currentFile = filePath;
try {
const metadata = await CloudStorageUtil.get().getFileMetadata(filePath);
this.fileMetadata = {
name: metadata.name,
size: ${(metadata.size / 1024).toFixed(2)} KB,
contentType: metadata.contentType,
updated: metadata.updated
};
} catch (error) {
console.error('获取文件详情失败:', error);
this.fileMetadata = null;
}
}

async deleteCurrentFile() {
if (!this.currentFile) return;

try {
  await CloudStorageUtil.get().deleteFile(this.currentFile);
  this.currentFile = '';
  this.fileMetadata = null;
  await this.loadFileList();
} catch (error) {
  console.error('删除文件失败:', error);
}

}

build() {
Column() {
Text('文件管理')
.fontSize(25)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 })

  // 文件列表
  List({ space: 10 }) {
    ForEach(this.fileList, (filePath) => {
      ListItem() {
        Row() {
          Text(filePath)
            .fontSize(16)
            .layoutWeight(1)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .maxLines(1)
          
          Button('查看')
            .width(80)
            .height(40)
            .onClick(() => this.showFileDetails(filePath))
        }
        .width('100%')
        .padding(10)
      }
    }, (filePath) => filePath)
  }
  .width('100%')
  .layoutWeight(1)
  
  // 文件详情
  if (this.fileMetadata) {
    Column() {
      Text('文件详情')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 15 })
      
      Divider()
      
      Row() {
        Text('名称:')
          .fontWeight(FontWeight.Bold)
          .width(100)
        Text(this.fileMetadata.name)
          .layoutWeight(1)
      }
      .margin({ bottom: 10 })
      
      Row() {
        Text('大小:')
          .fontWeight(FontWeight.Bold)
          .width(100)
        Text(this.fileMetadata.size)
          .layoutWeight(1)
      }
      .margin({ bottom: 10 })
      
      Row() {
        Text('类型:')
          .fontWeight(FontWeight.Bold)
          .width(100)
        Text(this.fileMetadata.contentType)
          .layoutWeight(1)
      }
      .margin({ bottom: 10 })
      
      Row() {
        Text('修改时间:')
          .fontWeight(FontWeight.Bold)
          .width(100)
        Text(this.fileMetadata.updated)
          .layoutWeight(1)
      }
      .margin({ bottom: 20 })
      
      Button('删除文件')
        .width(200)
        .height(50)
        .backgroundColor(Color.Red)
        .fontColor(Color.White)
        .onClick(() => this.deleteCurrentFile())
    }
    .width('90%')
    .padding(20)
    .margin({ top: 20 })
    .border({ width: 1, color: '#eeeeee' })
    .borderRadius(10)
  }
}
.width('100%')
.height('100%')
.padding(20)

}
}
第六部分:安全规则配置
6.1 基本安全规则
在AGC控制台的云存储服务中,配置安全规则:

rules_version = '2';
service cloud.storage {
match /{bucket}/{path=} {
// 允许认证用户读写自己的文件
match /users/{userId}/{file=
} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}

// 允许公开读取上传的文件
match /uploads/{file=**} {
  allow read;
  allow write: if request.auth != null;
}

// 默认拒绝所有其他访问
match /{path=**} {
  allow read, write: if false;
}

}
}
6.2 在应用中验证权限
在CloudStorageUtil.ets中添加权限检查:

// 添加至CloudStorageUtil类
public async checkPermission(path: string, operation: 'read' | 'write'): Promise {
try {
const ref = this.getRef(path);

if (operation === 'read') {
  await ref.getDownloadURL(); // 尝试获取下载URL
  return true;
} else {
  // 尝试写入一个测试文件
  const testRef = ref.child('.permission_test');
  await testRef.putString('test');
  await testRef.delete();
  return true;
}

} catch (error) {
return false;
}
}
第七部分:完整应用集成
7.1 创建主页面
修改entry/src/main/ets/pages/Index.ets:

@Entry
@Component
struct Index {
build() {
Column() {
Navigation() {
Column() {
Text('AGC云存储演示')
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 40 })

      Button('文件上传')
        .width(200)
        .height(50)
        .margin({ bottom: 20 })
        .onClick(() => {
          router.pushUrl({ url: 'pages/UploadPage' });
        })
      
      Button('文件下载')
        .width(200)
        .height(50)
        .margin({ bottom: 20 })
        .onClick(() => {
          router.pushUrl({ url: 'pages/DownloadPage' });
        })
      
      Button('文件管理')
        .width(200)
        .height(50)
        .onClick(() => {
          router.pushUrl({ url: 'pages/FileManagerPage' });
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
.width('100%')
.height('100%')

}
}
7.2 配置路由
在entry/src/main/resources/base/profile/main_pages.json中添加:

{
"src": [
"pages/Index",
"pages/UploadPage",
"pages/DownloadPage",
"pages/FileManagerPage"
]
}
总结
通过本教程,你已经完成了:

HarmonyOS 5项目中集成AGC云存储服务
实现了文件上传、下载和管理功能
配置了云存储安全规则
构建了完整的文件管理应用
AGC云存储提供了强大的文件管理能力,包括:

自动扩展的存储空间
文件访问权限控制
上传下载进度监控
文件元数据管理
你可以基于此项目进一步扩展,实现更复杂的文件操作功能,如断点续传、文件预览等。

posted @ 2025-06-28 22:28  暗雨YA  阅读(75)  评论(0)    收藏  举报