经过第一部分开发 React Native APP —— 从改造官方 Demo 开始(一)介绍,App 框架基本构建完成,这部分主要讨论 UI/交互、App 发布前的准备工作及如何发布,具体内容包括:

  • 在使用 react navigation 的前提下,iOS 实现单个页面从下往上(modal)的进入动画
  • 尺寸自适应
  • 设置启动页,更换桌面图标、app 展示名称、appID
  • 打包发布

一 扩展 react navigation

这里的扩展指的是实现可单独配置页面的进入方式(react navigation 默认只支持全局配置,要么 card,要么 modal,配置后所有页面进入动画相同)。

实现上述效果需要做两方面修改:StackNavigator API(在 route.js 中使用)和进入某个页面是的调用方式。

1.1 修改 StackNavigator API

修改后如果使页面默认状态为 card,只需要输入对应页面即可,比如 ..navigate('ScreenSome1');如果要使某个页面进入方式为 modal 只需要在路径上加上 Modal 比如:..navigate('ScreenSome2Modal')

需要注意的是如果页面进入方式为 modal,需要自定义 header,因为默认 header 样式失效,都叠在一块了

/*** 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();
复制代码

1.2 页面中调用

首先我们新建页面 ScreenSome2,接下来就让它以 modal 的形式进入(从屏幕下面进入),作为对比 ScreenSome1card 的形式进入(默认进入方式,从屏幕右侧进入)。

因为以 modal 形式进入的页面需要自定义 header,一般只是一个关闭按钮,以 ScreenSome2 为例:

/*** ScreenSome2/view.js* 自定义 header(关闭按钮)*/
<View>{/* TouchableHighlight 为关闭按钮的热区 */}<TouchableHighlightonPress={() => 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 页面中的代码:

/*** ScreenHome/view.js* 自定义 header(关闭按钮)*/{/* ScreenSome2 从屏幕右侧进入 */
}
<Buttontitle="goSome1"onPress={() => self.navigation.navigate("ScreenSome1")}
/>;{/* ScreenSome2 从屏幕下面进入 */
}
<Buttontitle="goSome2Modal"onPress={() => self.navigation.navigate("ScreenSome2Modal")}
/>;
复制代码

最终效果图:

二 自适应

自适应主要包括两方面:尺寸根据屏幕大小自适应,包括 fontSizewidth 等;图片分辨率根据屏幕分辨率自适应,也就常说的二倍图、三倍图等。

2.1 尺寸自适应

尺寸自适应的原理是通过获取手机屏幕的宽度,尺寸做相应比例的调整,为此封装了一个工具函数,放在了 config/pxToDp.js 中。

调整后的目录如下:

  • config/pxToDp.js 尺寸转换的工具函数

尺寸转换的工具函数在第一部分开发 React Native APP —— 从改造官方 Demo 开始(一)已经添加

1)编写自适应尺寸工具函数

因为所有涉及尺寸的数据都要转换(fontSizewidth等),所以对转换后的数据要做处理,保证: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>;
复制代码

2.3 图片分辨率自适应

手机分辨率越来越多,尤其安卓,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*/<Imagesource={require("../../assets/images/test.png")}style={{ height: pxToDp(80), width: pxToDp(80) }}
/>
复制代码

最终效果图如下:

  • iphone6: 2 倍图(图片放大后可以看到里面有 2X 字样)
  • iphone7Plus:3 倍图(图片放大后可以看到里面有 3X 字样)
  • Nexus4:2 倍图
  • Pixel2:3 倍图

三 修改桌面图标、App 展示名称,设置启动页

修改桌面图标、App 展示名称相对简单,设置启动页稍微麻烦。另外,iOS 修改桌面图标、App 展示名称,设置启动页都需要在 Xcode 中进行。

3.1 设置桌面图标

因为 App 图标对应多个尺寸,手动改写太麻烦,这个网站可以自动生成 MakeAppIcon。

并不是所有尺寸的图片都需要,见下文。

  • iOS

准确点讲不能叫设置桌面图标,而应该是 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 的屏幕很少了,那么这个文件夹就可以不要

3.2 修改 App 展示名称

  • iOS

调出工程设置菜单(双击工程名称或者单击然后然后右侧选择 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"// ...
}// ...
复制代码

3.3 设置启动页

这里使用了第三方插件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-screenexport default class ScreenHome extends Component {// ...other codecomponentDidMount() {// 隐藏启动页,如果不设置消失时间,在组件加载完启动页自动隐藏setTimeout(() => {SplashScreen.hide();}, 5000);}// ...other code
}
复制代码
  • iOS 设置

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:

  • 很多教程给出的启动页尺寸比上面的要多,有可能是 Xcode 版本不同导致,Xcode 9.2,iOS 7+ 只需要上面七个尺寸;
  • 名称并非一定要按照上面的要求,直接使用 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; // herepublic class MainActivity extends ReactActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {SplashScreen.show(this);  // heresuper.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 的颜色值作为状态栏的颜色。

