碰一碰分享直达古诗案例:一触即达的诗意传递
1. 介绍
在 HarmonyOS 分布式能力加持下,通过“碰一碰”实现古诗秒传的创新应用。用户只需将两台鸿蒙设备轻触,即可瞬间完成古诗内容传输与页面跳转,打造零门槛的跨设备文化共享体验。
用户体验:
充分展现 HarmonyOS“一次开发,多端部署”的优势,通过硬件级近场交互与软总线技术融合,让传统文化传承拥有更优雅的数字化表达,为教育、亲子等场景提供高效连接方案。
2. 效果
3. 使用 App Linking 实现应用间跳转
在 AGC 控制台开通 App Linking 服务
请先参考“应用开发准备”完成基本准备工作,再继续进行以下开发活动。
登录AppGallery Connect,点击“我的项目”。
在项目列表中点击您的项目。
在左侧导航栏中选择“增长 > App Linking”,进入 App Linking 页面,点击“立即开通”。
如果您的项目此时未设置数据处理位置,请在提示框内启用数据处理位置和设置默认数据处理位置,点击“确定”。
进入“项目设置 > 常规”页面,选择创建的 HarmonyOS 应用,查看应用的 APP ID,后续开发需要使用该 ID。
在开发者网站上关联应用
在开发者的网站域名服务器上做如下配置。后续当您配置该网站域名时,系统会通过此文件确认哪些应用才是合法归属于此域名的,使链接更加安全可靠。
创建域名配置文件 applinking.json,内容如下:
将配置文件放在域名服务器的固定目录下:
https://domain.name/.well-known/applinking.json
例如:开发者的服务器域名为www.example.com,则必须将applinking.json文件放在如下位置:
https://www.example.com/.well-known/applinking.json
在 AGC 控制台关联网址域名
基于 HarmonyOS 应用链接能力,需要为 HarmonyOS 应用创建关联的网址域名。如果用户已安装 HarmonyOS 应用,则用户点击域名下网址链接后,系统会默认打开该 HarmonyOS 应用内的相关页面。
登录AppGallery Connect,点击“我的项目”。
在项目列表中点击您的项目。
在左侧导航栏中选择“增长 > App Linking”,选择“应用链接(API>=12 适用)”页签,点击“创建”。
填写在开发者网站上关联应用的网址域名,例如:https://www.example.com。必须输入精确的域名,不可输入包含特殊字符的模糊网址。
设置完成后点击“发布”,AGC 会对该网站域名的配置文件所包含的应用与本项目内的应用列表进行交集校验。
如果域名的配置文件中有应用存在本项目中,则发布成功,点击“查看”可显示该域名关联的应用信息。
如果异步校验中,则状态为“发布中”。
如果配置文件中没有任何应用在本项目中,则发布失败,点击“查看”可显示发布失败原因。
4. 封装 ShareKitUtils 分享公共类
export class ShareKutUtils { private constructor() {} private static instance: ShareKutUtils;
public static getInstance(): ShareKutUtils { if (!ShareKutUtils.instance) { ShareKutUtils.instance = new ShareKutUtils(); } return ShareKutUtils.instance; }
/** * 分享回调 * 先截图当前屏幕,再分享 * @param sharableTarget * @param shareUrl */ async shareKitCallback(sharableTarget: harmonyShare.SharableTarget, shareUrl: string) { let windowClass:window.Window = await window.getLastWindow(getContext(this))
windowClass.snapshot((error, image) => { if (image) { ShareKutUtils.getInstance().pixelToFile(image).then((filePath: string) => { let shareData: systemShare.SharedData = new systemShare.SharedData({ // HYPERLINK显示为链接;HTML显示为网页;TEXT显示为文本;VIDEO显示为视频; // AUDIO显示为音乐;IMAGE显示为图片;FILE显示为文件; utd: utd.UniformDataType.HYPERLINK, content: shareUrl, thumbnailUri: filePath }); sharableTarget.share(shareData); }) console.log("xx snapshot success"); } else { console.log("xx snapshot failure: " + JSON.stringify(error)); } }); }
/** * PixelMap保存为缓存文件 * @param pixelImg * @returns */ pixelToFile(pixelImg:PixelMap):Promise<string>{ return new Promise((resolve,reject)=>{ const context: Context = getContext().getApplicationContext(); const path: string = context.cacheDir + "/cacheImage.jpg"; let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 } let file = fileIo.openSync(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE); const imagePackerApi: image.ImagePacker = image.createImagePacker(); imagePackerApi.packToFile(pixelImg, file.fd, packOpts, async(err: BusinessError) => { if (err) { console.error('packToFile failed.'); reject(null) } else { let imgUri = fileUri.getUriFromPath(file.path) resolve(imgUri) } }) }) }
}
复制代码
5. 应用 module.json5 配置
"entities"列表中必须包含"entity.system.browsable"。
"actions"列表中必须包含"ohos.want.action.viewData"。
"uris"列表中必须包含"scheme"为"https"且"host"为域名地址的元素,可选属性包含"path"、"pathStartWith"和"pathRegex",具体请参见“uris标签说明”。
"domainVerify"设置为 true,表示开启域名校验开关。
例如,声明应用关联的域名是www.example.com,则需进行如下配置。
{ "module": { "abilities": [ { "name": "EntryAbility", "srcEntry": "./ets/entryability/EntryAbility.ts", "icon": "$media:icon", "label": "$string:EntryAbility_label", // 请将exported配置为true;如果exported为false,仅具有权限的系统应用能够拉起该应用,否则无法拉起应用 "exported": true, "startWindowIcon": "$media:icon", "startWindowBackground": "$color:start_window_background", "skills": [ { "entities": [ "entity.system.home" ], "actions": [ // API19及以上版本须配置为"ohos.want.action.home",API18及以下版本请配置为"action.system.home" "ohos.want.action.home" ] }, { "entities": [ // entities必须包含"entity.system.browsable" "entity.system.browsable" ], "actions": [ // actions必须包含"ohos.want.action.viewData" "ohos.want.action.viewData" ], "uris": [ { // scheme须配置为https "scheme": "https", // host须配置为关联的域名 "host": "www.example.com", // path可选,表示域名服务器上的目录或文件路径,例如www.example.com/path1中的path1 // 如果应用只能处理部分特定的path,则此处应该配置应用所支持的path,避免出现应用不能处理的path链接也被引流到应用中的问题 "path": "path1" } ], // domainVerify须设置为true "domainVerify": true } // 若有其他跳转能力,如推送消息跳转、NFC跳转,可新增一个skill对象,防止与App Linking业务冲突 ] } ] }}
复制代码
6. 古诗页碰一碰分享监听
aboutToAppear(): void { // 开始启用监听 this.whiteListening() AppStorage.setOrCreate("obj", this.detailData) } aboutToDisappear(): void { // 禁用监听 this.whiteDisablingListening() } /** * 启用监听 */ private whiteListening() { harmonyShare.on('knockShare', this.whiteCallback); } /** * 禁用监听 */ private whiteDisablingListening() { harmonyShare.off('knockShare', this.whiteCallback); }
/** * 回调函数 * @param sharableTarget */ private whiteCallback(sharableTarget: harmonyShare.SharableTarget) { let obj = AppStorage.get("obj") as Record<string, string>; ShareKutUtils.getInstance().shareKitCallback(sharableTarget, `https://www.example.com/path1?action=detail&id=${obj.id}`)
}
复制代码
7. EntryAbility 参数接收
7.1 定义全局变量
let currentWindowStage: window.WindowStage;let selectPage: string | undefined = "";let id: string | undefined = "";
复制代码
7.2 冷启动时,接收参数存储在全局变量
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { // 从want中获取传入的链接信息。 let uri = want?.uri if (uri) { let urlObject = url.URL.parseURL(want?.uri); let action = urlObject.params.get('action') let dataId = urlObject.params.get('id')
if (action === "detail"){ selectPage = "Detail" id = dataId+"" } }
if (currentWindowStage !== undefined && currentWindowStage !== null) { this.onWindowStageCreate(currentWindowStage); } }
复制代码
7.3 热启动时,接收参数存储在全局变量
async onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) { // 从want中获取传入的链接信息。 let uri = want?.uri if (uri) { let urlObject = url.URL.parseURL(want?.uri); let action = urlObject.params.get('action') let dataId = urlObject.params.get('id')
if (action === "detail"){ selectPage = "Detail" id = dataId+"" } } if (currentWindowStage !== undefined && currentWindowStage !== null) { this.onWindowStageCreate(currentWindowStage); } }
复制代码
7.4 存储参数 id 到 AppStorage,并根据参数跳转到相应页面
onWindowStageCreate(windowStage: window.WindowStage): void { AppStorage.setOrCreate<string>("id", id); let targetPage: string; // 根据传递的targetPage不同,选择拉起不同的页面 switch (selectPage) { case 'Detail': targetPage = 'pages/Detail'; break; case 'Index': targetPage = 'pages/Index'; break; default: targetPage = 'pages/Index'; } if (currentWindowStage === undefined || currentWindowStage === null) { currentWindowStage = windowStage; }
windowStage.loadContent(targetPage, (err) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); }); }
复制代码
8. 古诗页获取参数
aboutToAppear() { const uid: string | undefined = AppStorage.get<string>('id')??"0"; }
复制代码
9. 总结
对应用要进行手动签名,不能使用 DevEco Studio 的自动签名功能,必须使用手动签名,否则无法拉起应用。分享公共类通过碰一碰后,把当前界面截图下来,当作分享预览页。在教育、亲子场景中展现显著价值:教师可高效分发诗词素材至学生平板,家长能便捷同步赏析内容至其它设备,实现跨形态设备的文化内容流转。未来,可拓展至多模态诗词互动、AI 诵读跟读等场景,结合鸿蒙分布式数据库实现多端批注同步,持续挖掘近场交互与传统文化数字化的结合点,为教育信息化与文化传承提供创新范式。
评论