NipGeihou's blog NipGeihou's blog
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
  • 常用软件
  • Git仓库推荐
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档

NipGeihou

我见青山多妩媚,料青山见我应如是
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
  • 常用软件
  • Git仓库推荐
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档
  • nodejs

  • css

  • 最佳实践

  • TypeScript

  • ajax

  • JavaScript

  • 前端工程化

  • React

  • nextjs

  • Flutter

  • Vue

  • Taro

  • ReactNative

    • React Native - 开始
      • 资料
      • 组件
        • 原生组件
        • 核心组件
      • 特定平台代码
        • Platform 模块
        • 特定平台后缀
      • 环境搭建
      • 原生开发
        • Native Modules 原生模块
        • TS接口
        • 配置
        • 生成原生接口代码
        • TS调用原生方法
        • 编写对应平台代码
        • Android
        • Native Modules 原生模块(旧)
        • 创建自定义原生模块文件
        • 重写getName()定义原生模块名称
        • 导出原生方法
        • 注册模块
  • Android

  • 笔记

  • 前端
  • ReactNative
NipGeihou
2026-08-12
目录

React Native - 开始

# 资料

  • 官网:https://reactnative.dev/ (opens new window)

# 组件

# 原生组件

在 Android 开发中,视图通常使用 Kotlin 或 Java 编写;在 iOS 开发中,则使用 Swift 或 Objective-C。而使用 React Native,你可以利用 React 组件通过 JavaScript 调用这些视图。在运行时,React Native 会为这些组件创建相应的 Android 和 iOS 视图。由于 React Native 组件与 Android 和 iOS 组件使用相同的视图,因此 React Native 应用的外观、体验和性能与其他应用并无二致。我们将这些平台支持的组件称为原生组件。

# 核心组件

React Native UI 组件 Android 原生视图 iOS 原生视图 Web 标签
<View> <ViewGroup> <UIView> A non-scrolling  <div>
<Text> <TextView> <UITextView> <p>
<Image> <ImageView> <UIImageView> <img>
<ScrollView> <ScrollView> <UIScrollView> <div>
<TextInput> <EditText> <UITextField> <input type="text">

# 特定平台代码

参考:Introduction · React Native (opens new window) React Native 提供了两种方法来区分平台:

  • 使用 Platform 模块.
  • 使用特定平台后缀.

# Platform 模块

import {Platform, StyleSheet} from 'react-native';

const styles = StyleSheet.create({
  // `Platform.OS`在 iOS 上会返回`ios`,而在 Android 设备或模拟器上则会返回`android`
  height: Platform.OS === 'ios' ? 200 : 100,
});

Platform.select() :

import {Platform, StyleSheet} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    ...Platform.select({
      ios: {
        backgroundColor: 'red',
      },
      android: {
        backgroundColor: 'green',
      },
      default: {
        // other platforms, web for example
        backgroundColor: 'blue',
      },
    }),
  },
});

# 特定平台后缀

BigButton.ios.js
BigButton.android.js

# 环境搭建

# 原生开发

因为某种原因,必须调用原生平台代码执行。

  • Native Modules:原生模块,指的是那些没有为用户提供用户界面的原生库。例如,用于存储数据、发送通知、处理网络事件的模块。这些模块可以作为函数或对象被 JavaScript 应用程序代码所调用。
  • Native Component:原生组件,通过 React 组件,应用程序的 JavaScript 代码可以调用原生平台的视图、小部件和控制器。

# Native Modules 原生模块

以调用 Android 和 iOS 接口实现原生持久存储能力:

# TS 接口

  • 根目录创建 specs 文件夹
  • 下创建 NativeLocalStorage.ts 文件,如需其他名字应以 Native 为前缀

specs/NativeLocalStorage.ts

import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';

export interface Spec extends TurboModule {
  setItem(value: string, key: string): void;
  getItem(key: string): string | null;
  removeItem(key: string): void;
  clear(): void;
}

export default TurboModuleRegistry.getEnforcing<Spec>(
  'NativeLocalStorage',
);

# 配置

"codegenConfig": {
  "name": "NativeLocalStorageSpec",
  "type": "modules",
  "jsSrcsDir": "specs",
  "android": {
    "javaPackageName": "com.nativelocalstorage"
  }
},

# 生成原生接口代码

在构建 Android 应用程序时,该过程会自动执行,无需手动操作。

cd android  

./gradlew generateCodegenArtifactsFromSchema

# TS 调用原生方法

// 如果 Turbo Native Module 不可用,该操作将返回 `null`
get<T>(name: string): T | null

// 如果 Turbo Native Module 不可用,就会抛出异常。该代码假设该模块始终可用。
getEnforcing<T>(name: string): T
import {useEffect, useState, type JSX} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  Text,
  TextInput,
  Button,
} from 'react-native';

import NativeLocalStorage from './specs/NativeLocalStorage';

