react-native
中使用Image
组件来显示图片,表面上和html
的img
标签大同小异,可是其source
属性包含的逻辑缺复杂的多,同时也和bundle
运行的方式也有关系。html
本篇文章将重点讲解下Image
中图片解析逻辑,以及如何自定义图片解析逻辑。react
react-native bundle --entry-file index.js --bundle-output ./bundle/ios/main.jsbundle --platform ios --assets-dest ./bundle/ios --dev false
react-native bundle --entry-file index.js --bundle-output ./bundle/android/index.bundle --platform android --assets-dest ./bundle/android --dev false
复制代码
首先看下iOS
和android
打包结果:android
iOS
会按照项目结构输出图片资源到咱们制定的目录assets
下。ios
android
中,drawable-mdpi
、drawable-xhdpi
、drawable-xxhdpi
等存放不一样分辨率屏幕下的图片,文件名的组成是目录和图片名称经过_
拼接。react-native
代码位于react-native/Libraries/Image/resolveAssetSource
服务器
resolveAssetSource.js
最终会export
如下内容:app
module.exports = resolveAssetSource;
module.exports.pickScale = AssetSourceResolver.pickScale;
module.exports.setCustomSourceTransformer = setCustomSourceTransformer;
复制代码
这里的重点是resolveAssetSource
,它会处理Image
的source
,并返回图片地址。函数
建立了AssetSourceResolver
,并传入getDevServerURL()
、getScriptURL()
、asset
。工具
若是存在自定义处理函数_customSourceTransformer
,就返回它的执行结果。它的设置就是经过setCustomSourceTransformer
来完成的。ui
不然就调用resolver.defaultAsset
,使用默认的逻辑处理图片。
/** * `source` is either a number (opaque type returned by require('./foo.png')) * or an `ImageSource` like { uri: '<http location || file path>' } */
function resolveAssetSource(source: any): ?ResolvedAssetSource {
if (typeof source === 'object') {
return source;
}
const asset = AssetRegistry.getAssetByID(source);
if (!asset) {
return null;
}
const resolver = new AssetSourceResolver(
getDevServerURL(),
getScriptURL(),
asset,
);
if (_customSourceTransformer) {
return _customSourceTransformer(resolver);
}
return resolver.defaultAsset();
}
复制代码
接下来看AssetSourceResolver.js
的代码。
咱们前文初始化AssetSourceResolver
,设置了三个参数:
bundle
所在位置里面包含了最终返回图片的逻辑:defaultAsset
,咱们分析以后能够获得:
server
经过以下代码拼接图片地址,这里使用serverUrl
要求bundle
文件和图片在同级目录而且在域名下,中间不能有二级目录。
this.fromSource(
this.serverUrl +
getScaledAssetPath(this.asset) +
'?platform=' +
Platform.OS +
'&hash=' +
this.asset.hash,
);
复制代码
解决方案是经过
setCustomSourceTransformer
替换serverUrl
,改成jsbundleUrl
。
app
这里不一样平台的处理方式又不同。
iOS
从资源中加载图片
android
分为两种:资源和文件系统(file://)
class AssetSourceResolver {
serverUrl: ?string;
// where the jsbundle is being run from
jsbundleUrl: ?string;
// the asset to resolve
asset: PackagerAsset;
constructor(serverUrl: ?string, jsbundleUrl: ?string, asset: PackagerAsset) {
this.serverUrl = serverUrl;
this.jsbundleUrl = jsbundleUrl;
this.asset = asset;
}
...
defaultAsset(): ResolvedAssetSource {
if (this.isLoadedFromServer()) {
return this.assetServerURL();
}
if (Platform.OS === 'android') {
return this.isLoadedFromFileSystem()
? this.drawableFolderInBundle()
: this.resourceIdentifierWithoutScale();
} else {
return this.scaledAssetURLNearBundle();
}
}
复制代码
咱们了解Image
组件的图片逻辑以后,就能够按需调整了,经过调用setCustomSourceTransformer
传入自定义函数来控制最终图片的访问地址。
我在项目中的处理是bundle
部署在服务器上,这种方式会有两个问题:
drawable-x
目录上面的问题都是图片没法显示,不知道看到文章的你是否也想到了解决办法?
本文同步发表于做者博客: React Native 图片资源那些事