• 9.1 引言
  • 9.2 效果演示
  • 9.3 意图框架介绍
  • 9.4 手机碰一碰分享介绍
  • 9.5 一镜到底介绍
  • 9.6 代码实现

9.1 引言

9.1.1 欢迎使用

在 React Native 工程中使用 HarmonyOS 特性功能,包括 意图分享、一镜到底 和 碰一碰传输。这些特性可显著提升用户交互体验,实现更加便捷和自然的跨设备数据传输方式。

为了帮助您快速上手,我们提供了以下资源供参考:

9.1.2 文档目的

本文档旨在向开发者清晰地传达以下关键信息:

1. 理解一镜到底、意图框架和碰一碰分享。

2. 如何在RN工程中集成意图框架、碰一碰和一镜到底的功能。

3. 建议在使用开发前,仔细阅读本文档。

9.2 效果演示

图9-1 意图分享成功

图9-2 小艺推荐中出现分享卡片

图9-3 未开启碰一碰监听

图9-4 碰一碰分享待接收

图9-5 一镜到底过度效果

9.3 意图框架介绍

9.3.1 Intents Kit简介

Intents Kit(意图框架服务)是HarmonyOS级的意图标准体系 ,意图连接了应用/元服务内的业务功能。

意图框架能帮开发者将应用/元服务内的业务功能,智能分发到各系统入口,这个过程即智慧分发。其中系统入口包括:小艺对话、小艺搜索、小艺建议。

9.3.2 Intents Kit优势

利用HarmonyOS的大模型、多维设备感知等AI能力,准确且及时地获取到用户显性、潜在意图,从而实现个性化、多模态、精准的智慧分发。

9.3.3 意图的运行逻辑

HarmonyOS、应用/元服务的交互中,意图运行方式分为意图调用和意图共享:

9.3.4 约束与限制

  • 设备限制

本Kit仅适用于Phone、Tablet、PC/2in1,暂不支持模拟器使用。

  • 地区限制

本Kit仅支持中国境内(不包含中国香港、中国澳门、中国台湾)提供服务。

  • 操作系统限制

HarmonyOS 5.0及以上。

9.4 手机碰一碰分享介绍

Share Kit推出碰一碰分享,支持用户通过碰一碰发起跨端分享,可实现传输图片、共享Wi-Fi等。

1 场景介绍

  • 宿主应用可以分享多个内容,如选中的多张图片等。

2 业务流程

图9-6

流程说明:

  1. 宿主应用注册碰一碰分享事件,并与亮屏的对端设备碰一碰。
  2. 宿主应用发现设备,调用碰一碰分享事件回调,在回调事件中构造分享数据并发送。
  3. 目标设备接收并处理分享数据。
  4. 宿主应用解除注册靠近分享事件。

3 使用约束

手机应用发起碰一碰分享时,双端设备需要在亮屏、解锁的状态下并且都已开启华为分享服务(系统默认开启),设备顶部轻碰即可触发。如果用户已手动关闭华为分享服务开关,轻碰事件触发时,用户会接收到系统通知提示开启。

Share Kit的处理机制:

  • 任意一端设备不支持碰一碰能力时,轻碰无任何响应。
  • 宿主应用无法获得分享结果,Share Kit会通过系统通知消息告知用户对端接收或拒绝。

4 环境要求

  • 支持的手机系统:HarmonyOS NEXT Release及以上版本。
  • 集成开发环境:DevEco Studio NEXT Beta1及以上版本。

9.5 一镜到底介绍

1 概述

一镜到底动效是页面切换时对相同或者相似的两个元素做的一种位置、大小等属性匹配的过渡动画效果,有助于提升用户操作任务的效率,增强视觉的流畅感,同时也增强动效的品质感,是转场设计中重点推荐的技法。

实现原理

一镜到底动效中整个页面会以一种平滑的方式从一个场景过渡到另一个场景。这种转场效果常用于展示不同页面之间的关联性,能够给用户带来流畅的视觉体验。

根据场景,可以将一镜到底动效分为两类:

  • 共享元素

    共享元素一般是转场前后持续存在的界面元素,即上文提到的持续元素,是在转场发生后希望用户关注到的焦点元素,它增强了转场的连续感。

9.6 代码实现

1.项目需要依赖package:

"@hadss/react_native_intents": "./packages/react_native_intents/hadss-react_native_intents-1.0.0-rc.0.tgz",
"@hadss/react_native_knock_share": "./packages/react_native_knock_share/hadss-react_native_knock_share-1.0.0-rc.0.tgz",
"@hadss/react_native_geometry_transition": "1.0.8"

9.6.1 意图框架接入

9.6.1.1 RN工程代码

