通过第一部分开发 React Native APP —— 从改造官方 Demo 开始(一)介绍,App 框架基本构建完成,这部分主要讨论 UI/交互、App 发布前的准备工做及如何发布,具体内容包括:html
完整 demo 在这 react-native-complete-demojava
这里的扩展指的是实现可单独配置页面的进入方式(react navigation 默认只支持全局配置,要么 card
,要么 modal
,配置后全部页面进入动画相同)。react
实现上述效果须要作两方面修改:StackNavigator
API(在 route.js
中使用)和进入某个页面是的调用方式。android
StackNavigator
API修改后若是使页面默认状态为 card,只须要输入对应页面便可,好比 ..navigate('ScreenSome1')
;若是要使某个页面进入方式为 modal 只须要在路径上加上 Modal 好比:..navigate('ScreenSome2Modal')
。ios
须要注意的是若是页面进入方式为 modal,须要自定义 header,由于默认 header 样式失效,都叠在一块了。git
/** * route.js * 自定义 StackNavigator,能够选择 screen 进入方式 */ const StackModalNavigator = (routeConfigs, navigatorConfig) => { const CardStackNavigator = StackNavigator(routeConfigs, navigatorConfig); const modalRouteConfig = {}; const routeNames = Object.keys(routeConfigs); for (let i = 0; i < routeNames.length; i++) { modalRouteConfig[`${routeNames[i]}Modal`] = routeConfigs[routeNames[i]]; } const ModalStackNavigator = StackNavigator( { CardStackNavigator: { screen: CardStackNavigator }, ...modalRouteConfig }, { // 若是页面进入方式为 modal,须要自定义 header(默认 header 样式失效,都叠在一块了) mode: "modal", headerMode: "none" } ); return ModalStackNavigator; }; // 设置路由 const AppNavigator = StackModalNavigator();
首先咱们新建页面 ScreenSome2
,接下来就让它以 modal 的形式进入(从屏幕下面进入),做为对比 ScreenSome1
以 card
的形式进入(默认进入方式,从屏幕右侧进入)。github
由于以 modal 形式进入的页面须要自定义 header,通常只是一个关闭按钮,以 ScreenSome2
为例:segmentfault
/** * ScreenSome2/view.js * 自定义 header(关闭按钮) */ <View> {/* TouchableHighlight 为关闭按钮的热区 */} <TouchableHighlight onPress={() => self.navigation.goBack()} underlayColor="transparent" style={{ display: "flex", justifyContent: "center", marginTop: pxToDp(30), width: pxToDp(150), height: pxToDp(90), backgroundColor: "yellow" }} > <Text style={{ marginLeft: pxToDp(24) }}>关闭</Text> </TouchableHighlight> <Text style={{ fontSize: pxToDp(36) }}>some2,以 modal 的形式进入</Text> </View>
而后就是更改进入 ScreenSome2
代码,这里是 ScreenHome
页面中的代码:react-native
/** * ScreenHome/view.js * 自定义 header(关闭按钮) */ { /* ScreenSome2 从屏幕右侧进入 */ } <Button title="goSome1" onPress={() => self.navigation.navigate("ScreenSome1")} />; { /* ScreenSome2 从屏幕下面进入 */ } <Button title="goSome2Modal" onPress={() => self.navigation.navigate("ScreenSome2Modal")} />;
最终效果图:android-studio
自适应主要包括两方面:尺寸根据屏幕大小自适应,包括 fontSize
,width
等;图片分辨率根据屏幕分辨率自适应,也就常说的二倍图、三倍图等。
尺寸自适应的原理是经过获取手机屏幕的宽度,尺寸作相应比例的调整,为此封装了一个工具函数,放在了 config/pxToDp.js
中。
调整后的目录以下:
config/pxToDp.js
尺寸转换的工具函数尺寸转换的工具函数在第一部分 开发 React Native APP —— 从改造官方 Demo 开始(一)已经添加
1)编写自适应尺寸工具函数
由于全部涉及尺寸的数据都要转换(fontSize
,width
等),因此对转换后的数据要作处理,保证:1.大于等于 1 的数字向上取整;2.小于 1 的数字,若是是 ios 平台统一设为 0.5;若是是安卓平台统一设为 1(由于安卓平台分辨率千差万别万别,低分辨率的屏幕显示 0.5 的尺寸会有锯齿状)。工具函数完整代码以下:
/** * pxToDp.js * 自适应布局 * @param uiElementPx: ui给的原始尺寸 */ import { Dimensions, Platform } from "react-native"; // app 只有竖屏模式,因此能够只获取一次 width const deviceWidthDp = Dimensions.get("window").width; // UI 默认给图是 750 const uiWidthPx = 750; function pxToDp(uiElementPx) { const transferNumb = uiElementPx * deviceWidthDp / uiWidthPx; if (transferNumb >= 1) { // 避免出现循环小数 return Math.ceil(transferNumb); } else if (Platform.OS === "android") { // 若是是安卓,最小为1,避免边框出现锯齿 return 1; } return 0.5; } export default pxToDp;
实际上,经过Dimensions.get('window').width
获取的屏幕宽度和本身想象的可能有出入,好比,iphone7 屏幕 4.7'',获取到的宽度是375
,华为 P9 是 5.2',但获取到的宽度倒是是360
!有点坑,这个工具函数还有待优化。
2)使用自适应尺寸工具函数
使用方法很简单,在须要转换单位的组件中将转换尺寸的工具函数引入,将须要转换的尺寸传入工具函数便可,以 ScreenHome
为例:
/** * ScreenHome/view.js */ // 引入尺寸转换工具函数 import pxToDp from "../../config/pxToDp"; // 将须要转换的单位传入 pxToDp 中 <Text style={{ fontSize: pxToDp(36) }}>home</Text>;
手机分辨率愈来愈多,尤为安卓,React Native 能够根据不一样分辨率加载不一样尺寸的图片,只需在图片命名上面加以区分。
好比咱们有张图片叫 test.png
,尺寸为 40 x 40
(单位像素),为了作到自适应屏幕分辨率,咱们还须要提供它的 2 倍图,3 倍图,这样,一张图片就对应 3 个尺寸,以下:
# 一张图片提供 3个尺寸 test.png # 尺寸 40 x 40 test@2x.png # 尺寸 80 x 80 test@3x.png # 尺寸 120 x 120
name@nx
是 n (n > 1) 倍图命名规范,React Native 也是根据命名判断图片尺寸的。
在引用图片的时候直接使用 不加倍率后缀的图片名,好比,直接使用 test.png
,以下:
/** * ScreenTab3/view.js */ <Image source={require("../../assets/images/test.png")} style={{ height: pxToDp(80), width: pxToDp(80) }} />
最终效果图以下:
2X
字样)3X
字样)修改桌面图标、App 展现名称相对简单,设置启动页稍微麻烦。另外,iOS 修改桌面图标、App 展现名称,设置启动页都须要在 Xcode 中进行。
由于 App 图标对应多个尺寸,手动改写太麻烦,这个网站能够自动生成 MakeAppIcon。
并非全部尺寸的图片都须要,见下文。
准确点讲不能叫设置桌面图标,而应该是 App 图标,由于咱们须要设置的不止有桌面展现的图标,还有设置时 app 图标、消息推送时 app 图标,此外若是要发布到 App store,还须要设置 Apple Store 展现用的 App 图标。
1)图片准备
以上不一样地方用到的 app 图标尺寸各不相同,具体以下(只针对 iphone,不包括 ipad,iwatch):
尺寸 | 名称 | 用途 | 是否必须 |
---|---|---|---|
120x120 | Icon-60@2x.png | 桌面图标 (2x) | 必须 |
180x180 | Icon-60@3x.png | 桌面图标 (3x) | 可选,但推荐设置 |
80x80 | Icon-40@2x.png | Spotlight 图标 (2x) | 可选,但推荐设置 |
120x120 | Icon-40@3x.png | Spotlight 图标 (3x) | 可选,但推荐设置 |
58x58 | Icon-29@2x.png | 设置图标 (2x) | 可选,但推荐设置 |
87x87 | Icon-29@3x.png | 设置图标 (3x) | 可选,但推荐设置 |
40x40 | Icon-20@2x.png | 通知图标 (3x) | 可选,但推荐设置 |
80x80 | Icon-20@3x.png | 通知图标 (3x) | 可选,但推荐设置 |
1024x1024 | iTunesArtwork@2x.png | App Store (2x) | 必须 |
名称不是说必定要和上面相同,但Icon
、尺寸(如60
)还有倍率(@nx)要有,类型为png
。
2)将图片拖放至 Xcode 指定位置,具体是:Project Navigator -> Images.xcassets -> AppIcon
,以下图
拖放完成后,经过文件管理器查看项目目录,也会发现相应图片。
安卓的 app 图标相对简单,只须要设置桌面图标。设置位置在 yourApp/android/app/src/main/res/
目录下,这个目录默认有四个文件夹,里面各对应放置了一种尺寸的桌面图标图片,图片尺寸不一样,但名称相同,统一为 ic_launcher.png
,具体以下所示:
文件夹名称 | 含义 | 文件夹内部图片尺寸 | 文件夹内部图片名称 |
---|---|---|---|
mipmap-ldpi | Low Density Screen | 36x36 | ic_launcher.png |
mipmap-mdpi | Medium Density Screen | 48x48 | ic_launcher.png |
mipmap-hdpi | High Density Screen | 72x72 | ic_launcher.png |
mipmap-xhdpi | Extra-high density screen | 96x96 | ic_launcher.png |
mipmap-xxhdpi | xx-high density screen | 144x144 | ic_launcher.png |
mipmap-xxxhdpi | xxx-high density screen | 192x192 | ic_launcher.png |
若是你使用了 MakeAppIcon 的服务,直接将对应文件夹所有放入 res/
目录下就好,否则就手动替换图标。
能够根据实际需求删除没必要要的文件,好比,120 DPI 的屏幕不多了,那么这个文件夹就能够不要
调出工程设置菜单(双击工程名称或者单击而后而后右侧选择 Targets --> yourProject),进入 info
选项,在 Custom iOS Target Properties
中添加 Bundle display name
,其 value
即是 App 的名称。具体设置以下图:
安卓修改 App 展现名称在这个文件中 yourApp/android/app/src/main/res/values/strings.xml
。
strings.xml
这个文件很简单,所有内容以下:
<resources> <string name="app_name">你的app名称</string> </resources>
替换 你的app名称
为你想要的名字就好。
NOTE:
安卓的话,还要修改默认包名(applicationId
),若是不修改,若是系统监测到当前应用的 applicationId
和已安装的某个应用相同而签名不一样,会报错:“签名不一致 该应用可能已被恶意篡改”。
在这个文件中修改包名: yourApp/android/app/build.gradle
:
// ... defaultConfig { applicationId "com.yourAppId" // ... } // ...
这里使用了第三方插件react-native-splash-screen,官网教程已经很详细,这里作简要介绍。
1)下载依赖
yarn add react-native-splash-screen
2)添加到项目中
react-native link react-native-splash-screen
3)在 React Native 配置
这里指的是设置启动页何时消失,下面的代码是首页加载完 5s 后启动页消失。
/** * ScreenHome/index.js * 设置启动页消失时间 */ import SplashScreen from "react-native-splash-screen"; // 引入 react-native-splash-screen export default class ScreenHome extends Component { // ...other code componentDidMount() { // 隐藏启动页,若是不设置消失时间,在组件加载完启动页自动隐藏 setTimeout(() => { SplashScreen.hide(); }, 5000); } // ...other code }
1)更新 AppDelegate.m
:
#import <React/RCTBundleURLProvider.h> #import <React/RCTRootView.h> #import "SplashScreen.h" // 导入启动页插件 @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ...其余代码 [self.window makeKeyAndVisible]; [SplashScreen show]; // 显示启动页 return YES; } @end
2)准备启动页图片
文件必须是 png 格式的图片,命名需对应尺寸,可参考下面的命名:
如需自动生成可以使用这个网页: appicon
尺寸 | 名称 | 用途 | 是否必须 |
---|---|---|---|
640 x 960 | Default@2x.png | iPhone 4 | 非必须,推荐设置 |
640 x 1136 | Default-568h@2x.png | iPhone 5 | 非必须,推荐设置 |
750 x 1334 | Default-667h@2x.png | iPhone 6, 竖屏 | 必须(必须有至少一个启动页图片) |
1242 x 2208 | Default-736h@3x.png | iPhone 6 Plus, 竖屏 | 非必须,推荐设置 |
2208 x 1242 | Default-Landscape-736h@3x.png | iPhone 6 Plus, 横屏 | 非必须,推荐设置 |
1125 × 2436 | Default-812h@3x.png | iPhone X, 竖屏 | 非必须,推荐设置 |
2436 x 1125 | Default-Landscape-812h@3x.png | iPhone X, 横屏 | 非必须,推荐设置 |
NOTE:
Default尺寸x尺寸.png
也能够;3)在 Xcode 中设置启动页
首先新建 LaunchImage
文件,操做步骤以下:
而后在 general
设置中将启动页指向刚才新建的 LaunchImage
文件,注意 Launch Screen File 必须为空,否则就指向 LaunchScreen.xib 中默认的启动页了:
1)更新 MainActivity.java
:
import android.os.Bundle; // here import com.facebook.react.ReactActivity; // react-native-splash-screen >= 0.3.1 import org.devio.rn.splashscreen.SplashScreen; // here // react-native-splash-screen < 0.3.1 import com.cboy.rn.splashscreen.SplashScreen; // here public class MainActivity extends ReactActivity { @Override protected void onCreate(Bundle savedInstanceState) { SplashScreen.show(this); // here super.onCreate(savedInstanceState); } // ...other code }
2)新建 launch_screen.xml
在 app/src/main/res/layout
中建立 launch_screen.xml
(若是没有 layout
目录,新建),内容以下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/launch_screen"> </LinearLayout>
3)准备不一样尺寸的启动页图片并放到项目中
安卓是经过文件夹路径寻找启动页面的,因此,多张尺寸的启动页名称相同,都为 launch_screen.png
,但要放在不一样文件夹中,文件夹放置目录为 yourApp/android/app/src/main/res/
,名称及对应放置的图片尺寸以下:
文件夹名称 | 含义 | 文件夹内部图片尺寸 | 文件夹内部图片名称 |
---|---|---|---|
drawable-ldpi | Low Density Screen | 240x320 | launch_screen.png |
drawable-mdpi | Medium Density Screen | 320x480 | launch_screen.png |
drawable-hdpi | High Density Screen | 480x800 | launch_screen.png |
drawable-xhdpi | Extra-high density screen | 720x1280 | launch_screen.png |
drawable-xxhdpi | xx-high density screen | 960x1600 | launch_screen.png |
drawable-xxxhdpi | xxx-high density screen | 1280x1920 | launch_screen.png |
建议直接从
480x800
起步放置 4 张图片就好。
4)优化启动页出现前的短暂白屏
到这里,启动页功能已经 ok,但若是仔细看,能够看到启动页出现前会有短暂白屏,此时可经过更改android/app/src/main/res/values/styles.xml
解决:
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <!--设置透明背景--> <item name="android:windowIsTranslucent">true</item> </style> </resources>
这种方案实际没有根本解决问题:会发现这样设置之后点击图片不能当即弹出应用,而有短暂的等待时间,待填坑。
5)解决安卓 6.0,7.0 安装配置完成后出现闪退,参考下面设置:
在 android/app/src/main/res/values
下面新建 colors.xml
文件,内容以下:
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- this is referenced by react-native-splash-screen and will throw an error if not defined. its value does nothing, just here to avoid a runtime error. --> <color name="primary_dark">#000000</color> </resources>
由于 react-native-splash-screen 须要一个名为 primary_dark
的颜色值做为状态栏的颜色。
设置完桌面图标、修改 APP 展现名称及设置启动页以后的效果图以下:
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
若是使用 mac,执行该命令的目录随意。但必定要保管好本身的 my-release-key.keystore
文件,若是忘记签名,不能在原有 App 上面升级,只能从新打包发布。同时,不要将 keystore
文件放入版本控制中。
1)首先将签名文件 my-release-key.keystore
放在目录 yourApp/android/app/
下
2)修改文件 yourApp/android/gradle.properties
添加下面代码 (替换 *****
为正确的 keystore 密码、别名、和 key 密码):
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore MYAPP_RELEASE_KEY_ALIAS=my-key-alias MYAPP_RELEASE_STORE_PASSWORD=***** MYAPP_RELEASE_KEY_PASSWORD=*****
3)添加签名信息到 app 的 gradle 配置中
编辑文件 yourApp/android/app/build.gradle
加入签名信息
android { ... defaultConfig { ... } signingConfigs { release { if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) { 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 } } }
在终端输入下面命令
cd android && ./gradlew assembleRelease
等待构建完成,即可以在 yourApp/android/app/build/outputs/apk/release/app-release.apk
中找到编译后的发布版本。
NOTE:若是遇到这个错误:Execution failed for task ':app:processReleaseResources'
,作下述修改:
在 yourApp/android/gradle.properties
文件最后添加下面代码:
classpath 'com.android.tools.build:gradle:3.0.0' distributionUrl=https://services.gradle.org/distributions/gradle-4.1-all.zip android.enableAapt2=false
若是还有其余问题,可参考下这篇文章:安卓打包发布那些坑
iOS 打包发布有些麻烦,对于大多数非 iOS 开发者的限制不是 React Native 自己,而是苹果自己的机制,好比,必需要有苹果开发者帐号。iOS 打包发布打算另写文章。若是要了解发布流程,能够参考这两篇文章:iOS 发布 App Store 详细图文教程,React Native iOS 详细打包步骤
注意一点:打包时--entry-file
安卓、iOS 是同一个入口文件index.js
,不在区分安卓/iOS
到目前位置,从改造官方 demo 开始,一个比较完整的 React Native App 完成了,在此基础上能够不断扩展完善。
固然,从生产角度来讲,这个 demo 的完成度不高,好比,不少样式仍是最原始的状态、好比 WebView(App 中嵌入 H5)、下拉刷新等也没有涉及。其中 WebView、下拉刷新等经常使用功能会逐步集成到这个 demo 中,但样式并不打算作过多优化,由于从使用角度来说,样式的完成度越高意味着可定制性越差,而且,那样也会致使代码的可读性变差。但愿这个 demo 能够成为完整、普适但不臃肿的脚手架。
不过,同一套代码,安卓和 iOS 上展现的样式会有不一样,针对这个,会写文章单独说明。
Choose transition mode for each screen in StackNavigator
React Native 开发适配心得
Apple Developer - App Icon
在模拟器安卓 4.0 上运行正常,在手机上安卓 6.0 7.0 都闪退 不知道什么状况求解
Issues with resources generated by react in Android Studio 3
React Native 的默认单位和自适应布局方案