3.4 最终效果图

设置完桌面图标、修改 APP 展示名称及设置启动页之后的效果图如下:

四 打包发布

4.1 安卓打包发布

  • 生成签名
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 文件放入版本控制中。

  • 设置 gradle 变量

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_PASSWORDkeyAlias MYAPP_RELEASE_KEY_ALIASkeyPassword 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
复制代码

如果还有其他问题,可参考下这篇文章:安卓打包发布那些坑

4.2 iOS 打包发布

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 的默认单位和自适应布局方案

开发 React Native APP —— 从改造官方Demo开始(二)相关推荐

  1. 开发 React Native APP —— 从改造官方Demo开始(2)

    还是摘自L小庸的文章,加入了一点个人的实践和理解 经过第一部分开发 React Native APP -- 从改造官方 Demo 开始(1)介绍,App 框架基本构建完成,这部分主要关注 UI/交互. ...

  2. 快速创建React Native App

    告诉大家一个好消息,为大家精心准备的React Native视频教程发布了,大家现可以看视频学React Native了. 快速创建React Native App 查看最新的React Native ...

  3. 利用 Create React Native App 快速创建 React Native 应用

    React Native App简介 打开React Native官方文档你会发现,在Getting Started章节下新添加一个Quick Start Tab页.Quick Start是在v0.4 ...

  4. 开始测试React Native App(下篇)

    前言: 在开始测试React Native App(上篇)中编写了redux-upload-queue针对Reducer和Action Creator的单元测试,测试代码可以在这里查阅.这篇文章基于开 ...

  5. 从终端运行React Native App时出错(iOS)

    本文翻译自:Error Running React Native App From Terminal (iOS) I am following the tutorial on the official ...

  6. React Native App设置amp;Android版发布

    React Native系列 <逻辑性最强的React Native环境搭建与调试>  <ReactNative开发工具有这一篇足矣>  <解决React Native ...

  7. 【天赢金创】Facebook:我们是如何构建第一个跨平台的React Native APP

    今年早些时候,我们介绍过iOS版的React Native. React Native带来的是用web方式的React - 自声明式的UI组件和快速的开发迭代来完成手机平台的功能,然后为了保持速度.保 ...

  8. React Native app闪退 显示 “很抱歉, ‘xxx’ 无法运行”的解决方法

    React Native app闪退 显示 "很抱歉, 'xxx' 无法运行" 这种情况一般是因为第三方库的配置有问题或者js 代码写的有问题 首先看看js代码是否有问题 去官方下 ...

  9. 如何开发React Native 原生模块(Native Modules)?看完这篇文章就够了(Android)

    期待已久的新课上线啦!解锁React Native开发新姿势,一网打尽React Native最新与最热技术,点我Get!!! 前言 一直想写一下我在React Native原生模块封装方面的一些经验 ...

最新文章

  1. 清北学堂模拟赛d2t4 最大值(max)
  2. django使用bootstrap快速美化 admin后台
  3. 力扣(LeetCode)258. 各位相加
  4. Spring Boot自定义错误页面
  5. vue项目使用npm run dev 编译到一半不动了
  6. vue设置多选框默认勾选_Vue实现全选和反选即Vue复选框增加全选功能
  7. 改jpg_|我来改第04期|—人物海报设计
  8. STM32网络之中断
  9. erwin怎么设置编码_Word页码的设置方式
  10. linux uucp 改为 root,ubuntu 10.04 /etc目录下找不到vsftpd.user_list和vsfepd.ftpusers两个文件?...
  11. html 空行_一篇文章学习html「经典案例」
  12. Pytorch数据的读取与存储
  13. (转)马克•柯霍德斯:一位王牌大空头的传奇人生
  14. 元素内容必须由格式正确的字符数据或标记组成_字符编码是什么?html5如何设置字符编码?...
  15. Windows下jmeter安装
  16. 如何编译生成dll文件以及如何调用dll文件
  17. 四分位数计算方法总结
  18. 文本分类上分微调技巧实战
  19. 台式计算机耗电,台式电脑和笔记本耗电量对比,分别是多少?
  20. vue 引入json地图_使用vue引入maptalks地图及聚合效果的实现

热门文章

  1. 正规式和有限自动机(转自csdn)
  2. AirPlay Android接收端学习一 协议
  3. Material Design之CollapsingToolbarLayout使用
  4. 如何使用金桔ibeacon进行准确的室内定位
  5. 用友财务共享系统付款单全流程图文演示
  6. System.currentTimeMillis()+time*1000
  7. centos 安装中文字体库
  8. 转:Metalink 账户
  9. (已更新)趣味制作生成微信小程序源码下载-安装简单方便
  10. 【L2-022 重排链表】天梯赛L2系列详细解答