react-native 开发 ,打包, 调试

react-native 开发

目录:

  1. 环境搭建
  2. 使用react-navigation,reducx
  3. 打包
  4. 常见bug
  5. 调试技巧

环境搭建

1.ios环境:

brew update && brew doctor
xcode-select --install
brew install node
brew install watchman

安装xcode;

启动 Xcode,并在Xcode > Preferences > Locations菜单中检查一下是否装有某个版本的Command Line Tools
https://reactnative.cn/docs/assets/GettingStartedXcodeCommandLineTools.png

推荐一个安装homebrew地址
homebrew下载慢解决方案
设置xcode

2.安卓环境:

安装java-sdk
android-studio

Android Studio 需要 Java Development Kit [JDK] 1.8 或更高版本。你可以在命令行中输入 javac -version来查看你当前安装的 JDK 版本。
注:android-studio较复杂详细查看官网

3. 安装react-native官方脚手架:

npm install react-native-cli -g

开发:

创建项目:
  1. react-native init demo
  2. yarn
引入 react-navigation:
  1. yarn add react-navigation
  2. yarn add react-native-gesture-handler
  3. react-native link react-native-gesture-handler
引入:图标库react-native-vector-icons
  1. npm install react-native-vector-icons
  2. react-native link react-native-vector-icons
引入 redux
  1. npm install --save redux
  2. npm install --save react-redux
  3. npm install --save-dev redux-devtools
  4. npm add redux-thunk

react-native-redux.png

在使用 React Navigation 的项目中,想要集成 redux 就必须要引入 react-navigation-redux-helpers 这个库。
npm install --save react-navigation-redux-helpers

文件目录:

all;.png

使用react-navigation:

  1. 两个基础组件
import { createStackNavigator, createAppContainer } from "react-navigation";

const AppNavigator=createAppContainer(createStackNavigator({//路由
    HomePage:{
        screen:HomePage
    },
    Page1:{
        screen:Page1,
        navigationOptions:(navigation => ({
            title:`页面名`
        }))
    },
    
   
}))
export default class App extends React.Component {
    render() {
      return <AppNavigator/>;
    }
  }

  1. 三个高阶组件
createSwitchNavigator

应用场景初始化app的时候使用,比如前几秒的广告或者logo

import {
  createStackNavigator, 
    createAppContainer,
    createSwitchNavigator,//切换路由导航
    createMaterialTopTabNavigator, //顶部导航
    createBottomTabNavigator, //底部导航
    createDrawerNavigator,// 抽屉
    DrawerItems,// 抽屉
} from "react-navigation";

const InitNavigator = createStackNavigator({// app初始化显示的路由
  WelcomePage: {
      screen: WelcomePage,
      navigationOptions: {
        header: null,
    }
  }
},{
  navigationOptions: {
      // header: null,// 可以通过将header设为null 来禁用StackNavigator的Navigation Bar
  }
})

const MainNavigator = createStackNavigator({// 业务路由
  WelcomePage: {
      screen: HomePage,
      navigationOptions: {
          header: null,
      }
  },
  DetailPage: {
    screen: DetailPage,
    navigationOptions: {
      title: 'DetailPage',
      headerBackTitle: null
        // header: null,
    }
  },
})

export const AppNavigator = createAppContainer(createSwitchNavigator({
  Init: InitNavigator,
  Main: MainNavigator,
}, {
  initialRouteName: 'Init',
}))

export default class App extends React.Component {
    render() {
      return <AppNavigator/>;
    }
  }

createBottomTabNavigator

底部导航
image

import MaterialIcons from 'react-native-vector-icons/MaterialIcons'// 图标库

const AppBottomNavigator = createBottomTabNavigator({下面bar
    PopularPage:{
      screen:PopularPage,
      navigationOptions:{
        tabBarLabel:"最热",
        tabBarIcon:({tintColor,focused})=>(
          <MaterialIcons
            name={"whatshot"}
            size={26}
            style={{
              color:tintColor
            }}
          />)

      }
    },
    ....
},
{
    tabBarOptions: {
        tabStyle: {
            minWidth: 50
        },
        upperCaseLabel: false,//是否使标签大写,默认为true
        scrollEnabled: true,//是否支持 选项卡滚动,默认false
        // activeTintColor: 'white',//label和icon的前景色 活跃状态下(选中)
        // inactiveTintColor: 'gray',//label和icon的前景色 活跃状态下(未选中)
        style: {
            backgroundColor: '#678',//TabBar 的背景颜色
        },
        indicatorStyle: {
            height: 2,
            backgroundColor: 'white',
        },//标签指示器的样式
        labelStyle: {
            fontSize: 13,
            marginTop: 6,
            marginBottom: 6,
        },//文字的样式
    },
}
)
createMaterialTopTabNavigator

