HarmonyOS App开发——职前通应用App开发(下)

1 HarmonyOS SDK开发能力

从 HarmonyOS NEXT Developer Preview(API 11)版本起,HarmonyOS SDK 以 Kit 维度提供丰富且完备的开放能力,广泛涵盖应用框架、系统、媒体、图形、应用服务、AI 六大关键领域。

(1)应用框架相关 Kit 开放能力

Ability Kit(程序框架服务):为应用的运行和管理提供了基础框架支持,助力开发者高效构建应用的基本结构和运行逻辑。

ArkUI(方舟 UI 框架):具备强大的用户界面开发能力,可帮助开发者创建美观、流畅且交互性强的应用界面。

(2)系统相关 Kit 开放能力

Universal Keystore Kit(密钥管理服务):负责安全地生成、存储和管理密钥,保障应用数据的安全性和隐私性。

Network Kit(网络服务):提供了一系列网络操作相关的功能和接口,使应用能够便捷地进行网络通信,实现数据的传输与交互。

(3)媒体相关 Kit 开放能力

Audio Kit(音频服务):支持音频的播放、录制、编辑等多种操作,为应用增添丰富的音频功能和体验。

Media Library Kit(媒体文件管理服务):可用于对媒体文件进行高效的管理,包括文件的存储、检索、分类等操作,方便应用处理多媒体资源。

(4)图形相关 Kit 开放能力

ArkGraphics 2D(方舟 2D 图形服务):专注于 2D 图形的绘制和处理,为应用实现各种精美的 2D 图形效果提供支持。

Graphics Accelerate Kit(图形加速服务):通过对图形处理进行加速优化,提升应用中图形渲染的速度和质量,增强视觉表现效果。

(5)应用服务相关 Kit 开放能力

Game Service Kit(游戏服务):提供了一系列针对游戏开发的服务和功能,如玩家账号管理、成就系统、排行榜等,助力打造更具吸引力的游戏应用。

Location Kit(位置服务):能够获取设备的地理位置信息,并提供相关定位功能,为基于位置的应用开发提供有力支持。

(6)AI 相关 Kit 开放能力

Intents Kit(意图框架服务):可实现应用之间的意图识别和交互,促进不同应用之间的协同工作和服务调用。

HiAI Foundation Kit(HiAI Foundation 服务):提供了人工智能相关的基础功能和工具,为开发者在应用中集成智能特性奠定基础。

平台网址,如图所示:

2 实战:职前通使用HarmonyOS SDK开发能力

2.1 应用框架

项目中遇到的问题:如何对微信、QQ、微博等业务数据及对象进行初始化?

解决方案:应用框架(Stage模型-UIAbility组件的应用),UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件。

当用户打开、切换和返回到对应应用时,应用中的UIAbility实例会在其生命周期的不同状态之间转换。UIAbility类提供了一系列回调,通过这些回调可以知道当前UIAbility实例的某个状态发生改变,会经过UIAbility实例的创建和销毁,或者UIAbility实例发生了前后台的状态切换。

UIAbility的生命周期包括Create、Foreground、Background、Destroy四个状态,如图所示:

EntryAbility.ets文件中的onCreate()方法,完成业务功能初始化,核心代码如下:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { this .context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) => { console.info(`setMissionContinueState: ${JSON.stringify(result)}`) }) this .wanderDo(want, launchParam) //PLV PLVBackgroundTaskManager.getInstance().setupContext(this .context) this .context.area = contextConstant.AreaMode.EL2 PLVMediaPlayerStartUp.start(this .context) //WX this .handleWeChatCallIfNeed(want) //QQ QQOpenApiHolder.create() //WB this .context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET)// 颜色模式 let result = WBAPI.getInstance().doWBAsResult(want, this .context) console.log("sdk_demo: oncreate dowbas result: " + result) WeiboLogger.logEnable = true ; // 调试时可以打开log开关 默认是false; new Utility().getSign(true ).then(sign => { // true:代表使用appid校验 false: 代表使用证书fingerprint校验 wbUtils.logger.debug("get sign: " + sign) // 获取debug和release包对应的签名,用于开放平台注册。获取完成可删除此代码。 }) wbUtils.logger.debug("AbilityStage onCreate") ... } onDestroy(): void { PLVBackgroundTaskManager.getInstance().destroy() ) } |

