当前位置: 首页 > news >正文

ReactNative 快速入门手册

1. 项目初始化

1.1. 创建新应用

如果之前安装了全局的 react-native-cli 包,请先将其卸载,以避免潜在的问题:

npm uninstall -g react-native-cli @react-native-community/cli

接下来,使用 React Native Community CLI 来生成一个新的项目。我们将创建一个名为 "MyApp" 的新 React Native 项目:

npx @react-native-community/cli@latest init MyApp

如果你是在现有应用中集成 React Native,或者在项目中安装了 Expo,或者为现有 React Native 项目添加 Android 支持,则不需要此步骤。你也可以使用第三方 CLI来设置 React Native 应用。

在初始化安装阶段,一定不要中断。

如果你在 iOS 上遇到问题,请尝试通过以下步骤重新安装依赖项:

cd ios  # 进入 ios 文件夹
bundle install  # 安装 Bundler
bundle exec pod install  # 安装 CocoaPods 管理的 iOS 依赖

如果你想使用特定的 React Native 版本创建新项目,可以使用 --version 参数:

npx @react-native-community/cli@X.XX.X init MyApp --version X.XX.X

你也可以使用 --template 参数开始使用自定义的 React Native 模板,了解更多信息可以查看文档。

1.2. 启动 Metro

Metro 是 React Native 的 JavaScript 构建工具。要启动 Metro 开发服务器,请在项目文件夹中运行以下命令:

yarn start

注意:如果你熟悉 Web 开发,Metro 类似于 Vite 和 webpack 等打包工具,但专为 React Native 设计。例如,Metro 使用 Babel 将 JSX 等语法转换为可执行的 JavaScript。

1.3. 启动应用程序

让 Metro Bundler 在其自己的终端中运行。然后在你的 React Native 项目文件夹中打开一个新终端,运行以下命令

yarn android

如果一切设置正确,应该很快看到新应用在 Android 模拟器中运行。

这是一种程序的启动方法,你也可以直接通过 Android Studio 来运行。

1.4. 工程化说明

1. 项目结构

创建项目后,我们优化目录结构,如下:

MyApp/
├── android/           # Android 原生代码
├── ios/               # iOS 原生代码
├── node_modules/      # npm 依赖包
├── src/               # 应用源代码
│   ├── components/    # 可复用组件
│   ├── screens/       # 页面组件
│   ├── navigation/    # 路由导航
│   ├── assets/        # 静态资源(图片、字体等)
│   ├── services/      # 网络请求或其他服务
│   └── utils/        # 工具函数
├── App.js            # 应用主入口
├── package.json      # npm 配置文件
├── babel.config.js   # Babel 配置
├── metro.config.js   # Metro bundler 配置
└── index.js          # React Native 入口文件

2. 重要文件与目录

  • android/: 包含 Android 原生代码和配置。你可以在这里修改 Android 特性、添加依赖或处理本地代码。

  • ios/: 包含 iOS 原生代码和配置。可以在这里修改 iOS 特性、添加依赖或处理本地代码。

  • src/: 应用的主要源代码目录。通常推荐将所有应用逻辑和组件放在这里,以便于管理和组织。

    • components/: 存放可复用的 UI 组件,通常是小的、独立的组件。

    • screens/: 应用的各个页面,通常是较大的组件,代表不同的视图或功能模块。

    • navigation/: 处理应用的路由和导航逻辑,通常会使用 @react-navigation/native 等库来管理导航。

  • assets/: 存放图片、字体和其他静态资源。

  • services/: 处理网络请求、API 调用或其他服务逻辑。

  • utils/: 存放通用的工具函数,例如格式化日期、处理字符串等。

  • App.js: 应用的主组件,是应用的入口点,通常在这里设置全局状态或根组件。

  • package.json: 定义项目的依赖和脚本。可以在这里添加或更新项目的 npm 包。

  • babel.config.js: Babel 的配置文件,用于转译 JavaScript 代码。

  • metro.config.js: Metro bundler 的配置文件,可以在这里自定义 bundler 行为,例如资源解析。

  • index.js: React Native 应用的入口文件,通常用于注册主组件并启动应用。

3. 项目配置

  • 依赖管理: 使用 npm 或 yarn 管理项目依赖,可以在 package.json 中查看和添加依赖。

  • 环境配置: 可以根据不同的环境需求在 ios 和 android 文件夹内配置项目设置,例如 API 地址、调试工具等。

  • 样式: 可以使用 StyleSheet 来管理样式,或引入 styled-components 等库进行更灵活的样式管理。

1.5. 关于 Expo 框架

使用 Expo 确实可以简化开发,但是又会多一些学习成本,所以对于初学者来说,我建议不要使用任何框架,而是直接用原生 React-Native 来完成开发,这样对于 React-Native 的学习才能更深入。

Expo 链接:https://github.com/expo

2. 常用组件与 API

2.1. 常用组件

React Native 提供了多种内置组件,方便开发者快速构建用户界面。以下是一些常用组件及其用法。

1. View

用法:View 是 React Native 中最基本的组件,用于构建 UI 的布局。它可以容纳其他组件,并支持样式和事件处理。这个组件可以当做 div 用。