const EMPTY = '<empty>';

function App(): JSX.Element {
  const [value, setValue] = useState<string | null>(null);

  const [editingValue, setEditingValue] = useState<string | null>(
    null,
  );

  useEffect(() => {
    const storedValue = NativeLocalStorage?.getItem('myKey');
    setValue(storedValue ?? '');
  }, []);

  function saveValue() {
    NativeLocalStorage?.setItem(editingValue ?? EMPTY, 'myKey');
    setValue(editingValue);
  }

  function clearAll() {
    NativeLocalStorage?.clear();
    setValue('');
  }

  function deleteValue() {
    NativeLocalStorage?.removeItem('myKey');
    setValue('');
  }

  return (
    <SafeAreaView style={{flex: 1}}>
      <Text style={styles.text}>
        Current stored value is: {value ?? 'No Value'}
      </Text>
      <TextInput
        placeholder="Enter the text you want to store"
        style={styles.textInput}
        onChangeText={setEditingValue}
      />
      <Button title="Save" onPress={saveValue} />
      <Button title="Delete" onPress={deleteValue} />
      <Button title="Clear" onPress={clearAll} />
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  text: {
    margin: 10,
    fontSize: 20,
  },
  textInput: {
    margin: 10,
    height: 40,
    borderColor: 'black',
    borderWidth: 1,
    paddingLeft: 5,
    paddingRight: 5,
    borderRadius: 5,
  },
});

export default App;

# 编写对应平台代码

# Android
package com.nativelocalstorage

import android.content.Context
import android.content.SharedPreferences
import com.nativelocalstorage.NativeLocalStorageSpec
import com.facebook.react.bridge.ReactApplicationContext

class NativeLocalStorageModule(reactContext: ReactApplicationContext) : NativeLocalStorageSpec(reactContext) {

  override fun getName() = NAME

  override fun setItem(value: String, key: String) {
    val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
    val editor = sharedPref.edit()
    editor.putString(key, value)
    editor.apply()
  }

  override fun getItem(key: String): String? {
    val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
    val username = sharedPref.getString(key, null)
    return username.toString()
  }

  override fun removeItem(key: String) {
    val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
    val editor = sharedPref.edit()
    editor.remove(key)
    editor.apply()
  }

  override fun clear() {
    val sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
    val editor = sharedPref.edit()
    editor.clear()
    editor.apply()
  }

  companion object {
    const val NAME = "NativeLocalStorage"
  }
}

# Native Modules 原生模块 (旧)

以创建一个 Calendar 原生模块为例

# 创建自定义原生模块文件

  • 使用 Android Studio 打开 rn 项目下的 android
  • 创建目录: android/app/src/main/java/com/your-app-name/
  • 目录下创建: CalendarModule.kt
package com.your-apps-package-name; // replace your-apps-package-name with your app’s package name
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod

class CalendarModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {...}

继承 ReactContextBaseJavaModule 类,使 React Native 视为原生模块

# 重写 getName () 定义原生模块名称

// add to CalendarModule.kt  

override fun getName() = "CalendarModule"

# 导出原生方法

通过 @ReactMethod 注解声明 JS 可调用的原生方法

import android.util.Log

@ReactMethod
fun createCalendarEvent(name: String, location: String) {
    Log.d("CalendarModule", "Create event called with name: $name and location: $location")
}

同步方法

  • 在 @ReactMethod 注解中添加配置 isBlockingSynchronousMethod = true
  • 不建议这么做,因为以同步的方式调用方法可能会带来严重的性能损失,并且可能会给你的原生模块引入与线程相关的 bug。
@ReactMethod(isBlockingSynchronousMethod = true)

# 注册模块

  • 创建目录: android/app/src/main/java/com/your-app-name/
  • 目录下创建: MyAppPackage.kt ,实现 ReactPackage 接口
  • 在 createNativeModules() 函数,添加实例化的 CalendarModule 到 NativeModules
package com.your-app-name // replace your-app-name with your app’s name

import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager

class MyAppPackage : ReactPackage {

    override fun createViewManagers(
        reactContext: ReactApplicationContext
    ): MutableList<ViewManager<View, ReactShadowNode<*>>> = mutableListOf()

    override fun createNativeModules(
        reactContext: ReactApplicationContext
    ): MutableList<NativeModule> = listOf(CalendarModule(reactContext)).toMutableList()
}
Note

值得注意的是,这种注册原生模块的方式会在应用启动时主动地初始化所有原生模块,从而增加了应用的启动时间。

上次更新: 2026/08/20, 18:03:47
Taro - 最佳实践
入门

← Taro - 最佳实践 入门→

最近更新
01
入门
08-20
02
Kotlin - 入门
08-12
03
3D打印机箱IO挡板
07-24
更多文章>
Theme by Vdoing | Copyright © 2018-2026 NipGeihou | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式