一招吃满鸿蒙春节活动流量,没有多设备也行
华为春节活动来了,上一个指定功能,APP可获得可观流量!
官方列了一大堆功能,但是我们要又快又达标完成,直接看前三个,
任选一项,只需几十行代码,就能完成活动任务!
1、碰一碰:碰一碰手机就能给好友“送福卡”!
2、智感握姿& 左右手感知:检测到用户左/右手持握时,自动把“拜年”“送福”等高频按钮移到左侧热区,让左/右手党单手也能秒发祝福。
3、隔空传送(一抓一放):隔空“抓”起“祝福”,轻轻一放送给好友,拜年仪式感瞬间拉满!
为什么只看前三个?因为这三个都是目前传播欲望最大的功能。
活动的描述看来,就是希望用户能主动分享。而且,这三个都是目前鸿蒙独一档的功能。
那么,现在问题来了,手上只有一台手机没有多余设备的开发者,第一个碰一碰很难测试。
所以,只剩下2、3可以选择。
有的开发者就要问了,3不是也需要两台设备吗?
是也不是,隔空投送只选择文件投送,源端只要能抓就行(系统会有视觉层的反馈),对端会自动存到图库或文件夹里。所以,在开发角度看,只需要把源端做好就行了。
点赞收藏,接下来选择其一快速做出功能:
- 左右手感知做一个新年祝福按钮。
- 隔空传送界面中的一个新春祝福截图。
一、让按钮“听话”地跟着你的手走:鸿蒙智感握姿开发
限制:需要升级到 HarmonyOS 6.0.0.115 或更高版本
第1步:申请权限
在 module.json5 文件中,添加以下权限
{
"requestPermissions": [
{
"name": "ohos.permission.INTELLIGENT_SENSE",
"reason": "用于识别用户握持手势"
},
{
"name": "ohos.permission.DETECT_GESTURE",
"reason": "用于检测握姿变化"
}
]
}
第2步:监听“握姿变化”
鸿蒙提供了一个叫 motion.on('holdingHandChanged', ...) 的接口,专门用来监听握姿变化。
我们定义几种握姿状态:
0:没拿手机1:左手握2:右手握3:双手握
import { motion } from '@kit.MultimodalAwarenessKit';
// 当前握姿状态
let currentHand = 2; // 默认右手
// 开始监听
motion.on('holdingHandChanged', (handStatus: number) => {
console.log('现在是:' + (handStatus === 1 ? '左手' : handStatus === 2 ? '右手' : '其他'));
currentHand = handStatus;
// 根据握姿更新按钮位置
updateButtonPosition(handStatus);
});
第3步:动态调整按钮位置
接下来,我们根据 currentHand 的值,决定按钮放在左边还是右边。
@Entry
@Component
struct SmartButtonPage {
@State buttonSide: string = 'right'; // 'left' 或 'right'
aboutToAppear() {
// 页面加载时开始监听
motion.on('holdingHandChanged', (status) => {
if (status === 1) {
this.buttonSide = 'left';
} else if (status === 2) {
this.buttonSide = 'right';
}
});
}
build() {
Stack() {
if (this.buttonSide === 'left') {
Row() {
Button('新年左边好')
.margin({ left: 30 })
}
} else {
Row() {
Button('新年右边好')
.margin({ right: 30 })
}
}
}
.width('100%')
.height('100%')
}
}
这样,只要你换手,按钮就会自动“跑”到新握持手的一侧!
如果要更细化,注意这些实战技巧:
-
支持左右手切换(最多3次)
鸿蒙系统默认允许用户在通话或使用 App 时左右手切换,但为了防止误触,最多只响应3次切换。你可以在代码里记录切换次数,超过就不再移动按钮。
-
什么情况下会失效?
- 手机晃动厉害(比如跑步、坐车)
- 手掌没贴紧手机
- 戴了厚手机壳或翻盖壳
- 双手同时握持
- 在横屏模式下(暂不支持)
二、抓起“祝福”送给朋友,鸿蒙隔空传送开发
整个流程分为三步:
- 监听手势:系统检测到用户做出“指向设备”的特定手势(如双指按压后指向)。
- 捕获内容:App 立即对当前界面或指定组件进行截图,生成图片数据。
- 一键投送:将图片通过华为分享(Huawei Share)协议,安全、快速地发送到目标设备。
✅ 优势:无需手动选择文件、无需打开分享菜单,体验丝滑自然。
第一步:封装分享核心逻辑(Immersive 工具类)
我们将所有与分享相关的复杂逻辑封装在一个单例工具类 Immersive 中,便于复用和管理。
1. 单例模式初始化 + 监听手势并执行分享
export class Immersive {
private static instance: Immersive;
private context: Context;
// 外部传入:如何获取要分享的图片
func?: () => Promise<image.PixelMap>;
private constructor(context: Context) {
this.context = context;
}
public static getInstance(context: Context): Immersive {
if (!Immersive.instance) {
Immersive.instance = new Immersive(context);
}
return Immersive.instance;
}
// 开启监听
public immersiveListening() {
if (canIUse('SystemCapability.Collaboration.HarmonyShare')) {
window.getLastWindow(this.context).then(win => {
const winId = win.getWindowProperties().id;
harmonyShare.on('gesturesShare', { windowId: winId }, async (target) => {
await this.immersiveCallback(target); // 触发分享
});
});
}
}
// 分享回调
async immersiveCallback(target: harmonyShare.SharableTarget) {
if (!this.func) return;
try {
const pixelMap = await this.func(); // 获取截图
const sharedData = await Immersive.exImg(this.context as any, pixelMap);
target.share(sharedData); // 发送给目标设备
} catch (err) {
console.error('分享失败:', err.message);
}
}
// 页面离开时记得关闭监听
public immersiveDisableListening() {
// ... 调用 harmonyShare.off()
}
}
2. 将截图保存为临时文件
系统分享通常需要文件 URI,因此我们要把内存中的 PixelMap 转成 JPEG 文件:
static async exImg(context: common.UIAbilityContext, pixelMap: image.PixelMap): Promise<systemShare.SharedData> {
const imagePacker = image.createImagePacker();
const picture = image.createPicture(pixelMap);
// 编码为高质量 JPEG
const buffer = await imagePacker.packing(picture, { format: "image/jpeg", quality: 100 });
// 保存到缓存目录
const filePath = ` $ {context.cacheDir}/ $ {Date.now()}.jpg`;
const file = fs.openSync(filePath, fs.OpenMode.WRITE_ONLY | fs.OpenMode.CREATE);
fs.writeSync(file.fd, buffer);
fs.closeSync(file.fd);
// 构造分享数据
return new systemShare.SharedData({
utd: utd.UniformDataType.JPEG,
uri: fileUri.getUriFromPath(filePath),
title: '新年祝福分享'
});
}
2.1将一个组件截图
this.getUIContext()
.getComponentSnapshot()
.getSync(target.id, { scale: 1, waitUntilRenderFinished: true });
//target.id 要截图的组件的.id('idString')
第二步:在页面中集成
1. 在 onShow 中启动监听
onShow = () => {
const im = Immersive.getInstance(this.getUIContext().getHostContext());
// 告诉工具类:如何获取要分享的内容
im.func = async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
// 对指定ID的组件截图(必须设置 .id())
const snapshot = this.getUIContext()
.getComponentSnapshot()
.getSync('newid123', { scale: 1, waitUntilRenderFinished: true });
resolve(snapshot);
} catch (e) {
reject(e);
}
}, 50);
});
};
im.immersiveListening(); // 启动监听
}
2. 在 onHide 中清理资源
onHide = () => {
const im = Immersive.getInstance(this.getUIContext().getHostContext());
im.immersiveDisableListening(); // 避免后台误触发
}
3. 确保组件有 ID
在 build() 函数中,绑定唯一 ID:
NewYearCard()
.id('newid123') // ← 必须设置!否则无法截图
做完后,调试,只要能抓去出隔空投送界面,且截图正常显示,就成功了。
常见问题
- 截图失败:检查组件是否设置了
.id(),且 ID 唯一 - 手势无响应:确认设备支持该功能,且未被省电策略限制
- 分享中断:确保两台设备距离较近(蓝牙/Wi-Fi 直连范围内)
我们仅用几十行代码,就为 App 增加了极具未来感的“手势隔空投送”能力。这不仅提升了用户体验,也充分展现了 HarmonyOS 分布式能力的强大。
除了截图,你还可以分享文本、文件、甚至实时音视频流,来提升这次活动的评级,获取更多流量!
点赞、收藏、分享。现在,就去试试吧,祝你节前吃顿好的。
更多推荐


所有评论(0)