import { View } from 'react-native';const MyComponent = () => {return (<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>{/* 其他组件 */}</View>);
};

2. Text

用法:Text 组件用于显示文本。支持多种文本样式,如字体、颜色、大小等。

import { Text } from 'react-native';const MyText = () => {return (<Text style={{ fontSize: 20, color: 'blue' }}>Hello, React Native!</Text>);
};

3. Image

用法:Image 组件用于显示图片,支持本地图片和网络图片。

import { Image } from 'react-native';const MyImage = () => {return (<Imagesource={{ uri: 'https://example.com/image.png' }}style={{ width: 100, height: 100 }}/>);
};

4. ScrollView

用法:ScrollView 组件用于创建可滚动的视图,适用于内容较多的场景。

import { ScrollView, Text } from 'react-native';const MyScrollView = () => {return (<ScrollView><Text>Item 1</Text><Text>Item 2</Text><Text>Item 3</Text>{/* 更多内容 */}</ScrollView>);
};

5. TextInput

用法:TextInput 组件用于接收用户输入。可以设置占位符、样式等属性。

import { TextInput } from 'react-native';const MyTextInput = () => {return (<TextInputstyle={{ height: 40, borderColor: 'gray', borderWidth: 1 }}placeholder="Type here"/>);
};

6. Button

用法:Button 组件用于创建按钮,支持点击事件。

import { Button } from 'react-native';const MyButton = () => {return (<Buttontitle="Click Me"onPress={() => alert('Button pressed!')}/>);
};

7. FlatList

用法:FlatList 组件用于高效地渲染长列表,支持性能优化。

import { FlatList, Text } from 'react-native';const DATA = [{ id: '1', title: 'Item 1' },{ id: '2', title: 'Item 2' },{ id: '3', title: 'Item 3' },
];const MyFlatList = () => {return (<FlatListdata={DATA}renderItem={({ item }) => <Text>{item.title}</Text>}keyExtractor={item => item.id}/>);
};

8. TouchableOpacity

用法:TouchableOpacity 组件用于实现可点击的元素,支持透明度变化。

import { TouchableOpacity, Text } from 'react-native';const MyTouchable = () => {return (<TouchableOpacity onPress={() => alert('Tapped!')}><Text style={{ fontSize: 20 }}>Tap Me</Text></TouchableOpacity>);
};

9. Modal

用法:Modal 组件用于创建模态窗口,适用于需要用户注意的对话框。

import { Modal, View, Text, Button } from 'react-native';const MyModal = () => {const [modalVisible, setModalVisible] = useState(false);return (<View><Button title="Show Modal" onPress={() => setModalVisible(true)} /><Modaltransparent={true}visible={modalVisible}animationType="slide"><View style={{ marginTop: 50 }}><Text>This is a Modal!</Text><Button title="Hide Modal" onPress={() => setModalVisible(false)} /></View></Modal></View>);
};

10. SafeAreaView

用法:用于给页面给出安全区域的处理

<SafeAreaView style={backgroundStyle}><StatusBar />
</SafeAreaView>

2.2. 样式表

在 React Native 中,样式表的管理和应用非常重要。

React Native 提供了 StyleSheet API,方便开发者创建和管理组件的样式。以下是对 StyleSheet API 的详细介绍,包括主题的实现方案和 StyleSheet 的原理。

1. Stylesheet API

(1). 基本用法

StyleSheet API 允许开发者创建样式对象,使用 CSS 样式的语法来定义样式属性。这些样式对象可以直接应用到组件上,提高了样式的可读性和可维护性。

import { StyleSheet, View, Text } from 'react-native';const styles = StyleSheet.create({container: {flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: '#f5fcff',},text: {fontSize: 20,color: 'blue',},
});const MyComponent = () => {return (<View style={styles.container}><Text style={styles.text}>Hello, React Native!</Text></View>);
};

(2). 性能优化

使用 StyleSheet.create 方法创建样式对象的一个主要好处是性能优化。React Native 会在内部对样式进行优化,避免在每次渲染时重新计算样式,从而提高性能。

2. 主题的实现方案

主题在应用中是一个重要的概念,允许开发者根据不同的环境(如浅色模式和深色模式)或用户偏好动态切换样式。以下是一些实现方案:

(1). 使用 Context API

可以使用 React 的 Context API 来创建主题上下文,允许在应用中轻松访问当前主题。

import React, { createContext, useContext, useState } from 'react';const ThemeContext = createContext();const ThemeProvider = ({ children }) => {const [theme, setTheme] = useState('light'); // 默认主题const toggleTheme = () => {setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));};return (<ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>);
};const useTheme = () => useContext(ThemeContext);

(2). 在组件中使用主题

通过 useTheme Hook 可以在组件中访问和使用当前主题。

const ThemedComponent = () => {const { theme } = useTheme();const styles = StyleSheet.create({container: {flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: theme === 'light' ? '#fff' : '#333',},text: {color: theme === 'light' ? '#000' : '#fff',},});return (<View style={styles.container}><Text style={styles.text}>Current Theme: {theme}</Text></View>);
};

3. Stylesheet 的原理

