鸿蒙系统开发【应用接续】基本功能
应用接续
介绍
基于ArkTS扩展的声明式开发范式编程语言编写的一个分布式视频播放器,主要包括一个直播视频播放界面,实现视频播放时可以从一台设备迁移到另一台设备继续运行,来选择更合适的设备继续执行播放功能以及PAD视频播放时协同调用手机编辑发送弹幕功能。
效果预览
使用说明
- 准备手机端与平板端两台设备,并且登录同一华为账号,双端设备打开WI-FI和蓝牙,建议双端设备接入同一个局域网,可提升数据传输的速度
- 双端设备均安装此应用
- 滑动浏览手机端视频,打开平板端应用
- 点击平板端手机输入按钮,调起手机端输入内容,提交后平板端查看
具体实现
- 在实现协同接口前,应用需要申请协同所需的访问控制权ohos.permission.DISTRIBUTED_DATASYNC。 在requestPermissions字段中增加权限声明ohos.permission.DISTRIBUTED_DATASYNC
- 同时需要在应用首次启动时弹窗向用户申请授权,在用户手动允许授权后,应用才会真正获取相应权限,从而成功访问操作目标对象。 在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 Datalet 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 ExitwantParam["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 dataif (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {// Restore migrated data from wantlet activeLive = want?.parameters?.activeLive;AppStorage.setOrCreate<number>('activeLive', activeLive as number);Logger.info(activeLive as string);// Explicit invocation of page restorethis.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 dataif (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {// Restore migrated data from wantlet activeLive = want?.parameters?.activeLive;AppStorage.setOrCreate<number>('activeLive', activeLive as number);Logger.info(activeLive as string);// Explicit invocation of page restorethis.contentStorage = new LocalStorage();Logger.info('Ability onNewWant restoreWindowStage');this.context.restoreWindowStage(this.contentStorage);}}// Check permission granting and dynamically apply for permissionsasync checkPermissions(): Promise<void> {const permissions: Array<Permissions> = ['ohos.permission.DISTRIBUTED_DATASYNC'];let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permissions[0]);// Verifying Permission Grantingif (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {// GrantedLogger.info('Permission already granted.');} else {// Not granted. Dynamically apply for authorization in the dialog box displayed to the userlet 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 permissionsasync checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {let atManager = abilityAccessCtrl.createAtManager();let grantStatus: abilityAccessCtrl.GrantStatus = -1;// Obtains the token IDlet 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 abilityLogger.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 resourcesLogger.info('Ability onWindowStageDestroy');}onWindowStageRestore(windowStage: window.WindowStage): void {WindowUtil.requestFullScreen(windowStage, this.context);}onForeground(): void {// Ability has brought to foregroundLogger.info('Ability onForeground');}onBackground(): void {// Ability has back to backgroundLogger.info('Ability onBackground');}
}
- 获取目标设备的设备ID。
- 在发起端设置目标组件参数,调用startAbilityForResult()接口启动目标端UIAbility,异步回调中的data用于接收目标端UIAbility停止自身后返回给调用方UIAbility的信息。
- 在目标端UIAbility任务完成后,调用terminateSelfWithResult()方法,将数据返回给发起端的UIAbility。
- 发起端UIAbility接收到目标端UIAbility返回的信息,对其进行处理。
以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下:
内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!
鸿蒙【北向应用开发+南向系统层开发】文档
鸿蒙【基础+实战项目】视频
鸿蒙面经
为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!
相关文章:

鸿蒙系统开发【应用接续】基本功能
应用接续 介绍 基于ArkTS扩展的声明式开发范式编程语言编写的一个分布式视频播放器,主要包括一个直播视频播放界面,实现视频播放时可以从一台设备迁移到另一台设备继续运行,来选择更合适的设备继续执行播放功能以及PAD视频播放时协同调用手…...
nextTick方法的作用是什么?什么时候会用到
nextTick 方法在 Vue.js 中扮演着重要的角色,它用于在下次 DOM 更新循环结束之后执行延迟回调。这主要用于确保在 Vue 完成 DOM 更新后执行依赖于 DOM 的操作。 作用 确保 DOM 更新完成:Vue 的 DOM 更新是异步的,当你修改了数据后࿰…...

多 NodeJS 环境管理
前言 对于某个项目依赖特定版本的 NodeJS,或几个项目的 NodeJS 版本冲突时,需要在系统中安装多个版本的 NodeJS,这时可以使用一些工具来进行多个 NodeJS 的管理。 有很多类似的 NodeJS 管理工具,如 nvm, nvs, n 等,接…...
解决网站被植入跳转木马病毒
概述 网站被植入跳转木马病毒是一种常见的安全威胁,它可能导致网站用户被重定向到恶意站点。本文将指导您如何检测、清除这类木马病毒以及采取预防措施。 步骤1:确认感染 首先,需要确认您的网站确实受到了跳转木马的影响。 示例ÿ…...

Node.js(6)——npm软件包管理
npm npm是Node.js标准的软件包管理器。 使用: 初始化清单文件:npm init-y(得到package.json文件,有则略过此命令)下载软件包:npm i 软件包名称使用软件包 示例: 初始状态下npm文件夹下只有server.js,下载软件包前看…...

