深入研究React Native以进行Android开发

本文概述

  • HERE
  • 创建一个新项目
  • 为/ r / pics创建搜索应用
  • React Native很棒!
几年前, 我的一个同事告诉我有关React Native的信息。我非常怀疑。我认为这只是另一个跨平台的框架, 在现实生活中永远无法使用-我几乎不知道自己是多么的错误。
多年过去了, React Native技能变得非常需求。既然有一段时间我学到了一些新知识, 所以我想为什么不试一试呢?今天, 我是React Native的拥护者。
缺点:
  • 你不能再使用Android Studio
  • 并非所有应用程序或功能都可以使用React Native
  • React Native是一个新颖的框架, 更新可能会对你当前的代码库产生负面影响
  • JavaScript不是严格类型的语言
  • React Native需要运行JavaScript引擎, 这可能使其性能降低
优点:
  • 简单易学
  • Android和iOS应用程序之间的共享代码库, 仅需细微调整即可匹配平台体验
  • 实时和热加载, 意味着不再需要无限的构建时间
  • 两个平台的本机组件
  • 不断完善
  • 积极发展的社区
  • 大量的图书馆
  • 博览会消除了拥有Mac进行iOS开发的需要
  • 减少人力资源—尽管你可能仍需要进行一些Android / iOS本机开发, 但这种情况很少见。
我可以继续下去, 但让我们在这里停止, 继续本博客文章的主题。在这篇文章中, 我将创建四个基于React Native的Android应用程序:
  1. 基本的计数器, 带有用于递增和递减计数器的按钮
  2. 搜寻r / pics subreddit的应用程式
  3. 通用登录页面
  4. 浏览r / pics subreddit的应用程序
HERE 如上所述, 我们无法将Android Studio用于React Native开发。我们需要替代品。 React Native可以使用任何可用的现代文本编辑器(Atom, VS Code, Sublime Text, Brackets等)进行开发, 但是由于我们具有Android Studio体验, 因此我最喜欢的是由同一家公司构建的WebStorm。尽管WebStorm是付费应用程序(每年129 $), 但是你可以安装它的Early Access版本。 WebStorm的EAP构建是免费的并且相当稳定。如果你喜欢完全免费的编辑器, 请使用VS Code。微软甚至为此开发了惊人的React Native插件, 并且效果很好。
创建一个新项目 先决条件:你的计算机上安装了Android SDK, Node和React Native。
有两种创建新的React Native项目的方法。
  1. 常规方式。使用WebStorm GUI或使用终端命令:react-native init AwesomesrcminiProject
  2. 简便的” 创建React Native应用程序” 。 create-react-native-app AwesomesrcminiProject
如果你使用create-react-native-app, 则将使用expo自举创建的项目。我不会详细介绍, 但是基本上, 这意味着你无需安装Xcode即可在iOS上运行该应用。通过expo.io的功能和其他一些功能, 使客户端始终保持最新状态也更加容易。但是你不能添加本机代码。因此, 如果你要开发特定功能, 则可能需要从expo中退出应用程序, 而要使用常规的React Native项目。
我将使用第一种方法。
让我们运行项目。首先, 打开仿真器或连接设备。如果使用WebStorm GUI创建了项目, 则只需选择一个配置即可。在WebStorm的右上角, 单击” 运行” 按钮左侧的下拉菜单, 选择” Android” , 然后单击” 运行或调试” 。如果使用Terminal创建了项目, 则可以添加新的React Native配置或使用Terminal运行它:
cd AwesomesrcminiProject react-native run-android

如果一切顺利, 将会看到以下屏幕:
深入研究React Native以进行Android开发

文章图片
结构和基本设置
项目内值得注意的项目是:
  • android-预先配置有React Native支持的Android Studio项目。
  • ios-Xcode项目已预先配置有React Native支持。
  • node_modules-包含React Native框架和其他Javascript库的文件夹。
  • index.js-我们的应用程序的入口点。
  • App.js-已加载初始组件。
让我们在项目根目录内创建一个文件夹” src” , 然后将App.js移到该文件夹??中。你必须更新index.js导入以匹配新的App.js位置。
import App from './src/App';

删除App.js中的所有内容并粘贴以下代码:
import React from 'react'; import {Text} from 'react-native'; export default class App extends React.Component { render() { return ( < Text> Hello srcmini< /Text> ); } }