React Native 的 StyleSheet API 处理样式的过程包括多个步骤,从样式的创建到应用于组件,涉及到性能优化、样式合并和跨平台支持等多个方面。以下是对这一过程的深入分析。

(1). 样式的创建

当你调用 StyleSheet.create 时,React Native 会进行以下操作:

  • 样式对象的定义:你定义的样式对象被存储为一个不可变的对象。这意味着在样式创建后,它的属性不会被修改,从而提高了性能,因为 React Native 不需要在每次渲染时重新计算样式。

  • 映射到原生代码:React Native 将这些样式对象映射到原生代码中。这是通过将 JavaScript 对象转换为原生视图的样式属性来实现的。这种转换使得 React Native 能够与 Android 和 iOS 的原生 UI 组件进行交互。

(2). 样式的存储与优化

在调用 StyleSheet.create 后,样式会被存储在内存中。React Native 维护一个样式表缓存,以避免在每次渲染时重新创建样式。具体过程如下:

  • 缓存机制:样式表在应用中被缓存,React Native 会通过样式的 ID 来引用它们。这种机制确保了样式的快速访问。

  • 样式的优化:在创建样式时,React Native 会分析每个样式的属性,决定哪些属性可以在原生端高效处理,哪些属性需要进行额外的处理。例如,flex、padding、margin 等布局相关属性会被优化为原生布局引擎可以直接使用的形式。

(3). 样式的应用

将样式应用到组件的过程相对复杂,涉及以下步骤:

  • 组件渲染:当一个组件被渲染时,React Native 会检查其属性中的 style 属性。

  • 样式合并:如果组件的 style 属性是一个数组,React Native 会将所有样式合并。合并过程中后面出现的样式会覆盖前面样式的同名属性。可以通过特定的方式将多个样式合并成一个对象,以便进行比较或传递。

const styles = [baseStyle, additionalStyle];
const combinedStyle = StyleSheet.flatten(styles);
  • 应用样式到原生组件:合并后的样式通过桥接(Bridge)机制发送到原生层。React Native 使用 JSON 格式将这些样式传递给原生视图。

(4). 样式的更新与重新渲染

  • 响应式更新:当组件的状态或属性变化时,React 会触发重新渲染。此时,它会重新计算需要应用的样式并根据新的状态合并样式。

  • 原生与 JavaScript 的交互:React Native 通过异步的方式与原生代码进行交互,确保在样式更新时不会阻塞 UI 渲染。样式的变化通过消息传递机制推送到原生层,原生组件会在下一个渲染周期中更新样式。

(5). 跨平台支持

React Native 还提供了平台特定的样式支持。通过 Platform 模块,开发者可以为不同的平台定义特定的样式,这些样式在创建时被单独处理,以确保在 Android 和 iOS 上有最佳的表现。

import { Platform, StyleSheet } from 'react-native';const styles = StyleSheet.create({button: {backgroundColor: Platform.OS === 'ios' ? 'blue' : 'green',padding: 10,},
});

2.3. 路由处理

在 React Native 中,路由处理是应用导航的重要组成部分。

通过使用 @react-navigation 库,可以轻松地创建和管理不同的屏幕和导航结构。以下是对你提供的代码示例的详细讲解。

1. 项目依赖

在 package.json 中,你列出了几个与路由相关的依赖:

"@react-navigation/bottom-tabs": "6.6.1",
"@react-navigation/native": "6.1.18",
"@react-navigation/stack": "6.4.1",
"@react-navigation/native-stack": "6.11.0",
"react-native-screens": "3.35.0",
"react-native-safe-area-context": "4.14.0"
  • @react-navigation/native: 核心导航库,提供基本的导航功能。

  • @react-navigation/bottom-tabs: 用于创建底部标签导航的库。

  • @react-navigation/native-stack: 提供原生堆栈导航的实现,具有更好的性能。

  • react-native-screens: 优化应用性能的库,支持原生屏幕管理。

  • react-native-safe-area-context: 提供安全区域支持,确保在刘海屏或其他特殊屏幕形状下的内容显示正确。

2. 创建底部标签导航

在 src/routers/index.tsx 中,你首先创建了底部标签导航组件:

const TabBar = createBottomTabNavigator();function BottomBar() {return (<TabBar.NavigatorscreenOptions={{headerShown: false,}}><TabBar.Screenname="TabHome"component={HomeScreen}options={{tabBarLabel: '首页',}}/><TabBar.Screenname="TabOther"component={DetailScreen}options={{tabBarLabel: '其他',}}/></TabBar.Navigator>);
}
  • createBottomTabNavigator: 创建底部标签导航器。

  • TabBar.Navigator: 定义底部导航的容器。

  • TabBar.Screen: 定义每个标签页及其对应的组件。

headerShown: false 表示在底部标签导航中不显示头部。

3. 创建堆栈导航

接下来,创建一个堆栈导航组件,用于管理更复杂的导航结构:

