碰一碰,秒更新!游戏近场快传助力多人联机无缝组队

在多人联机游戏场景中,玩家组队对战时因游戏版本不一致导致的体验中断问题长期存在。当游戏更新资源包体积庞大时,未及时更新的玩家需依赖网络下载,不仅消耗流量,还因等待时间过长引发用户流失。

HarmonyOS SDK 游戏服务(Game Service Kit)推出的游戏近场快传服务支持设备在彼此靠近的情况下进行游戏数据交换,已更新版本的玩家可发送自身资源包给未更新队友,助其迅速完成游戏更新,提升玩家体验。

功能优势

  • 无需网络:近场快传技术无需依赖网络,在无网络或网络不稳定的环境下,玩家也能轻松分享游戏资源或组队。玩家只需将两台支持近场快传的设备靠近,即可自动建立连接并开始传输,操作简单快捷。

  • 高速传输:游戏近场快传技术传输速度最高可达100MB/S,能够显著提升游戏资源的传输效率。

  • 跨设备兼容:游戏近场快传支持多种设备平台,如Phone、PC/2in1、Tablet,实现无缝传输。

使用步骤

  1. 设备靠近:玩家需要将支持游戏近场快传的设备靠近,以确保能够建立稳定的通信链路。

  2. 选择传输内容:在游戏内或专门的传输应用中,玩家需要选择要传输的游戏资源或数据。

  3. 开始传输:一旦设备间建立连接,玩家即可启动传输过程,等待资源传输完成。

接入步骤

以下示例中使用的API说明详见接口文档

开发流程

导入模块

导入Game Service Kit及公共模块。

复制代码
import { abilityAccessCtrl, AbilityConstant, UIAbility, common } from "@kit.AbilityKit";
import { hilog } from '@kit.PerformanceAnalysisKit';
import { gameNearbyTransfer } from '@kit.GameServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';

申请权限

申请ohos.permission.DISTRIBUTED_DATASYNC权限用于设备发现。

复制代码
let atManager = abilityAccessCtrl.createAtManager();
let uiAbilityContext = this.getUIContext()?.getHostContext() as common.UIAbilityContext;
try {
  atManager.requestPermissionsFromUser(uiAbilityContext, ['ohos.permission.DISTRIBUTED_DATASYNC']).then((data) => {
    hilog.info(0x0000, 'nearby', '%{public}s', 'data: ' + JSON.stringify(data));
  }).catch((err: object) => {
    hilog.error(0x0000, 'nearby', '%{public}s', 'err: ' + JSON.stringify(err));
  })
} catch (err) {
  hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
}

创建游戏近场快传服务并注册相关回调

导入相关模块后,需先调用create接口创建游戏近场快传服务,然后注册各回调事件。

复制代码
public create() {
  let uiAbilityContext = this.getUIContext()?.getHostContext() as common.UIAbilityContext;
  let initParam: gameNearbyTransfer.CreateParameters = {
    abilityName: uiAbilityContext.abilityInfo.name,
    context: uiAbilityContext,
    moduleName: uiAbilityContext.abilityInfo.moduleName,
    needShowSystemUI: false // 是否展示系统UI,true为展示,false为不展示,默认为false
  };
  try {
    gameNearbyTransfer.create(initParam).then((createResult) => {
      hilog.info(0x0000, '[nearby]', '%{public}s', 'create success' + createResult.localDeviceName);
      this.registerCallback();
    }).catch((err: BusinessError) => {
      hilog.error(0x0000, '[nearby]', '%{public}s', 'create error' + (err as Error).message);
    })
  } catch (err) {
    hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
  }
}

// 注册监听
public registerCallback() {
  try {
    gameNearbyTransfer.on('connectNotify', connectNotifyCallBack);
    gameNearbyTransfer.on('receivePackageInfo', receivePackageInfoCallBack);
    gameNearbyTransfer.on('transferNotify', transferNotifyCallBack);
    gameNearbyTransfer.on('error', errorCallBack);
  } catch (err) {
    hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
  }
}

function connectNotifyCallBack(callback: gameNearbyTransfer.ConnectNotification) {
}

function receivePackageInfoCallBack(callback: gameNearbyTransfer.PackageInfo) {

}

function transferNotifyCallBack(callback: gameNearbyTransfer.TransferNotification) {

}

function errorCallBack(callback: gameNearbyTransfer.ReturnResult) {

}

接收端接受协同

接收端实现onCollaborate回调,回调中调用acceptCollaboration接口接受协同。

