reactnative_reactnative- - CSDN
  • ReactNative是由Facebook公司发布的可以进行混合开发的开源技术框架。通过ReactNative可以为iOS和Android两个系统开发应用程序,“Learn once,write anywhere”。使用ReactNative开发,既拥有Native的良好人机交互...
  • 完全征服React Native

    2018-10-22 21:38:05
    React Native是Facebook于2015年推出的跨平台开发...本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合
  • 写一个用reactnative 的项目 可以用于查看GitHub最受欢迎与最热项目的App。 项目开始 HomePage.js PS 可以先拖动到底部看下效果图 新建一个reactnative项目 ,底部因为有四个tab 选项卡 那么 我使用一个第三方组件...

    写一个用reactnative 的项目 可以用于查看GitHub最受欢迎与最热项目的App。

    https://github.com/liudao01/ReactNativeProject

    github地址 还在更新中

    项目开始 HomePage.js

    PS 可以先拖动到底部看下效果图

    新建一个reactnative项目 ,

    底部因为有四个tab 选项卡 那么 我使用一个第三方组件react-native-tab-navigator

    并且新建一个HomePage.js,关于第三方组件可以看下这篇文章 http://blog.csdn.net/true100/article/details/68066649

    这里单独说下 npm install react-native-tab-navigator --save 后面这个–save 这个的作用是用户把这个库加入到package.json中去.

    在Homepage.js里面 使用react-native-tab-navigatior

    这是 index.android.js

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View
    } from 'react-native';
    
    
    import Homepage from "./js/pages/HomePage";
    export default class testP extends Component {
      render() {
        return (
          <View style={styles.container}>
            <Homepage/>
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
      }
    });
    
    AppRegistry.registerComponent('testP', () => testP);
    
    

    这是 Hmepage.js

    /**
     * Created by liuml on 2017/9/8.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    } from 'react-native';
    import TabNavigator from 'react-native-tab-navigator';
    import TabNavigatorItem from "react-native-tab-navigator/TabNavigatorItem";
    
    export default class Homepage extends Component {
    
        // 构造
        constructor(props) {
            super(props);
            // 初始状态
            this.state = {selectedTab: 'papular'};
        }
    
    
        render() {
    
            return <View style={styles.container}>
                <TabNavigator>
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'papular'}
                        title="最热"
                        slectedTitleStyle={{color: '#FFF'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_popular.png')}></Image>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_popular.png')}/>}
                        onPress={() => this.setState({selectedTab: 'papular'})}>
    
                        <View style={{backgroundColor: '#FF0', flex: 1}}/>
                    </TabNavigator.Item>
    
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'trending'}
                        slectedTitleStyle={{color: '#0F0'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_trending.png')}/>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_trending.png')}/>}
                        onPress={() => this.setState({selectedTab: 'trending'})}
                        title="趋势">
    
                        <View style={{backgroundColor: '#0F0', flex: 1}}/>
                    </TabNavigator.Item>
    
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'favorite'}
                        slectedTitleStyle={{color: '#0F0'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_favorite.png')}/>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_favorite.png')}/>}
                        onPress={() => this.setState({selectedTab: 'favorite'})}
                        title="收藏">
    
                        <View style={{backgroundColor: '#0FF', flex: 1}}/>
                    </TabNavigator.Item>
    
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'my'}
                        slectedTitleStyle={{color: '#0F0'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_my.png')}/>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_my.png')}/>}
                        onPress={() => this.setState({selectedTab: 'my'})}
                        title="我的">
    
                        <View style={{backgroundColor: '#FFF', flex: 1}}/>
                    </TabNavigator.Item>
    
                </TabNavigator>
            </View>
    
        }
    }
    
    const styles = StyleSheet.create({
    
        container: {
            flex: 1
        },
        icon: {
            width: 26,
            height: 26
        }
    
    });
    
    

    解释:

    我这里拿出一个item 出来解释

    renderSelectedIcon 这是选中后的图片
    tintColor 是给图片渲染
    title 就是名字
    我在构造函数中定义了一个变量selectedTab 让他默认是最热

    // 初始状态
    this.state = {selectedTab: ‘papular’};

    然后在item中判断selected={this.state.selectedTab === ‘papular’} 值是否为最热

    通过selected 判断是否选中状态 根据值是否相等

    在onPress 点击事件 里面给他重新设置值

    在每个item 中间可以看到我填充了一个view

    <View style={{backgroundColor: '#FF0', flex: 1}}/>
    
    

    这个就是作为填充的视图

    
            
                    <TabNavigator.Item
                        selected={this.state.selectedTab === 'papular'}
                        title="最热"
                        slectedTitleStyle={{color: '#FFF'}}
                        renderIcon={() => <Image style={styles.icon}
                                                 source={require('../../res/images/ic_popular.png')}></Image>}
                        renderSelectedIcon={() =>
                            <Image style={[styles.icon, {tintColor: '#63B8FF'}]}
                                   source={require('../../res/images/ic_popular.png')}/>}
                        onPress={() => this.setState({selectedTab: 'papular'})}>
    
                        <View style={{backgroundColor: '#FF0', flex: 1}}/>
                    </TabNavigator.Item>
    

    然后 看下效果图

    image


    最后看下这个第三方库react-native-TabNavigator的item的源码 直接在import哪里点击引入就好(android studio
    怎么点这里就怎么点)

    
    export default class TabNavigatorItem extends React.Component {
      static propTypes = {
        renderIcon: PropTypes.func,
        renderSelectedIcon: PropTypes.func,
        badgeText: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
        renderBadge: PropTypes.func,
        title: PropTypes.string,
        titleStyle: Text.propTypes.style,
        selectedTitleStyle: Text.propTypes.style,
        tabStyle: ViewPropTypes.style,
        selected: PropTypes.bool,
        onPress: PropTypes.func,
        allowFontScaling: PropTypes.bool,
      };
    
      static defaultProps = {
      };
    
      render() {
        let child = React.Children.only(this.props.children);
        return React.cloneElement(child, {
          style: [child.props.style, this.props.style],
        });
      }
    }
    
    

    可以看到 renderIcon renderSelectedIcon 等等的声明都在这里


    最热页面 PapularPage.js : 以及导航栏 NavigationBar.js

    说下对应关系 homepage 里面包含了最热页面 PapularPage.js 最热页面里面包含了导航栏 NaivgationBar.js

    关于react native 布局 这篇文章很不错错 http://www.jianshu.com/p/688b9108a922

    先写NavigationBar.js

    
    /**
     * Created by liuml on 2017/9/11.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        StatusBar,
        Platform,
        Image,
        TouchableOpacity
    } from 'react-native';
    
    export default class NavigationBar extends Component {
    
        render() {
            return <View style={styles.container}>
                <View style={styles.container}>
                    <StatusBar hidden={false} barStyle="light-content"/>
                </View>
                {/*顶部导航栏*/}
                <View style={styles.navBar}>
                    <View style={styles.navBar}></View>
                    <View style={styles.titleWrapper}>
                        <Text style={styles.title}>热门</Text>
                    </View>
    
                    <View style={styles.rightBar}>
                        <TouchableOpacity activeOpacity={0.7}>
                            <Image source={require('../../res/images/ic_search_white_48pt.png')}></Image>
                        </TouchableOpacity>
                        <TouchableOpacity activeOpacity={0.7}>
                            <Image source={require('../../res/images/ic_more_vert_white_48pt.png')}></Image>
                        </TouchableOpacity>
    
                    </View>
                </View>
            </View>
        }
    }
    const styles = StyleSheet.create({
    
        container: {
            backgroundColor: '#63B8FF',
        },
        statusBar: {
            height: Platform.OS === 'ios' ? 20 : 0
        },
        navBar: {
            flexDirection: 'row',
            justifyContent: 'space-between',
            alignItems: 'center',
    
        },
        titleWrapper: {
            flexDirection: 'column',
            justifyContent:'center',
            alignItems:'center',
            position:'absolute',
            left:40,
            right:40,
        },
        title: {
            fontSize: 16,
            color: '#FFF'
        },
        rightBar: {
            flexDirection: 'row',
            alignItems: 'center',
            paddingRight:8
        }
    });
    
    
    

    看下效果图

    mark

    分析 从样式分析

    statusBar

    NavigationBar 会包含状态栏,还有顶部导航栏 状态栏用到一个控件 StatusBar (ios用的)

    注意这里ios和android 稍微有点不同了ios StatusBar 有效果 就是显示顶部的状态栏.安卓没效果

    关于状态栏说下 ios 可以使用 android 无效果 所以得区分下 这里我使用了Platfrom 判断是ios 还是android

    navBar

    flexDirection: ‘row’, 让主轴方向是横向

    justifyContent: ‘space-between’, 让主轴排列方式是在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首

    对齐,每行最后一个元素与行尾对齐。( 这里面有个技巧: 因为控件只有三个

    会造成热门文字不在中间, 那么我就在最左边再添加一个view )

    titleWrapper

    flexDirection: ‘column’, 让主轴方向是纵轴

    justifyContent: ‘center’, 主轴排列方式居中

    alignItems: ‘center’, 交叉轴的排列方式也是居中的

    position: 'absolute',
        left: 40,
        right: 40,   
    

    说下为什么这里需要position ,可以尝试下不加position 会造成热门并不在中间.那么就给他使用position 并且微调下

    position enum(‘absolute’,‘relative’)属性设置元素的定位方式,为将要定位的元素定义定位规则。

    absolute 生成绝对定位的元素,元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。

    relative:生成相对定位的元素,相对于其正常位置进行定位。因此,“left:20” 会向元素的 LEFT 位置添加 20 像素。

    title

    没啥说的就是设置了颜色和大小

    navBtn

    也没啥说的 就是给设置了宽高 右边的搜索和更多的图片宽高

    rightBar

    包裹右面两个图片的样式

    flexDirection: ‘row’, 主轴方向横向

    alignItems: ‘center’, 主轴对齐方式居中对齐

    paddingRight: 8 居右8?  我不清楚这个是dp 还是像素
    

    TouchableOpacity(透明度变化)

    TouchableOpacity组件介绍
    该组件封装了响应触摸事件。当点击按下的时候,该组件的透明度会降低。该组件使用过程中

    并不会改变视图的层级关系,而且我们可以非常容易的添加到应用并且不会产生额外的异常错误。

    创建 PapularPage.js 里面包含了NavigationBar.js

    /**
     * Created by liuml on 2017/9/11.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    }from 'react-native';
    
    import NavigationBar from "../compoent/NavigationBar.js"
    export default class PapularPage extends Component {
    
        render() {
            return <View style={styles.container}>
                <NavigationBar/>
            </View>
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1
        }
    });
    

    没啥说的 非常简单就是把NavigationBar加入到了这个Papular页面

    把上面的做好之后的效果图就是我上面的效果图


    OK 下面在PapularPage页面内添加 可以左右滑动的控件(选项卡控件)

    react-native-scrollable-tab-view

    用到一个第三方组件 http://www.jianshu.com/p/b7788c3d106e

    上面有使用方式 我把他引入我的项目

    
    /**
     * Created by liuml on 2017/9/11.
     */
    import React, {Component} from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        Image
    }from 'react-native';
    
    import NavigationBar from "../compoent/NavigationBar.js"
    import ScrollableTabView from "react-native-scrollable-tab-view"
    export default class PapularPage extends Component {
    
        render() {
            return <View style={styles.container}>
                <NavigationBar/>
                <ScrollableTabView
                    tabBarBackgroundColor="#63B8FF"
                    tabBarActiveTextColor="#FFF"
                    tabBarInactiveTextColor="#F5FFFA"
                    tabBarUnderlineStyle={{backgroundColor: "#E7E7E7", height: 2}}>
                    <Text tabLabel='IOS'/>
                    <Text tabLabel='Android'/>
                    <Text tabLabel='Java'/>
                    <Text tabLabel='JavaScript'/>
                </ScrollableTabView>
            </View>
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1
        }
    });
    
    

    mark

    比较简单没啥说的.

    现在的数据是写死的 后面会动态改变

    tabBarUnderlineStyle(style)
    设置DefaultTabBar和ScrollableTabBarTab选中时下方横线的颜色

    tabBarBackgroundColor(String)
    设置整个Tab这一栏的背景颜色

    tabBarActiveTextColor(String)
    设置选中Tab的文字颜色

    tabBarInactiveTextColor(String)
    设置未选中Tab的文字颜色

    tabBarTextStyle(Object)
    设置Tab文字的样式,比如字号、字体等


    下面是关于布局的总结:

    容器的属性

    flexDirection

    flexWrap

    justifyContent

    alignItems

    项目的属性

    flex

    alignSelf

    flexDirection属性

    flexDirection属性决定主轴的方向(即项目的排列方向)。
    它可能有4个值:

    row:主轴为水平方向,起点在左端。

    row-reverse:主轴为水平方向,起点在右端。

    column(默认值):主轴为垂直方向,起点在上沿。

    column-reverse:主轴为垂直方向,起点在下沿。

    flexWrap属性

    默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。它可能取三个值。

    (1)nowrap(默认):不换行。

    (2)wrap:换行,第一行在上方。

    justifyContent属性

    justify-content属性定义了项目在主轴上的对齐方式。

    它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。
    flex-start(默认值):左对齐

    flex-end:右对齐

    center: 居中

    space-between:两端对齐,项目之间的间隔都相等。

    space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

    alignItems属性

    align-items属性定义项目在交叉轴上如何对齐。
    它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

    flex-start:交叉轴的起点对齐。

    flex-end:交叉轴的终点对齐。

    center:交叉轴的中点对齐。

    baseline: 项目的第一行文字的基线对齐。

    stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

    flex属性

    flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

    flex-grow属性

    flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

    如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

    alignSelf属性

    alignSelf属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。

    默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

    该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

    展开全文
  • 2015年9月15日,Facebook发布了 React Native for Android,把 Web 和原生平台的 JavaScript 开发技术扩展到了 Google 的流行移动平台。什么是React NativeReact Native 让开发者使用 JavaScript 和 React 编写应用...

    2015年9月15日,Facebook发布了 React Native for Android,把 Web 和原生平台的 JavaScript 开发技术扩展到了 Google 的流行移动平台。


    什么是React Native

    React Native 让开发者使用 JavaScript 和 React 编写应用,利用相同的核心代码就可以创建 Web,iOS 和 Android 平台的原生应用。React Native 的宗旨是,学习一次,高效编写跨平台原生应用。

    官方的github地址为:https://facebook.github.io/react-native/


    React Native有什么优点

    1.提供了原生的控件支持

    使用 React Native 你可以使用原生的控件,入在iOS平台我们可以使用UITabBar控件,在Android平台我们可以使用Drawer控件。这样,就让我们的App从使用上和视觉上拥有像原生App一样的体验。而且使用起来也非常简单。

    2.异步执行

    所有的JavaScript逻辑与原生的代码逻辑都是在异步中执行的。原生的代码逻辑当然也可以添加自己的额外的线程。

    这个特性意味着,我们可以将图片解码过程的线程从主线程中抽离出来,在后台线程将其保存在磁盘中,在不影响UI的情况下计算调整布局等等。

    所以,这些让React Native开发出来的App都是较为的流畅。

    这个之间的通信过程也是有序列化来完成的,这个就让我们可以使用Chrome Developer Tools 来完成JavaScript逻辑的调试,当然我们也能够在模拟器和物理设备上调试。

    3.触屏处理
    React Native实现了高性能的图层点击与接触处理。

    4.Flexbox的布局样式
    使布局将变得更简单,这就使我们为什么要将网页的布局模式切换到React Native的Flexbox布局模式。Flexbox让UI布局变得简单,入使用margin和padding的嵌套模式。当然,React Native 同样也支持网页原生的一些属性布局模式,如FontWeight之类的。这些声明的布局和样式,都会存在内联的机制将其优化。

    5.Polyfills机制
    React Native也支持我们使用第三方的JavaScript库,来方便我们的开发。支持npm中的成千上万的模块。

    6.基于React JS
    拥有React JS的优良特性。


    跨平台框架这么多?为什么重点关注React Native?

    如我们之前所介绍的,Android与IOS跨平台开发框架如此这多,如之前我们介绍的PhoneGap、Xamarin等,为什么我们重点的关注React Native呢?

    1. Facebook所开源的框架
      我们知道,所有的开源框架,只有是一线的大公司研发出来的才能够保证框架的维护性、可用性。当然,这样也会吸引更多的开发者使用这个框架,才能够使我们在人才储备上有人可用。并不是说,框架多好就能够用的。如国内的CrossApp,虽然很好用,但是知名度不够,造成我们研发、bug反馈、人才招聘上的种种窘境。

    2. React JS技术的革命
      这个东西也就是国内的很多跨平台框架没有关注的地方,Facebook使用了React JS已经有了好几年的技术变革,特别是JSX与Virtual DOM的加入,给使用JavaScript来开发Native App简直是一个质的飞跃。

    3. BAT团队已经投入研发与使用
      如果很多中小型公司,看不清方向,这个我们倒是可以模仿BAT的脚步。现在的BAT公司内部,特别是A,已经投入了大量的人力在React Native上面,听说TMall App已经开始使用React 进行重构。

    我们可以看到,目前对于Facebook来说,他们的新业务线也将直接使用了React Native的开发模式


    搭建React Native 的 Windows 环境

    NodeJs、Python、Android SDK、JDK

    由于我们大天朝网络的限制,很多依赖的库都fetch不下来。所以整个React Native的环境搭建,命令执行都是一个痛苦的过程。(就连NodeJS我都快下了半天的时间)

    我在Windows平台上搭建环境弄了差不多一周的时间,都没有弄下来,特别是下面这个问题一直困扰着我

    bash: ulimit: open files: cannot modify limit: Too many open files

    后面得到了高人的指点,借给我了一个梯子,并在我的Mac设备上成功的运行了自己的第一个React Native项目。哭~~~

    下面是我的运行步骤,大多数是和官方的介绍一样的:

    我们先从Github上获取React Native的代码

    github地址:https://github.com/facebook/react-native

    git clone https://github.com/facebook/react-native.git

    进入React Native 并使用npm 进行安装

    npm install -g react-native-cli

    注意
    - 使用npm进行安装,需要搭建好完整的nodejs环境,nodejs地址:https://nodejs.org
    - npm install 需要依赖于很多国外资源,自备翻墙梯子


    新建自己的React Native项目,这里命名为AwsomeProject

    react-native init AwsomeProject

    运行完后,如果环境变量没有配置错误,react 将会帮我们生成一个AwsomeProject的文件夹目录。

    里面内如如下所示:


    运行Android App

    $ cd AwesomeProject
    $ react-native run-android

    看起来很简单的两句命令,但是里面隐藏这很多的陷阱。
    - 确保Gradle的环境配置好了,这里还会动态的down很多Gradle的依赖文件,不翻墙估计依赖文件都下不下来
    - 需要安装好自己的Python环境(怎么安装google吧),React Native 的 packager需要 python的支持
    - 这个东西,只能运行在Android模拟器上,真机运行必须失败,至于为什么后面在介绍

    注意好上面三点,就能在模拟器上看到如下画面了


    运行iOS App

    ios相对就简单了很多,直接打开 ios/AwesomeProject.xcodeproj 文件,使用Xcode编译运行就能出现和Android类似的界面了。我的效果如下:

    注意,同样只能够在模拟器上运行

    React Native的优势和劣势:(转):

    React Native的优势

    相对Hybird app或者Webapp:

    • 不用Webview,彻底摆脱了Webview让人不爽的交互和性能问题
    • 有较强的扩展性,这是因为Native端提供的是基本控件,JS可以自由组合使用
    • 可以直接使用Native原生的「牛逼」动画(在FB Group这个app里面,面板滑出带一点果冻弹动,面板基于某个点展开这种动画随处可见,这种动画用Native code来做小菜一碟,但是用Web来做就难上加难)。

    相对于Native app:

    • 可以通过更新远端JS,直接更新app,不过这快成为各家大型Native app的标配了…

    劣势

    • 扩展性仍然远远不如web,也远远不如直接写Native code(这个不用废话解释了吧)
    • 从Native到Web,要做很多概念转换,势必造成双方都要妥协。最终web要用一套CSS的阉割版,Native要费劲地把这个阉割版转换成native原生的表达方式(比如iOS的Constraint\origin\Center等属性),两边都会不爽。

    /*
    * @author zhoushengtao(周圣韬)
    * @since 2015年9月30日 凌晨 1:00:20
    * @weixin stchou_zst
    * @blog http://blog.csdn.net/yzzst
    * @交流学习QQ群:341989536
    * @私人QQ:445914891
    /
    这里写图片描述

    展开全文
  • 投稿 | 亦枫责编 | 唐小引Udacity 移动端团队最近删除了 App 中使用 React Native 语言开发的相关功能。我们收到大量有关我们用法或 React ...
        

    640?wx_fmt=gif

    640?wx_fmt=png

    投稿 | 亦枫

    责编 | 唐小引

    Udacity 移动端团队最近删除了 App 中使用 React Native 语言开发的相关功能。

    我们收到大量有关我们用法或 React Native 的问题以及为什么我们停止投入资源和精力在 RN 上。

    在这篇文章中,我希望能够回答我们收到的大多数问题并深入了解:

    • 我们团队的规模和组成是什么?

    • 为什么我们优先考虑尝试 React Native?

    • 放弃的原因是什么?

    • 什么有用?什么没有?

    • ……还有更多

    我当然不会声称自己是 React Native 的专家。我们团队中的其他人比我有更有经验,但我相信他们也不会自称专家。

    我将根据我们自己的经验谈论在我们的特定情况下做什么和不做什么。至于 React Native 是否适合你的团队/项目取决于你,但希望这篇文章能够提供额外有用的数据点供你参考。

    “React Native 是否适合你的团队/项目取决于你。”

    我还是想指出,这些经验和意见来自 Udacity 的移动工程团队,而不是其他任何人。这里的想法并不反映任何其他团队使用或构建 React 或 React Native 内容的意见。


    640?wx_fmt=png

    团队


    首先要搞清楚的事情。我们的团队是什么样的?团队规模,经验和所在组织有能力将 React Native 的可行性在项目中产生实际影响。

    我们的移动端团队分布在 iOS 和 Android 平台上。

    一、团队规模

    最初引入 React Native 时:

    • 1 名 iOS 开发

    • 2 名 Android 开发

    • 1 名产品经理

    • 1 名设计师

    到了今天:

    • 4 名 iOS 开发

    • 3 名 Android 开发

    • 1 名产品经理

    • 1 名设计师

    在我们使用 React Native 长达 18 个月的过程中,我们的 iOS 和 Android 团队的规模都在保持增长。

    团队更由一位新的产品经理负责。

    我们通过多名设计师和设计范例进行过转型。

    二、开发背景

    引入 React Native 时,使用 JavaScript 和 React 范例的每个团队有多舒适?

    • iOS

    iOS 团队的唯一开发人员之前拥有丰富的 Javascript 和 Web 开发经验,非常乐意使用 React Native 开发。

    如今,四个 iOS 开发者中至少有三个习惯并适应使用 Javascript 和 React Native 技术。

    • Android

    在引入 React Native 时,两位 Android 开发人员中有一位对 Javascript 感到满意。另一位(也就是我自己)只有很少的 Javascript,React 或 web 开发背景。

    后来加入团队的其他 Android 开发人员也几乎没有 Javascript 或 Web 经验。


    640?wx_fmt=png

    我们的 Apps


    我们的产品是做什么的?

    我们的手机应用旨在为将 Udacity 学习体验带到你的手机设备上。它们支持身份验证,内容发现,程序注册(在某些情况下还有支付),最后支持各种程序和内容类型的学习材料的消费。

    这些应用也是新的实验性功能和计划的试验场所,目的在于改善用户的整体学习效果。

    一、代码库规模

    • iOS:97,400 行(.swift,.h,.m 格式)

    • Android:93,000 行(xml,java,kotlin,gradle)

    二、同等

    引入 React Native 后,应用程序的功能也非常接近。

    随着时间的推移,核心体验大致相当,但每个团队都增加有或多或少的对另一个平台的经验。

    此外,由于国际需求的扩大,本地化和更小的 apk size 等成为 Android 团队越来越重视的事情。Android 团队还与其他地区的团队密切合作,针对非 iOS 需要考虑的市场特定功能。


    640?wx_fmt=png

    为什么以及我们如何采用 RN


    一、我们为什么要引入?

    我们开始推出全新的移动端专有功能。我们希望在两个平台上快速进行实验和验证,因此跨平台开发非常具备吸引力。

    因为它是一个新的并且独立的功能,所以被认为是尝试跨平台开发的契机。

    选择 React Native 有几个原因:

    • 作为跨平台解决方案提高了可行性;

    • 大多数(2/3 的开发人员)团队适应 Javascript 和 Web 开发;

    • 提高了开发速度;

    • 来自公司外其他团队的成功经验。

    二、我们是如何引入的?

    最初的 React Native 功能是在一个单独的 GitHub 仓库中构建的,并作为 Git 子分支分别并入 iOS 和 Android 仓库。

    这样可以实现非常快速的原型设计,并且如果需要,可以将该功能作为独立产品发布。

    更多的经验是原型,最终我们在 React Native 代码库中引入了第二个更大的功能。

    三、时间线

    • 2016 年 8 月:为功能 1 创建 React Native repo

    • 2016 年 11 月:Android 平台发布功能 1

    • 2016 年 11 月:功能 2 开始开发

    • 2016 年 12 月:功能 3 开始原型设计

    • 2017 年 1 月:功能 1 开发结束

    • 2017 年 2 月:功能 2 发布

    • 2017 年 3 月:功能 3 原型设计结束

    • 2017 年 11 月:Android 更新功能 2

    • 2017 年 12 月:功能 4 原型作为独立应用程序。由于性能问题,最终取消了对原生的支持

    • 2018 年 2 月:iOS 更新功能 2

    • 2018 年 4 月:功能 1 从 Android 平台中删除

    • 2018 年 6 月:从两个应用中删除功能 2


    640?wx_fmt=png

    去除的动机?


    答案直截了当。

    我们从应用程序中删除最后的 React Native 代码,因为唯一剩下的 React Native 开发的功能已经下线,我们不再需要支持。

    一、“为什么我们停止投入 React Native ?”

    这是一个更有趣的问题。

    想到下面几点原因:

    • 同时在两个平台上开发的功能数量减少;

    • Android 特定产品需求的增加;

    • 对长期维护成本感到失望;

    • Android 团队不倾向继续使用 React Native。


    640?wx_fmt=png

    我们用什么取而代之?


    我们已经部署和删除的 React Native 相关功能不再需要支持,自然不需要替代者。


    640?wx_fmt=png

    好的方面?


    我们进军 React Native 的哪些方面进展顺利?

    • 入手 React Native 开始在两个平台上构建运行确实非常简单

    • 能够从更庞大的 React 和 Javascript 生态系统中提取使用很多现有的 librayies 和工具

    • 我们能够同时在两个平台上对功能 1 进行原型设计

    • 跨平台团队的单个开发人员能够同时为两个平台构建大部分功能 2

    • 团队对 React Native 的共同理解有所加深


    640?wx_fmt=png

    我们遇到哪些问题?


    在我们使用 React Native 期间,我们遇到了许多问题。其中一些归因于我们的工作流程,一些归因于我们的用例,而另一些则归因于 React Native 本身。

    一、设计和体验的挑战

    • 平台一致的 UI / UX

    因为我们将一些新的屏幕集成到现有更大的用户体验当中,所以我们希望新的 React Native 代码能够遵循原生平台模式和现有样式。这意味着我们不一定能为两个平台使用相同的 UI 设计。

    在 React Native 中确保每个平台自身的样式并不困难,但它确实需要了解每个代码库中使用的设计范例。最简单的是,这需要平台检查以及每个系统的自定义小部件。

    对于我们来说,这通常需要与每个平台的开发人员和设计人员沟通,来了解所需要的内容,或者两者都使用单一样式。这通常会导致 Android 方面的体验与其他应用截然不同。

    一些更复杂的情况下,需要额外的开发平台特定代码来自定义应用体验。

    这样的例子之一是确保返回/前进按钮图标的适配。由于需要将新的 React Native 功能集成到现有应用当中,为确保返回/前进图标和返回按钮按下的正确行为,需要针对 React Native 代码库修改 Android 特定原生代码。

    • 原生设计的更改可能需要更改 React Native 代码以处理集成点

    不止一次,Android 应用的导航结构发生变化,这要求我们更新 React Native 代码。

    React Native 功能不必被隔离到自己的 Activity 中,而是必须移动到一个 fragment 中,放置在一个带有 BottomNavigationView 的屏幕中,然后在它自己和其他原生 fragments 之间协调。

    这种类型的平台修改需要返回到单独的代码库,进行更改,更新集成,并确保新修改也不会对 iOS 平台产生负面影响。

    • 设备特定问题

    “碎片化”也好,“多样化”也罢,不论你怎么称呼,留给我们一个不争的事实是有更多独特的 Android 设备配置需要特殊考虑。

    我们多次发现布局不适应不同尺寸的 Android 手机。我们发现在最新的 iPhone 或 Pixel 设备上运行流畅的动画,在 Android 广泛使用的国际市场的低端设备上却运行不佳。

    这些肯定不是唯一的 React Native 问题;这些是 Android 上常见的开发挑战,但随着平台特定检查和考虑因素的增加,我们不得不开始考虑使用 React Native 实际节省了多少时间。

    • 全球增长

    在我们使用 React Native 的过程中,国际化成为 Android 团队的一个更大的挑战。我们有几个国际办事处要求实现本地化并减少 apk 大小。

    React Native 中的字符串本地化可以完成,因为它确实需要额外的设置。在我们的例子中,它需要更改单独的仓库。这增加了本地化任务的复杂性,这在寻求其他团队的本地化帮助时并不理想。这直接减少了 React Native 功能的本地化频率。

    我们能够在这段时间减少我们的 apk 大小,但是包含 React Native 的代码规模相当大,我们无法解决这些问题。删除最后一个 RN 功能后,我们的 apk 减小 10M 左右,包括资源删除和 React Native 本身的剔除。

    二、集成挑战

    • 与原生组件和导航结构集成

    根据我们的经验,如果是一个独立的功能,将 React Native 集成到现有应用程序中可能非常简单,然而如果需要与现有组件紧密集成并与之通信,则可能会遇到一些挑战。

    我们发现自己经常需要大量的桥接代码实现原生和 React Native 组件之间的通信。当我们需要更改 React Native 组件适应我们的导航层次结构的位置时,相关代码至少需要一次更新。

    • 工具/构建问题

    将 React Native 所需的更新合并到每个应用的构建过程中。我们使用 CircleCI (持续集成工具)来构建我们需要重新配置的项目,以支持额外的 React Native 构建步骤。

    就像前面说的那样,在 Android 方面,这并不像我们想象的那样简单。

    一旦我们的构建需要更新包含所需的 React Native 任务时,CircleCI 的发布编译时间增加大约 20%。

    从我们的代码库中删除最终的 React Native 功能后,我们看到了以下提升:

    1. CircleCI 编译时间从 15min 减少到 12min 左右

    2. 发布 apk 大小从 28.4MB 降低至 18.1MB

    Android 团队也遇到过 Android/Gradle 构建工具与 React Native 冲突的问题。最近我们一直在解决 Gradle 4 版本的问题。

    iOS 团队也面临着相当大的挑战。

    配置构建非常痛苦,因为我们的 React Native 的文件结构并不标准。鉴于我们独立的项目仓库,我们从 srcroot/ReactNative 拉取 React Native 代码,并且许多现有的构建工具采用了默认的 app 结构,即 /ReactNative/ios/... ios。

    此外,我们使用 cocoapods 进行依赖管理,这是最初建议的融入 React Native 的方式,但在后续已被弃用。我们非标准的文件结构进一步加剧这种情况,导致我们不得不在 Podfile 中包含一些令人讨厌的黑客式操作,以便能从正确的位置读取到。

    由于 cocoapods 不再是包含 React Native 的规范方式,因此 Podfile 更新依赖于要社区去更新,这并不总是同步的。在几个版本中,css/Yoga 依赖更新掉了,但是 Podfile 却引用了一个不正确的版本... 最后没办法,我们使用一些黑科技手段解决这种问题。

    最后,iOS 项目的 CI(持续集成)也是一个痛点。我们现在必须添加一个 npm 依赖层,并确保在继续安装之前正确更新它们。这为我们的构建步骤增加大量的时间。

    还有一个引发崩溃的问题,因为一个包含 package.lock 文件的 npm 版本,而另一个版本没有包含,导致我们在 React Native 升级过程中安装了不正确的依赖版本。


    640?wx_fmt=png

    React Native 挑战


    一、文档

    React Native 作为一个生态一直在快速发展,我们发现文档经常跟不上。特别是在我们首次采用时,我们发现特定版本的文档/答案可能关联不上。

    关于集成 React Native 到现有项目的文档在当时似乎很少。这是我们更新 CI 构建所面临挑战的一个因素。

    随着 React Native 不断发展,文档和支持社区的贡献得到了改善。如果我们今天开始,我们可能会更容易找到一些问题的答案。

    二、导航

    我们最初使用的是 NavigationExperimental,它不是最容易使用的导航库。当 ReactNavigation 出现时,它迅速成为社区广泛接受的导航,并且在 ReactNavigation 真正完全成熟之前 NavigationExperimental 已经被废弃。

    三、性能

    如前所述,有些时候会注意到一些性能问题。

    我们能够制作一些非常漂亮的动画,这些动画在规范的 iOS 和 Android 设备上看起来非常不错,但在国际市场上比较普遍的低端 Android 设备上却表现不佳。

    进入应用的 React Native 部分时,加载时间比我们想要的要长。看上去往往不像是无缝过渡。

    在对独立功能 4 进行原型设计时,绘制渲染性能是一个非常大的问题,以致 React Native 被放弃来达到支持原生体验。

    四、滞后于原生平台

    因为它不是与 iOS 或 Android 一起构建的,所以 React Native 有时会落后于原生平台。它通常很大程度上依赖于社区来支持新的原生功能。

    其中一个例子就是迫切需要为 iPhone X 设备提供 SafeArea 支持。我们最终选择在短时间内不使用 SafeArea 支持该功能。使用 SafeAreaView 是跨平台开发人员需要了解的开发兼容应用程序的平台特定功能的一个示例。

    在其他时候,React Native 在采用新平台要求方面落后,例如要求在 2018 年 8 月之前针对 api 26 开发 Android 应用程序。这个需求尚有几个未解决的问题。

    五、打破更新

    React Native 的非向后兼容升级非常令人沮丧。一个例子是当 React Native 升级它的底层 React 库时 PropType 被弃用。

    如果不再维护我们自己的自定义分支,许多第三方库就会变得无法使用。


    640?wx_fmt=png

    维护挑战


    维护代码库的 React Native 部分有时对我们来说是一个挑战。如前所述,Android 通常需要额外的工作,无论是与现有代码集成还是修复 UI 适配问题。这导致 iOS 和 Android 在 React Native 代码库的不同分支上工作,因此一个平台不会减慢另一个平台的步伐。

    由于这种分支,代码的分歧开始慢慢形成,并且使它们达到奇偶校验所需的努力有所增加。结果,对一个平台的更新没有立即添加到另一个平台。

    React Native 的变化速度也带来了挑战。由于可能会破坏更改,因此更新依赖项以获取新功能或错误修复并不总是很快。

    同样,有时这会导致冲突增加,从而减慢代码的维护速度。由于团队规模小,精力有限,如果它不是 React Native 代码中的简单/快速修复,由于可能需要额外的开发工作,它的处理可能性要低得多。

    添加 React Native 之后,并不总是清楚错误存在于什么级别。它是否存在于两个平台中?还是只在一个平台上?如果仅在一个平台上,是在原生代码还是 React Native 代码中?这些问题增加的复杂性有时会减慢质量保证过程。

    当需要修复代码库的 React Native 部分中的问题时,我们现在必须同时考虑 iOS 和 Android,并且可能使用 3 个开发堆栈而不是 1 个。

    此外,只有不到 100%的团队感觉 React Native 效率很高,能够迅速进入并修复某些东西的开发人员的数量也减少了。


    640?wx_fmt=png

    我们能够做些什么?


    我相信我们遇到的一些问题是我们的用例所特有的,但是我们可以做些不同的事情来缓解其中的一些问题。

    一、减少分歧

    我们本可以更好地保持每个应用程序与 React Native repo 中的最新更改保持同步。我相信保持这些更新同步将有助于增强我们为这些功能开发更强的真正的跨平台开发。

    在更多的设备上测试,特别是在 Android 上,这样能够在早期发现更多 UI / 性能问题,并允许我们在上线之前修复它们。通过在新需求开始工作之前解决问题,这也可以减少代码分歧的数量。

    二、更一致的设计

    从一开始就更具体的设计方案可能会改善功能的原生外观。其中一个具体示例是使用与其他原生应用程序一致的文本/边距值,而不是在新体验中选择新值并在两个平台上使用它。

    三、更好的团队理解

    对 React Native 不太熟悉的团队成员可能已经做了更多努力以适应额外的开发任务。这会增加能够快速解决代码问题的人数。


    640?wx_fmt=png

    是否有我们认为更合适的用例?


    我相信我们团队中没有任何人认为 React Native 没有它的优点。我当然相信 React Native 非常适合用例。

    • 你是否需要在两个平台上快速从头开始构建/构建新应用程序?

    • 你是否正在构建一个应用程序/功能,无论平台如何,其外观/行为都相同?

    你有没有想要为移动设备贡献的备用开发周期的 Javascript 开发人员?

    如果对这些问题中的任何一个回答“是”,React Native 可能是你的可行性选择。

    特别是,我认为如果你有 Javascript/React 的背景,并且正在寻找构建一个不需要太多原生代码的应用程序,那么 React Native 是一个非常有吸引力的选择。它将使您能够开始在移动设备上构建,而无需学习 2 种不同的技术栈。

    对于完全跨平台应用程序的开发,React Native 也是一个很好的选择。


    640?wx_fmt=png

    我们会再次使用 React Native 吗?


    iOS 和 Android 团队在这方面意见不一。

    一、iOS

    有可能。iOS 团队通常很高兴与 React Native 合作,并考虑使用它构建新功能。此外,在产品方面,我们产品经理对在 iOS 上运行的 React Native 解决方案比对 Android 更有信心。

    二、Android

    不会。理想情况下,Android 团队将来不会投入精力到 React Native。我们发现与 React Native 组件集成的过程很麻烦,并且感觉到所有 Android 设备的体验都不是很好。

    此外,还有一种倾向于坚持单一开发技术战的感觉,而不是在 Android 框架之上添加新的抽象层和可能的 bugs。

    我们的感觉是,React Native 在 Android 上运行新功能的速度更快,但从早期阶段到完美版本再到长期维护需要更长的时间。


    640?wx_fmt=png

    我们会再另一种跨平台解决方案吗?


    作为一个团队,我们可能不会在不久的将来投入跨平台开发。iOS 团队可以使用 React Native 构建一些东西,并且仍然限定于 iOS,因为他们团队通常更喜欢这种体验。

    个人而言,团队成员会继续关注 React Native 和 Flutter。随着 React Native 和 Flutter 等解决方案的不断发展,我们将继续为我们的团队评估它们。


    640?wx_fmt=png

    总结

    这就是我们今天所处的境地。

    我们对 React Native 如何适应我们的团队和路线图有了更好的理解。我们可以利用这些信息为我们团队的正确技术选择做出明智的判断。

    “我们能否明确地说出 React Native 是否适合你?没有。”

    我们看到了 React Native 的优点以及局限性。我们能否明确地说出 React Native 是否适合你?

    没有。

    但是,在评估 React Native 是否适用于你的项目时,希望我们的经验可以作为帮你带来一些额外参考点。

    声明:本文为作者投稿,版权归作者所有,如需转载,请联系原作者。

    640?wx_fmt=jpeg


    征稿啦

    CSDN 公众号秉持着「与千万技术人共成长」理念,不仅以「极客头条」、「畅言」栏目在第一时间以技术人的独特视角描述技术人关心的行业焦点事件,更有「技术头条」专栏,深度解读行业内的热门技术与场景应用,让所有的开发者紧跟技术潮流,保持警醒的技术嗅觉,对行业趋势、技术有更为全面的认知。

    如果你有优质的文章,或是行业热点事件、技术趋势的真知灼见,或是深度的应用实践、场景方案等的新见解,欢迎联系 CSDN 投稿,联系方式:微信(guorui_1118,请备注投稿+姓名+公司职位),邮箱(guorui@csdn.net)。


    ————— 推荐阅读 —————

    640?wx_fmt=jpeg

    640?wx_fmt=jpeg

    640?wx_fmt=png

    640?wx_fmt=gif

    640?wx_fmt=gif

    展开全文
  • 新公司采用React Native开发,所以就顺利入坑了… React Native启动白屏是一个很普遍但又很严重的问题,网上也有很多文章,这里就此问题,从分析到常用的解决方案做一个简单的总结。 先看图,白屏的现象: 图中...

    新公司采用React Native开发,所以就顺利入坑了…

    React Native启动白屏是一个很普遍但又很严重的问题,网上也有很多文章,这里就此问题,从分析到常用的解决方案做一个简单的总结。

    先看图,白屏的现象:

    白屏现象

    图中手机为ZTE星星2号(专用测试机,为嘛?因为公司没给配啊,还有自己买的,所以就是专用的喽),Andriod 4.4的,可以看到白屏现象很严重,最后用自己的华为mate9,Android 8.0系统进行了测试,依然存在白屏的现象。

    网上的解决方案,大概分为两种:

    • 对ReactRootView以及ReactInstanceManager进行预加载,也就是说在本地配置一个启动界面,然后开始预加载RN的核心引擎,等完毕后直接跳转到RN的主界面,RN的主界面拿到初始化好的ReactRootView直接进行加载。这种方案,自己尝试了下,并不可行,只是减少了白屏的显示时间,实际上依然会有一小段时间的白屏现象。另外,采用这种方式,RN中组件的生命周期会得不到正确的执行。

    • 在白屏上预先覆盖一张图片用于遮掩白屏,等到RN相关的ReactRootView初始化完毕后再移除掉,作者的博客:https://www.jianshu.com/p/78571e5435ec 此方案可行,测试了一下,确实解决了白屏的问题,但是我没选择此方案,因为我觉得还不够完美。

    下面就这两个方案做一下简单的分析。

    预加载方式

    我的React Native 版本号为0.53.3,ReactActivity是RN的入口

    ReactActivity源码

    public abstract class ReactActivity extends Activity
        implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
    
      private final ReactActivityDelegate mDelegate;
    
      protected ReactActivity() {
        //构造中初始化相关的委派类
        mDelegate = createReactActivityDelegate();
      }
    
      /**
       * Called at construction time, override if you have a custom delegate implementation.
       */
      protected ReactActivityDelegate createReactActivityDelegate() {
        return new ReactActivityDelegate(this, getMainComponentName());
      }
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //调用了委派类的onCreate方法
        mDelegate.onCreate(savedInstanceState);
      }
    }
    

    ReactActivityDelegate源码

    public class ReactActivityDelegate {
    
      public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) {
        mActivity = activity;
        mMainComponentName = mainComponentName;
        mFragmentActivity = null;
      }
    
      public ReactActivityDelegate(
        FragmentActivity fragmentActivity,
        @Nullable String mainComponentName) {
        mFragmentActivity = fragmentActivity;
        mMainComponentName = mainComponentName;
        mActivity = null;
      }
    
      protected @Nullable Bundle getLaunchOptions() {
        return null;
      }
    
      protected ReactRootView createRootView() {
        return new ReactRootView(getContext());
      }
    
      protected ReactNativeHost getReactNativeHost() {
        return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
      }
    
      public ReactInstanceManager getReactInstanceManager() {
        return getReactNativeHost().getReactInstanceManager();
      }
    
      protected void onCreate(Bundle savedInstanceState) {
        if (mMainComponentName != null) {
          //mMainComponentName一定不会为空,所以一定会执行loadApp方法
          loadApp(mMainComponentName);
        }
        mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
      }
    
      //RN的白屏问题就是出现在这里,两个比较耗时的函数分别为getReactNativeHost().getReactInstanceManager()和mReactRootView.startReactApplication,
      //预先缓存就是针对这里的,把这一步的操作,提前完成,然后用的时候,直接从内存开始加载
      protected void loadApp(String appKey) {
        if (mReactRootView != null) {
          throw new IllegalStateException("Cannot loadApp while app is already running.");
        }
        mReactRootView = createRootView();
        mReactRootView.startReactApplication(
          getReactNativeHost().getReactInstanceManager(),
          appKey,
          getLaunchOptions());
        getPlainActivity().setContentView(mReactRootView);
      }
    }
    

    ReactRootViewCacheManager工具类源码

    public class ReactRootViewCacheManager {
    
        private static HashMap<String,ReactRootView> rootViewHashMap = new HashMap<>();
    
        /**
         * 预加载RN渲染引擎
         * @param activity
         */
        public static void init(Activity activity,String moduleName){
            //包含了,立刻返回
            if(rootViewHashMap.containsKey(moduleName))return;
            //ReactRootView 直接new就可以了
            ReactRootView mReactRootView = new ReactRootView(activity);
            //在MainApplication中提前初始化ReactInstanceManager
            ReactInstanceManager reactInstanceManager = ((MainApplication) activity.getApplication()).getReactNativeHost().getReactInstanceManager();
            //第一个参数为ReactInstanceManager
            //第二个参数建议和RN主界面中getMainComponentName返回的内容一样,也就是此函数中的第二个形参moduleName
            //第三个参数为null即可
            mReactRootView.startReactApplication(reactInstanceManager,moduleName,null);
            rootViewHashMap.put(moduleName,mReactRootView);
        }
    
        /**
         * 获取指定的reactrootview
         * @param moduleName
         * @return
         */
        public static ReactRootView getReactRootView(String moduleName){
            ReactRootView reactRootView = rootViewHashMap.get(moduleName);
            if(reactRootView != null){
                ViewParent parent = reactRootView.getParent();
                if(parent != null && parent instanceof ViewGroup){
                    ((ViewGroup)parent).removeAllViews();
                }
            }
            return reactRootView;
        }
    }
    

    大概流程就是在本地的SplashActivity的onCreate中先调用ReactRootViewCacheManager.init方法,完成后在执行跳转到RN主界面即可,这里需要注意的细节,我们需要简单修改下ReactActivity的源码和ReactActivityDelegate的源码,怎么办?很简单,复制ReactActivity的源码到新创建的BaseReactActivity中,复制ReactActivityDelegate到BaseReactActivityDelegate中,并且把BaseReactActivity中的ReactActivityDelegate全部替换成BaseReactActivityDelegate即可。

    SplashActivity源码

    public class SplashActivity extends Activity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ReactRootViewCacheManager.init(this,MainActivity.COMPONENT_NAME);
            //因为ui线程是从上到下执行的,所以到这里了,就表示预加载成功
            startActivity(new Intent(this,MainActivity.class));
        }
    }
    

    BaseReactActivityDelegate源码只关注loadApp函数

    protected void loadApp(String appKey) {
            if (mReactRootView != null) {
                throw new IllegalStateException("Cannot loadApp while app is already running.");
            }
            String mainComponentName = ((BaseReactActivity) getPlainActivity()).getMainComponentName();
            //从缓存中读取初始化好的ReactRootView,如果不为空直接进行加载
            ReactRootView reactRootView = ReactRootViewCacheManager.getReactRootView(mainComponentName);
            if(reactRootView == null){
                mReactRootView = createRootView();
                mReactRootView.startReactApplication(
                        getReactNativeHost().getReactInstanceManager(),
                        appKey,
                        getLaunchOptions());
                getPlainActivity().setContentView(mReactRootView);
            }else{
                getPlainActivity().setContentView(reactRootView);
            }
    }
    

    第二种方案

    此方案不做代码演示了,相信大家已经明白其中的流程了,说下他存在的问题,依然会有白屏现象,只不过这白屏现象不是RN造成的,而是安卓App本身就有白屏。

    自己使用的方案就是解决安卓app启动白屏的思路,用到自定义主题,也就是android:windowBackground的属性。

    <!-- 主题的方式解决rn启动白屏问题 -->
    <style name="AppTheme.Main" parent="TranslucentTheme" >
        <item name="android:windowBackground">@drawable/splash</item>
    </style>
    
    
    <activity
            //配置主题
            android:theme="@style/AppTheme.Main"
            android:name=".activity.MainActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
            android:label="@string/app_name"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
     </activity>
     <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    

    看下最终效果图

    最终效果图

    遗留的问题和第二个解决方案类似,无法自由控制白屏的时间。

    展开全文
  • ReactNative开发——自定义组件定义组件我自定义了一个对话框,这个对话框的样子如图所示: 直接上代码:/** * 直接导出组件,不用写module.exports=ConfirmDialog */ export default class ConfirmDialog ...
  • React Native 三端(Web、iOS、Android)同构是指在不改动原 React Native 的代码下,让其在浏览器中运行出和在 React Native 环境下一样的页面。对于使用 React Native 开发的页面,如果又单独为 Web 平台重复写一...
  • 前言React Native 是最近非常火的一个话题,因为它的语法简介,跨平台等特性,赢得了各大平台的青睐,虽然前期是有一些坑。基本概念解释React 是一套可以用简洁的语法高效绘制 DOM 的框架,所谓的“高效”,是因为 ...
  • 在浏览器中我们可以通过&lt;a&gt;标签与url实现不同页面之间的跳转,利用浏览器的...React Navigation就是这样一个源于ReactNative社区的用于实现界面导航的js库。通过如下方法安装react navigation到你的...
  • react native实现登录...demo下载:react-native 完整实现登录功能1.完整目录2.实现的界面3.主界面的代码实现import React, { Component } from 'react'; import { ToolbarAndroid, AppRegistry, StyleSheet, Tex
  • (一)前言 前几节课程我们对于React Native的一些基础配置,开发工具以及调试,Android项目移植做了相关讲解,今天一起来学习一下另外一个比较重要的知识点,就是React Native项目签名打包。 刚创建的React Native...
  • (一)前言 现在几讲我们对于React Native一些基础做了相关讲解(例如:环境搭建,开发IDE,调试以及升级降级等),今天开始正式进入UI相关组件学习的阶段了。首先我们来讲一个非常基础的组件View。 刚创建的React Native...
  • 摘要 2015年是React Native发展的一年,2016年必定是React Native蓬勃的一年!2016年React Native很可能成为最为成功的开源技术之一。为什么React Native这么火呢?那么React Native相比H5、Native又有哪些优势呢?...
  • 来自俄罗斯新西伯利亚的开发者Dima日前在GitHub上开源了一款名为React Native Desktop的开发利器,可以让开发者使用React Native构建OS X桌面应用程序,并分享了自己研发所得的示例,项目截至目前已经收获了五千多...
  • 最近做了两个React Native(以后简称RN)的项目,重新Review一下相关的项目代码,期望下次使用的时候可以有更好的结构,更好的规范和约束已帮助大家减少bug,提高开发效率; ​ 在做了一些原生Android开发,iOS开发和基于...
  • 由于其他的原因,对于React Native相关的内容最近没有投入太多的关注,从去年年底出版了《React Native移动开发实战》后,对于React Native的关注就比较少了。最近由于公司之前的项目需要,所以React Native又重新...
  • 1 前言最近打算真的开始学习一下跨平台APP开发,一直在关注RN,因此也打算真的开始学习下(其实是笔者的公司也开始有这种跨平台的需求了,笔者在一家传统公司)。...需要的开发环境主要有node.js + react native +
  • 移动端应用高速发展, 本教程便是使用ReactNative开发的高性能基于原生应用跨Android与iOS两大平台的大型综合App。 本实战项目使用react native 开发招聘,房产,点餐,商城,二手车,本地商务的大型综合门户性...
  • 首先我们要有个概念:react native里面是兼容大部分我们在css里面用到的布局方式,此外接触过css里面flex布局方式的话,我们会发现react native内的flex布局方式基本上和css里的flex布局方式类似,所以不要觉得react...
1 2 3 4 5 ... 20
收藏数 60,046
精华内容 24,018
关键字:

reactnative