@hadss/react_native_intents
v1.0.0-rc.0
Published
RN react_native interface package
Downloads
2
Readme
@hadss/react_native_intents
介绍
为 React Native 提供意图框架分享能力,包括共享和删除意图。该库封装了鸿蒙insightIntent的相关功能,开发者可通过简洁接口在 React Native 中向意图框架共享意图。意图框架根据共享的数据学习规律,在合适的时机在系统入口将对应的InsightIntent推荐给用户。
工程目录
.
├─harmony
│ ├─IntentsHO // Harmony
│ | └─intents.har // Turbo Modules接口har包
│ ├─IntentsOH // OpenHarmony
│ │ └─intents.har // Turbo Modules接口har包
| ├─intents
│ │ └─src
│ │ ├─main
│ │ │ └─ets
│ │ │ ├─IntentsModule.ets // Turbo Modules接口ArkTS实现
│ │ │ ├─IntentsModulePackage.ets // IntentsModuleFactory
│ │ │ └─IntentsModuleSpec.ts // Turbo Modules接口
│ │ ├─HORealization
│ │ │ ├─IntentsModule.ets // Harmony环境差异化源码
│ │ └─OHRealization
│ │ └─IntentsModule.ets // OpenHarmony环境差异化源码
| └─build-profile.json5 // 编译配置文件(多环境Harmony/OpenHarmony)
├─src
│ ├─index.ts // React Native 模块导出
│ └─turbo
| └─IntentsModule.ts // React Native Turbo Modules接口安装与使用
进入到工程目录并输入以下命令:
npm
npm install @hadss/react_native_intentsyarn
yarn add @hadss/react_native_intentsLink
目前OpenHarmony暂不支持AutoLink,所以Link步骤需要手动配置。
首先需要使用DevEco Studio打开项目里的OpenHarmony工程,在工程根目录的oh-package.json5添加overrides字段:
{
"overrides": {
"@rnoh/react-native-openharmony" : "./react_native_openharmony"
}
}意图框架配置
意图前置配置: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/intents-access-flow 开发者需要参照上述官方文档中的Intents Kit接入流程 进行操作: 1.选择特性确定意图 2.调试白名单申请 3.端侧意图调用调试工具申请 4.意图声明文件中注册意图 5.开发实现意图调用/意图共享 6.端到端验证特性 7.应用市场上架软件包(应用/元服务) 8.意图框架注册
本库涉及开发接入的主要工作在实现4、5两个步骤: 1.意图声明文件中注册意图(意图回调注册-鸿蒙实现) 2.实现意图调用(鸿蒙端实现)/意图共享(React Native实现) 其他工作请开发者自行申请完成
1.意图声明文件中注册意图-鸿蒙端处理: 参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/intents-habit-rec-access-programme#section12621163216260 以歌曲续听推荐特性为例,首先要注册播放歌曲意图(PlayMusic),其他意图见各垂域意图Schema。开发者需要编辑对应的意图配置 PROJECT_HOME/entry/src/main/resources/base/profile/insight_intent.json文件,实现意图注册。
{
// 应用支持的意图列表
// 必须声明应用支持插件包含的必选意图,应用上架时会进行校验
"insightIntents": [
{
// 意图名称
// 名称应当遵循意图框架规范,当前仅支持预置垂域意图,不允许自定义
// 应用内意图名称唯一,不允许出现相同的名称定义
"intentName": "PlayMusic",
// 意图所属的垂域
"domain": "MusicDomain",
// 意图版本号
// 插件引用意图时会校验该版本号,只有和插件定义的版本号一致才能正常调用
"intentVersion": "1.0.1",
// 意图调用逻辑入口
// 根据意图调用文件实际路径和实际名称进行填写,此处文件仅做示意
"srcEntry": "./ets/entryability/InsightIntentExecutorImpl.ets",
"uiAbility": {
// 意图所在module、ability,以及代码相对路径入口
"ability": "EntryAbility",
// UIAbility支持前后台两种执行模式
"executeMode": [
"background",
"foreground"
]
}
}
]
}
2.实现意图调用(鸿蒙端实现)/意图共享(React Native实现) 2.1 实现意图调用(鸿蒙端实现) 意图执行组件为uiAbility的意图调用 当开发者注册的意图承载的运行组件为uiAbility时,开发者需要自己实现InsightIntentExecutor,上述意图声明文件中的srcEntry对应文件,并在对应回调实现打开落地页(点击推荐卡片跳转的界面)的能力,PlayMusic的意图调用字段定义见各垂域意图Schema:https://developer.huawei.com/consumer/cn/doc/service/intents-schema-0000001901962713 具体步骤如下方示例代码: 继承InsightIntentExecutor。 重写对应方法,例如目标拉起前台页面,则可重写onExecuteInUIAbilityForegroundMode方法。 通过意图名称,识别播放歌曲意图(PlayMusic),在对应的方法中传递意图参数(param),并拉起对应落地页(如歌曲落地页)。
import { insightIntent, InsightIntentExecutor } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 意图调用样例
*/
export default class InsightIntentExecutorImpl extends InsightIntentExecutor {
private static readonly PLAY_MUSIC = 'PlayMusic';
/**
* override 执行前台UIAbility意图
*
* @param name 意图名称
* @param param 意图参数
* @param pageLoader 窗口
* @returns 意图调用结果
*/
onExecuteInUIAbilityForegroundMode(name: string, param: Record<string, Object>, pageLoader: window.WindowStage):
Promise<insightIntent.ExecuteResult> {
// 根据意图名称分发处理逻辑。接入方可根据实际业务实现页面跳转
switch (name) {
case InsightIntentExecutorImpl.PLAY_MUSIC:
return this.playMusic(param, pageLoader);
default:
break;
}
return Promise.resolve({
code: -1,
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((resolve, reject) => {
let para: Record<string, string> = {
'result': JSON.stringify(param)
};
let localStorage: LocalStorage = new LocalStorage(para);
// TODO 实现意图调用,loadContent的入参为歌曲落地页路径,例如:pages/Index
pageLoader.loadContent('pages/Index', localStorage)
.then(() => {
let entityId: string = (param.items as Array<object>)?.[0]?.['entityId'];
// TODO 调用成功的情况,此处可以打印日志
resolve({
code: 0,
result: {
message: 'Intent execute succeed'
}
});
})
.catch((err: BusinessError) => {
// TODO 调用失败的情况
resolve({
code: -1,
result: {
message: 'Intent execute failed'
}
})
});
})
}
}
2.2 意图共享(React Native实现) 通过库中接口在React Native侧进行意图分享、删除的操作 代码案例:
import React from 'react';
import {
Alert,
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
} from 'react-native/Libraries/NewAppScreen';
import { Intents } from "@hadss/react_native_intents";
function App(): JSX.Element {
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
flex: 1
};
const handleGetSid = async () => {
Alert.alert(`${JSON.stringify(await Intents.getSid(true))}`);
};
const handleShareIntentPlayMusic = async () => {
await Intents.shareIntent([
{
"intentName": "PlayMusic",
"intentVersion": "1.0",
"identifier": "52dac3b0-6520-4974-81e5-25f0879449b5",
"intentActionInfo": {
"actionMode": "EXECUTED",
"executedTimeSlots": {
"executedStartTime": 1747328400000,
"executedEndTime": 1747328452000
},
"currentPercentage": 50
},
"intentEntityInfo": {
"entityName": "Music",
"entityId": "C10194368",
"entityGroupId": "C10194321312",
"displayName": "测试歌曲",
"description": "NA",
"logoURL": "https://www-file.huawei.com/-/media/corporate/images/home/logo/huawei_logo.png",
"keywords": [
"华为音乐",
"化妆"
],
"rankingHint": 99,
"expirationTime": 1747328452000,
"metadataModificationTime": 1747328452000,
"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(`意图分享成功`);
})
};
const handleDeleteEntity = async () => {
try {
await Intents.deleteEntity('Music', ['C10194368'])
Alert.alert(`意图deleteEntity成功`);
} catch (error) {
Alert.alert(`意图deleteEntity失败,${JSON.stringify(error)}`);
}
};
const handleDeleteIntent = async () => {
try {
await Intents.deleteIntent('PlayMusic')
Alert.alert(`意图deleteIntent成功`);
} catch (error) {
Alert.alert(`意图deleteIntent失败,${JSON.stringify(error)}`);
}
};
return (
<SafeAreaView style={backgroundStyle}>
<View style={styles.container}>
{/* 按钮1 GetSid */}
<View style={styles.buttonGroup}>
<Text style={styles.label}>GetSid</Text>
<TouchableOpacity style={styles.button}
onPress={() => {
handleGetSid()
}} >
<Text style={styles.buttonText}>GetSid</Text>
</TouchableOpacity>
</View>
{/* 按钮2 PlayMusic */}
<View style={styles.buttonGroup}>
<Text style={styles.label}>ShareIntent</Text>
<TouchableOpacity style={styles.button}
onPress={() => {
handleShareIntentPlayMusic()
}}>
<Text style={styles.buttonText}>ShareIntent类型: PlayMusic</Text>
</TouchableOpacity>
</View>
{/* 按钮3 DeleteEDeleteIntentntity */}
<View style={styles.buttonGroup}>
<Text style={styles.label}>DeleteIntent</Text>
<TouchableOpacity style={styles.button}
onPress={() => {
handleDeleteIntent()
}} >
<Text style={styles.buttonText}>DeleteIntent</Text>
</TouchableOpacity>
</View>
{/* 按钮4 DeleteEntity*/}
<View style={styles.buttonGroup}>
<Text style={styles.label}>DeleteEntity</Text>
<TouchableOpacity style={styles.button}
onPress={() => {
handleDeleteEntity()
}} >
<Text style={styles.buttonText}>DeleteEntity</Text>
</TouchableOpacity>
</View>
</View>
</SafeAreaView>
);
}
// 样式
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
buttonGroup: {
marginVertical: 12,
alignItems: 'center'
},
label: {
fontSize: 14,
color: '#666',
marginBottom: 8
},
button: {
backgroundColor: '#007AFF',
paddingVertical: 12,
paddingHorizontal: 32,
borderRadius: 25
},
buttonText: {
color: 'white',
fontSize: 16
}
});
export default App;
引入鸿蒙端代码
使用前需要在EntryAbility.ets文件中的合适位置,缓存IntentsContext,以供意图turoModule内方法使用 例如:
import { common } from '@kit.AbilityKit';
import { RNAbility } from '@rnoh/react-native-openharmony';
const TAG: string = 'EntryAbility';
export default class EntryAbility extends RNAbility {
getPagePath() {
AppStorage.setOrCreate('IntentsContext', this.context as common.Context)
return 'pages/Index';
}
}目前有两种方法:
通过har包引入(在IDE完善相关功能后该方法会被遗弃,目前首选此方法)。
说明: har包位于三方库安装路径的
harmony文件夹下。a. 打开
entry/oh-package.json5,添加以下依赖:"dependencies":{ "@rnoh/react-native-openharmony": "file:../react_native_openharmony", "@hadss/react_native_intents": "file:../../node_modules/@hadss/react_native_intents/harmony/IntentsHO/intents.har", }b. 配置CMakeLists和引入RNOHGeneratedPackage:
打开
entry/src/main/cpp/CMakeLists.txt,添加:project(rnapp) cmake_minimum_required(VERSION 3.4.1) set(CMAKE_SKIP_BUILD_RPATH TRUE) set(OH_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules") set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(RNOH_CPP_DIR "${OH_MODULE_DIR}/@rnoh/react-native-openharmony/src/main/cpp") set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated") set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments") set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie") add_compile_definitions(WITH_HITRACE_SYSTRACE) set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use + file(GLOB GENERATED_CPP_FILES "./generated/*.cpp") add_subdirectory("${RNOH_CPP_DIR}" ./rn) add_library(rnoh_app SHARED + ${GENERATED_CPP_FILES} "./PackageProvider.cpp" "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp" ) target_link_libraries(rnoh_app PUBLIC rnoh)c. 打开
entry/src/main/cpp/PackageProvider.cpp,添加:#include "RNOH/PackageProvider.h" + #include "generated/RNOHGeneratedPackage.h" using namespace rnoh; std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) { return { + std::make_shared<RNOHGeneratedPackage>(ctx) }; }d. 在ArkTs侧引入AvoidModulePackage:
打开
entry/src/main/ets/RNPackagesFactory.ts,添加:... + import { IntentsModulesPackage } from '@hadss/react_native_intents/ts';; export function createRNPackages(ctx: RNPackageContext): RNPackage[] { return [ + new IntentsModulePackage(ctx), ]; }e. 运行:
点击右上角的
sync按钮或者在终端执行:
cd entry ohpm install然后编译、运行即可。
说明 若项目启动时报错:can not find record '&@rnoh/react-native-openharmony/generated/ts&X.X.X'。需在entry\oh_modules@rnoh\react-native-openharmony\ts.ts文件中添加export * from './generated/ts',并删除.cxx文件夹、build文件夹,然后执行sync操作同步代码。
直接链接源码。
如需使用直接链接源码,请参考直接链接源码说明。
API
说明: "Platform"列表示支持的平台,All表示支持所有平台。
意图框架接口
Intents | Name | Description | Type | Platform | | ------------------- | -----------------------------------------------------| -------- | --------- | | shareIntent | 共享已执行或预期的InsightIntent。 | (insights: InsightIntent[])=>Promise | OpenHarmony | | deleteIntent | 删除InsightIntent。如果设置了identifiers参数,则删除intent名称下的identifiers对应的记录。否则,删除意图名称下的所有记录。intentName:string 表示意图的名称;identifiers:string[] 表示意图的标识符。 | (intentName: string, identifiers?: string[])=>Promise | OpenHarmony | | deleteEntity | 按实体名称下的实体ID删除。 entityName:string 表示实体的名称;entityIds:string[] 表示意图实体的标识符。| (entityName: string, entityIds: string[])=>Promise | OpenHarmony | | getSid | 获取Service Open ID。renew: boolean 是否强制从云端获取新的服务开放ID。如果为true,从云端获取新的服务开放ID;如果为false,则优先获取本地存储的服务开放ID。 | (renew: boolean)=>Promise | OpenHarmony |
InsightIntent
| Name | Description | Type | Platform | | :----------------- | :----------------------------------------------------------------| :--------- | :-------- | | intentName | 表示意图名称,例如:'PlayMusic'。 | string | OpenHarmony | | intentVersion | 表示意图版本,当前为初始版本'1.0'。 | string | OpenHarmony | | identifier | 表示意图的标识符,开发者按照自身业务需要生成,作为单条共享记录的唯一标识符。该字段的生成方式可参考UUID生成方式,或基于时间戳生成随机字符串。例如:'52dac3b0-6520-4974-81e5-25f0879449b5'。 | string | OpenHarmony | | intentActionInfo | 表示意图的执行信息,例如:已执行或预测将要执行意图的时间。 | IntentActionInfo | OpenHarmony | | intentEntityInfo | 表示意图的实体信息,包含行为和事件。 | IntentEntityInfo | OpenHarmony |
IntentActionInfo
| Name | Description | Type | Platform | | :----------------- | :----------------------------------------------------------------| :--------- | :-------- | | [key: string] | 表示值的类型为包含一个或多个键值对的对象。其中键的类型为字符,值的类型为Object,键和值的取值范围因意图名称而异,具体请参考各垂域意图Schema。 | object | OpenHarmony |
IntentEntityInfo
| Name | Description | Type | Platform | | :----------------- | :----------------------------------------------------------------| :--------- | :-------- | | entityId | 表示意图实体的标识符,开发者按照自身业务需要生成,作为单条实体的唯一标识符。该字段的生成方式可参考UUID生成方式,或基于时间戳生成随机字符串。例如:'C10194368'。 | string | OpenHarmony | | entityName | 表示意图实体的名称。取值请参考各垂域意图Schema。 | string | OpenHarmony | | [key: string] | 意图实体的其他信息,表示为一个或多个键值对。其中键的类型为字符,值的类型为Object,键和值的取值范围因意图名称而异,具体请参考各垂域意图Schema。 | object | OpenHarmony |
各垂域意图Schema:https://developer.huawei.com/consumer/cn/doc/service/intents-schema-0000001901962713 意图配置接口参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/intents-arkts-api-insightintent#section13611343185915
依赖
本示例依赖@ohos/hvigor-ohos-plugin,且最低版本为4.3.0。 使用DevEco Studio版本大于本示例推荐版本,请根据 DevEco Studio 提示更新 hvigor 插件版本。 SID获取需联网、登录华为账号并同意小艺建议的用户协议和隐私政策。
约束与限制
意图共享和意图调用的测试,当前无法由开发者独立完成,烦请根据Intents Kit接入流程,通过邮箱向华为意图框架接口人提交验收申请,由接口人配合开发者一同完成测试验收。 本示例仅支持标准系统上运行,支持设备:Phone | Tablet。 地区限制:仅支持中国境内(不包含中国香港、中国澳门、中国台湾)提供服务。 操作系统限制:HarmonyOS 5.0及以上。 DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。 HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。
