阅读视图

发现新文章,点击刷新页面。

📳 React Native 震动指南:Haptic Feedback vs 原生 Vibration 到底怎么选?

📳 React Native 震动指南:Haptic Feedback vs 原生 Vibration 到底怎么选?

在 React Native 开发中,当我们接到“App 需要加点震动反馈”的需求时,通常会面临两个选择:使用 RN 自带的 Vibration API,还是引入第三方库 react-native-haptic-feedback

很多开发者(包括产品经理和老板)对这两者的区别并没有清晰的概念,导致做出来的效果要么“震得手麻”,要么“根本感觉不到”。

本文将从使用场景硬件原理代码实现三个维度,深度对比这两种震动方案。


🛠 核心区别速览

维度 Vibration (RN 原生) react-native-haptic-feedback (第三方)
底层硬件 传统转子马达 / 线性马达的强震动模式 iOS Taptic Engine / Android 线性马达触觉模式
震动体感 强烈、持久、粗糙(放在桌上会有明显的“嗡嗡”声) 细腻、短促、清脆(模拟真实的物理按键质感)
使用场景 强提醒、高风险警告、来电、闹钟 UI 交互、点赞、列表滚动阻尼感、下拉刷新
控制维度 只能控制震动的时间长度和频率节奏 只能控制震动的类型(轻击、重击、成功、错误)
依赖安装 无需安装,React Native 自带 需要 yarn add 并进行 pod install

场景一:老板说“遇到高风险操作,给我狠狠地警告用户!” 🚨

首选方案:React Native 原生 Vibration API

当你需要引起用户的强力注意,比如应用内收到紧急工单、监控报警、或者像文章开头提到的“高风险提示”时,你需要的是传统的大震动。这种震动甚至在手机放在桌面上时,都能发出物理共振的声音。

代码实现:持续的警报震动

原生 Vibration 最强大的地方在于支持传入一个 Pattern(节奏数组),并且可以无限循环。

import { Vibration, Platform, Button } from 'react-native';

// 触发高风险警报
const triggerAlert = () => {
  // Pattern 数组: [等待时间, 震动时间, 等待时间, 震动时间...]
  const pattern = Platform.OS === 'android' 
    ? [0, 1000, 500] // Android: 立即开始,震1秒,停0.5秒,不断循环
    : [0, 1000];     // iOS: 系统会按固定时长重复震动
  
  // 第二个参数 true 表示开启无限循环
  Vibration.vibrate(pattern, true);
};

// 停止震动(必须手动调用,否则会一直震)
const stopAlert = () => {
  Vibration.cancel();
};

⚠️ 避坑指南

  • iOS 平台对单次 Vibration.vibrate() 的时长参数是直接忽略的,固定只震动 400ms 左右。要实现长震动,必须使用 Pattern 数组。
  • 连续震动非常耗电且容易引起用户反感,务必提供明确的停止机制(如点击确认按钮后调用 Vibration.cancel())。

场景二:产品经理说“点赞按钮要像真实弹簧按键一样有手感” ✨

首选方案:react-native-haptic-feedback

如果你的需求是提升 App 的质感和高级感,比如点赞时的心跳感、滑动选择器时的齿轮滴答感、或者密码输入错误的轻微抖动,那么原生的 Vibration 绝对不能用,因为它会震得用户手麻。

此时必须使用 react-native-haptic-feedback,它调用的是 iOS 昂贵的 Taptic Engine 和 Android 的高级马达 API。

代码实现:细腻的 UI 触觉反馈

首先需要安装库:

yarn add react-native-haptic-feedback
cd ios && pod install

然后在代码中调用特定的“质感类型”:

import ReactNativeHapticFeedback from 'react-native-haptic-feedback';

const options = {
  enableVibrateFallback: true, // 如果设备不支持触觉反馈,退级为普通震动
  ignoreAndroidSystemSettings: false, // 尊重用户的系统震动设置
};

// 场景 A:普通按钮点击(清脆)
const onLightPress = () => {
  ReactNativeHapticFeedback.trigger('impactLight', options);
};

// 场景 B:操作成功提示(带有特定的成功节奏)
const onSuccess = () => {
  ReactNativeHapticFeedback.trigger('notificationSuccess', options);
};

// 场景 C:表单输入错误提示
const onError = () => {
  ReactNativeHapticFeedback.trigger('notificationError', options);
};

支持的常用类型有

  • 交互类: impactLight, impactMedium, impactHeavy, rigid, soft
  • 通知类: notificationSuccess, notificationWarning, notificationError
  • 其他: selection (滑动列表时的阻尼感)

总结与建议

在实际项目中,这两种方案往往是共存的,而不是二选一:

  1. 涉及 UI 微交互(如点赞、开关 Switch、下拉刷新、展开菜单):必须用 Haptic Feedback
  2. 涉及系统级提醒(如新消息到来、重大错误、业务规定的高风险预警):必须用原生 Vibration

下次再遇到“加个震动”的需求,记得先问清楚:“是要提醒用户,还是要提升手感?” 答案决定了你的技术选型!

🛡️ React Native 截屏保护方案全网大比拼:到底该用哪个库?

在开发涉及金融、医疗、企业内部数据或版权内容(如付费视频、文章)的 React Native 应用时,防止用户截屏和录屏是一项至关重要的安全需求。

