ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-shake — 摇一摇事件监听

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📌 开发环境声明:本文基于 React Native 0.72.90 版本进行开发适配


🚀 一、开篇引言

摇一摇是移动应用中常见的交互方式,广泛应用于摇一摇抽奖、摇一摇换题、摇一摇反馈等场景。react-native-shake 是 React Native 社区中简单易用的摇一摇事件监听组件,可以检测用户摇晃手机的动作并触发相应事件。本文将带你深入了解如何在 HarmonyOS 平台上集成和使用这个有趣的交互组件。

1.1 大纲

  • ✅ react-native-shake 的核心概念与工作原理
  • ✅ HarmonyOS 平台的完整集成流程
  • ✅ 摇一摇事件监听与处理
  • ✅ API 的深度解析
  • ✅ 实际应用场景的最佳实践

1.2 适用人群

  • 正在进行 React Native 鸿蒙化迁移的开发者
  • 需要实现摇一摇功能的开发者
  • 对跨平台传感器组件开发感兴趣的技术爱好者

1.3 为什么选择 react-native-shake?

特点 说明
简单易用 API 极简,几行代码即可实现
跨平台一致 iOS、Android、HarmonyOS 表现一致
轻量级 无需复杂配置,开箱即用
事件驱动 基于订阅模式,灵活管理监听生命周期
低功耗 智能检测,不影响设备续航

📦 二、库概览

2.1 基本信息

项目 内容
库名称 @react-native-ohos/react-native-shake
原库名称 react-native-shake
版本信息 5.6.3 (RN 0.72) / 6.0.2 (RN 0.77)
官方仓库 https://github.com/Doko-Demo-Doa/react-native-shake
鸿蒙仓库 https://gitcode.com/openharmony-sig/rntpc_react-native-shake
开源协议 MIT

2.2 版本兼容性

三方库版本 支持RN版本 是否支持Autolink
~6.0.2 0.77 No
~5.6.3 0.72 Yes
<=5.6.2-0.0.1@deprecated 0.72 No

2.3 核心能力矩阵

能力项 描述 HarmonyOS 支持
添加监听 addListener 方法 ✅ 完全支持
移除监听 remove 方法 ✅ 完全支持
移除所有监听 removeAllListeners 方法 ✅ 完全支持

2.4 技术架构图

原生平台层
Bridge Layer
React Native 应用层
RNShake Module
addListener
remove
removeAllListeners
Native Module
ShakePackage
ShakeModule
Android

SensorManager
iOS

CMMotionManager
HarmonyOS

Accelerometer

2.5 典型应用场景

场景 描述 示例
摇一摇抽奖 摇动触发抽奖活动 🎰 营销活动、福利发放
摇一摇换题 摇动切换题目或内容 📝 题库应用、随机推荐
摇一摇反馈 摇动触发反馈入口 💬 用户反馈、问题报告
摇一摇刷新 摇动刷新页面内容 🔄 内容刷新、数据更新
摇一摇彩蛋 隐藏功能触发 🥚 彩蛋功能、隐藏菜单

⚡ 三、快速开始

3.1 环境要求

依赖项 版本要求
React Native 0.72.x / 0.77.x
RNOH (鸿蒙框架) 0.72.90 / 0.77.18
HarmonyOS SDK 6.0.0.47+ (API 20)
DevEco Studio 5.0.3+ / 6.0+
Node.js 16.18.0+ / 18.x

3.2 一键安装

创建鸿蒙项目的过程不再进行描述,不懂得看这篇:https://blog.csdn.net/u011178696/article/details/151932277

bash 复制代码
npm install @react-native-ohos/react-native-shake@5.6.3-rc.1

或使用 yarn:

bash 复制代码
yarn add @react-native-ohos/react-native-shake@5.6.3-rc.1

3.3 验证安装

安装完成后,检查 package.json 文件:

json 复制代码
{
  "dependencies": {
    "@react-native-ohos/react-native-shake": "^5.6.3-rc.1"
  }
}

🔧 四、HarmonyOS 平台配置