复制代码
export default class EntryAbility extends UIAbility { 
  // 协同回调
  onCollaborate(wantParam: Record<string, Object>): AbilityConstant.CollaborateResult {
    try {
       gameNearbyTransfer.acceptCollaboration(wantParam);
    } catch (err) {
       hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
    }
    hilog.info(0x0000, '[nearby]', '%{public}s', 'onCollaborate: accept collaborate');
    return AbilityConstant.CollaborateResult.ACCEPT;
  }
}

接收端发布自身游戏近场快传服务

接收端调用publishNearbyGame接口发布自身游戏近场快传服务。

复制代码
try {
  gameNearbyTransfer.publishNearbyGame().then(() => {
    hilog.info(0x0000, '[nearby]', '%{public}s', 'publishNearbyGame success');
  }).catch((err: BusinessError) => {
    hilog.error(0x0000, '[nearby]', '%{public}s', 'publishNearbyGame error');
  })
} catch (err) {
  hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
}

发送端绑定接收端游戏近场快传服务

发送端绑定接收端游戏近场快传服务支持如下两种方式:自动绑定和选择绑定。

这里以自动绑定为例,发送端调用autoBindNearbyGame接口自动绑定接收端近场快传服务。

复制代码
try {
  gameNearbyTransfer.autoBindNearbyGame().then(() => {
    hilog.info(0x0000, '[nearby]', '%{public}s', 'autoBindNearbyGame success');
  }).catch((err: BusinessError) => {
    hilog.error(0x0000, '[nearby]', '%{public}s', 'autoBindNearbyGame error');
  })
} catch (err) {
  hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
}

接收端发送自身文件信息

收到建链成功回调后,接收端调用sendPackageInfo接口发送自身文件,如版本信息、包信息(包名和扩展数据的字符长度范围:[0, 2048]、版本号字符长度范围:[0, 256]、文件列表最多10000条)。

复制代码
function connectNotifyCallBack(callback: gameNearbyTransfer.ConnectNotification) {
  if (callback.connectState == gameNearbyTransfer.ConnectState.CONNECTED) {
    // 连接成功回调,判断当前是否为接收端。若当前设备为接收端,请设置为true,否则请设置为false。
    let isReceive = true;
    if (!isReceive) {
      return;
    }
    // 接收端收到连接回调后需要处理,发送资源包信息给发送端
    let packageInfo: gameNearbyTransfer.PackageInfo = {
      name: 'com.huawei.xxxx',
      files: [],
      version: '1.1.0',
      extraData: 'extraData'
    };
    let fileInfo: gameNearbyTransfer.FileInfo = {
      path: "/xxx/xxxx/files/data.zip", // 使用沙箱路径
      hash: 'fileHash' // 可选
    };
    packageInfo.files?.push(fileInfo);
    try {
      gameNearbyTransfer.sendPackageInfo(packageInfo).then(() => {
        hilog.info(0x0000, '[nearby]', '%{public}s', 'sendPackageInfo success');
      }).catch((err: BusinessError) => {
        hilog.error(0x0000, '[nearby]', '%{public}s', 'sendPackageInfo error');
      });
    } catch (err) {
      hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
    }
  }
}

发送端对比后传输资源包

发送端收到接收端发送的版本信息后进行对比,调用replyPackageInfoResult上报对比结果,根据对比结果决定是否需要调用transferPackageData接口发送资源包数据。

复制代码
function receivePackageInfoCallBack(callback: gameNearbyTransfer.PackageInfo) {
  // 比较版本,决定是否需要发送资源包,也可以比较文件hash
  let packageInfoResult: gameNearbyTransfer.PackageInfoResult = {
    packageInfoResultCode: gameNearbyTransfer.PackageInfoResultCode.PACKAGE_AVAILABLE_COMPARED
  };
  try {
    // 上报对比结果
    gameNearbyTransfer.replyPackageInfoResult(packageInfoResult).then(() => {
      let packageData: gameNearbyTransfer.PackageData = {
        name: 'com.huawei.gamenearbydemo',
        version: '1.0.0',
        files: [{
          srcPath: '/data/xxxx/a.zip', // srcPath是需要发送文件的沙箱路径,详情请参见应用沙箱目录。
          destPath: 'xxxx/a.zip'       // destPath是接收文件的自定义路径,完整的沙箱路径是fileStoragePath+destPath,详情请参见应用沙箱目录。
        }] 
      }
      try {
        // 发送资源包
        gameNearbyTransfer.transferPackageData(packageData).then(() => {
          // 发送成功
        }).catch((err: BusinessError) => {
          // 发送异常
          hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);          
        });
      } catch (err) {
        hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
      }
    }).catch((err: BusinessError) => {
      // 上报异常
      hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
    });
  } catch (err) {
    hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
  }
}

