欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一篇搞懂React-Native

程序员文章站 2024-02-04 08:09:10
...

一篇搞懂React-Native

前言

提示:一篇针对RN项目开发的速成笔记,拥有它轻松掌握React-Native项目开发。


1、在项目目录中打开Powershell

2、在Powershell命令行中输入 初始化项目命令(使用react-native-cli):react-native init <项目名称>

3、先要数据线链接手机或者打开模拟器

4.检查设备链接情况(先要链接手机并打开开发者模式或者打开模拟器)

5.进入项目目录 运行

react-native run-android
已启动项目

6.项目建设

6.1.导入注册插件使用的AppRegistry import {AppRegistry} from ‘react-native’

6.2.导入组件 MyHomePageApp——组件 import MyHomePageApp from ‘路径’ /组件 只能使用.js后缀的文件

 a.在RN中,不能使用网页中的所有标签,像div,p,img不能用 
 b.RN提供View来实现布局,需要的组件从'react-native'中导入  import {View,Text} from 'react-native'  具体见文档-组件
 c.在RN中,所有文本,必须使用RN提供的Text组件进行包裹,否则会报错
 d.Platfrom 平台检测const instructions = Platfrom.select({ });   StyleSheet 样式相关组件,专门用来创建样式的  const styles = StyleSheet.create({ })
 e.Image 组件   <Image source={ repuire('本地路径')  or   {uri:'url地址'}  }></Image>
 f.Button组件和ActivityIndicator组件 
 g.ScrollView组件和flatList组件
 h.tab栏需安装 react-native-tab-navigator 包 使用见文档UI  https://github.com/ptomasroos/react-native-tab-navigator
 i.icon图标推荐使用 react-native-vector-icons 包 安装环境步骤见文档 https://github.com/oblador/react-native-vector-icons  
  (1)装包, 
  (2)编辑 android/app/build.gradle文件,增加一下内容(带+号标记需增加项)
        ... ...
        import com.android.build.OutputFile
        + project.ext.vectoricons = [ iconFontNames: [ 'MaterialIcons.ttf', 'EvilIcons.ttf' ,'FontAwesome.ttf' ] // Name of the font files you want to copy 
           ]   
        + apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
     ,并启用FontAwesome.ttf字体文件库,修改iconFontNames: [ 'MaterialIcons.ttf', 'EvilIcons.ttf' ,'FontAwesome.ttf']
  (3)复制react-native-vector-icons包中Fonts文件内容至android/app/src/main/assets/fonts
  (4)编辑android/settings.gradle ,增加一下内容(带+号标记需增加项)
         + include ':react-native-vector-icons'
         + project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
   (5)编辑android/app/build.gradle,增加一下内容(带+号标记需增加项)
          dependencies {
            ...
            implementation "com.facebook.react:react-native:+"  // From node_modules
            + compile project(':react-native-vector-icons')
          }
   (6)编辑 android/app/src/main/java/...MainApplication.java,增加一下内容(带+号标记需增加项)
            package com.myapp;
            + import com.oblador.vectoricons.VectorIconsPackage;
            ....

            @Override
             protected List<ReactPackage> getPackages() {
                return Arrays.<ReactPackage>asList(
                     new MainReactPackage()
                 +   , new VectorIconsPackage()  ***安装 Android SDK License 29.0.1 后此步可省略
                 );
              }
     (7)' 需要安装Android SDK License 26.0.1   //***安装 Android SDK License 29.0.1 后此步可省略
     (8)import Icon from 'react-native-vector-icons/FontAwesome';
         const myIcon= <Icon name="rocket" size={30} color="#900" />;
    j.swiper轮播图推荐使用 react-native-swiper 包 安装步骤见文档: https://github.com/leecade/react-native-swiper
      * 轮播图的外面必须加一个有高度的外套View,需要自动轮播 autoplay=true  loop=true,见文档 *
    k.九宫格布局注意手机默认是纵向流式布局,要改变方向 flexDirection:'row',flexWrap:'wrap'
    l. router 路由推荐使用 react-native-router-flux 包及所需依赖包 安装步骤见文档: https://github.com/aksonov/react-native-router-flux
      * Router相当于React中的HashRouter 
      * Stack 是一个分组的容器,它不表示具体路由,专门用来给路由分组,路由规则 Scene 都要放在 Stack 中;
      * Scene 就表示一个具体的路由规则,好比React中的Route,其属性有key,component,title,path,hideNavBar,...;  key是编程式导航需要的,路由规则具有唯一性;component 为导航去到的目标组件;hideNavBar 是否隐藏导航栏;
      (1)装路由包及依赖包:yarn add react-native-router-flux  react-native-screens  react-native-gesture-handler  react-native-reanimated  react-native-safe-area-context  @react-native-community/masked-view 
      (2)引入路由包组件,创建导航目标组件和路由规则:
          import { Router , Stack , Scene } from 'react-native-router-flux'   
           <Router sceneStyle={{backgroundColor:'#FFFFFF'}}>
               <Stack key="root">
                   <Scene key="app" component={App} title="这是App组件" hideNavBar/>
                   <Scene key="movielist" component={MovieList} title="热映电影列表" hideNavBar={false} />
               </Stack>
           </Router>
     (3)使用react-native提供的TouchableHighlight 控件包裹需要点击的唯一DOM元素,可接收元素的style,并增加 underlayColor='white' 点击时背景色为'white' ,如:
        <Scene style={styles.box}  key="movielist" component={MovieList} title="热映电影列表" hideNavBar={false} /> 中的 key="movielist";
      (4)在TouchableHighlight 控件上使用onPress事件,引入react-native-router-flux的Actions进行编程式导航,Actions即表示进行JS的路由操作,如: 
          View/:
              <TouchableHighlight style={styles.box} onPress={this.goMovieList} underlayColor='white'>
                              <View >
                                    <Image source={require('../../images/menu5.png')} sytle={{height:60,width:60}}></Image>
                                    <Text style={{fontSize:20}}>热映电影</Text>
                              </View>    
                         </TouchableHighlight>
              js/:  goMovieList=()=>{ Actions.movielist() }     //movielist是路由规则中Scene唯一的key值
     m.数据请求使用 fetch('API').then((res)=>res.json()).then((data)=>console.warn(data)) data即请求回来的数据,可保存在state中;
     n. 使用React-native的组件 Flatlist 对电影列表进行展示, 见文档:https://reactnative.cn/docs/flatlist   ,如 
            //渲染电影列表
              renderList=()=>{
                  if(this.state.isLoading){
                    return <ActivityIndicator size='large' color="#ccc"></ActivityIndicator>
                  }
                  return <View>
                               <SafeAreaView>
                                   <FlatList
                                    // horizontal
                                     style={{backgroundColor:'white'}}
                                    data={this.state.movies}
                                    ItemSeparatorComponent={this.renderSeparator} //渲染分割线
                                    renderItem={({item})=> this.renderItem(item)} //渲染电影列表,注意{item,index,sparator}需要引用
                                    keyExtractor={item => item.id}
                                    onEndReachedThreshold={0.5}
                                    onEndReached={this.loadNextPage}
                                    />
                               </SafeAreaView>
                           </View>
                   }
             //渲染每一项
               renderItem=(props) => (
                  <TouchableHighlight 
                  onPress={() =>this.goMovieInfo({id:props.id})}
                 //   onShowUnderlay={separators.highlight}
                 //   onHideUnderlay={separators.unhighlight}
                  underlayColor='white' 
                  style={{backgroundColor: 'white',
                  padding: 10, marginVertical: 10,marginHorizontal: 10,
                  alignItems:'center'}}
                  >
                     <View style={{width:'100%',flexDirection:'row'}}>
                           <Image source={{uri:props.images.small}} style={{height:220,width:160}}></Image>
                           <View style={{paddingHorizontal:20,justifyContent:'space-around',flex:1}}>
                                  <Text style={{fontSize:22}}>电影名称:<Text>{props.title}</Text></Text>
                                  <Text style={{fontSize:22}}>电影类型:<Text>{props.genres}</Text></Text>
                                  <Text style={{fontSize:22}}>制作年份:<Text>{props.year}</Text></Text>
                                  <Text style={{fontSize:22}}>豆瓣评分:<Text>{props.rating.average}</Text></Text>
                           </View>
                    </View>
                 </TouchableHighlight>
              )
             //渲染分割线
                renderSeparator=()=>{
                    return <View style={{borderTopWidth:1,borderColor:'#ccc',marginHorizontal:20}}></View>
                }
             //加载更多
                loadNextPage=()=>{
                    if(this.state.nowPage + 1 > this.state.totalPage){return}
                    this.setState({
                         nowPage:this.state.nowPage +1
                    },this.getMoviesByPage())
                 }
            // 带参数导航 去到电影详情页面
                goMovieInfo=(props)=>{
                    Actions.movieinfo(props)
                 }

