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 图片解析流程
加载全部内容