顶部导航
image

const AppTopNavigator=createMaterialTopTabNavigator({//上面bar
    Page1: {
        screen: Page1,
        navigationOptions: {
            tabBarLabel: 'java',
            
        }
    },
    Page2: {
        screen: Page2,
        navigationOptions: {
            tabBarLabel: 'android',
            
        }
    },
    Page3: {
        screen: Page4,
        navigationOptions: {
            tabBarLabel: 'ios',
            
        }
    },
},
{
    tabBarOptions: {
        tabStyle: {
            minWidth: 50
        },
        upperCaseLabel: false,//是否使标签大写,默认为true
        scrollEnabled: true,//是否支持 选项卡滚动,默认false
        // activeTintColor: 'white',//label和icon的前景色 活跃状态下(选中)
        // inactiveTintColor: 'gray',//label和icon的前景色 活跃状态下(未选中)
        style: {
            backgroundColor: '#678',//TabBar 的背景颜色
        },
        indicatorStyle: {
            height: 2,
            backgroundColor: 'white',
        },//标签指示器的样式
        labelStyle: {
            fontSize: 13,
            marginTop: 6,
            marginBottom: 6,
        },//文字的样式
    },
}
)


  1. 跳转和传值
export default class HomePage extends Component{
  render() {
    const {navigation} = this.props;
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Welcome to HomePage</Text>
        <Button 
        title={"gopage1"}
        onPress={()=>{
            navigation.navigate("Page1",{name:"动态的"})
        }}
        />
        <Button 
        title={"goback"}
        onPress={()=>{
          navigation.goBack();
        }}
        />
      </View>
    );
  }
}
 //目标页面获取值,setParams是改变当前页面的params
const {navigation} = this.props;
const {state, setParams} = navigation;
const {params} = state;

redux

  1. js/App.js
import React, {Component} from 'react';
import {Provider} from 'react-redux';
import AppNavigator from './navigation/AppNavigators';
import store from './store'

type Props = {};
export default class App extends Component<Props> {
    render() {
        /** * 将store传递给App框架 */
        return <Provider store={store}>
            <AppNavigator/>
        </Provider>     }
}

文件输出口,store和navigation输出配置到这个页面

  1. js/action/action.js
import { onThemeChange,onShowMyName } from './theme'
export default {
    onThemeChange,
    onShowMyName
}

输出事件的操作

  1. js/reducer/theme/
    theme.js=>
import Types from '../../action/types';
const defaultState = {
    theme: "blue",
    name: "no name"
}
export default function onAction(state =defaultState, action ){
    switch (action.type){
        case Types.THEME_CHANGE:
            return {
                ...state,
                theme: action.theme
            };
            case Types.NAME_CHANGE:
            return {
                ...state,
                name: action.name
            };
        default:return state;    
    }
}
    

js/reducer/index.js=>

import {combineReducers} from 'redux'
import theme from './theme'
import {rootCom, RootNavigator} from '../navigation/AppNavigators';

//1.指定默认state,获取路由信息
const navState = RootNavigator.router.getStateForAction(RootNavigator.router.getActionForPathAndParams(rootCom));
/** * 2.创建自己的 navigation reducer, */
const navReducer = (state = navState, action) => {
    
    const nextState = RootNavigator.router.getStateForAction(action, state);

    // 如果`nextState`为null或未定义,只需返回原始`state`
    return nextState || state;
};

/** * 3.合并reducer * @type {Reducer<any> | Reducer<any, AnyAction>} */
const index = combineReducers({
    nav: navReducer,
    theme: theme,
});

export default index;

修改数据,合并所有reducer

  1. js/store/index.js
import {applyMiddleware, createStore} from 'redux'
import thunk from 'redux-thunk'
import reducers from '../reducer'
import {middleware} from '../navigation/AppNavigators'