6.3.AppRegistry.registerComponent(‘项目名称’,()=>App)

7.调用手机摄像头(带+号标记需增加项)

(1) 摄像头栏需安装 react-native-image-picker 包 使用见文档  https://github.com/react-native-image-picker/react-native-image-picker/
(2) 运行  react-native link 自动注册相关组件到原生配置中;
(3)  打开  ./android/app/src/main/AndroidManifest.xml 文件,添加以下内容:
          <uses-permission ... />
     +  <uses-permission android:name="android.permission.CAMERA" />
     +  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
(4) 在项目中添加如下代码:
          //第一步
         import {launchCamera} from 'react-native-image-picker';
        //创建拍照时的配置对象
         var photoOptions = {
             //底部弹出框选项
             title: '请选择',
             cancelButtonTitle:'取消',
             takePhotoButtonTitle:'拍照',
             chooseFromLibraryButtonTitle:'选择相册',
             quality:0.75,//拍照质量0-1
             allowsEditing:true,
             noData:false,//拍照时不带日期
             storageOptions:{
                    skipBackup:true,  //跳过备份
                    path:'images'
              },
              saveToPhotos:true,//(布尔值)仅适用于launchCamera,将捕获的图像/视频文件保存到公共照片
              mediaType:'photo',//如果是 'video',详见文档 https://github.com/react-native-image-picker/react-native-image-picker/#note-on-file-storage
              maxWidth:300,
              maxHeight:300,
              cameraType:'front',
          }
           //第二部
          constructor(props){
              super(props);
              this.state={
                   imgURL:''
               }
           }
           //第三步
          render(){
                 return <View style={{alignItems:'center',paddingTop:200}}>
                       <Image source={{uri:this.state.imgURL}} style={{width:200,height:200,borderRadius:100}}></Image>
                       <Button title='拍照'  onPress={this.cameraAction}></Button>
                 </View>
           }
           //第四步
           cameraAction = ()=>{
        	launchCamera(photoOptions, (response)=>{
            		console.warn('response'+response);
            		if(response.didCancel){
                	return
            		}
            		this.setState({
                		imgURL:response.uri
            		})
        	})
             }

