前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版

React Native Icon 与启动图设置 iOS 和 Android 双端配置实战

首页2019-10-04 15:10:12Front-End
RNReactiOSAndroid启动图应用图标

功能都写完了,准备打个包给产品看看,结果桌面上蹲着一个 React Native 默认的灰色图标,点开还先闪一屏白,然后才是首页。这时候你会发现,改图标和加启动页这件事,在 RN 里根本不是「换张图」那么简单:iOS 要一整套 AppIcon.appiconset,Android 要六套 mipmap,启动页两端的机制还完全不一样,Android 压根没有原生启动图这个概念。

这篇把我配一次图标和启动屏踩到的东西整理成了一条流水线,从批量生成资源开始,到 Android 和 iOS 各自往哪个目录放、要改哪几个文件,再到那个恼人的启动白屏怎么消掉。每一步都有截图,做完应该长什么样也写在图后面。

在本篇文章中,我们将从浅入深,和大家一起学习以下知识:

  • iOS 和 Android 各自需要哪些尺寸的图标和启动图,为什么两端差别这么大
  • 怎么用一张 1024×1024 的原图批量生成全套资源,不用手动裁
  • Android 端替换 mipmap 图标、改应用名称的具体位置
  • react-native-splash-screen 的接入方式,以及原生侧那两行代码分别在做什么
  • iOS 端替换 AppIcon.appiconset、配置 LaunchImage 的完整路径
  • 启动瞬间那一屏白色是哪来的,怎么用 windowIsTranslucent 处理掉

# 一、先搞清楚两端各自要什么

动手之前先把资源需求理一遍,不然生成完一堆图不知道往哪塞。

iOS 这边,应用图标放在 ios/项目名/Images.xcassets/AppIcon.appiconset 这个目录里。它是一个「资源集」,里面有一份 Contents.json 声明每个槽位对应多大的图,Xcode 按这份清单去找文件。少一个尺寸,编译时 Xcode 会在 Images.xcassets 那一屏给你标黄警告,上传 App Store Connect 的时候则会直接被校验打回来。所以 iOS 的图标不能只放一张。

Android 这边简单一些,图标放在 android/app/src/main/res/ 下面的一组 mipmap-* 目录里,按屏幕密度分成 mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi 几档,系统会自己挑最合适那一档来用。

启动图的差别就大了。iOS 系统层面就支持启动图,App 冷启动时先渲染 LaunchScreen,等 RN 的 JS 环境跑起来再切到首页,这个过程是系统托管的。Android 没有这个东西,你必须自己拿一个 Activity 的主题背景去顶住,或者装 react-native-splash-screen 这类库,手动控制显示和隐藏。

这就是为什么同样一句「加个启动页」,Android 那边要多改三个文件。

# 二、用图标工厂批量生成全套资源

手动裁十几个尺寸是纯粹的体力活,交给工具就行。

方式一

如果你的项目里正好也有 Ionic 那一套,可以直接复用它的资源生成能力,参考 Ionic 项目里生成不同尺寸的启动图和图标。Ionic CLI 的做法是让你只准备 resources/icon.png 和 resources/splash.png 两张原图,命令跑完自动铺满两端所有尺寸。

方式二

纯 RN 项目用在线的图标工厂更直接。

各种尺寸 Icon 图标生成

工具地址是 https://icon.wuruihong.com/ ,上传一张 1024×1024 的 PNG,勾选要生成的平台,几秒钟就能拿到一个压缩包。原图这里有个要求,必须是不带圆角、不带透明通道的正方形 PNG,圆角是系统自己裁的,你自己先裁好反而会出现二次圆角;带 alpha 通道的图上传 App Store 会被直接拒绝。

拿到压缩包之后分两端放:

  1. 安卓下替换 andriod/app/src/main/res/ 下的 mipmap 文件即可
  2. iOS 下替换如下

下面这张图是 iOS 端图标资源该放的位置,也就是 Xcode 工程里 Images.xcassets 下的 AppIcon 资源集。

iOS 端图标资源在 Images.xcassets 的 AppIcon.appiconset 目录中的文件结构

替换完之后回 Xcode 点开 Images.xcassets > AppIcon,每个槽位都应该有缩略图,没有空槽就说明尺寸齐了。如果某个格子是空的,多半是文件名和 Contents.json 对不上,把工厂生成的整个文件夹连同 Contents.json 一起覆盖过去最省事。

各种尺寸启动图图标生成

启动图也可以使用图标工厂生产了 https://icon.wuruihong.com/splash ,入口和图标是分开的,别在图标那个页面上传启动图原图。

  1. 安卓下拷贝生成的文件到 andriod/app/src/main/res/ 目录下

生成结果按密度分好了目录,下面这张图是 Android 启动图生成后的目录结构。

图标工厂生成的 Android 启动图按屏幕密度分成多个 drawable 目录

对照着往 res/ 下面拷就行,同名目录直接合并。这张是拷贝完成后 res/ 目录里应该呈现的样子。

拷贝完成后 Android res 目录下的资源分布

  1. iOS 下拷贝生成的该文件夹替换即可

iOS 的启动图会生成成一个 LaunchImage.launchimage 资源集,同样是整个文件夹替换。

图标工厂生成的 iOS 启动图资源集目录

替换后在 Xcode 的 Images.xcassets 里能看到多出来一个 LaunchImage 条目,里面按设备型号分好了槽位。