但是,当你去 GitHub 或 npm 搜索 "React Native screen capture" 或 "screenshot prevent" 时,会发现五花八门的第三方库,而且很多都已经年久失修。到底该选哪一个?本文将为你全网盘点主流方案,并深入解析底层的实现原理。


🏆 核心库巅峰对决

目前社区里讨论度最高的两个库是 react-native-capture-protectionreact-native-screenshot-prevent。如果你正在这两者之间纠结,这里直接给出结论:强烈建议使用 react-native-capture-protection

以下是详尽的对比维度:

特性 / 维度 react-native-capture-protection 🏆 react-native-screenshot-prevent ⚠️
维护状态 活跃更新,支持最新的 React Native 版本。 已停更(最新版本停留在 2 年前),有大量未解决的 Issue。
Android 支持 支持 FLAG_SECURE,且完美适配 Android 14 的全新截屏检测 API。 仅支持基础的 FLAG_SECURE,在较新系统和机型上可能存在兼容性问题。
iOS 支持 保护全面(包含截屏、录屏、多任务切换台隐藏),内部实现较新。 使用旧版的黑科技,在 iOS 15+ 之后容易出现布局穿透异常或彻底失效。
API 设计 现代化,提供 Hooks (useCaptureProtection) 和 Provider。 传统的方法调用,API 设计较老,在现代函数式组件中使用不够优雅。
Expo 支持 完全兼容(提供 Expo Config Plugin,支持 Dev Client)。 不支持 Expo,需要手动修改原生代码。

🌐 其他全网主流方案盘点

除了上述两强相争,全网范围内还有以下几个常见的选择,适用于不同的特定场景:

1. expo-screen-capture (Expo 官方护航)

  • 优势:Expo 官方维护,极度稳定,文档完善。
  • 劣势:在 Android 上可以通过 preventScreenCaptureAsync() 完美阻止截屏;但在 iOS 上,官方出于遵守 Apple 规范的考量,仅提供截屏“检测”(监听事件),不提供截屏“阻止”功能
  • 适用场景:只要求 Android 阻止截屏,iOS 侧只需要做到“截屏后警告用户”的合规类应用。

2. react-native-screen-capture

  • 优势:API 极简,同时附带了屏幕常亮 (keepAwake) 功能。
  • 劣势:功能相对单一,缺乏对现代系统(如 Android 14 隐私政策)的精细化适配,社区维护力度一般。

💡 原理大揭秘:为什么 iOS 阻止截屏那么难?

了解这些库的底层原理,有助于你理解为什么老旧的库在 iOS 上特别容易失效。

🤖 Android 端:稳如泰山的系统 API

在安卓端,实现截屏保护非常规范。几乎所有的库都是调用了安卓系统底层的 WindowManager.LayoutParams.FLAG_SECURE。 这是一个非常可靠的系统级 API,一旦开启,系统会自动在底层拦截截屏、录屏行为,并在多任务切换台(App Switcher)中将 App 画面涂黑。开发者不需要搞任何黑科技。

🍎 iOS 端:与苹果斗智斗勇的“黑科技”

Apple 官方从未提供过阻止截屏的公开 API。 官方只提供了监听截屏的通知(UIApplicationUserDidTakeScreenshotNotification)。

那么,那些宣称能“阻止截屏”的 iOS 库是怎么做到的呢? 它们利用了系统的一个“特性”——UITextField 的密码输入模式 (isSecureTextEntry = true)

当 iOS 屏幕上存在密码输入框时,系统为了保护用户密码不被恶意应用录屏窃取,会在截屏和录屏时自动把该区域模糊或涂黑。 这些第三方库的原理就是:在整个 App 的最顶层盖一个透明的、巨大的密码输入框。由于这是一个 Hack 方案,所以一旦 iOS 系统升级(比如修改了 View 渲染层级或事件分发机制),就很容易出现“点击事件穿透失败”(导致 App 无法点击)或者“白屏”的惨剧。这也是为什么一定要选择持续维护的库的原因。


🚀 最佳实践:如何优雅地接入

对于现代 React Native 项目,接入 react-native-capture-protection 是目前的最优解。

1. 安装依赖

如果你使用 yarn:

yarn add react-native-capture-protection

iOS 别忘了安装 Pods:

cd ios && pod install

2. 现代化的 Hooks 使用方式

我们通常不需要全 App 屏蔽截屏,只需要在特定的敏感页面(如支付页、个人信息页)开启保护:

import React, { useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { CaptureProtection, useCaptureProtection } from 'react-native-capture-protection';

export default function SecureScreen() {
  const { protectionStatus, status } = useCaptureProtection();

  useEffect(() => {
    // 组件挂载时:开启全面保护(阻止截屏、录屏、多任务预览)
    CaptureProtection.prevent({
      screenshot: true,
      record: true,
      appSwitcher: true
    });

    return () => {
      // 组件卸载时:恢复允许截屏,避免影响 App 其他非敏感页面
      CaptureProtection.allow();
    };
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.title}>🔒 受保护的敏感数据</Text>
      <Text>尝试截屏或录屏,你会发现画面被隐藏了!</Text>
      <Text>当前保护状态: {status}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  title: { fontSize: 20, fontWeight: 'bold', marginBottom: 20 }
});

结语

在 React Native 中实现截屏保护,Android 岁月静好,iOS 则是黑魔法的狂欢。选择像 react-native-capture-protection 这样与时俱进、维护良好的库,能帮你省去无数在各个 iOS 版本间适配排雷的日日夜夜。

🔗 参考链接

❌