4.1 权限配置

⚠️ 此库需要加速度计权限,必须在 module.json5 中配置。

打开 entry/src/main/module.json5,添加权限:

json 复制代码
"requestPermissions": [
  {
    "name": "ohos.permission.ACCELEROMETER"
  }
]

🎉 5.6.3 版本支持 AutoLink,可自动完成原生端配置!

如果你的项目已接入 AutoLink,安装依赖后会自动完成原生端配置,无需手动操作。

Autolink 框架指导文档:https://gitcode.com/openharmony-sig/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md

⚠️ 如果你使用的是 6.0.2 或更高版本,需要手动配置原生端代码。

步骤 1:配置 oh-package.json5

在项目根目录的 oh-package.json5 文件中添加(根据自己的版本来,不一定是我这个版本):

json 复制代码
{
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}
步骤 2:引入 HAR 包

entry/oh-package.json5 文件中添加依赖:

json 复制代码
"dependencies": {
  "@rnoh/react-native-openharmony": "0.72.90",
  "@react-native-ohos/react-native-shake": "file:../../node_modules/@react-native-ohos/react-native-shake/harmony/shake_package.har"
}
步骤 3:配置 CMakeLists.txt

entry/src/main/cpp/CMakeLists.txt 文件中添加:

diff 复制代码
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")

+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-shake/src/main/cpp" ./shake_package)

+ target_link_libraries(rnoh_app PUBLIC rnoh_shake)
步骤 4:配置 PackageProvider.cpp

entry/src/main/cpp/PackageProvider.cpp 文件中添加:

diff 复制代码
+ #include "ShakePackage.h"

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
+     std::make_shared<ShakePackage>(ctx)
    };
}
步骤 5:引入 ShakePackage

entry/src/main/ets/RNPackagesFactory.ts 文件中添加:

diff 复制代码
+ import { ShakePackage } from "@react-native-ohos/react-native-shake/ts";

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
+   new ShakePackage(ctx)
  ];
}

📱 五、基础使用

5.1 添加摇一摇监听

最基础的使用方式:

ts 复制代码
import RNShake from 'react-native-shake';

useEffect(() => {
  const subscription = RNShake.addListener(() => {
    console.log('检测到摇一摇!');
  });

  return () => {
    subscription.remove();
  };
}, []);

5.2 完整示例

ts 复制代码
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import RNShake from 'react-native-shake';

export default function App() {
  const [shakeCount, setShakeCount] = useState(0);

  useEffect(() => {
    const subscription = RNShake.addListener(() => {
      setShakeCount((prev) => prev + 1);
    });

    return () => {
      subscription.remove();
    };
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.title}>摇一摇计数器</Text>
      <Text style={styles.count}>{shakeCount}</Text>
      <Text style={styles.hint}>摇晃手机试试!</Text>
    </View>
  );
}

🎨 六、进阶用法

6.1 摇一摇触发动画

结合动画效果增强用户体验:

ts 复制代码
import { Animated } from 'react-native';

const [scale] = useState(new Animated.Value(1));

useEffect(() => {
  const subscription = RNShake.addListener(() => {
    Animated.sequence([
      Animated.timing(scale, {
        toValue: 1.2,
        duration: 100,
        useNativeDriver: true,
      }),
      Animated.timing(scale, {
        toValue: 1,
        duration: 100,
        useNativeDriver: true,
      }),
    ]).start();
  });

  return () => subscription.remove();
}, []);

6.2 摇一摇触发随机内容

ts 复制代码
const items = ['🍎', '🍊', '🍋', '🍇', '🍓', '🍑'];
const [currentItem, setCurrentItem] = useState('🍎');

useEffect(() => {
  const subscription = RNShake.addListener(() => {
    const randomIndex = Math.floor(Math.random() * items.length);
    setCurrentItem(items[randomIndex]);
  });

  return () => subscription.remove();
}, []);

6.3 移除所有监听

tsx 复制代码
RNShake.removeAllListeners();

📚 七、API 详解