const Stack = createNativeStackNavigator();function Navigator() {return (<NavigationContainer><Stack.NavigatorscreenOptions={{headerTitleAlign: 'center',headerBackTitleVisible: false,gestureEnabled: true,gestureDirection: 'horizontal',...Platform.select({android: {headerStatusBarHeight: StatusBar.currentHeight,},}),headerStyle: {backgroundColor: Colors.primary,},}}><Stack.Screen name="BottomBar" component={BottomBar} /><Stack.Screen name="Home" component={HomeScreen} /><Stack.Screen name="Details" component={DetailScreen} /><Stack.Screen name="Topics" component={TopicsScreen} /></Stack.Navigator></NavigationContainer>);
}
  • createNativeStackNavigator: 创建一个原生堆栈导航器。

  • NavigationContainer: 作为导航树的根容器,提供路由上下文。

  • Stack.Navigator: 定义堆栈导航的容器。

  • Stack.Screen: 定义堆栈中的每个屏幕及其对应的组件。

⚙️ 执行 pod 安装依赖:npx pod-install ios,如果不成功可能是网络问题,或者 进到 ios 文件夹,执行 pod install

如果是安装了原生内容,需要 pod 构建,我建议大家用 Xcode 打开。

4. 路由处理过程

  • 导航结构:在此示例中,定义了一个底部标签导航(BottomBar)和多个堆栈屏幕(Home、Details、Topics)。用户可以在底部标签之间切换,同时也可以通过堆栈导航访问详细信息和主题。

  • 屏幕的渲染:当用户切换到某个标签时,BottomBar 中的对应组件会被渲染。在这个底部导航中,HomeScreen 和 DetailScreen 是两个标签页。

  • 堆栈导航:如果在 HomeScreen 中,我们希望导航到 DetailScreen,可以使用 navigation.navigate('Details') 方法来实现。这将把 DetailScreen 推入堆栈中,并自动管理返回操作。

  • 状态管理:在导航中,React Navigation 会自动管理导航状态,例如当前活动的屏幕、参数传递等。每当导航状态变化时,相关的组件会重新渲染以反映新的状态。

5. 主题和样式

在 Navigator 函数中,你还通过 screenOptions 为导航器设置了一些样式和行为选项:

  • headerTitleAlign: 设置头部标题的对齐方式。

  • headerBackTitleVisible: 是否在返回按钮上显示标题。

  • gestureEnabled: 是否启用手势返回功能。

  • headerStyle: 设置头部的样式,例如背景颜色。

2.4. 常用API

1. AsyncStorage

用于本地存储简单数据,以键值对的形式存储。

