本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

核心功能

  • 分布式文件系统为应用提供跨设备文件访问的能力

  • 两个设备上安装同一应用时,通过基础文件接口可跨设备读写另一个设备上该应用分布式目录下的文件

1.2 应用场景

  • 多设备数据流转:设备组网互联之后,设备A上的应用可访问设备B上的同应用分布式目录下的文件

  • 文件共享机制:期望应用文件被其他设备访问时,只需将文件移动到分布式目录即可

二、注意事项

2.1 目录说明

  1. distributedfiles目录

    • 为本应用在多设备间共享文件的合集

    • 路径:/data/storage/el2/distributedfiles/

    • 注意:为避免误删其他设备生成的文件,应用在执行删除操作前,请务必确认操作是否符合预期

  2. .remote_share/目录

    • 路径:/data/storage/el2/distributedfiles/.remote_share/

    • 由系统自动创建并管理

    • 开发者不得手动删除该目录下的文件

    • 该目录中的文件与应用的base目录直接映射(不占用额外存储空间)

    • 任何删除操作可能导致base目录中的原始文件永久丢失

三、开发步骤

3.1 步骤一:分布式组网

设备要求

  • 两个设备登录同一账号

  • 保证设备蓝牙和Wi-Fi功能开启

  • 蓝牙无需互连

  • Wi-Fi无需接入同一个局域网

3.2 步骤二:授权分布式数据同步权限

权限特点

  • 分布式数据同步权限的授权方式为user_grant

  • 需要调用requestPermissionsFromUser接口

  • 动态弹窗的方式向用户申请授权

实现代码

import { common, abilityAccessCtrl } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

let atManager = abilityAccessCtrl.createAtManager();

try {
  // 以动态弹窗的方式向用户申请授权
  atManager.requestPermissionsFromUser(context, ['ohos.permission.DISTRIBUTED_DATASYNC'])
    .then((result) => {
      console.info(`request permission result: ${JSON.stringify(result)}`);
    }).catch((err: BusinessError) => {
      console.error(`Failed to request permissions from user. Code: ${err.code}, message: ${err.message}`);
    });
} catch (error) {
  let err: BusinessError = error as BusinessError;
  console.error(`Catch err. Failed to request permissions from user. Code: ${err.code}, message: ${err.message}`);
}

3.3 步骤三:访问跨设备文件

核心机制

  • 同一应用不同设备之间实现跨设备文件访问

  • 只需要将对应的文件放在应用沙箱的分布式目录即可

3.3.1 设备A:创建测试文件
import { fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

let pathDir: string = context.distributedFilesDir;
// 获取分布式目录的文件路径
let filePath: string = pathDir + '/test.txt';

try {
  // 在分布式目录下创建文件
  let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  console.info('Succeeded in creating.');
  
  // 向文件中写入内容
  fs.writeSync(file.fd, 'content');
  
  // 关闭文件
  fs.closeSync(file.fd);
} catch (error) {
  let err: BusinessError = error as BusinessError;
  console.error(`Failed to openSync / writeSync / closeSync. Code: ${err.code}, message: ${err.message}`);
}
3.3.2 设备B:读取测试文件

说明:通过分布式设备管理的接口获取设备networkId

import { fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
import { distributedDeviceManager } from '@kit.DistributedServiceKit';

// 通过分布式设备管理的接口获取设备A的networkId信息
// ...
let dmInstance = distributedDeviceManager.createDeviceManager('com.example.hap');
let deviceInfoList: distributedDeviceManager.DeviceBasicInfo[] = dmInstance.getAvailableDeviceListSync();

if (deviceInfoList && deviceInfoList.length > 0) {
  console.info(`Success to get available device list`);
  let networkId = deviceInfoList[0].networkId;
  
  // 定义访问公共文件目录的回调
  let listeners: fs.DfsListeners = {
    onStatus: (networkId: string, status: number): void => {
      console.info('Failed to access public directory');
    }
  };
  
  // 开始跨设备文件访问
  fs.connectDfs(networkId, listeners).then(() => {
    console.info('Success to connect dfs');
    
    let pathDir: string = context.distributedFilesDir;
    // 获取分布式目录的文件路径
    let filePath: string = pathDir + '/test.txt';
    
    try {
      // 打开分布式目录下的文件
      let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE);
      
      // 定义接收读取数据的缓存
      let arrayBuffer = new ArrayBuffer(4096);
      
      // 读取文件的内容,返回值是读取到的字节个数
      class Option {
        public offset: number = 0;
        public length: number = 0;
      };
      let option = new Option();
      option.length = arrayBuffer.byteLength;
      
      let num = fs.readSync(file.fd, arrayBuffer, option);
      
      // 打印读取到的文件数据
      let buf = buffer.from(arrayBuffer, 0, num);
      console.info('read result: ' + buf.toString());
      
      fs.closeSync(file);
    } catch (error) {
      let err: BusinessError = error as BusinessError;
      console.error(`Failed to openSync / readSync. Code: ${err.code}, message: ${err.message}`);
    }
  }).catch((error: BusinessError) => {
    let err: BusinessError = error as BusinessError;
    console.error(`Failed to connect dfs. Code: ${err.code}, message: ${err.message}`);
  });
}
3.3.3 设备B:断开链路
import { BusinessError } from '@kit.BasicServicesKit';
import { distributedDeviceManager } from '@kit.DistributedServiceKit';
import { fileIo as fs } from '@kit.CoreFileKit';

// 获取设备A的networkId
// ...
let dmInstance = distributedDeviceManager.createDeviceManager('com.example.hap');
let deviceInfoList: distributedDeviceManager.DeviceBasicInfo[] = dmInstance.getAvailableDeviceListSync();

if (deviceInfoList && deviceInfoList.length > 0) {
  console.info(`Success to get available device list`);
  let networkId = deviceInfoList[0].networkId;
  
  // 关闭跨设备文件访问
  fs.disconnectDfs(networkId).then(() => {
    console.info(`Success to disconnect dfs`);
  }).catch((err: BusinessError) => {
    console.error(`Failed to disconnect dfs. Code: ${err.code}, message: ${err.message}`);
  });
}

四、相关API

4.1 权限申请相关

  • 权限名称ohos.permission.DISTRIBUTED_DATASYNC

  • 申请方式abilityAccessCtrl.createAtManager().requestPermissionsFromUser()

  • 授权类型:user_grant(需要用户动态授权)

4.2 分布式文件访问相关

API 功能 所属模块
context.distributedFilesDir 获取分布式目录路径 @kit.AbilityKit
fs.connectDfs() 连接分布式文件系统 @kit.CoreFileKit
fs.disconnectDfs() 断开分布式文件系统连接 @kit.CoreFileKit
fs.DfsListeners 分布式文件访问状态监听 @kit.CoreFileKit

4.3 设备管理相关

API 功能 所属模块
distributedDeviceManager.createDeviceManager() 创建设备管理器 @kit.DistributedServiceKit
getAvailableDeviceListSync() 获取可用设备列表 @kit.DistributedServiceKit
DeviceBasicInfo.networkId 获取设备网络ID @kit.DistributedServiceKit

流程总结

1. 设备准备
   ↓ 同一账号登录,开启蓝牙和Wi-Fi
2. 权限申请
   ↓ 动态申请DISTRIBUTED_DATASYNC权限
3. 设备A操作
   ↓ 在分布式目录创建/写入文件
4. 设备B操作
   ↓ 获取设备A的networkId
   ↓ 连接分布式文件系统(fs.connectDfs)
   ↓ 读取分布式目录文件
   ↓ 断开连接(fs.disconnectDfs)

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