2.2 系统

项目中遇到的问题:如何保障个人登录数据安全?

解决方案:使用数据加密,在创建signUtils目录下创建RSA.ets文件和Base64Util.ets文件,用于设置秘钥规则。

使用inputCodeView.ets文件内调用了该方法

项目内的某些请求链接需要传递签名,采用了RSA加密算法,传入需要签名的字符串,通过封装的签名算法,获取加密后的签名字符串。

如:登录获取验证码时。

(1)RSA.ets文件,核心代码如下:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| static async encrypt(data: cryptoFramework.DataBlob, pubKey: cryptoFramework.PubKey, transformation: crypto.RSA_TRAN = 'RSA1024|PKCS1'): Promise<cryptoFramework.DataBlob> { return CryptoUtil.encrypt(data, pubKey, null , transformation); } static encryptSync(data: cryptoFramework.DataBlob, pubKey: cryptoFramework.PubKey, transformation: crypto.RSA_TRAN = 'RSA1024|PKCS1'): cryptoFramework.DataBlob { return CryptoUtil.encryptSync(data, pubKey, null , transformation); } static async decrypt(data: cryptoFramework.DataBlob, priKey: cryptoFramework.PriKey, transformation: crypto.RSA_TRAN = 'RSA1024|PKCS1'): Promise<cryptoFramework.DataBlob> { return CryptoUtil.decrypt(data, priKey, null , transformation); } static decryptSync(data: cryptoFramework.DataBlob, priKey: cryptoFramework.PriKey, transformation: crypto.RSA_TRAN = 'RSA1024|PKCS1'): cryptoFramework.DataBlob { return CryptoUtil.decryptSync(data, priKey, null , transformation); } |

(2)Base64Util.ets文件,核心代码如下:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| static encode(array: Uint8Array): Promise<Uint8Array> { const base64 = new util.Base64Helper(); return base64.encode(array); } static encodeSync(array: Uint8Array): Uint8Array { const base64 = new util.Base64Helper(); const result = base64.encodeSync(array); return result; } static encodeToStr(array: Uint8Array, options?: util.Type): Promise<string> { const base64 = new util.Base64Helper(); return base64.encodeToString(array, options); } static encodeToStrSync(array: Uint8Array, options?: util.Type): string { const base64 = new util.Base64Helper(); const result = base64.encodeToStringSync(array, options); return result; } static decode(array: Uint8Array | string, options?: util.Type): Promise<Uint8Array> { const base64 = new util.Base64Helper(); return base64.decode(array, options); } static decodeSync(array: Uint8Array | string, options?: util.Type): Uint8Array { const base64 = new util.Base64Helper(); const result = base64.decodeSync(array, options); return result; } |