区块链核心概念与技术架构简介
引言 区块链,一种分布式账本技术,不仅为数字货币提供了基础设施,更在金融、供应链、物联网等多个领域展现出广泛的应用前景。区块链技术被认为是继蒸汽机、电力、互联网之后,下一代颠覆性的核心技术。 如果说蒸汽机释放了人们的…...

≌图概念凸显包含射线V的直线W是比V长的线
黄小宁 x轴中:各非负数点xh≥0都变回自己即都作恒等变换,其余点x-h都变号为xh就使x轴失去负数点而变为射线V{xh≥0}。这x轴变为射线V⊂x轴是不保距变换即不是x轴的刚体运动使x轴不≌V⊂x轴(小学生都知道x轴不≌射线V)。据≌图概念…...
子路由的配置方法?
子路由的配置方法主要涉及到在Vue-router中定义嵌套路由,即一个路由内部包含多个子路由。以下是配置子路由的基本步骤: 1. 定义父路由 首先,在Vue Router中定义父路由。父路由可以像其他普通路由一样定义,但通常会有一个组件与之…...
【大模型从入门到精通2】openAI api的入门介绍2
互动对话界面的搭建 让我们来看看如何建立一个互动对话界面,用户可以在此输入查询,系统实时处理并显示响应。 import panel as pn # 用于构建图形用户界面# 初始化对话历史记录和GUI组件 conversation_history [] input_widget pn.widgets.TextInpu…...

【前端编程小白】的HTML从零入门到实战
之前有高中毕业生读了博客,想让我帮他找一些前端入门的内容,他们报的计算机专业,想利用开学前夕学习一下,我给他推荐了一些菜鸟教程呀什么的。后来想,看来还是很多人需要一些更加入门的可成的,而且很多教程…...
easyexcel读文件入批量入es
1. 封装实体类,并对应excel表中的列 Data public class User {private String md5;private String id; ExcelProperty(value "age")private String age;ExcelProperty(value "username")private String name;} 2. 批量入库 private void in…...

JS+H5打字练习器
实现功能 1.导入.TXT文件到打字练习内容(部分浏览器可能出于安全问题限制了这一步操作) 2.输入文本到打字练习内(弹出输入框,将要练习的内容输入至输入框) 3. 开始练习,并根据正误在打字练习内容文本上修…...

windows系统关闭开机自检硬盘
效果: 注册表关闭开机硬盘自检,你可以按照以下步骤操作: 打开注册表编辑器: 按 Win R 键打开“运行”对话框。输入 regedit 并按回车,打开注册表编辑器。 定位到自检相关的键: 依次展开以下路径&#x…...
【多线程开发 5】实践使用Lock和Condition
Lock和Condition Lock 线程之间同步或者竞争都需要锁这类结构,一般我们都会用Object的wait和signal搭配synchronized关键字进行多线程开发,但是很多时候会造成死锁的现象,这是因为synchroniezd无法破坏死锁的产生条件,但是Lock接…...
2.4-结构化并发:协程的结构化异常管理
文章目录 协程结构化异常流程协程结构化异常流程和取消流程的区别子协程异常为什么要连带取消父协程? CoroutineExceptionHandler异常协程异常的最后一道拦截:CoroutineExceptionHandlerCoroutineExceptionHandler 为什么只能设置给最外层协程才有效&…...
Android 12.0 debug版本打开OEM解锁开关功能实现
通常为了方便push在debug版本会采用如下命令 adb root adb disable-verity 提示: Device is locked. Please unlock the device first. 查找日志可以发现system/core/set-verity-state/set-verity-state.cpp文件中is_avb_device_locked方法里 这个获取ro.boot…...

linux用户组练习
准备工作 [rootlocalhost ~]# watch -n 1 tail -n 5 /etc/group使用watch 动态监控 1.建立用户组 shengcan,其id 为2000 2.建立用户组 caiwu,其id 为 2001 3.足建立用户组 jishu,其id 为 2002 4.建立用户lee,指定其主组id为sh…...

[Docker][Docker Container]详细讲解
目录 1.什么是容器?2.容器命令1.docker creatre2.docker run3.docker ps4.docker logs5.docker attach6.docker exec7.docker start8.docker stop9.docker restart10.docker kill11.docker top12.docker stats13.docker container inspect14.docker port15.docker c…...

塑造美好心灵,激发创造活力|第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展开展
第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展 展览现场 由中央美术学院、景德镇陶瓷大学、景德镇陶文旅控股集团共同主办,由中国非物质文化遗产保护协会陶瓷分会、中国文化艺术发展促进会陶瓷专业委员会、中央美术学院陶瓷艺术研究院、中央美术学院少儿美术教…...
鸿蒙开发刷新单个item会闪一下处理
鸿蒙开发刷新单个item会闪一下 首先我用的是懒加载方式,改变某位数据后我调listener.onDataChange(index),发现item的改动是变了,但是item也闪了一下。 先分析为什么item会闪一下 其他是因为item上有图片,加载的网络图。你onDataChange(index)时,它会重新加载这一item,…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...