import { Intents } from '@hadss/react_native_intents';
// 以分享音乐为例;注意此处shareIntent方法接受的数组里数据可替换为想分享的数据(如:视频数据)
const handleShareIntentPlayMusic = async (data: any) => {
    await Intents.shareIntent([
   {
    'intentName': 'PlayMusic',
    'intentVersion': '1.0',
    'identifier': // uuid,
    'intentActionInfo': {
      'actionMode': 'EXECUTED',
      'executedTimeSlots': {
        'executedStartTime': 1637393212000,
        'executedEndTime': 1637393112000
      },
      'currentPercentage': 50
    },
    'intentEntityInfo': {
      'entityName': 'Music',
      'entityId': 'C10194368',
      'entityGroupId': 'C10194321312',
      'displayName': '测试1',
      'description': 'NA',
      'logoURL':
          'https://www-file.huawei.com/-/media/corporate/images/home/logo/huawei_logo.png',
      'keywords': ['华为音乐', '化妆'],
      'rankingHint': 99,
      'expirationTime': 1637393212000,
      'metadataModificationTime': 1637393212000,
      'activityType': ['1', '2', '3'],
      'artist': ['测试歌手1', '测试歌手2'],
      'lyricist': ['测试词作者1', '测试词作者2'],
      'composer': ['测试曲作者1', '测试曲作者2'],
      'albumName': '测试专辑',
      'duration': 244000,
      'playCount': 100000,
      'musicalGenre': ['流行', '华语', '金曲', '00后'],
      'isPublicData': false
    }
  }
    ]).then(() => {
      Alert.alert(`意图分享成功`);
    })
  };

<TouchableOpacity
   style={ styles.button}
   onPress={() => {
     setActiveIndex(8)
     handleShareIntentPlayMusic()
   }}
>
   <Text style={styles.btnText}>sharelntent</Text>
</TouchableOpacity>

9.6.1.2 HarmonyOS工程代码

步骤一:在工程如下目录(src/main/ets/entryability)下加入InsightIntentExecutorImpl.ets文件。

import Logger from '../utils/Logger';

import { insightIntent, InsightIntentExecutor } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import type { BusinessError } from '@kit.BasicServicesKit';

const TAG: string = 'InsightIntentExecutorImpl';

/**
 * 意图执行样例
 */
export default class InsightIntentExecutorImpl extends InsightIntentExecutor {
  private static readonly PLAY_MUSIC = 'PlayMusic';
  private static readonly VIEW_REPAYMENT = 'PlayVideo';
  private static readonly ERROR_CODE = -1;

  /**
   * override 执行前台UiAbility意图
   *
   * @param name 意图名称
   * @param param 意图参数
   * @param pageLoader 窗口
   * @returns 意图调用结果
   */
  onExecuteInUIAbilityForegroundMode(name: string, param: Record<string, Object>, pageLoader: window.WindowStage):
    Promise<insightIntent.ExecuteResult> {
    Logger.info(TAG, `onExecuteInUIAbilityForegroundMode name: ${name}, param: ${JSON.stringify(param)}`);
    // 根据意图名称分发处理逻辑
    switch (name) {
      case InsightIntentExecutorImpl.PLAY_MUSIC:
        Logger.info(TAG, `PLAY_MUSIC}`);
        return this.playMusic(param, pageLoader);
      case InsightIntentExecutorImpl.VIEW_REPAYMENT:
        Logger.info(TAG, `PLAY_Video}`);
        return this.viewRepayment(param, pageLoader);
      default:
        Logger.info(TAG, `no intent match`);
        break;
    }
    Logger.info(TAG, `no intent match`);
    return Promise.resolve({
      code: InsightIntentExecutorImpl.ERROR_CODE,
      result: {
        message: 'unknown intent'
      }
    } as insightIntent.ExecuteResult);
  }

  /**
   * 实现调用播放音乐功能
   *
   * @param param 意图参数
   * @param pageLoader 窗口
   */
  private playMusic(param: Record<string, Object>,
    pageLoader: window.WindowStage): Promise<insightIntent.ExecuteResult> {
    return new Promise(() => {
      let para: Record<string, string> = {
        'result': `intent execute success, entityId: ${param.entityId}`
      };
      let localStorage: LocalStorage = new LocalStorage(para);
      // TODO 实现意图调用
      pageLoader.loadContent('pages/Index', localStorage)
        .then(() => {
          // TODO 调用成功的情况
          Logger.info(TAG, "Intent execute succeed");
        })
        .catch((err: BusinessError) => {
          // TODO 调用失败的情况
          Logger.error(TAG, `Intent execute failed: ${JSON.stringify(err)}`);
        });
    });
  }