(3)Sign.ets文件,导入加密算法,封装加密规则签名,核心代码如下:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| import { CryptoHelper } from "./CryptoHelper" import { RSA } from "./RSA" import { priKeyStr, pubKeyStr } from "./rsaKey" export function sign (url: string) { //签名 const dataBlob = CryptoHelper.strToDataBlob(url, 'utf-8') const keyPair1 = RSA.getConvertKeyPairSync(pubKeyStr, priKeyStr, 'base64') const signDataBlob1 = RSA.signSync(dataBlob, keyPair1.priKey) const signStr1 = CryptoHelper.dataBlobToStr(signDataBlob1, 'base64') return signStr1 } |

(4)inputCodeView.ets文件,导入签名,使用签名规则对数据完成加密,代码如下:

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| import { asciiSort, auth, EmitterKey, inputCodeViewParam, iUser, Logger, objectToQueryString, UrlParam } from "basic" import { promptAction } from "@kit.ArkUI" import { getVerificationApi, mesLoginApi } from "../../api/Index" import { sign } from "basic/src/main/ets/signUtils/Sign" import { emitter } from "@kit.BasicServicesKit" import { preferences } from "@kit.ArkData" import ImageCode from "../../components/ImageCode" const str = objectToQueryString(data) const url = asciiSort(str) const Sign = sign(url) const res = await getVerificationApi({ device_type: this .device_type, phone: this .param.phoneNumber, randcode: a, sign: Sign }) if (res.data.msg == '成功') { promptAction.showToast({ message: '验证码发送成功' }) return } |

2.3 媒体

项目中遇到的问题:如何保障视频嵌入丝滑流畅?

解决方案:使用媒体播放插件(视频播放器的应用),在coursePlayView.ets文件中,应用有课程播放的功能,其中播放器的设置及使用主要在该文件里。

(1)CoursePlayView.ets文件,核心代码如下:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| import { commonItemModule, createId, getDisplayWindowHeight, getDisplayWindowWidth, isLandscape, isPortrait, parent, PLVMediaPlayerDownloadCenterPageParam, PLVMediaPlayerHandleOnEnterBackgroundComponent, PLVMediaPlayerScenes, PLVMediaPlayerSingleVideoPageParam, PLVMPDownloadItemViewModel, PLVMPMediaControllerViewModel, PLVMPMediaViewModel , PLVMPPageControlViewModel , PLVOrientationManager, PLVOrientationManagerObserver, toCenterOf, toMiddleOf, toTopOf } from 'media-player-common' |

声明操作视频组件对象,核心代码如下:

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| private viewModel: PLVMPMediaViewModel = this.dependScope.get(PLVMPMediaViewModel); private controllerViewModel: PLVMPMediaControllerViewModel = this.dependScope.get(PLVMPMediaControllerViewModel) |

加载视频播放器,核心代码如下:

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // 视频播放器 XComponent({ id: `plv_media_player_single_video_xcomponent`, type: "surface", libraryname: "plvplayer_xcomponent", controller: this .componentController }) { } .id(this .plv_media_player_single_video_xcomponent) .width(this .videoWidth) .height(this .videoHeight) .alignRules({ center: toCenterOf(parent), middle: toMiddleOf(parent) }) .onLoad((xcomponent) => { this.viewModel .setXComponent(xcomponent) this .viewModel.onScreenshot = async () => { return await this .getUIContext() .getComponentSnapshot() .get(this .plv_media_player_single_video_xcomponent) } }) |

实现效果,如图所示:

2.4 图形

项目中遇到的问题:如何实现图形验证码,用于做登录验证?

解决方案:使用图形服务能力,项目代码位置:components/ImageCode.ets文件中,由于登录、注册、找回密码等功能都需要用到获取手机验证码功能,为了用户的安全,加入了人机验证的方式,实现方式为图形验证码验证。其中,生成图形验证码用到了ArkGraphics 2D(方舟2D图形服务 )主要提供图形绘制与显示相关的能力。

ImageCode.ets文件,核心代码如下:

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| //用来配置CanvasRenderingContext2D对象的参数,包括是否开启抗锯齿,true表明开启抗锯齿。 private settings: RenderingContextSettings = new RenderingContextSettings(true ) //用来创建CanvasRenderingContext2D对象,通过在canvas中调用CanvasRenderingContext2D对象来绘制。 private context : CanvasRenderingContext2D = new CanvasRenderingContext2D (this .settings) //指定canvas要绘制的图形的宽(可使用@Prop装饰器装饰,由调用此组件的父组件传递) @State canvas_width: number = 100; //指定canvas要绘制的图形的高 @State canvas_height: number = 40; //用于接收图形验证码的文本值 @State verifyCode: string = '' sCode: string = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,m,n,p,q,r,s,t,u,v,w,x,y,z,2,3,4,5,6,7,8,9"; aCode: string[] = this .sCode.split(","); aLength: number = this .aCode.length; //回调 sendResult = (result: boolean) => { } |

生成4位验证码,核心代码如下:

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| drawImgCode(context: CanvasRenderingContext2D, canvas_width: number = 100, canvas_height: number = 40): string { //用于保存验证码 let showCode: string = '' //清楚当前画布内容,用作刷新画布 context.clearRect(0, 0, canvas_width, canvas_height) for (let i = 0; i < 4; i++) { //这里的for循环可以控制验证码位数 const j = Math.floor(Math.random() * this.aLength); //获取到随机的索引值 const deg = Math.random() - 0.5; //产生一个随机弧度 const txt = this.aCode[j]; //得到随机的一个内容 showCode += txt.toLowerCase(); //转小写 const x = 20 + i * 20; //文字在canvas上的x坐标 const y = canvas_height / 2 + Math.random() * 10; //文字在canvas上的y坐标 context.font = "20vp sans-serif"; context.translate(x, y); context.rotate(deg); context.fillStyle = this.getColor(); context.fillText(txt, 0, 0); context.rotate(-deg); context.translate(-x, -y); } for (let i = 0; i <= 5; i++) { //验证码上显示线条 context.strokeStyle = this.getColor(); context.beginPath(); context.moveTo(Math.random() * canvas_width, Math.random() * canvas_height); context.lineTo(Math.random() * canvas_width, Math.random() * canvas_height); context.stroke(); } return showCode } |

实现效果,如图所示:

2.5 应用服务

项目中遇到的问题:如何保证文件存储安全?

解决方案:使用应用服务(文件管理的应用),这里使用到文件管理,项目代码位置在components/playerTabComp.ets,在该文件中应用从网络下载课程文件资料到本地文件管理器的功能,主要实现方式为:先下载文件到沙箱内,再拉起文件管理器,用户自行选择文件保存路径,把沙箱内的文件复制到本地文件管理器中。

playerTabComp.ets文件中,实现下载过程从职前通网址上下载到应用沙箱,核心代码如下:

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| const filepath = filesDir + '/' + name // 开始下载,从职前通网站上下载到沙箱目录 await request.downloadFile(context, { url: 'https://static.zhiqiantong.cn' + url, filePath: filepath }).then((downloadTask: request.DownloadTask) => { downloadTask.on('complete', () => { console.info('download complete') let file = fs.openSync(filesDir + '/' + name, fs.OpenMode.READ_WRITE) let arrayBuffer = new ArrayBuffer(1024) let readLen = fs.readSync(file.fd, arrayBuffer) let buf = buffer.from(arrayBuffer, 0, readLen) console.info(`The content of file: {buf.toString()}\`) fs.closeSync(file) }); downloadTask.on("progress", (current, total) =\> { **// 存储当前资料的下载进度到 Map 中** ****this**** .downloadProgressMap.set(name, { current, total }) ****this**** .getDownloadProgressText(name, index) }); downloadTask.on("complete", () =\> { promptAction.showToast({ message: \`{name}下载完成` }) this .save(name) }) }) |

从沙箱目录,拷贝到手机本地存储,核心代码如下:

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // 从沙箱目录,拷贝到手机本地存储 save(name: string) { let fileNameArr = [name] const documentSaveOptions = new picker.DocumentSaveOptions() ; // 创建文件管理器保存选项实例 documentSaveOptions.newFileNames = fileNameArr // 保存文件名(可选) const documentViewPicker = new picker.DocumentViewPicker; documentViewPicker.save(documentSaveOptions) .then((documentSaveResult) => { // 获取到到图片或者视频文件的URI后进行文件读取等操作 let filePath = '' let uri = '' uri = documentSaveResult[0] filePath = getContext().filesDir + '/' + fileNameArr[0] // 沙箱路径文件 let sanFile = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE) //公共路径 let pubFile = fs.openSync(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE) // 将文件从沙箱路拷贝到公共路径 fs.copyFileSync(sanFile.fd, pubFile.fd) fs.closeSync(sanFile) fs.closeSync(pubFile) promptAction.showToast({ message: `下载完成,请前往文件管理器查看` }) }) .catch((err: Error) => { console.error(`Invoke documentPicker.select failed, message is ${err.message}`); }) } |

实现效果,如图所示:

2.6 自由流转(视频续播)

项目中遇到的问题:如何保障设备间协同学习和跨端迁移?

解决方案:使用视频续播。

应用场景:A设备正在播放,要在B设备上续播,职前通以"智能视频续播"为核心功能亮点,通过HarmonyOS开放能力实现了跨设备无缝学习体验。该功能允许用户在任何HarmonyOS设备上中断学习后,可在其他设备上从同一时间点继续观看,学习进度实时同步,保证更高质量的学习效果。

传统跨设备播放的两大痛点:

(1)传统方案下,各设备独立记录播放进度,导致用户在手机、平板、智慧屏等设备间切换时,学习进度无法自动同步,需手动定位上次播放位置,甚至重新加载视频,严重影响学习连贯性。

(2)传统投屏方案需手动重新连接,且可能因设备性能差异,如解码能力不足,导致画质下降、卡顿,打断学习流程,造成体验割裂。

解决方案有以下三点:

(1)利用HarmonyOS的分布式数据管理能力。通过HarmonyOS的分布式数据库,实现学习进度跨设备同步,用户可在手机、平板、智慧屏等设备间无缝切换学习;学习进度自动保存,无需手动记录时间点;节省用户重新寻找上次学习位置的时间。

(2)全局播放状态管理:利用媒体会话管理能力,统一维护播放状态,避免多设备间的数据冲突,保证进度精准同步。

(3)用户切换设备时,自动恢复至上次播放位置,无需手动调整;学习进度同步延迟<200ms,体验流畅无感知。

通过HarmonyOS开放能力,彻底解决传统方案下的状态割裂与体验断层问题,实现真正的跨设备无缝续播,让学习体验更连贯、高效。

实现效果,设备A正在播放,要在设备B上续播,视频流转续播前的状态,如图所示:

点击下方的应用图标,视频流转续播中的状态,如图所示:

视频流转续播后的状态,如图所示:

代码实现主要包含以下五个步骤。

第一步:配置应用接续能力,module.json5文件,核心代码如下:

第二步:设备A开启冷启动,配置接续默认关闭,EntryAbility.ets文件,核心代码如下:

第三步:在课程播放页开启接续能力,进入页面打开流转能力,coursePlayView.ets文件,核心代码如下:

传递相应参数,代码如下:

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| AppStorage.setOrCreate<number>('continue_courseId', this .param.courseId) //流转 AppStorage.setOrCreate<number>('continue_progress', viewState.currentProgress) //流转 //流转 AppStorage.setOrCreate<string>('continue_handleObjPROMAX', handleObjPROMAX.videoId) AppStorage.setOrCreate<number>('continue_selectId', this .kPointId) AppStorage.setOrCreate<number>('continue_scrollToIndex', this .scrollToIndex) |

第四步:设备B点击图标开始接续,EntryAbility.ets文件中需要完成

(1)触发onContinue,保存数据并传输到b设备

(2)触发wanderDo,取出数据

核心代码如下:

第五步:设备B应用入口,检测到需要接续则跳转课程播放页,Index.ets文件中核心代码如下:

2.7 碰一碰(AppLinking)

项目中遇到的问题:如何实现学习课程快速分享?

解决方案:使用碰一碰分享,即App Linking。

应用场景:A设备,B设备通过碰一碰视频分享。

HarmonyOS课程视频学习平台创新性地采用了"碰一碰"分享功能,用户只需将手机轻触另一台HarmonyOS设备,即可瞬间完成课程视频的分享。这一功能极大简化了传统分享流程,创造了全新的课程协作学习体验。

核心开放能力应用与价值:

(1)碰一碰服务能力,应用场景是设备间快速建立连接、课程信息极速传输、自动跳转至播放页面。带来的价值是实际价值,操作简单,仅需轻碰,分享耗时缩短到2秒内实现设备迁移,自由流转。

(2)分布式软总线能力,建立设备间高速数据传输通道,保持多设备间低延迟通信。

(3)统一数据管理能力,课程数据自动同步,设备能力自动适配。

该功能已成为职前通平台最具辨识度的特色,在教育行业创造了全新的设备互联体验。

实现效果,设备A,设备B通过碰一碰视频分享,如图所示:

手机碰一碰,开启视频流转,如图所示:

将课程从设备A流转到设备B,如图所示:

完成课程流转,如图所示:

代码实现主要包含以下几个步骤。

第一步:目标方,客户端开发,在DevEco Studio中配置关联的网址域名。module.json5文件中核心代码如下:

第二步:目标方,客户端开发,处理传入的链接,EntryAbility.ets文件中,使用冷启动、热启动的方式,处理传入链接,核心代码如下:

第三步:客户端开发,调用系统接口,触发链接跳转。Index.ets文件作为应用入口:

冷启动直接跳转对应课程详情页面,核心代码如下:

热启动运用了线程通信,热启动的时候会通知跳转对应课程详情页面,核心代码如下:

至此,App Linking配置完毕

第四步:接下来结合系统分享碰一碰分享链接,再通过系统自动识别链接调用App Linking,在hwShare.ets文件中,封装的系统分享,核心代码如下:

3 小结

职前通鸿蒙应用通过深度整合HarmonyOS SDK的六大领域开放能力,不仅实现了在线学习的基础功能,如课程播放、离线下载、安全验证等,更通过自由流转与碰一碰分享两大创新功能,解决了传统跨设备学习的体验割裂问题,构建了"无缝、高效、智能"的全场景学习生态。这一实践验证了HarmonyOS SDK在分布式能力、图形处理、数据安全等方面的技术优势,为教育行业的鸿蒙化应用开发提供了可复用的参考范式,也为用户带来了更连贯、更智能的智慧学习体验。

相关推荐
摘星编程4 小时前
React Native鸿蒙版:Image图片占位符
react native·react.js·harmonyos
大雷神4 小时前
HarmonyOS智慧农业管理应用开发教程--高高种地-- 第30篇:设置与帮助系统
harmonyos
Swift社区5 小时前
HarmonyOS 自定义组件与布局实践
华为·harmonyos
鸿蒙开发工程师—阿辉7 小时前
让 AI 帮你编译部署鸿蒙应用:harmonyos-build-deploy Skill
华为·harmonyos
盐焗西兰花7 小时前
鸿蒙学习实战之路-Reader Kit构建阅读器最佳实践
学习·华为·harmonyos
一起养小猫9 小时前
Flutter for OpenHarmony 实战:记忆棋游戏完整开发指南
flutter·游戏·harmonyos
飞羽殇情9 小时前
基于React Native鸿蒙跨平台开发构建完整电商预售系统数据模型,完成参与预售、支付尾款、商品信息展示等
react native·react.js·华为·harmonyos
Betelgeuse7610 小时前
【Flutter For OpenHarmony】TechHub技术资讯界面开发
flutter·ui·华为·交互·harmonyos
国服第二切图仔11 小时前
openJiuwen智能体平台部署搭建及政务通助手工作流智能体开发实战
华为·政务·智能体