const logger = store => next =>  action =>{ // 自定义中间件
    if( typeof action === 'function' ) {
        
    } else {
    // console.log("action",action)

    }
    const resut =next( action );
    // console.log("state",store.getState())
}
 
const middlewares = [
    middleware,
    logger,
    thunk
];
/** * 创建store */ 
export default createStore(reducers, applyMiddleware(...middlewares));

创建store

redux+react-navigation使用

1.配置Navigation

import React from 'react';
import {createStackNavigator, createSwitchNavigator} from 'react-navigation';
import {connect} from 'react-redux';
import {createReactNavigationReduxMiddleware, createReduxContainer} from 'react-navigation-redux-helpers';

export const rootCom = 'Init';//设置根路由

export const RootNavigator = createSwitchNavigator({
   ...
});

/** * 1.初始化react-navigation与redux的中间件, * 该方法的一个很大的作用就是为reduxifyNavigator的key设置actionSubscribers(行为订阅者) * 设置订阅者@https://github.com/react-navigation/react-navigation-redux-helpers/blob/master/src/middleware.js#L29 * 检测订阅者是否存在@https://github.com/react-navigation/react-navigation-redux-helpers/blob/master/src/middleware.js#L97 * @type {Middleware} */
export const middleware = createReactNavigationReduxMiddleware(
state => state.nav,
    'root'
    
);
 
/** * 2.将根导航器组件传递给 reduxifyNavigator 函数, * 并返回一个将navigation state 和 dispatch 函数作为 props的新组件; * 注意:要在createReactNavigationReduxMiddleware之后执行 */
const AppWithNavigationState = createReduxContainer(RootNavigator, 'root');

/** * State到Props的映射关系 * @param state */
const mapStateToProps = state => ({
    state: state.nav,//v2
});
/** * 3.连接 React 组件与 Redux store */
export default connect(mapStateToProps)(AppWithNavigationState);

  1. 配置Reducer
import {combineReducers} from 'redux'
import theme from './theme'
import {rootCom, RootNavigator} from '../navigator/AppNavigators';

//1.指定默认state
const navState = RootNavigator.router.getStateForAction(RootNavigator.router.getActionForPathAndParams(rootCom));

/** * 2.创建自己的 navigation reducer, */
const navReducer = (state = navState, action) => {
    const nextState = RootNavigator.router.getStateForAction(action, state);
    // 如果`nextState`为null或未定义,只需返回原始`state`
    return nextState || state;
};

/** * 3.合并reducer * @type {Reducer<any> | Reducer<any, AnyAction>} */
const index = combineReducers({
    nav: navReducer,
    theme: theme,
});

export default index;

3.配置store

import {applyMiddleware, createStore} from 'redux'
import thunk from 'redux-thunk'
import reducers from '../reducer'
import {middleware} from '../navigator/AppNavigators'

const middlewares = [
    middleware,
];
/** * 创建store */
export default createStore(reducers, applyMiddleware(...middlewares));

4.在组件中应用

import React, {Component} from 'react';
import {Provider} from 'react-redux';
import AppNavigator from './navigator/AppNavigators';
import store from './store'

type Props = {};
export default class App extends Component<Props> {
    render() {
        /** * 将store传递给App框架 */
        return <Provider store={store}>
            <AppNavigator/>
        </Provider>     }
}

5.订阅state

import React from 'react';
import {connect} from 'react-redux';

class TabBarComponent extends React.Component {
    render() {
        return (
            <BottomTabBar
                {...this.props}
                activeTintColor={this.props.theme}
            />         );
    }
}

const mapStateToProps = state => ({
    theme: state.theme.theme,
});

export default connect(mapStateToProps)(TabBarComponent);

6.触发action改变state

import React, {Component} from 'react';
import {connect} from 'react-redux'
import {onThemeChange} from '../action/theme'
import {StyleSheet, Text, View, Button} from 'react-native';

type Props = {};
class FavoritePage extends Component<Props> {
    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.welcome}>FavoritePage</Text>                 <Button
                    title="改变主题色"
                    onPress={() => {
                        // let {dispatch} = this.props.navigation;
                        // dispatch(onThemeChange('red'))
                        this.props.onThemeChange('#096');
                    }} 
                />             </View>         );
    }
}

const mapStateToProps = state => ({});

const mapDispatchToProps = dispatch => ({
    onThemeChange: (theme) => dispatch(onThemeChange(theme)),
});
export default connect(mapStateToProps, mapDispatchToProps)(FavoritePage);

