IT学徒、技术民工、斜杠青年,机器人爱好者、摄影爱好 PS、PR、LR、达芬奇潜在学习者
共 212 篇文章
React Native是目前移动端跨平台开发的选择之一,另一种是Flutter,目前安卓平台还是以Android原生开发和java为主,IOS端以Object-c和Swift为主,ReactNative作为一种新的跨平台开发方式,目前可使用的包还不多,但是我认为对于个人开发者还是比较方便的,所以这里把我实现的方式(因为真的很烦)
一定要翻墙 !一定要翻墙!一定要翻墙!
因为配置的工具比较多,各软件版本一定要对!各软件版本一定要对!各软件版本一定要对!
重要的事情说三遍!重要的事情说三遍!重要的事情说三遍!(所以这句话为什么要说三遍?因为很重要!因为很重要!因为很重要!(禁止套娃))
不然你就会像我一样,装了删,删了重装,关键你还不知道到底是五个工具哪个有问题(往事不要再提)
python是免费的
https://www.oracle.com/java/technologies/javase-jdk8-downloads.html
npm install -g react-native-cli
测试连接设备
adb devices
react-native init [文件名]
cd [文件名]
npx react-native run-android
(如果你看到这里了,无论你看到上面多么复杂,难受,可以忽略了)
目前官方推荐使用第二种
使用Expo方式安装和使用
npm install -g create-react-native-app
创建项目
create-react-native-app appName
cd appName
启动项目
npm start
启动项目后会生成二维码
手机端下载安装App,打开App扫描二维码,等待加载完成,即可热刷新
注意:
react-native官方的导航器
npm install @react-navigation
React Navigation带有三种默认的navigator。
StackNavigator
- 为应用程序提供了一种页面切换的方法,每次切换时,新的页面会放置在堆栈的顶部TabNavigator
- 用于设置具有多个Tab页的页面DrawerNavigator
- 用于设置抽屉导航的页面stackNavigator是最常用的一种navigator
import React from 'react';
import { View, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';
const HomeScreen = () => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
const DetailsScreen = () => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
const RootNavigator = StackNavigator({
Home: {
screen: HomeScreen,
},
Details: {
screen: DetailsScreen,
},
});
export default RootNavigator;
tab导航栏
import React from 'react';
import { View, Text } from 'react-native';
import { TabNavigator } from 'react-navigation'; // 1.0.0-beta.14
import Ionicons from 'react-native-vector-icons/Ionicons'; // Supported builtin module
const HomeScreen = () => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
const ProfileScreen = () => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile Screen</Text>
</View>
);
const RootTabs = TabNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
Profile: {
screen: ProfileScreen,
navigationOptions: {
tabBarLabel: 'Profile',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
});
export default RootTabs;
抽屉导航栏
import React from 'react';
import { View, Text } from 'react-native';
import { DrawerNavigator } from 'react-navigation'; // 1.0.0-beta.14
import Ionicons from 'react-native-vector-icons/Ionicons'; // Supported builtin module
const HomeScreen = () => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
const ProfileScreen = () => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile Screen</Text>
</View>
);
const RootDrawer = DrawerNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
drawerLabel: 'Home',
drawerIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
Profile: {
screen: ProfileScreen,
navigationOptions: {
drawerLabel: 'Profile',
drawerIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-person' : 'ios-person-outline'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
});
export default RootDrawer;
导入包
yarn add @react-navigation/bottom-tabs
<Stack.Screen
name="Home"
component={Home}
options={{
headerTitle: '首页',
headerLeft: () => (
<Button
onPress={() => alert('This is a button!')}
title="我"
color="#f56f"
/>
),
headerRight: () => (
<Button
onPress={() => alert('This is a button!')}
title="I扫一扫"
color="#35ff"
/>
),
}}
/>
安装包
yarn add @react-navigation/drawer
导入包
import {
createDrawerNavigator, //创建侧边栏必备
DrawerContentScrollView, //创建内容
DrawerItemList, //创建项目条
} from '@react-navigation/drawer';
三种方法:fetch、 axios、async await
这里用axios
安装包
安装包
npm i react-native-swiper –save
导入包
import Swiper from ‘react-native-swiper’;
github源地址
https://github.com/leecade/react-native-swiper
<View style={styles.swiper}>
<Swiper showsButtons={true} autoplay={true}>//设置自动轮播、轮播按钮
<View style={styles.slide1} >
<Text style={styles.text}>Hello Swiper</Text>
{/* <Image source={{ uri:'http://q6mb9zdoi.bkt.clouddn.com/linux.jpg' }}></Image> */}
</View>
<View style={styles.slide2}>
<Text style={styles.text}>Beautiful</Text>
</View>
<View style={styles.slide3}>
<Text style={styles.text}>And simple</Text>
</View>
</Swiper>
</View>
安装包
yarn add react-native-image-picker
导入包
import ImagePicker from 'react-native-image-picker';
使用
Git hub源地址:https://github.com/react-native-community/react-native-image-picker
https://github.com/lesliesam/react-native-wheel-picker
安装包
npm i react-timer-mixin --save
react native的webrtc包
安装
npm install react-native-webrtc --save
使用RN的typescript模版生成项目
npx react-native init MyApp --template react-native-template-typescript
github 地址:https://github.com/react-native-community/react-native-template-typescript
修改package.json文件
"dependencies": {
// ...模板自带的包
// ...
"@react-native-community/async-storage": "1.9.0", // 相当于localStorage(可选)
"@react-native-community/masked-view": "0.1.9", // 路由所需要的包 (必须)
"@react-navigation/stack": "5.2.10", // 路由所需要的包 (必须)
"react": "16.11.0",
"react-dom": "16.11.0",
"react-native": "0.62.2",
"react-native-gesture-handler": "1.6.0", // 路由所需要的包,原生手势系统 (必须)
"react-native-reanimated": "^1.8.0", // 路由所需要的包 (必须)
"react-native-safe-area-context": "0.7.3", // 路由所需要的包 (必须)
"react-native-screens": "^2.3.0", // 路由所需要的包 (必须)
"react-native-webview": "8.0.0", // RN打开webView容器,原生调用 (可选)
"react-redux": "5.0.7",
"redux": "4.0.0",
"redux-thunk": "2.3.0"
},
"devDependencies": {
// ...模板自带的包
// ...
"@babel/plugin-transform-runtime": "^7.9.0", // babel的插件包(必须)
"@babel/preset-typescript": "^7.9.0", // babel的编译ts(必须)
"@react-navigation/core": "3.4.2", // rn路由在H5里运行的核心包(必须)
"@react-navigation/web": "1.0.0-alpha.8", // rn路由在H5里运行的核心包(必须)
"babel-loader": "^8.1.0", // webpack loader(必须)
"file-loader": "3.0.1", // webpack loader(必须)
"html-webpack-plugin": "^4.2.0", // webpack plugin(必须)
"react-native-web": "0.12.2", // rn组件映射为WEB的dom(必须)
"webpack": "4.42.1", // 打包rn项目到h5(必须)
"webpack-cli": "3.3.2", // 打包rn项目到h5(必须)
"webpack-dev-server": "3.5.1" // 调试rn项目到h5(必须)
},
https://juejin.cn/post/6844904130851373063#heading-6
useAppState
查看app状态是在后台还是打开中
import { useAppState } from '@react-native-community/hooks'
const currentAppState = useAppState()
npm install -g exp
exp login (此处需要在expo官网注册账号,然后登录)
配置app.json
{
"expo": {
"name": "Your App Name",
"icon": "./path/to/your/app-icon.png",
"version": "1.0.0",
"slug": "your-app-slug",
"sdkVersion": "XX.0.0",
"ios": {
"bundleIdentifier": "com.yourcompany.yourappname"
},
"android": {
"package": "com.yourcompany.yourappname"
}
}
}
exp build:android
原生打包有两种方式,一是React Native内打包,二是Android Studio打包,这里采用React Native打包,Android Studio打包以后更新(我看了好几篇博客,听说AS打包很慢,而且会常常出错。
1.生成Android签名证书
进入JDK/bin目录,在目录下打开cmd窗口执行命令:
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
执行后设置密钥库密码以及发布信息,记住密码,my-release-key是生成apk的名字。
密钥库里应该已经生成了一个单独的密钥,有效期为10000
天
2.设置Gradle变量
在/android/gradle.properties
文件末尾加入代码
MYAPP_RELEASE_STORE_FILE=your keystore filename
MYAPP_RELEASE_KEY_ALIAS=your keystore alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****
等号右边的部分用自己的项目替换
3.修改Gradle配置文件
在/android/app/build.gradle
下添加以下代码
4.签名打包APK
在项目的android
目录下启动终端,运行命令
./gradlew assembleRelease
自动进行打包
5.将APK发送到手机上执行
打包成功的APK文件默认安装在/[项目名]/android/app/build/outputs/apk/
下,后缀为.apk,
打包博客链接
https://www.jianshu.com/p/1380d4c8b596
rn 官方的默认推荐方式是大家使用 rn 开发并作为独立的 app 使用,但是对于较大体量的 app 考虑到框架迁移的成本以及对技术保持怀疑的态度 都不会直接使用 rn 开发一个独立的 app;反而更多的是将 rn 作为内部的一些独立模块/页面.
熟悉 rn 的同学应该都清楚,想要 rn 页面在 app 中启动需要内置其一堆底层框架,或者 rn 的 jsbundle; 而内置 rn 的 jsbundle 又分为两种,其优缺点也都较为明显
jsbundle 全量内置
jsbundle 部分内置
采用jsbundle 部分内置,资源动态下发的方式,我们简单介绍一下其整体的思路:
我们主要从如下几个方面考虑做性能优化:
rn 的 bundle 由哪些部分组成: 图片资源 + bundle;
而一个 bundle 又由: 全局变量声明+polyfill+模块定义+require四部分组成
优化的思路大致有如下几个方向:
抽离公共包
使用 metro 的processModuleFilter
过滤掉哪些我们不需要打包到业务 bundle 的模块
const commonModules = ["react", "react-native", "redux", "自己的业务模块"];
// 一个简单的例子
function processModuleFilter(module) {
//过滤掉path为base-modules的一些模块(基础包内已有)
if (module["path"].indexOf("base-modules") >= 0) {
return false;
}
//过滤掉node_modules内的一些通用模块(基础包内已有)
for (const ele of commonModules) {
if (module["path"].indexOf("node_modules" + ele) > 0) {
return false;
}
}
//其他就是应用代码
return true;
}
Module diff
module diff
的主要思路为必须前后两次构建的资源包,进行 module diff;这样下发 jsbundle 的时候只下发增量部分。这里一般主要和离线包进行配合使用,要考虑的有:
https://juejin.cn/post/6964607946336501797#heading-4
Fabric 是 React Native 新的架构中渲染器,是新架构的主要部分,也是新旧架构中变化最大的地方。
在使用 react
开发的时候,对于 react-dom
,我们都再熟悉不过。Web 端我们几乎都能看到 ReactDOM.render
作为 react
框架渲染的入口
react-dom
作为一个独立的库,担起了 react
和 Web
之间的桥梁。在 react
的 render 和 commit 阶段, react-dom
会创建或更新 DOM 树,并且最终渲染到 Web
页面上
react-dom = react-native-renderer + fabric + native api
在 React-Native
应用中,我们似乎并没有见到类似 ReactDOM.render
的入口,经常看到的是
AppRegistry.registerComponent(appName, () => App);
如果我们在 react-native
源码中顺着 AppRegistry.registerComponent
看下去,可以找到这样一段代码
// Libaries/ReactNative/renderApplication.js
if (fabric) {
require('../Renderer/shims/ReactFabric').render(
renderable,
rootTag,
null,
useConcurrentRoot,
);
} else {
require('../Renderer/shims/ReactNative').render(renderable, rootTag);
}
看到这里,就看到了熟悉的 render
方法。暴露这个 render
方法的是 ReactFabric
和 ReactNative
这两个文件。这两个也正分别是 React Native 新旧两种架构下的渲染器
react-native-renderer
和 react
配合,在 react
的 render 和 commit 阶段共同工作,但是这次不同的是,针对 Native(Android/iOS) 环境,不需要 react-native-renderer
去生成 DOM 树,而是转换为 Native 能理解的树形结构,我们称之为 Shadow Tree
。因为 Shadow Tree
要依赖 Yoga(C++ 库)
去计算 layout
,因此 Shadow Tree
要维护在 C++ 侧或原生侧。这就迎来了我们的主角 Fabric
Fabric 渲染器承担起了生成 Shadow Tree
和调用 Yoga
计算 layout 的主要工作。 react-native-renderer
在与 react
配合时,会有创建和更新 Shadow Tree
节点的需要,这时就只需要调用 Fabric
暴露给 JS 侧的方法,就可以轻松的同步完成
Fabric 的两大转变:
JSI
的存在, react-native-renderer
作为 JS 代码,能够畅通无阻的调用 Fabric
的 C++ 代码。关于 Bridge 通信和 JSI,可以参考之前的文章。quark-design:https://quark-design.hellobike.com/#/zh-CN/component/cell-react