7.1 RNShake 方法

addListener

添加摇一摇事件监听器,返回一个订阅对象。

tsx 复制代码
const subscription = RNShake.addListener(() => {
  console.log('摇一摇触发!');
});

subscription.remove();
removeAllListeners

移除所有摇一摇事件监听器。

tsx 复制代码
RNShake.removeAllListeners();

⚠️ 八、注意事项与常见问题

8.1 权限要求

权限名称 说明
ohos.permission.ACCELEROMETER 加速度计权限

8.2 常见问题

Q1: 摇一摇不触发?

A: 检查是否已配置 ohos.permission.ACCELEROMETER 权限。

Q2: 如何调整灵敏度?

A: 当前版本使用默认灵敏度,暂不支持自定义灵敏度配置。

Q3: 监听器没有正确移除?

A: 确保在 useEffect 的清理函数中调用 subscription.remove()

Q4: 摇晃时弹出 React Native Dev Menu?

A: 这是 React Native 开发模式的默认行为。在开发环境中,摇晃设备会触发开发者菜单。有以下解决方案:

  1. 生产环境自动禁用:在 release 构建中,开发者菜单会自动禁用,不会影响用户体验。

  2. 开发环境临时禁用 :如果需要在开发环境测试摇一摇功能,可以在 Index.ets 中修改 rnInstanceConfig 配置,设置 devMenuEnabled: false

  3. 调整摇晃灵敏度 :可以适当降低 react-native-shake 的触发频率,避免与系统开发者菜单冲突。


💻 九、完整示例代码

精美摇一摇示例

ts 复制代码
import React, { useState, useEffect, useRef } from 'react';
import {
  View,
  Text,
  StyleSheet,
  SafeAreaView,
  Animated,
  TouchableOpacity,
} from 'react-native';
import RNShake from 'react-native-shake';

const emojis = ['🎲', '🎰', '🎯', '🎪', '🎨', '🎭'];
const messages = [
  '运气不错!',
  '再来一次!',
  '好运连连!',
  '惊喜不断!',
];

