亲宝软件园·资讯

展开

react-native只保留3x图原理解析

lcwlucky 人气:0

引言

我们的react-native项目中,一张图片一般会存在1x, 1.5x, 2x, 3x几种尺寸(1.5x是android特有的),以便在不同屏幕尺寸的手机加载对应尺寸的图片。

1. 输出构建产物

如果我们在代码中引入了一张图片,例如

// index.js
import bg from './bg.png';
.
├── index.js
├── bg.png
├── bg@1.5x.png
├── bg@2x.png
└── bg@3x.png

通过以下命令构建bundle

ios

react-native bundle --entry-file ./index.ts --platform ios --bundle-output ios.js --assets-dest ./ios

android

react-native bundle --entry-file ./index.ts --platform android --bundle-output android.js --assets-dest ./android

打包出来的图片资源如下

drawable-mdpi: 1x

drawable-hdpi: 1.5x

drawable-xhdpi: 2x

drawable-xxhdpi: 3x

可以看到,ios会将图片都放入同一个文件夹,通过scale后缀区分。而android则将不同的scale文件分别放入对应的scale文件夹,文件名都是一样的。

如果当前图片只存在3x图,打包出来的文件夹结构如下

2. RN如何决定加载哪张scale图片?

那么RN是如何决定加载哪张scale图片呢?

// react-native/Libraries/Image/AssetUtils.js
// metro打包时会检查当前图片存在哪些scale,将它们从小到大排序组成一个scales数组
// 比如上面的bg.png对应的scales为[1, 1.5, 2, 3]
export function pickScale(scales: Array<number>, deviceScale?: number): number {
  if (deviceScale == null) {
    deviceScale = PixelRatio.get();
  }
  // Packager guarantees that `scales` array is sorted
  for (let i = 0; i < scales.length; i++) {
    if (scales[i] >= deviceScale) {
      return scales[i];
    }
  }
  // If nothing matches, device scale is larger than any available
  // scales, so we return the biggest one. Unless the array is empty,
  // in which case we default to 1
  return scales[scales.length - 1] || 1;
}

通过源码得知,RN根据当前手机的ratio加载对应的scale图片。如果当前手机的ratio没有匹配到正确的scale图片,则会获取第一个大于当前手机ratio的scale图片。

例如当前手机的scale为2,如果存在2x图片,则返回2x图片。如果没有2x图,则会向上获取3x图。

3. repo中是否可以只保留3x图?

既然如此,那么我们能否在repo中仅仅保留3x图呢?这样打包出来的assets资源就可以变小了。

如果是低ratio的手机,当不存在低scale图片时,RN也会加载到3x图。

3.1 资源上传

在我们项目打包构建bundle和生成对应的assets资源后,需要将它们都上传cdn。

在上传之前,会先将bundle和不同的scale图片分别压缩到对应zip中

android 直接将不同的drawable文件夹压缩,比如 drawable-xxhdpi > hash.1.5x.zip

ios会从assets目录中找出所有同样的scale图片进行压缩。 比如

a@3x.png, b@3x.png > hash.3x.zip

然后将1x.zip, 1.5x.zip, 2x.zip, 3x.zip都上传cdn。

3.2 资源下载

native侧发现有新的RN更新时会下载对应的zip。这里我们native侧做了一个优化,他们不是下载全量的scale.zip, 而是根据当前手机的ratio下载对应的scale.zip。即如果当前手机ratio为2,则只会下载2x.zip(根据手机屏幕ratio下载,资源更小,下载速度更快,占用内存更小)。

所以假如我们在repo中只保留3x图,那么打包后上传cdn时,只有3x.zip存在图片资源,其他scale zip是空的。那么假如用户当前手机的ratio为2, 那么只会下载2x.zip, 而RN此时加载一张图片时,发现找不到对应的2x图,就会尝试加载3x图,然而native并没有下载3x图,导致在ratio为2的手机中加载图片失败。

如上分析,如果repo只保留3x图,对于ratio为3的手机其实没有影响,只影响低ratio的手机

4. 结论

终上所述在repo中我们不能仅仅只保留3x图(除非不支持低ratio的手机,或者native全量下载图片资源)。

更多阅读: react-native 图片解析流程

加载全部内容

相关教程
猜你喜欢
用户评论