鸿蒙系统开发【应用接续】基本功能

news2024/11/13 12:24:34

应用接续

介绍

基于ArkTS扩展的声明式开发范式编程语言编写的一个分布式视频播放器,主要包括一个直播视频播放界面,实现视频播放时可以从一台设备迁移到另一台设备继续运行,来选择更合适的设备继续执行播放功能以及PAD视频播放时协同调用手机编辑发送弹幕功能。

效果预览

1

使用说明

  1. 准备手机端与平板端两台设备,并且登录同一华为账号,双端设备打开WI-FI和蓝牙,建议双端设备接入同一个局域网,可提升数据传输的速度
  2. 双端设备均安装此应用
  3. 滑动浏览手机端视频,打开平板端应用
  4. 点击平板端手机输入按钮,调起手机端输入内容,提交后平板端查看

具体实现

  1. 在实现协同接口前,应用需要申请协同所需的访问控制权ohos.permission.DISTRIBUTED_DATASYNC。 在requestPermissions字段中增加权限声明ohos.permission.DISTRIBUTED_DATASYNC
  2. 同时需要在应用首次启动时弹窗向用户申请授权,在用户手动允许授权后,应用才会真正获取相应权限,从而成功访问操作目标对象。 在EntryAbility类中实现以下函数,从而在调用时动态弹窗向用户申请权限。
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { abilityAccessCtrl, AbilityConstant, bundleManager, Permissions, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { WindowUtil } from '../utils/WindowUtil';
import Logger from '../utils/Logger';

export default class EntryAbility extends UIAbility {
  contentStorage?: LocalStorage;

  onContinue(wantParam: Record<string, Object>) {
    Logger.info(wantParam.version.toString(), wantParam.targetDevice.toString());

    // Preparing to Migrate Data
    let activeLive: number = AppStorage.get<number>('activeLive') as number;

    // Save the data to be migrated in the 'data' field of wantParam.
    wantParam['activeLive'] = activeLive;
    // Setting the Source End Not to Exit
    wantParam["ohos.extra.param.key.supportContinueSourceExit"] = false;

    Logger.info(activeLive.toString());
    return AbilityConstant.OnContinueResult.AGREE
  }

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    Logger.info('Ability onCreate');
    this.checkPermissions();

    // If the invoking reason is migration, set the status to migratable to cope with cold start (ensuring migration continuity)
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
        Logger.info(JSON.stringify(result));
      });
    }

    // Cold start of the application: Restore the saved migration data
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      // Restore migrated data from want
      let activeLive = want?.parameters?.activeLive;
      AppStorage.setOrCreate<number>('activeLive', activeLive as number);
      Logger.info(activeLive as string);
      // Explicit invocation of page restore
      this.contentStorage = new LocalStorage();
      Logger.info('Ability onCreate restoreWindowStage');
      this.context.restoreWindowStage(this.contentStorage);
    }
  }

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
    Logger.info('Ability onCreate');

    // If the invoking reason is migration, set the status to migratable to cope with hot start (ensuring migration continuity)
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
        Logger.info(JSON.stringify(result));
      });
    }

    //During the warm start of an application: Restore the saved migration data
    if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
      // Restore migrated data from want
      let activeLive = want?.parameters?.activeLive;
      AppStorage.setOrCreate<number>('activeLive', activeLive as number);
      Logger.info(activeLive as string);
      // Explicit invocation of page restore
      this.contentStorage = new LocalStorage();
      Logger.info('Ability onNewWant restoreWindowStage');
      this.context.restoreWindowStage(this.contentStorage);
    }
  }

  // Check permission granting and dynamically apply for permissions
  async checkPermissions(): Promise<void> {
    const permissions: Array<Permissions> = ['ohos.permission.DISTRIBUTED_DATASYNC'];

    let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permissions[0]);
    // Verifying Permission Granting
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      // Granted
      Logger.info('Permission already granted.');
    } else {
      // Not granted. Dynamically apply for authorization in the dialog box displayed to the user
      let atManager = abilityAccessCtrl.createAtManager();
      try {
        atManager.requestPermissionsFromUser(this.context, ['ohos.permission.DISTRIBUTED_DATASYNC'], (err, data) => {
          Logger.info(JSON.stringify(data));
        });
      } catch (err) {
        Logger.error(JSON.stringify(err));
        return;
      }
    }
  }

  // Get the grant status of the current app's permissions
  async checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
    let atManager = abilityAccessCtrl.createAtManager();
    let grantStatus: abilityAccessCtrl.GrantStatus = -1;

    // Obtains the token ID
    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 (err) {
      Logger.error(JSON.stringify(err));
    }

    try {
      grantStatus = await atManager.checkAccessToken(tokenId, permission);
    } catch (err) {
      Logger.error(JSON.stringify(err));
    }
    return grantStatus;
  }

  onDestroy(): void {
    Logger.info('Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    Logger.info('Ability onWindowStageCreate');

    WindowUtil.requestFullScreen(windowStage, this.context);
    WindowUtil.updateStatusBarColor(this.context, true);

    windowStage.loadContent('pages/LivePage', (err) => {
      if (err.code) {
        Logger.error(JSON.stringify(err) ?? '');
        return;
      }
      Logger.info('Succeeded in loading the content.');
    });
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    Logger.info('Ability onWindowStageDestroy');
  }

  onWindowStageRestore(windowStage: window.WindowStage): void {
    WindowUtil.requestFullScreen(windowStage, this.context);
  }

  onForeground(): void {
    // Ability has brought to foreground
    Logger.info('Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    Logger.info('Ability onBackground');
  }
}
  1. 获取目标设备的设备ID。
  2. 在发起端设置目标组件参数,调用startAbilityForResult()接口启动目标端UIAbility,异步回调中的data用于接收目标端UIAbility停止自身后返回给调用方UIAbility的信息。
  3. 在目标端UIAbility任务完成后,调用terminateSelfWithResult()方法,将数据返回给发起端的UIAbility。
  4. 发起端UIAbility接收到目标端UIAbility返回的信息,对其进行处理。

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

在这里插入图片描述

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1974538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么选择的开放式耳机好用?2024超值耳机分享!

耳机在当前数字化时代已成为我们生活、娱乐乃至工作中的重要部分。随着市场需求的增长&#xff0c;消费者对耳机的期望也在提高&#xff0c;他们不仅追求音质的卓越&#xff0c;还关注佩戴的舒适度和外观设计。虽然传统的入耳式和半入耳式耳机在音质上往往能够满足人们&#xf…

JavaFX布局-Accordion

JavaFX布局-Accordion 一个可扩展的面板&#xff0c;包括标题、内容与TitledPane配合一起使用 public static Accordion demo1() {// 创建AccordionAccordion accordion new Accordion();// 内边距accordion.setPadding(new Insets(10, 10, 10, 10));for (int i 1; i < 1…

PSINS工具箱函数介绍——avperrset

目录 avperrset是设置avp误差的函数使用方法函数源代码源代码解析 avperrset是设置avp误差的函数 输入为角度误差、速度误差、位置误差。 输出也是角度误差、速度误差、位置误差。 看起来输入和输出都一样&#xff0c;为什么还要这个函数呢&#xff1f; 那是因为这个函数可以进…

计算机网络-PIM-DM密集模式工作原理

一、PIM-DM基础概念 PIM-DM主要用在组成员较少且相对密集的网络中&#xff0c;通过"扩散-剪枝"的方式形成组播转发树&#xff08;SPT&#xff09;。 PIM-DM在形成SPT的过程中&#xff0c;除了扩散&#xff08;Flooding&#xff09;&#xff0c;剪枝&#xff08;Prune…

基于YOLOv10的裂缝检测系统

基于YOLOv10的裂缝检测系统 (价格80) 包含 【裂缝】 1个类 通过PYQT构建UI界面&#xff0c;包含图片检测&#xff0c;视频检测&#xff0c;摄像头实时检测。 &#xff08;该系统可以根据数据训练出的yolov10的权重文件&#xff0c;运用在其他检测系统上&#xff0c;如火…

Logic Error: 如何识别和修复逻辑错误

&#x1f9e9; Logic Error: 如何识别和修复逻辑错误 &#x1f50d; &#x1f9e9; Logic Error: 如何识别和修复逻辑错误 &#x1f50d;摘要引言正文内容一、什么是逻辑错误&#xff1f; &#x1f914;1.1 逻辑错误的定义1.2 逻辑错误的特征 二、常见的逻辑错误类型 &#x1f…

深度洞察·情感保鲜与经济可持续的共鸣——解锁情感与品牌长青的密码

深度洞察情感保鲜与经济可持续的共鸣——解锁情感与品牌长青的密码 在这个快节奏的时代&#xff0c;我们常常在探寻&#xff0c;为何曾经那份心动的激情会逐渐褪色&#xff0c;如同你我点解&#xff0c;两人并肩却渐失“feel”&#xff0c;想要转身离去&#xff1f;或许&#…

分享5款ai头像工具,助你轻松实现社交新形象

如今&#xff0c;无论是社交媒体上的个人形象塑造&#xff0c;还是虚拟世界中的角色扮演&#xff0c;一个独特而吸引人的AI头像都能成为你个性化的代表。 例如&#xff0c;ai头像男古风通常代表着一种对传统文化的尊重和热爱&#xff1b;而现代简约头像可能代表着一种追求简洁…

U盘数据恢复不再难:2024年4款工具,找回你“躲藏”的记忆

现在市面上有一些非常棒的U盘数据恢复软件&#xff0c;它们特别好用&#xff0c;就算你对电脑不太懂也能轻松搞定。这些软件能在几分钟之内帮你检查U盘&#xff0c;找出那些被误删的照片、文件和视频&#xff0c;让你可以轻松把它们找回来。不管你是自己用还是工作需要&#xf…

bus hound简单使用记录,抓取usb hid数据

有很多博文介绍&#xff0c;如参考&#xff0c;但在实际操作中很迷茫&#xff0c;第一步的选设备就一脸懵&#xff0c;下面是实际使用过程 使用这个bus hound的原因 在调试一个usb的自定义hid时出现很多数据无效&#xff0c;但有些又可用&#xff0c;所以想用软件查看真正的上…

科普文:微服务之Spring Cloud 组件API网关Gateway

API网关是一个服务器&#xff0c;是系统的唯一入口。从面向对象设计的角度看&#xff0c;它与外观模式类似。API网关封装了系统内部架构&#xff0c;为每个客户端提供一个定制的API。它可能还具有其它职责&#xff0c;如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响…

OpenAI API giving error: 429 Too Many Requests

题意&#xff1a;OpenAI API 返回错误&#xff1a;429 请求过多 问题背景&#xff1a; I am trying to make a request to the openai API with the following code in express nodeJS: 我正在尝试使用以下 Express Node.js 代码向 OpenAI API 发送请求&#xff1a; import …

MolGAN网络架构:用于小分子图的隐式生成模型

MolGAN&#xff1a;小分子图的隐式生成模型 文章目录 一、说明二、简介三、背景知识3.1.分子作为图表3.2.隐式方法与基于可能性的方法2.3 改进的 WGAN2.4.确定性策略梯度 四、模型说明4.1生成器4.2.判别器和奖励网络 五、实验5.1 数据集5.2 生成器架构5.3 判别器和奖励网络架构…

打造前端开发的利器--NPM

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

YOLOv8添加注意力模块并测试和训练

YOLOv8添加注意力模块并测试和训练 参考bilibili视频 yolov8代码库中写好了注意力模块&#xff0c;但是yolov8的yaml文件中并没用使用它&#xff0c;如下图的通道注意力和空间注意力以及两者的结合CBAM&#xff0c;打开conv.py文件可以看到&#xff0c;其中包含了各种卷积块的…

ClinicalAgent:结合大模型的临床试验多智能体系统

ClinicalAgent&#xff1a;结合大模型的临床试验多智能体系统 提出背景ClinicalAgent 框架规划智能体功效智能体安全智能体 解法解法 子解法1&#xff08;因为需要处理复杂的数据和多变量&#xff09; 子解法2&#xff08;因为需要及时反馈临床试验中的变化&#xff09; 子解…

海信聚好看的DBDocter软件使用心得

在墨天轮大会看到这个软件,好称是内核级别的诊断工具, 工作空闲下载免费看看 结果要1.7GB还TAR. DBdoctor是一款内核级数据库性能诊断软件。可以对数据库做细粒度的扫描&#xff0c;帮助您一分钟内找到数据库性能问题&#xff0c;实现性能诊断百倍提效。针对数据库性能诊断门…

ICML 2024:从历史数据中挖掘最优策略,高效完成50+任务,“离线策略提升的在线演员-评论家”研究工作

长期以来&#xff0c;如何提升数据利用效率被认为是强化学习落地应用的一大桎梏。过去非策略&#xff08;off-policy&#xff09;的强化学习虽然能反复利用收集到的数据来进行策略优化&#xff0c;然而这些方法未能最大限度地利用重放缓冲区&#xff08;Replay buffer&#xff…

新手小白学习PCB设计,立创EDA专业版

本教程有b站某UP主的视频观后感 视频链接&#xff1a;http://【【教程】零基础入门PCB设计-国一学长带你学立创EDA专业版 全程保姆级教学 中文字幕&#xff08;持续更新中&#xff09;】https://www.bilibili.com/video/BV1At421h7Ui?vd_sourcefedb10d2d09f5750366f83c1e0d4a…

JAVA进阶学习13

文章目录 2.2.3 综合输入和输出方法进行文件拷贝2.2.4 字节流读取时乱码的问题 2.3 字符流的方法概述2.3.1 FileReader方法2.3.2 FileWriter方法2.3.3 小结 三、高级IO流3.1 缓冲流3.1.1 字节缓冲流3.1.2 字符缓冲流 3.2 转换流3.3 序列化流3.3.1 序列化流3.3.2 反序列化流 3.4…