export default function App() {
  const [shakeCount, setShakeCount] = useState(0);
  const [currentEmoji, setCurrentEmoji] = useState('🎲');
  const [message, setMessage] = useState('摇晃手机试试');
  const [isShaking, setIsShaking] = useState(false);

  const scaleAnim = useRef(new Animated.Value(1)).current;
  const rotateAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    const subscription = RNShake.addListener(() => {
      handleShake();
    });

    return () => {
      subscription.remove();
    };
  }, []);

  const handleShake = () => {
    if (isShaking) return;

    setIsShaking(true);
    setShakeCount((prev) => prev + 1);

    const randomEmoji = emojis[Math.floor(Math.random() * emojis.length)];
    const randomMessage = messages[Math.floor(Math.random() * messages.length)];
    setCurrentEmoji(randomEmoji);
    setMessage(randomMessage);

    Animated.sequence([
      Animated.parallel([
        Animated.timing(scaleAnim, {
          toValue: 1.3,
          duration: 150,
          useNativeDriver: true,
        }),
        Animated.timing(rotateAnim, {
          toValue: 1,
          duration: 150,
          useNativeDriver: true,
        }),
      ]),
      Animated.parallel([
        Animated.timing(scaleAnim, {
          toValue: 1,
          duration: 150,
          useNativeDriver: true,
        }),
        Animated.timing(rotateAnim, {
          toValue: 0,
          duration: 150,
          useNativeDriver: true,
        }),
      ]),
    ]).start(() => {
      setIsShaking(false);
    });
  };

  const resetCount = () => {
    setShakeCount(0);
    setCurrentEmoji('🎲');
    setMessage('摇晃手机试试');
  };

  const spin = rotateAnim.interpolate({
    inputRange: [0, 1],
    outputRange: ['0deg', '360deg'],
  });

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.header}>
        <Text style={styles.title}>摇一摇</Text>
      </View>

      <View style={styles.content}>
        <Animated.View
          style={[
            styles.emojiContainer,
            {
              transform: [{ scale: scaleAnim }, { rotate: spin }],
            },
          ]}
        >
          <Text style={styles.emoji}>{currentEmoji}</Text>
        </Animated.View>

        <Text style={styles.message}>{message}</Text>

        <View style={styles.statsContainer}>
          <View style={styles.statItem}>
            <Text style={styles.statValue}>{shakeCount}</Text>
            <Text style={styles.statLabel}>摇动次数</Text>
          </View>
        </View>
      </View>

      <View style={styles.footer}>
        <TouchableOpacity style={styles.resetButton} onPress={resetCount}>
          <Text style={styles.resetButtonText}>重置计数</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#1a1a2e',
  },
  header: {
    padding: 20,
    backgroundColor: '#16213e',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#fff',
    textAlign: 'center',
  },
  content: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    paddingHorizontal: 20,
  },
  emojiContainer: {
    width: 140,
    height: 140,
    borderRadius: 70,
    backgroundColor: '#16213e',
    justifyContent: 'center',
    alignItems: 'center',
    marginBottom: 30,
    borderWidth: 3,
    borderColor: '#00d4ff',
    shadowColor: '#00d4ff',
    shadowOffset: { width: 0, height: 0 },
    shadowOpacity: 0.5,
    shadowRadius: 20,
    elevation: 10,
  },
  emoji: {
    fontSize: 64,
  },
  message: {
    fontSize: 22,
    fontWeight: '600',
    color: '#00d4ff',
    marginBottom: 40,
  },
  statsContainer: {
    flexDirection: 'row',
  },
  statItem: {
    alignItems: 'center',
    backgroundColor: '#16213e',
    paddingHorizontal: 40,
    paddingVertical: 20,
    borderRadius: 20,
  },
  statValue: {
    fontSize: 40,
    fontWeight: 'bold',
    color: '#fff',
  },
  statLabel: {
    fontSize: 14,
    color: '#888',
    marginTop: 5,
  },
  footer: {
    padding: 20,
  },
  resetButton: {
    backgroundColor: '#00d4ff',
    paddingVertical: 14,
    borderRadius: 12,
    alignItems: 'center',
  },
  resetButtonText: {
    fontSize: 16,
    color: '#1a1a2e',
    fontWeight: '600',
  },
});

🔗 十、相关资源


📝 十一、总结

本文详细介绍了 react-native-shake 在 HarmonyOS 平台的使用方法。通过 Shake 组件,你可以轻松实现摇一摇交互功能。

核心要点

  • ✅ 简单易用的 API 设计
  • ✅ 基于订阅模式的事件监听
  • ✅ 需要配置加速度计权限
  • ✅ 记得在组件卸载时移除监听

希望本文能帮助你在 HarmonyOS 项目中顺利集成摇一摇功能!

相关推荐
大雷神2 小时前
HarmonyOS APP<玩转React>开源教程十七:模块详情页面
harmonyos
程序员大辉2 小时前
KaihongOS 5.0:免费的鸿蒙 X86 桌面系统,普通电脑也能装
华为·电脑·harmonyos
大雷神2 小时前
HarmonyOS APP<玩转React>开源教程十八:课程详情页面
前端·react.js·开源·harmonyos
弓.长.2 小时前
ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-waterfall-flow — 瀑布流布局组件
react native·react.js·harmonyos
弓.长.2 小时前
ReactNative for OpenHarmony项目鸿蒙化三方库:@react-native-ohos/image-editor
react native·react.js·harmonyos
特立独行的猫a11 小时前
CMake与GN构建系统对比及GN使用指南
harmonyos·cmake·openharmony·构建·gn
墨狂之逸才17 小时前
🛡️ React Native 截屏保护方案全网大比拼:到底该用哪个库?
react native
敲代码的约德尔人17 小时前
React Compiler 完全指南:2026 年自动性能优化的革命
react.js
墨狂之逸才17 小时前
📳 React Native 震动指南:Haptic Feedback vs 原生 Vibration 到底怎么选?
react native