  /**
   * 实现调用查看还款功能
   *
   * @param param 意图参数
   * @param pageLoader 窗口
   */
  private viewRepayment(param: Record<string, Object>,
    pageLoader: window.WindowStage): Promise<insightIntent.ExecuteResult> {
    return new Promise(() => {
      let para: Record<string, string> = {
        'result': JSON.stringify(param)
      };
      let localStorage: LocalStorage = new LocalStorage(para);
      // TODO 实现意图调用
      pageLoader.loadContent('pages/Index', localStorage)
        .then(() => {
          // TODO 调用成功的情况
          Logger.info(TAG, "Intent execute succeed");
        })
        .catch((err: BusinessError) => {
          // TODO 调用失败的情况
          Logger.error(TAG, `Intent execute failed: ${JSON.stringify(err)}`);
        });
    });
  }
};

步骤二:在工程的entry目录下的oh-package.json5中增加依赖。

 {
  "license": "",
  "devDependencies": {},
  "author": "",
  "name": "entry",
  "description": "Please describe the basic information.",
  "main": "",
  "version": "1.0.0",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.70",
    "@hadss/react_native_geometry_transition": "file:../libs/geometry_transition.har",
    "@hadss/react_native_intents": "file:../libs/intents.har",
    "@hadss/react_native_knock_share": "file:../libs/knock_share.har"
  }
}
import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
import { SampleTurboModulePackage } from './turbo/SampleTurboModulePackage';
import { GeometryTransitionViewPackage } from '@hadss/react_native_geometry_transition/ts';
import { IntentsModulesPackage } from '@hadss/react_native_intents';
import { KnockShareModulePackage } from '@hadss/react_native_knock_share';


export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SampleTurboModulePackage(ctx),
    new GeometryTransitionViewPackage(ctx),
    new IntentsModulesPackage(ctx),
    new KnockShareModulePackage(ctx)
  ];
}

9.6.2 手机碰一碰接入

9.6.2.1 RN工程代码

import { KnockShare, SharedRecord} from "@hadss/react_native_knock_share";
// 1. 启用碰一碰监听
KnockShare.addKnockShareListener()
// 2. 启用成功后,手机碰一碰
KnockShare.setKnockShareData(shareData)
// 3. 关闭碰一碰监听
 KnockShare.removeKnockShareListener();
// 本示例提供三种不同分享场景

9.6.2.2 HarmonyOS工程代码

import { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
import { SampleTurboModulePackage } from './turbo/SampleTurboModulePackage';
import { GeometryTransitionViewPackage } from '@hadss/react_native_geometry_transition/ts';
import { IntentsModulesPackage } from '@hadss/react_native_intents';
import { KnockShareModulePackage } from '@hadss/react_native_knock_share';


export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SampleTurboModulePackage(ctx),
    new GeometryTransitionViewPackage(ctx),
    new IntentsModulesPackage(ctx),
    new KnockShareModulePackage(ctx)
  ];
}

9.6.3 一镜到底接入

9.6.3.1 RN工程代码

// 引入HarmonyOS一镜到底RN依赖
import { GeometryTransitionView } from '@hadss/react_native_geometry_transition';
//使用组件包装,设定viewID,此ID和HarmonyOS工程下的ID一致
 <GeometryTransitionView style={[styles.buttonContainer, { marginBottom: 12 }]} geometryViewID={'test'} ref={nativeRef} pageType={'current'}>
     <TouchableOpacity  style={styles.btn}  onPress={() => handlePress('bundle/knockshare.harmony.bundle', 'KnockSharePage')}>
         <Text style={{ color: 'white' }}>碰一碰分享</Text>
      </TouchableOpacity>         
 </GeometryTransitionView>

9.6.3.2 HarmonyOS工程代码

// 在页面中使用,以FeaturesPage.ets为例
// 必须用animateTo方法包裹路由跳转
 aboutToAppear() {
    this.startCountDown();
    emitter.on({ eventId: Constants.EVENT_ID_2 }, () => {
      animateTo({ duration: 700 }, () => {
        this.navPathStack.pop(false);
      });
    });
  }
// 此处使用了倒计时跳转和背景图。主要geometryTransition方法,入参必须和RN侧设置的ID一致
      Stack() {
        Image($r('app.media.imgBg'))
          .width('100%')
          .height('100%')
          .objectFit(ImageFit.Cover)
        Row() {
          Text(`${this.countdown} 跳过`)
            .fontSize(14)
            .fontColor(Color.White)
        }
        .backgroundColor('rgba(0, 0, 0, 0.05)')
        .alignItems(VerticalAlign.Center)
        .justifyContent(FlexAlign.Center)
        .width(77)
        .height(36)
        .margin({top: 60, right: 20})
        .borderRadius(18)
        .onClick(() => {
          this.countdown = 0
          clearInterval(this.timer)
        })
      }
      .width('100%')
      .height('100%')
      .backgroundColor('#40000000')
      .geometryTransition('test')
      .alignContent(Alignment.TopEnd)
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