7.处理安卓物理返回键

import React, {Component} from 'react';
import {BackHandler} from "react-native";
import {NavigationActions} from "react-navigation";
import {connect} from 'react-redux';
import DynamicTabNavigator from '../navigator/DynamicTabNavigator';
import NavigatorUtil from '../navigator/NavigatorUtil';

type Props = {};

class HomePage extends Component<Props> {
    componentDidMount() {
        BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
    }

    componentWillUnmount() {
        BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
    }

    /** * 处理 Android 中的物理返回键 * https://reactnavigation.org/docs/en/redux-integration.html#handling-the-hardware-back-button-in-android * @returns {boolean} */
    onBackPress = () => {
        const {dispatch, nav} = this.props;
        //if (nav.index === 0) {
        if (nav.routes[1].index === 0) {//如果RootNavigator中的MainNavigator的index为0,则不处理返回事件
            return false;
        }
        dispatch(NavigationActions.back());
        return true;
    };

    render() {
        return <DynamicTabNavigator/>;
    }
}

const mapStateToProps = state => ({
    nav: state.nav,
});

export default connect(mapStateToProps)(HomePage);

打包

  1. 安卓:
// 1.android/app目录下,执行cmd命令
$ keytool -genkeypair -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000

// 2.把签名配置加入到项目的 gradle 配置中编辑你项目目录下的android/app/build.gradle,添加如下的签名配置:
...
android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file('my-release-key.keystore')
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias my-key-alias
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}

// 3. 配置打包命令到package.js,并执行
 "scripts": {
    ...
    "build_android": "cd android && ./gradlew assembleRelease",//打包
    "clear_android": "./gradlew clear" // 重新打包需要先执行这个命令
 }

// 4.针对不同的 CPU 架构生成 APK 以减小 APK 文件的大小
// 在android/app/build.gradle中来生成针对不同 CPU 架构的 APK。
- ndk {
-   abiFilters "armeabi-v7a", "x86"
- }
- def enableSeparateBuildPerCPUArchitecture = false
+ def enableSeparateBuildPerCPUArchitecture = true
+ 
+ def enableProguardInReleaseBuilds = true
// 5. 生成的 APK 文件位于
android/app/build/outputs/apk/release/app-release.apk,
它已经可以用来发布了。
  1. ios:

https://www.jianshu.com/p/5bdce8da4d88

调试技巧

  1. 安卓开发推荐使用真机调试(打开开发者选项,),加react-native官方启动命令:react-native run-android(adb devices 可以查看是否有可用的安卓模拟器)

  2. ios开发推荐使用,打开xcode,进行调试(真机调试较慢,react-native官方启动命令react-native run-ios:又慢又会启动失败(ノへ ̄、))

调试常见的bug

  1. *检测文件是报错,更新电脑不更新代码(出现场景,打开项目就报错了):关闭一下终端,用xcode(or react-native run-android)重启软件

  2. react-navigation:createAppContainer独立页面是用的时候需要加入

  3. Invariant Violation: View config not found for name tabNavigator(有问题的变量名). Make sure to start component names with a capital letter:
    有问题的变量名(首字母大写)

  4. *引入的包出现问题的时候:https://github.com/facebook/react-native/issues/4968

  5. 没有正确引入报错的时候(一般出现在依赖的依赖需要被页面导入时)比如:
    https://stackoverflow.com/questions/52071280/error-while-running-react-native-app?r=SearchResultsimage.png

  6. *用React native编译IOS 报错:Application AwesomeProject has not been registered

解决:控制台窗口,关闭xcode,重新编译

  1. *打包安卓出现 Keystore was tampered with, or password was incorrect

检查文件路径,参数是否正确

  1. 卸载androidStudio

https://www.jianshu.com/p/17ce8f0ad542

  1. .未完待续

调试用的demo

AwesomeProject(简单react-navigation使用包括bottom,top,switch,navigator;高性能列表FlatList,)
image

rnNavigationText(高阶react-navigation使用)
wx20190429-184155@2x.png

rnReduxTest(react-navigation+redux如何使用开发;Fetch使用;AsyncStorage离线缓存;封装离线缓存框架等)
wx20190429-185040@2x.png

ps:点击鼠标左键,进入下载页

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值