在 Xcode 的 Images.xcassets 中看到生成好的 LaunchImage 资源集

这里有个坑要注意,图标工厂是第三方工具,它对新机型尺寸的支持是滞后的。我当时生成出来的槽位就少了几个新设备的,Xcode 里那几格是空的。空槽不会导致编译失败,但那些机型上启动图会被拉伸或者留黑边,介意的话得手动补。

# 三、Android 端替换图标和名称

资源到位了,接下来是两端各自的接线工作,先说 Android。

修改图标和名称

找到根目录 /android/app/src/main/res,把生成好的 mipmap-* 目录整个覆盖进去。

Android 项目 res 目录下按密度划分的 mipmap 图标目录

覆盖完成后,res/ 下每个 mipmap- 开头的目录里都应该有一个 ic_launcher.png(有些模板还会带 ic_launcher_round.png,圆形图标,Android 7.1 之后的启动器会用它)。文件名不要改,AndroidManifest.xml 里 android:icon="@mipmap/ic_launcher" 是按这个名字找的。

应用名称改的是另一个地方,在 android/app/src/main/res/values/strings.xml 里的 app_name 字段,改完重新编译就能在桌面上看到新名字。

启动页

Android 的启动页要靠库来做,原文这几条说明我原样保留:

  • 在 react-native 的 android 中的启动图和 IOS 不相同点在于,android 没有默认的启动图,在 IOS 里面有
  • 使用插件 import SplashScreen from 'react-native-splash-screen';
  • https://github.com/crazycodeboy/react-native-splash-screen

把生成好的启动页按下图这个格式处理即可,也就是按密度放进 drawable-* 系列目录。

Android 启动页图片按 drawable 密度目录分类存放的格式

放完之后目录里应该出现 launch_image.png 这类文件,名字要和后面 XML 里引用的 @drawable/launch_image 保持一致。这一步做错的表现很典型:编译报 resource drawable/launch_image not found,一眼就能定位。

# 四、iOS 端改 App 名称和图标

修改 app 名称

编辑 ios/test/Info.plist 文件(test 换成你自己的工程名),改 CFBundleDisplayName 这一项。

<key>CFBundleDisplayName</key>
- <string>$(PRODUCT_NAME)</string>
+ <string>测试程序</string>
@前端进阶之旅: 代码已经复制到剪贴板

这段改的是「显示在桌面图标下面的名字」。默认值 $(PRODUCT_NAME) 是个变量,会取工程的 Product Name,通常是英文工程名。要注意 CFBundleDisplayName 和 CFBundleName 是两个字段,前者是给用户看的显示名,后者是包内部的短名,长度限制更严;桌面显示不对的时候优先改前者。中文名直接写中文即可,Info.plist 是 UTF-8 的。

修改应用图标

应用图标对尺寸有要求,比较简单的方式是准备一张 1024*1024 的图片,然后使用 图标工厂在线生成。

这里直接从 Sketch iOS 图标设计模板中选取了一张图片,生成后的结果如下。

用图标工厂生成的 iOS 全套尺寸图标结果预览

生成结果是一个完整的 AppIcon.appiconset 文件夹,里面每个 PNG 的文件名都带着尺寸标识。

生成结果中 AppIcon.appiconset 文件夹内的各尺寸图标文件

我们可以直接用生成好的内容替换默认的图标即可,也就是替换 ios/test/Images.xcassets/AppIcon.appiconset 中的内容。如果不需要全部尺寸,可以用 Xcode 打开项目,点击 Images.xcassets > AppIcon 拖入相应尺寸的图标。

替换完记得在 Xcode 里 Command + Shift + K 清一次编译缓存再跑,不然模拟器上大概率还是老图标。这个我踩过,以为是资源没替对,翻了半天目录,其实只是缓存没清。

# 五、接入 react-native-splash-screen

添加启动页可以使用 react-native-splash-screen 库,通过它可以控制启动页的显示和隐藏。

它解决的问题是什么呢?RN 应用冷启动时,原生容器起来得很快,但 JS bundle 加载和首屏渲染需要时间,这中间那段空档如果不遮住,用户看到的就是一片白。这个库做的事就是在原生侧先把一张全屏图盖上去,等你在 JS 里确认首屏数据准备好了,再手动调用 SplashScreen.hide() 把它撤掉。

$ yarn add react-native-splash-screen

$ react-native link react-native-splash-screen
@前端进阶之旅: 代码已经复制到剪贴板

这两条命令,第一条装包,第二条把原生依赖自动接进 iOS 和 Android 工程。补充一句时效性的说明:react-native link 是当年(RN 0.60 之前)的做法,0.60 之后 RN 引入了 autolinking,装完包直接 cd ios && pod install 就行,不需要也不应该再跑 link,跑了反而可能导致重复链接。老项目沿用上面这套写法没问题,新项目按 autolinking 走。

Android

编辑 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
}
@前端进阶之旅: 代码已经复制到剪贴板
fe
  • 一、先搞清楚两端各自要什么
  • 二、用图标工厂批量生成全套资源
  • 三、Android 端替换图标和名称
  • 四、iOS 端改 App 名称和图标
  • 五、接入 react-native-splash-screen
  • 六、iOS 端配置 LaunchImage
  • 总结
  • 参考

← Vue核心梳理 组件通信 生命周期 Vuex 与路由原理React Native iOS 打包发布全流程 从离线 bundle 到内测分发 →