我们粘贴的代码非常简单。我们创建了一个类App(React.Component的子类), 该类重写render()方法并返回Text组件。 React.Component是使用JSX构建UI的基类。 export default修饰符使该类公开。
现在, 我们准备开始设计布局。
使用Flexbox进行布局
Flexbox与LinearLayout相似, 但是Flexbox远远超出了LinearLayout的功能。
此JSX片段:
< View style={{ flex: 1, flexDirection: 'row' }}> < View style={{ width: 100, height: 100, backgroundColor: '#9575CD' }}/> < View style={{ width: 100, height: 100, backgroundColor: '#7E57C2' }}/> < View style={{ width: 100, height: 100, backgroundColor: '#673AB7' }}/> < /View>

渲染此布局:
深入研究React Native以进行Android开发

文章图片
而此XML:
< LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> < /LinearLayout>

呈现此:
深入研究React Native以进行Android开发

文章图片
JSX代码看起来很熟悉, 是吗?让我们使用在JSX和Android XML中看起来相似的布局为布局创建一个” 字典” (或备忘单)。
请注意, 功能不一定相等。我正在尝试帮助React Native新手掌握React Native中布局系统的思想。请参阅官方指南以获取详细信息。
考虑以下JSX属性:
flex: 1

等效于:
android:layout_width="match_parent" android:layout_height="match_parent"

此JSX片段:
< View style={{flex: 1, flexDirection: 'row'}}> < View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> < /View>

而这个XML:
< LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> < /LinearLayout>

两者都生成此输出:
深入研究React Native以进行Android开发

文章图片
同样, 此JSX:
< View style={{flex: 1, flexDirection: 'column'}}> < View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> < /View>

而这个XML:
< LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> < /LinearLayout>

产生这个:
深入研究React Native以进行Android开发

文章图片
为了在容器内获得正确的位置, 我们通常会结合使用flexDirection, alignItems和justifyContent属性。
此JSX:
< View style={{flex: 1, flexDirection: 'column', alignItems: 'center'}}> < View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> < /View>

而这个XML:
< LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical"> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> < /LinearLayout>

将产生以下布局:
深入研究React Native以进行Android开发

文章图片
此JSX:
< View style={{flex: 1, flexDirection: 'column', justifyContent: 'center'}}> < View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> < /View>

而这个XML
< LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="vertical"> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> < /LinearLayout>

将产生以下布局:
深入研究React Native以进行Android开发

文章图片
此JSX:
< View style={{flex: 1, flexDirection: 'row', justifyContent: 'center'}}> < View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> < /View>

而这个XML:
< LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="horizontal"> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> < /LinearLayout>

将产生以下布局:
深入研究React Native以进行Android开发