import AsyncStorage from '@react-native-async-storage/async-storage';/// 存储数据
const storeData = async (value) => {try {await AsyncStorage.setItem('@storage_Key', value);} catch (e) {// 保存错误}
};// 读取数据
const getData = async () => {try {const value = await AsyncStorage.getItem('@storage_Key');if (value !== null) {// 值已存在}} catch (e) {// 读取错误}
};

2. Fetch API

用于进行网络请求,类似于浏览器的 fetch。

const fetchData = async () => {try {let response = await fetch('https://api.example.com/data');let json = await response.json();console.log(json);} catch (error) {console.error(error);}
};

3. Linking

用于处理外部链接,如打开网页或拨打电话。

import { Linking } from 'react-native';// 打开网页
const openURL = async (url) => {const supported = await Linking.canOpenURL(url);if (supported) {await Linking.openURL(url);}
};// 拨打电话
const makeCall = (phoneNumber) => {Linking.openURL(`tel:${phoneNumber}`);
};

4. DeviceInfo

获取设备信息,如型号、系统版本等,需安装 react-native-device-info

import DeviceInfo from 'react-native-device-info';const getDeviceInfo = async () => {const deviceId = await DeviceInfo.getDeviceId();const systemVersion = await DeviceInfo.getSystemVersion();console.log(`Device ID: ${deviceId}, System Version: ${systemVersion}`);
};

5. Permissions

请求和检查设备权限,需安装 react-native-permissions。

import { PermissionsAndroid } from 'react-native';const requestLocationPermission = async () => {try {const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,{title: '位置权限',message: '需要访问您的位置',buttonNeutral: '稍后询问',buttonNegative: '取消',buttonPositive: '确认',});if (granted === PermissionsAndroid.RESULTS.GRANTED) {console.log('您可以使用位置');} else {console.log('位置权限被拒绝');}} catch (err) {console.warn(err);}
};

6. Vibration

控制设备震动。

import { Vibration } from 'react-native';// 震动1000毫秒
const triggerVibration = () => {Vibration.vibrate(1000);
};

7. Share

用于分享内容到其他应用,如社交媒体。

import { Share } from 'react-native';const shareMessage = async () => {try {const result = await Share.share({message: '这是要分享的消息',});if (result.action === Share.sharedAction) {if (result.activityType) {// 共享到特定活动} else {// 仅共享}} else if (result.action === Share.dismissedAction) {// 共享被取消}} catch (error) {alert(error.message);}
};

8. StatusBar

控制状态栏的样式和行为。

import { StatusBar } from 'react-native';// 设置状态栏样式
const setStatusBar = () => {StatusBar.setBarStyle('light-content', true);StatusBar.setBackgroundColor('#000000');
};

3. 多端开发方案

在开发跨平台移动应用时,React Native 提供了一系列工具和策略,以便在 iOS 和 Android 之间实现良好的适配。这一适配思路不仅确保了应用的功能一致性,还能针对不同平台的特性优化用户体验。以下是具体的适配思路和方法:

3.1. 使用 Platform API

React Native 中的 Platform 模块是实现跨平台适配的基础。它提供了对当前平台的识别能力,使开发者能够根据不同平台调整组件的渲染和样式。

常用属性与方法:

  • Platform.OS:返回当前运行的操作系统,可以用于条件渲染。

  • Platform.select():根据当前平台返回适合的值,允许为每个平台定义不同的样式或组件。

import { Platform, StyleSheet } from 'react-native';const styles = StyleSheet.create({container: {flex: 1,...Platform.select({android: { backgroundColor: 'green' },ios: { backgroundColor: 'red' },default: { backgroundColor: 'blue' },}),},
});

这种方式使得代码更具可读性和可维护性,同时减少了条件语句的复杂性。

3.2. 利用 React Native 提供的常量

React Native 还提供了一些平台特定的常量,可以帮助开发者获取设备信息,从而优化适配。例如,使用 PlatformConstants(在最新版本中可能直接通过Platform或其他模块体现,此处为原文本内容)来获取设备的硬件和系统信息,这些信息可用于条件渲染或功能限制。

常用常量:

  • isPad:判断当前设备是否为 iPad。

  • forceTouchAvailable:判断当前设备是否支持 3D Touch(仅限 iOS)。

  • osVersion:获取当前操作系统的版本信息。

import { Platform } from 'react-native';if (Platform.isPad) {// 针对 iPad 的特定逻辑
}

3.3. 适配图片和资源

在处理多端时,图片资源的管理也非常重要。可以根据不同平台选择不同的图片资源,以确保最佳的加载和显示效果。

const imageSource = Platform.select({ios: require('./images/image_ios.png'),android: require('./images/image_android.png'),
});

3.4. 使用第三方库

许多第三方库提供了跨平台支持,使得开发者能够更轻松地实现平台适配。例如,使用 react-native-elements 或 react-native-paper 可以获取一致的 UI 组件,这些组件自动适配不同的平台。

3.5. 性能和体验优化

除了视觉适配外,性能和用户体验也是跨平台开发中不可忽视的部分。

可以根据不同平台的特性,调整动画效果、事件响应等。例如,Android 上的返回按钮行为可能与 iOS 的导航模式有所不同,这需要在逻辑上进行适配。

4. 原生模块开发与接入

你的应用可能需要一些平台功能,但这些功能并不是直接通过 React Native 或社区维护的众多第三方库提供的。你可能想要复用一些现有的 Objective-C、Swift、Java、Kotlin 或 C++ 代码。React Native 提供了一套强大的 API,帮助你将原生代码与 JavaScript 应用代码连接起来。

原生内容分为两部分:

  • 原生模块:没有用户界面的原生库,比如持久存储、通知、网络事件等。这些功能可以作为 JavaScript 函数和对象供用户使用。

  • 原生组件:可以通过 React 组件在你的应用的 JavaScript 代码中使用的原生视图、小部件和控制器。

在过往的开发中,我们统一使用 NativeModules,但是新的架构下,React-Native 抽象出了两个新概念用于使用与新架构下的原生模块与原生组件,分别为:

  • Turbo Native Module

  • Fabric Native Components

NativeModules 是已弃用的原生模块和组件 API。尽管如此,由于我们的互操作层,你仍然可以在新架构下使用很多旧版库。你可以考虑:

  • 使用替代库;

  • 升级到对新架构支持更好的新版本库;

  • 将这些库自己移植为 Turbo 原生模块或 Fabric 原生组件。

原生组件的开发与接入请点击此处查看参考文档,本文中介绍原生模块的开发与接入。

4.1. 原生模块开发与接入 (iOS)

我们来实现 Web Storage API 的 localStorage。

为了让它在移动端工作,我们需要使用 Android 和 iOS 的 API:

  • Android: SharedPreferences

  • iOS: NSUserDefaults

1. 声明类型规范

React Native 提供了一个名为 Codegen 的工具,可以根据用 TypeScript 或 Flow 编写的规范生成适用于 Android 和 iOS 的平台特定代码。这个规范声明了在你的原生代码与 React Native JavaScript 运行时之间传递的方法和数据类型。Turbo 原生模块既是你的规范,也是你编写的原生代码,以及从规范生成的 Codegen 接口。

创建一个规范文件:在应用根目录下创建一个名为 specs 的新文件夹,文件夹里创建一个名为 NativeLocalStorage.ts 的新文件。

以下是 localStorage 规范的实现:

// 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') as Spec;

2. 配置 Codegen 运行

React Native Codegen 工具会根据规范生成平台特定的接口和样板代码。为此,Codegen 需要知道在哪里找到我们的规范以及该如何处理它。更新你的 package.json,如下:

{"scripts": {"start": "react-native start","test": "jest"},"codegenConfig": {"name": "NativeLocalStorageSpec","type": "modules","jsSrcsDir": "specs","android": {"javaPackageName": "com.nativelocalstorage"}},"dependencies": {...}
}

在将所有内容连接到 Codegen 后,我们需要准备我们的原生代码。

CocoaPods 生成的项目中,通过脚本自动运行 Codegen。

cd ios
bundle install
bundle exec pod install

输出内容大致如下:

...
Framework build type is static library
[Codegen] Adding script_phases to ReactCodegen.
[Codegen] Generating ./build/generated/ios/ReactCodegen.podspec.json
[Codegen] Analyzing /Users/me/src/TurboModuleExample/package.json
[Codegen] Searching for codegen-enabled libraries in the app.
[Codegen] Found TurboModuleExample
[Codegen] Searching for codegen-enabled libraries in the project dependencies.
[Codegen] Found react-native
...

3. 使用 Turbo 原生模块编写应用代码

使用 NativeLocalStorage,以下是修改后的 App.tsx,它包含了一些我们希望持久化的文本、一个输入字段和一些按钮来更新该值。

TurboModuleRegistry 支持两种获取 Turbo 原生模块的方式:

  • get<T>(name: string): T | null:如果 Turbo 原生模块不可用,则返回 null。

  • getEnforcing<T>(name: string): T:如果 Turbo 原生模块不可用,则抛出异常。假定该模块始终可用。

// App.tsx
import React from 'react';
import {SafeAreaView,StyleSheet,Text,TextInput,Button,
} from 'react-native';import NativeLocalStorage from './specs/NativeLocalStorage';const EMPTY = '<empty>';function App(): React.JSX.Element {const [value, setValue] = React.useState<string | null>(null);const [editingValue, setEditingValue] = React.useState<string | null>(null);React.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(editingValue ?? EMPTY);setValue('');}return (<SafeAreaView style={{flex: 1}}><Text style={styles.text}>当前存储的值是:{value ?? '无值'}</Text><TextInputplaceholder="请输入要存储的文本"style={styles.textInput}onChangeText={setEditingValue}/><Button title="保存" onPress={saveValue} /><Button title="删除" onPress={deleteValue} /><Button title="清空" 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;

4. 编写原生平台代码

准备好后,我们将开始编写原生平台代码。这个过程分为两个部分:

注意:本指南展示的是如何创建一个仅适用于新架构的 Turbo 原生模块。如果你需要同时支持新架构和旧架构,请参阅我们的向后兼容性指南。

现在我们开始编写 iOS 平台代码,确保 localStorage 在应用关闭后仍然可用。

第一步:准备Xcode项目。

我们需要使用 Xcode 准备 iOS 项目。完成以下六个步骤后,你将拥有实现生成的 NativeLocalStorageSpec 接口的 RCTNativeLocalStorage。

(1). 打开 CocoaPods 生成的 Xcode 工作区。

cd ios
open TurboModuleExample.xcworkspace

如下图所示:

(2). 在 Xcode 工作区中,右键点击 app 目录,选择“新建组”,将新组命名为NativeLocalStorage。

(3). 在 NativeLocalStorage组中,选择“新建=>从模板创建文件”。

(4). 使用 Cocoa Touch Class 模板创建新文件。

(5). 将 Cocoa Touch Class 命名为 RCTNativeLocalStorage,并选择 Objective-C 语言。

(6). 将 RCTNativeLocalStorage.m重命名为 RCTNativeLocalStorage.mm,使其成为一个 Objective-C++ 文件。

第二步:实现 localStorage,使用 NSUserDefaults。

首先更新 RCTNativeLocalStorage.h:

// NativeLocalStorage/RCTNativeLocalStorage.h
#import <Foundation/Foundation.h>
#import <NativeLocalStorageSpec/NativeLocalStorageSpec.h>NS_ASSUME_NONNULL_BEGIN@interface RCTNativeLocalStorage : NSObject <NativeLocalStorageSpec>@endNS_ASSUME_NONNULL_END

然后更新我们的实现,使用带有自定义套件名称的 NSUserDefaults:

// NativeLocalStorage/RCTNativeLocalStorage.mm
#import "RCTNativeLocalStorage.h"static NSString *const RCTNativeLocalStorageKey = @"local-storage";@interface RCTNativeLocalStorage()
@property (strong, nonatomic) NSUserDefaults *localStorage;
@end@implementation RCTNativeLocalStorageRCT_EXPORT_MODULE(NativeLocalStorage)- (id)init {if (self = [super init]) {_localStorage = [[NSUserDefaults alloc] initWithSuiteName:RCTNativeLocalStorageKey];}return self;
}- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {return std::make_shared<facebook::react::NativeLocalStorageSpecJSI>(params);
}- (NSString * _Nullable)getItem:(NSString *)key {return [self.localStorage stringForKey:key];
}- (void)setItem:(NSString *)value key:(NSString *)key {[self.localStorage setObject:value forKey:key];
}- (void)removeItem:(NSString *)key {[self.localStorage removeObjectForKey:key];
}- (void)clear {NSDictionary *keys = [self.localStorage dictionaryRepresentation];for (NSString *key in keys) {[self removeItem:key];}
}@end

重要事项:RCT_EXPORT_MODULE 导出并注册模块,使用我们在 JavaScript 环境中访问它的标识符:NativeLocalStorage。更多详细信息请查看相关文档。

你可以使用 Xcode 跳转到 Codegen 的 @protocol NativeLocalStorageSpec,也可以用 Xcode 生成存根。

在模拟器上构建并运行代码:

yarn run ios

4.2. 原生模块开发与接入(Android)

React-Native 层的开发与 iOS 一致,我们从 Android 平台开发展开。

以下是针对 Android 部分的完整实现和优化:

现在,我们来实现 Android 平台代码,以确保 localStorage 在应用关闭后能够持久保存。

首先,实施生成的 NativeLocalStorageSpec 接口:

android/app/src/main/java/com/nativelocalstorage/NativeLocalStorageModule.java

package com.nativelocalstorage;import android.content.Context;
import android.content.SharedPreferences;
import com.nativelocalstorage.NativeLocalStorageSpec;
import com.facebook.react.bridge.ReactApplicationContext;public class NativeLocalStorageModule extends NativeLocalStorageSpec {private static final String NAME = "NativeLocalStorage";public NativeLocalStorageModule(ReactApplicationContext reactContext) {super(reactContext);}@Overridepublic String getName() {return NAME;}@Overridepublic void setItem(String value, String key) {SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);SharedPreferences.Editor editor = sharedPref.edit();editor.putString(key, value);editor.apply();}@Overridepublic String getItem(String key) {SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);return sharedPref.getString(key, null);}@Overridepublic void removeItem(String key) {SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);sharedPref.edit().remove(key).apply();}@Overridepublic void clear() {SharedPreferences sharedPref = getReactApplicationContext().getSharedPreferences("my_prefs", Context.MODE_PRIVATE);sharedPref.edit().clear().apply();}
}

接下来,我们需要创建 NativeLocalStoragePackage,它将该模块注册到 React Native 运行时中,并将其包装为 Turbo Native Package:

android/app/src/main/java/com/nativelocalstorage/NativeLocalStoragePackage.java

package com.nativelocalstorage;import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;import java.util.HashMap;
import java.util.Map;public class NativeLocalStoragePackage extends TurboReactPackage {@Overridepublic NativeModule getModule(String name, ReactApplicationContext reactContext) {if (name.equals(NativeLocalStorageModule.NAME)) {return new NativeLocalStorageModule(reactContext);} else {return null;}}@Overridepublic ReactModuleInfoProvider getReactModuleInfoProvider() {return new ReactModuleInfoProvider() {@Overridepublic Map<String, ReactModuleInfo> get() {Map<String, ReactModuleInfo> map = new HashMap<>();map.put(NativeLocalStorageModule.NAME, new ReactModuleInfo(NativeLocalStorageModule.NAME,         // nameNativeLocalStorageModule.NAME,         // classNamefalse,                                 // canOverrideExistingModulefalse,                                 // needsEagerInitfalse,                                 // isCXXModuletrue                                   // isTurboModule));return map;}};}
}

最后,我们需要在主应用中告诉 React Native 如何找到这个包,这称为在 React Native 中“注册”该包。

将其添加到 getPackages 方法中返回的列表中:

android/app/src/main/java/com/turbomoduleexample/MainApplication.java

package com.turbomoduleexample;import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactHost;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactHost;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import com.nativelocalstorage.NativeLocalStoragePackage;import java.util.ArrayList;
import java.util.List;public class MainApplication extends Application implements ReactApplication {private final ReactNativeHost reactNativeHost = new DefaultReactNativeHost(this) {@Overridepublic List<ReactPackage> getPackages() {List<ReactPackage> packages = new PackageList(this).getPackages();packages.add(new NativeLocalStoragePackage());return packages;}@Overridepublic String getJSMainModuleName() {return "index";}@Overridepublic boolean getUseDeveloperSupport() {return BuildConfig.DEBUG;}@Overridepublic boolean isNewArchEnabled() {return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;}@Overridepublic boolean isHermesEnabled() {return BuildConfig.IS_HERMES_ENABLED;}};@Overridepublic ReactHost getReactHost() {return DefaultReactHost.getDefaultReactHost(getApplicationContext(), reactNativeHost);}@Overridepublic void onCreate() {super.onCreate();SoLoader.init(this, false);if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {DefaultNewArchitectureEntryPoint.load();}}
}

现在,你可以在模拟器上构建并运行代码:

yarn run android

5. 应用构建发布

在构建和发布 React Native 应用时,主要涉及到 iOS 和 Android 两个平台的特定配置和步骤。

以下是详细的内容,包括应用信息配置、图标配置、打包和发布的过程。

5.1. 应用信息配置

1. iOS 配置

  • 项目设置:打开 Xcode,选择你的项目文件(.xcworkspace),在“General”选项卡中配置应用名称、版本、构建号和 Bundle Identifier。

  • info.plist: 修改 Info.plist文件,添加应用的描述、权限说明等。
<key>CFBundleDisplayName</key>
<string>MyApp</string>
<key>CFBundleIdentifier</key>
<string>com.example.myapp</string>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
  • 启动页:配置 ios 项目下的 LaunchScreen。

2. Android 配置

  • AndroidManifest.xml: 在 android/app/src/main/AndroidManifest.xml 中配置应用信息,如应用名称、图标、权限等。
<applicationandroid:name=".MainApplication"android:label="MyApp"android:icon="@mipmap/ic_launcher">...
</application>
  • build.gradle: 在 android/app/build.gradle 文件中设置应用的版本和包名。
android {...defaultConfig {applicationId "com.example.myapp"versionCode 1versionName "1.0"}
}

5.2. 图标配置

图标的生成,可以使用 https://www.appicon.co/ 一键生成。

1. iOS 图标

  • 图标资源:在 Xcode 的 Assets.xcassets 中,添加应用图标。确保按照 Apple 的图标规格提供不同尺寸的图标。

2. Android 图标

  • 图标资源:在 android/app/src/main/res 目录下的各个 mipmap 文件夹中(如 mipmap-mdpi,mipmap-hdpi 等)放置不同尺寸的应用图标。

5.3. 打包

1. iOS 打包

  • 使用 Xcode: 在 Xcode 中选择 Product > Archive 进行打包。

  • 导出: 打包完成后,会打开 Archives 窗口,选择最新的构建,点击 "Distribute App",根据提示选择导出方式(App Store、Ad Hoc 等)。

2. Android 打包

  • 命令行打包: 在项目根目录下,运行以下命令生成 APK。
cd android
./gradlew assembleRelease
  • APK 文件: 打包完成后,APK 文件将位于 android/app/build/outputs/apk/release 目录中。

5.4. 发布

1. iOS 发布

  • App Store Connect: 登录 App Store Connect,创建一个新的应用条目,并填写必要的信息。

  • 上传应用: 使用 Xcode 或者 Transporter 将生成的 .ipa 文件上传到 App Store Connect。

  • 审核: 提交审核,等待 Apple 的审核通过。

2. Android 发布

  • Google Play Console: 登录 Google Play Console,创建一个新的应用。

  • 上传 APK: 在“版本”部分上传生成的 APK 文件,填写应用的描述、图标、截图等信息。

  • 发布: 提交应用,等待 Google 的审核通过。

6. 补充资料

  • React-Native 官方文档:https://reactnative.dev/docs/getting-started

  • React-Native 导航库:https://reactnavigation.org/docs/getting-started

  • React-Native 样式表:https://reactnative.dev/docs/stylesheet

  • Material Design UI 库:https://callstack.github.io/react-native-paper/

  • 基于 Tailwind 的 UI 库:https://gluestack.io/

  • 小清新 UI 库:https://tamagui.dev/

  • 构建分发平台:https://www.pgyer.com/

  • 苹果发布:https://appstoreconnect.apple.com/

  • 老架构下的原生模块开发与集成:https://reactnative.dev/docs/legacy/native-modules-intro

  • 新架构下的原生模块开发与集成:https://reactnative.dev/docs/turbo-native-modules-introduction

  • Turbo Native Module 架构:https://github.com/reactwg/react-native-new-architecture/blob/main/docs/turbo-modules.md

  • Fabric Native Components 架构:https://github.com/reactwg/react-native-new-architecture/blob/main/docs/fabric-native-components.md

  • React-Native 新架构:https://reactnative.dev/architecture/landing-page

  • 优化 js 引擎:https://github.com/facebook/hermes

http://www.dtcms.com/a/572612.html

相关文章:

  • 【C++:map和set的使用】C++ map/multimap完全指南:从红黑树原理入门到高频算法实战
  • GPT-OSS大模型Attention架构设计
  • 基于Mask R-CNN和TensorRT的高效草莓实例分割
  • RV1126 NO.38:OPENCV查找图形轮廓重要API讲解
  • 腾讯WAIC发布“1+3+N”AI全景图:混元3D世界模型开源,具身智能平台Tairos亮相
  • 各种开源闭源大模型,包括自己本地部署的一些8b 14b模型,支持函数调用(功能调用)function call吗?
  • Spring Boot 深度剖析:从虚拟线程到声明式 HTTP 客户端,再到云原生最优解
  • 创新的商城网站建设网站页面怎么设计
  • 2016年网站建设总结php网站开发工资多少
  • 线程3.1
  • Kubernetes基础概念和命令
  • 技术干货-MYSQL数据类型详解
  • 备份工具:rsync、Tar、Borg、Veeam 备份与恢复方案
  • 深入 Pinia 工作原理:响应式核心、持久化机制与缓存策略
  • 【前端】动态插入并渲染大量数据的方法-时间分片:使用requestAnimationFrame+DocumentFragment
  • 耶鲁大学Hello Robot研究解读:人类反馈策略的多样性与有效性
  • Unity摄像机鼠标右键旋转功能
  • Spring AI Alibaba文生图实战:从零开始编写AI图片生成Demo
  • 文本编辑器做网站国外设计师
  • 网站多久电子信息工程就业方向
  • 大连网站seo顾问企业开发网站公司
  • 南京网站设计搭建公司网站怎么做rss
  • 外包做网站谷歌seo优化
  • 博物馆网站 建设方案外贸短视频营销
  • 网站如何在360做提交微信开发公司怎么样
  • 广州微网站建设信息设计图案大全
  • 苏州吴中区专业做网站郑州哪里可以做网站
  • cms网站开发毕设简述网站建设的方法
  • 怎样建立网站挣钱网站建设功能选择表
  • 郑州加盟做网站开源程序网站