华为春节活动来了,上一个指定功能,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次切换。你可以在代码里记录切换次数,超过就不再移动按钮。

  • 什么情况下会失效?

    • 手机晃动厉害(比如跑步、坐车)
    • 手掌没贴紧手机
    • 戴了厚手机壳或翻盖壳
    • 双手同时握持
    • 在横屏模式下(暂不支持)

二、抓起“祝福”送给朋友,鸿蒙隔空传送开发

整个流程分为三步:

  1. 监听手势:系统检测到用户做出“指向设备”的特定手势(如双指按压后指向)。
  2. 捕获内容:App 立即对当前界面或指定组件进行截图,生成图片数据。
  3. 一键投送:将图片通过华为分享(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 分布式能力的强大。

除了截图,你还可以分享文本、文件、甚至实时音视频流,来提升这次活动的评级,获取更多流量!

点赞、收藏、分享。现在,就去试试吧,祝你节前吃顿好的。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