文章图片
此JSX:
< View style={{flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center'}}> < View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> < View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> < /View>

和这个XML:
< LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> < View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> < /LinearLayout>

将产生以下布局:
深入研究React Native以进行Android开发

文章图片
经验教训:如果我们有flexDirection:row’ , 则alignItems在Y轴上起作用, justifyContent在X轴上起作用。一切都针对flexDirection:” 列” 进行了镜像-justifyContent影响Y轴, alignItems影响Y轴。
justifyContent:” 灵活启动” 重力=” 开始|左”
alignItems:” 弹性启动” 重力=” 开始|左”
justifyContent:” flex-end” 重力=” 结束|右”
alignItems:’ flex-end’ 重力=” 结束|右”
自己尝试。将justifyContent值设置为” 周围” , “ 之间” 和” 均匀” 。
国家管理
为了更新应用程序状态, 你将使用React的状态变量。每当状态更新时, 都会调用render()。
将以下代码复制到你的应用中:
import React from 'react'; import {Button, Text, View} from 'react-native'; export default class App extends React.Component { /* Initialize state object with variable 'number' set to 0 and variable name with value of empty string */ state = {number: 0}; render() { return ( < View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', flex: 1, padding: 20 }}> < Button title='Decrement' color='#e57373' onPress={() => this.decrement()}/> < Text> {/* Text will be automatically updated whenever state.number has changed value */} Value = http://www.srcmini.com/{this.state.number} < /Text> < Button title='Increment' color='#64B5F6' {/* Set listener for click */} onPress={() => this.increment()}/> < /View> ); } //Declaration of decrement function decrement() { //To update the state we need invoke this.setState //with new value for variable 'number' this.setState({number: this.state.number - 1}); } increment() { this.setState({number: this.state.number + 1}); } }

深入研究React Native以进行Android开发

文章图片
如果你点击DECREMENT和INCREMENT按钮, 则会看到该文本会自动为你更新。无需显式使用textView.setText(” Value” +数字)。
状态功能之所以派上用场, 有多种原因:
  • 轻松获取值-你始终知道在何处以及如何获取特定变量的值。
  • 数据未绑定到特定的小部件。
  • 具有多个依赖于公共值更改的小部件。
为/ r / pics创建搜索应用 现在, 我们已经掌握了基本知识, 让我们创建一些更复杂的东西:/ r / pics的搜索应用程序。 Reddit提供了一个简单明了的JSON API端点, 因此我们无需再进行其他工作即可获得身份验证以使其正常工作。
React Native提供了一个内置的Fetch API。由于我们大多数人可能都习惯于翻新及其易用性, 因此我们将使用axios。你可以通过终端命令安装axios
使用纱线(我的首选方法):
纱线添加轴
或使用npm:
npm安装axios
进口:
import React from 'react'; import { TextInput, View, Text, Image, ActivityIndicator, Platform, StyleSheet } from 'react-native'; import axios from 'axios'; TextInput = EditText, ActivityIndicator = ProgressBar Platform - Platform detecting module StyleSheet - Module for creating stylesheets and moving them away from JSX

创建类:
export default class App extends React.Component { }

初始化状态。我们需要:
  • loading-用于显示进度条。
  • 错误-显示在发出REST API请求时是否产生一些错误。
  • imgUrl-预览搜索到的图像。
  • 文字-搜索查询。
state = {text: '', loading: false, error: null, imgUrl: null};

添加JSX代码。我们具有TextInput和Image组件的垂直布局。
render() { return ( //Predefined style. See below < View style={styles.containerStyle}> {/* returnKeyType ~ imeOptions onSubmitEditing ~ et.OnEditorActionListener */} < TextInput style={styles.textInputStyle} placeholder="Enter text to search an image" returnKeyType='search' autoFocus={true} onChangeText={(text) => this.setState({text})} onSubmitEditing={() => this.searchPicture()}/> {/* Render error Image component if this.state.imgUrl is not equal to null */} { this.state.imgUrl & & < Image source={{uri: this.state.imgUrl}} style={{flex: 1}}/> } < /View> ); }

新的东西:
onChangeText={(text) => this.setState({text})} onSubmitEditing={() => this.searchPicture()} { this.state.imgUrl & & < Image source={{uri: this.state.imgUrl}} style={{flex: 1}}/> }

第一种方法与使用TextWatcher组件的EditText做类似的工作。老实说, React Native更好。
触发searchPicture()后, 在键盘上按下返回键(et.OnEditorActionListener)时, 将调用第二种方法。
当imgUrl不为null或未定义时, 将渲染Image, 因为” & & ” 运算符不会检查第二个参数(如果第一个参数已为false)。
你可能想知道为什么this.state.imgUrl为假。好吧, 当在JavaScript中使用逻辑运算符时, 除了‘’(一个空字符串), 0, false, null或undefined以外的其他都是真。无需进行特定检查。
searchPicture() { //Default state this.setState({loading: true, error: null, imgUrl: null}); axios.get('https://www.reddit.com/r/pics/search.json', { params: { //the get param map restrict_sr: 'on', //search only /r/pics limit: 1, //limit to one search item sort: 'new', //sort by creation date q: this.state.text //our search query } }).then(response => { //promise is resolved and 'then' block is triggered //set state with new values this.setState({ imgUrl: response.data.data.children[0] .data.preview.images[0].source.url, error: null, loading: false }) }).catch(error => {//Some error occurred //set error this.setState({error: error.message, loading: false, imgUrl: null}) }) }

开始了。该应用程序现在应该可以正常工作了。输入搜索字符串, 然后按回车键。
深入研究React Native以进行Android开发

文章图片
由于我们的应用程序也已经准备好呈现ActivityIndi??cator和错误, 因此我们需要在Image组件之后添加一些代码:
{ //Separate method this.renderProgress() } {/* Render error Text component if this.state.error is not equal to null */} { this.state.error & & < Text style={{margin: 16, color: 'red'}}> {this.state.error} < /Text> }

你也可以将渲染组件移到主要render()方法之外:
renderProgress() { //If this.state.loading is true //return View containing a progressbar //View takes style array if (this.state.loading === true) { return ( < View style={ [styles.containerStyle, {justifyContent: 'center'}]}> < ActivityIndicator color='#e57373'/> < /View> ); } }

剩下的就是样式。将它们放在App类之外。
const styles = StyleSheet.create({ containerStyle: { flexDirection: 'column', flex: 1, //Since React Native is cross platform //let's handle both platforms. //Add top margin to fix status bar overlap marginTop: Platform.OS === 'ios' ? 20 : 0, }, textInputStyle: { marginLeft: 16, marginRight: 16, height: Platform.OS === 'ios' ? 30 : undefined } });

现在, 我们可以添加一些其他调整, 例如在启动应用程序时自动打开软键盘。
请注意, 有一种更简单的方法可以使TextInput自动聚焦(autoFocus = {true}道具), 但是就本示例而言, 我们将不再使用它。
用prop添加对TextInput的引用:
ref = {ref => this.searchInput = ref}
并重写componentDidMount()生命周期方法, 如下所示:
componentDidMount(){ this.searchInput.focus(); }

重新加载应用程序, 键盘会自动为我们打开。
组件生命周期方法
我们已经创建了一个组件, 但是让我们来回顾一下组件的整个生命周期。
这是React的生命周期流程:
  • constructor()-构造函数总是在应用程序启动时被调用
  • 静态_getDerivedStateFromProps_(属性, 状态)-在渲染之前和更新之后调用。返回用于更新状态的对象。返回null不更新任何内容。
  • render()-每个React Component类都需要渲染。用于渲染视图。
  • componentDidMount()-在呈现组件并将其安装到视图树后调用。
  • shouldComponentUpdate(nextProps, nextState)-状态或道具更改后调用。每次状态更新后, 返回值默认为true。如果返回true, 则调用render()。
  • getSnapshotBeforeUpdate(prevProps, prevState)-在提交呈现输出之前调用。
  • componentDidUpdate(prevProps, prevState, 快照)-呈现新更新后调用。在第一个render()之后不会调用它。
  • componentWillUnmount()-在组件卸载和销毁之前调用。
深入研究React Native以进行Android开发

文章图片
可重复使用的组件
在项目上工作时, 我们经常需要创建可重用的组件。有两种创建组件的方法:
  1. 创建一个扩展React.Component的类。如果需要生命周期方法, 则应使用此方法。
  2. 通过编写返回View的函数以简化语法。
由于我们已经创建了Component类, 因此可以为此实例创建一个函数。
假设我们需要一个< CardView> 的类似物。在./src目录下创建一个” 公用” 文件夹。
创建CardView.js。
import React from "react"; import {View} from "react-native"; export default CardView = (props) => { return ( //Style will be merged from default containerStyle //and props.style. props.style attributes will override //values if parameters are same. < View style={{...styles.containerStyle, ...props.style}}> {/* props.children contain subviews add this line if the component is container */} {props.children} < /View> ); }; const styles = { containerStyle: { borderRadius: 4, margin: 5, padding: 5, elevation: 5, shadowColor: 'black', shadowRadius: 5, shadowOpacity: 0.5, shadowOffset: {width: 0, height: 3}, backgroundColor: 'white' } };

使用我们新的CardView布局的LoginForm:
import React from "react"; import {TextInput, Platform, Button, StyleSheet} from "react-native"; import CardView from "../common/components/CardView"; export default class LoginForm extends React._Component _{ render() { return ( //Override default style < CardView style={{ borderRadius: 4, backgroundColor: '#fff' }}> < TextInput placeholder="Email" style={styles.textInputStyle}/> < TextInput placeholder="Password" style={styles.textInputStyle} secureTextEntry={true}/> < Button color="#841584" title="Login" onPress={() => console.log("onLoginPress")} buttonStyle={styles.buttonStyle}/> < /CardView> ); } } const styles = StyleSheet.create({ buttonStyle: { elevation: 5, height: 40 }, textInputStyle: { padding: 10, //Additional params to make //iOS inputs prettier ...Platform.select({ ios: { borderRadius: 2, marginTop: 5, backgroundColor: '#eeeeee' } }) } });

将LoginForm类导入App类中, 并用View包装
< View style={{flex: 1, justifyContent: 'center'}}> < LoginForm/> < /View>

如果你调整样式中的参数, 则可以获得更好的东西。
深入研究React Native以进行Android开发

文章图片
导航
导航到不同的场景是大多数应用程序中必不可少的部分。我们将创建一个Reddit / r / pics浏览器应用。
在React Native中创建导航非常容易。
先决条件
  • 使用yarn或npm安装反应导航
  • 用yarn或npm安装axios
首先创建两个不同的组件。
注意:你应该已经熟悉下面的大多数代码。我将全班粘贴。
PictureList.js:
import React from 'react'; import { ActivityIndicator, FlatList, Image, Text, TouchableHighlight, View } from "react-native"; import axios from "axios"; import CardView from "../common/CardView"; export default class PictureList extends React.Component { state = {loading: true, error: null, posts: null}; componentDidMount() { axios.get('https://www.reddit.com/r/pics.json') .then(response => { this.setState({ posts: response.data.data.children, loading: false }) }).catch(error => { this.setState({ error: error.message, loading: false }) }) } render() { return ( < View style={{flex: 1, justifyContent: 'center'}}> // FlatList ~ ListView // data - DataSource for the List // renderItem - function returns View item // keyExtractor - Unique id for items{this.state.posts & & < FlatList data=http://www.srcmini.com/{this.state.posts} renderItem={this.renderItem.bind(this)} keyExtractor={(item) => (item.data.id +'')}/> } {this.state.loading & & < ActivityIndicator size="large" color="#f4511e"/> } < /View> ); } navigateToPicture(title, url) { this.props.navigation.navigate('PicturePreview', { 'title': title, 'url': url }) } renderItem(item) { //Destructuring values from item //Read more 'ES6 destructuring' const {data} = item.item; const {title} = data; const {url} = data.preview.images[0].source; return ( //Clickable view < TouchableHighlight onPress={() => this.navigateToPicture(title, url)}> {/Reusing our CardView/} < CardView> < Image style={{height: 150}} source={{uri: url}}/> < Text style={{padding: 5}}> {title}< /Text> < /CardView> < /TouchableHighlight> ) } }

PicturePreview.js:
import React from 'react'; import {Image} from "react-native"; export default class PicturePreview extends React.Component { //Destructure navigation //Set title to header static _navigationOptions = ({navigation}) => ({ title: navigation.state.params.title }); render() { const {url} = this.props.navigation.state.params; return (< Image style={{flex: 1}} source={{uri: url}}/> ) } }

navigationOptions将由React-Navigation自动调用。
现在转到App.js
注意:React-Navigation中有许多导航类型。今天, 我们将专注于StackNavigation。请参考官方网站了解详细信息。
import React from 'react'; import {createStackNavigator} from "react-navigation"; import PictureList from "./components/PictureList"; import PicturePreview from "./components/PicturePreview"; export default class App extends React.Component { render() { return ( < Router/> ); } } //Customize the header_ const NavigationOptions = { headerTintColor: '#fff', headerStyle: { backgroundColor: '#f4511e', } }; //Create the router. const Router = createStackNavigator({ //Name the screen 'PictureList': { //Link the Component screen: PictureList, //Additional navigation options navigationOptions: { title: '/r/pics Browser', ...NavigationOptions } }, 'PicturePreview': { screen: PicturePreview, navigationOptions: NavigationOptions } }, { //Root initialRouterName: 'PictureList' } );

如你所见, 我们需要做的就是创建一个导航路由器, 并使应用程序呈现它。如果一切顺利, 我们将提供功能强大的Reddit / r / pics浏览器应用程序。
Android:
深入研究React Native以进行Android开发

文章图片
iOS:
深入研究React Native以进行Android开发

文章图片
React Native很棒! 自从开始编程以来, 我就拥有纯粹的移动开发经验。但是现在我可以使用React编写几乎所有内容:移动, 桌面和Web。
如果你决定开始使用React Native开发下一个令人惊叹的应用程序, 你会发现它有它的怪癖和一些错误, 但是React Native非常实用, 适合大多数项目。
【深入研究React Native以进行Android开发】相关:构建QR扫描仪:React Native Camera教程

    推荐阅读