8.签名打包发布Release版本的APK安装包 参考网页文档:(带+号标记需增加项)

8.1 https://www.jianshu.com/p/1380d4c8b596

8.2 https://blog.csdn.net/fengyuzhengfan/article/details/51958848

(1) 正确配置所有RN环境
(2) 在CMD命令行中,运行这句话:keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
其中:my-release-key.keystore 表示你要生成的签名文件名称,需要保存记录;
-alias 参数后面的别名是你将来为应用签名时所需要用到的,所以也需要保存记录;
当运行这个命令的时候,需要输入一系列的参数,及口令的密码,是**,很重要,也需要保存记录;
(3)当生成了签名之后,my-release-key.keystore这个签名文件存放在 C:\Users\wuyaohua> 中;
(4) 设置gradle变量
a.将你的签名证书copy到 android/app目录下;
b.编辑~/.gradle/gradle.properties或…/android/gradle.properties(一个是全局gradle.properties,一个是项目中的gradle.properties,大家可以根据需要进行修改) ,加入如下代码:
MYAPP_RELEASE_STORE_FILE=your keystore filename
MYAPP_RELEASE_KEY_ALIAS=your keystore alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****
提示:以上用正确的证书密码、alias以及key密码替换掉 。
(5) 在gradle配置文件中添加签名配置
编辑 android/app/build.gradle文件添加如下代码:

           ...  
           android {  
             ...  
             defaultConfig { ... }  
             signingConfigs {
         +       release {
         +       storeFile file(MYAPP_RELEASE_STORE_FILE)
         +        storePassword MYAPP_RELEASE_STORE_PASSWORD
        +            keyAlias MYAPP_RELEASE_KEY_ALIAS
        +            keyPassword MYAPP_RELEASE_KEY_PASSWORD
                }
              }
              buildTypes {  
                 release {  
                        ...  
         +             signingConfig signingConfigs.release  
                  }  
               }  
            }  
            ...  
    (6) 签名打包APK
           进入项目根目录下的android文件夹打开终端输入: ./gradlew assembleRelease
    (7) 签名打包成功后你会在 “android/app/build/outputs/apk/”目录下看到签名成功后的app-release.apk文件。
           提示:如果你需要对apk进行混淆打包 编辑android/app/build.gradle:
                   /**     
                   * Run Proguard to shrink the Java bytecode in release builds.  
                   */  
                    def enableProguardInReleaseBuilds = true
                   adb devices

总结

本文是作者亲自整理,如对你有帮助,请收藏转发并尊重原创,谢谢! ——corder吴