处理资源包传输进度信息

发送端和接收端在传输回调中处理传输进度信息。

复制代码
function transferNotifyCallBack(callback: gameNearbyTransfer.TransferNotification) {
  if (callback.transferState == gameNearbyTransfer.TransferState.SEND_PROCESS) {
    // 处理发送进度,如显示进度条和速率
  }
  if (callback.transferState == gameNearbyTransfer.TransferState.SEND_FINISH) {
    // 发送完成
  }
  if (callback.transferState == gameNearbyTransfer.TransferState.RECEIVE_PROCESS) {
    // 处理接收进度,如显示进度条和速率
  }
  if (callback.transferState == gameNearbyTransfer.TransferState.RECEIVE_FINISH) {
    // 接收完成,获取到资源包存储的沙箱路径
    let fileStoragePath = callback.fileStoragePath;
    // 对fileStoragePath下的文件做处理
  }
}

处理已接收资源包后销毁服务

对已接收数据做好处理或转移后,调用destroy接口销毁服务。若服务销毁后再次使用近场快传服务,需重新创建游戏近场快传服务并注册相关回调。

复制代码
public destroy() {
  // 取消回调注册
  this.unregisterCallback();
  // 销毁服务
  try {
    gameNearbyTransfer.destroy().then(() => {
      hilog.info(0x0000, '[nearby]', '%{public}s', 'destroy success');
    }).catch((err: Error) => {
      hilog.error(0x0000, '[nearby]', '%{public}s', 'destroy error' + (err as Error).message);
    });
  } catch (err) {
    hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
  }
}
public unregisterCallback() {
  try {
    gameNearbyTransfer.off('connectNotify', connectNotifyCallBack);
    gameNearbyTransfer.off('receivePackageInfo', receivePackageInfoCallBack);
    gameNearbyTransfer.off('transferNotify', transferNotifyCallBack);
    gameNearbyTransfer.off('error', errorCallBack);
    // 发送端选择手动绑定接收端且已订阅discovery事件
    gameNearbyTransfer.off('discovery', discoveryCallBack);
  } catch (err) {
    hilog.error(0x0000, '[nearby]', '%{public}s', 'error' + (err as Error).message);
  }
}
function connectNotifyCallBack(callback: gameNearbyTransfer.ConnectNotification) {
}
function receivePackageInfoCallBack(callback: gameNearbyTransfer.PackageInfo) {
}
function transferNotifyCallBack(callback: gameNearbyTransfer.TransferNotification) {
}
function errorCallBack(callback: gameNearbyTransfer.ReturnResult) {
}
function discoveryCallBack(callback: gameNearbyTransfer.DiscoveryResult) {
}

了解更多详情>>

访问游戏服务联盟官网

获取游戏近场快传开发指导文档

相关推荐
鸿蒙小白龙4 小时前
基于 OpenHarmony 6.0 的智能充电桩技术方案与实现
能源·harmonyos·鸿蒙·鸿蒙系统·open harmony
电子小子洋酱4 小时前
BearPi小熊派 鸿蒙入门开发笔记(4)
笔记·华为·harmonyos
熊猫钓鱼>_>5 小时前
【案例实战】鸿蒙分布式智能办公应用的架构设计与性能优化
分布式·华为·harmonyos
鸿蒙小白龙6 小时前
Openharmony应用开发之Ability异常退出与UIAbility数据备份开发实战
harmonyos·鸿蒙·鸿蒙系统·open harmony
Damon小智6 小时前
RedPlayer 视频播放器在 HarmonyOS 应用中的实践
音视频·harmonyos·鸿蒙·小红书·三方库·redplayer
猫林老师18 小时前
HarmonyOS分布式硬件共享:调用手机摄像头的手表应用
华为·交互·harmonyos
前端世界1 天前
HarmonyOS应用开发指南:Toast无法显示的完整排查流程与实战案例
华为·harmonyos
安卓开发者1 天前
鸿蒙NEXT Wear Engine穿戴侧应用开发完全指南
ubuntu·华为·harmonyos
安卓开发者1 天前
鸿蒙Next振动开发指南:打造沉浸式触觉反馈体验
华为·harmonyos