android studio drawable图片找不到_React Native 图片那些事

0fa18628e523fce33b16f6f4b534cbcf.png

react-native中使用Image组件来显示图片,表面上和htmlimg标签大同小异,但是其source属性包含的逻辑缺复杂的多,同时也和bundle运行的方式也有关系。

本篇文章将重点讲解下Image中图片解析逻辑,以及如何自定义图片解析逻辑。

1. 打包结构

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

首先看下iOSandroid打包结果:

839ac1ad9dc0208484c9bddebcdc799d.png

iOS会按照项目结构输出图片资源到我们制定的目录assets下。

android中,drawable-mdpidrawable-xhdpidrawable-xxhdpi等存放不同分辨率屏幕下的图片,文件名的组成是目录和图片名称通过_拼接。

2. 图片链接生成逻辑

代码位于react-native/Libraries/Image/resolveAssetSource

resolveAssetSource.js最终会export以下内容:

module.exports = resolveAssetSource;
module.exports.pickScale = AssetSourceResolver.pickScale;
module.exports.setCustomSourceTransformer = setCustomSourceTransformer;
  • resolveAssetSource: 图片地址拼接工具
  • pickScale: 像素比工具
  • setCustomSourceTransformer: 自定义图片链接处理方式

这里的重点是resolveAssetSource,它会处理Imagesource,并返回图片地址。

创建了AssetSourceResolver,并传入getDevServerURL()getScriptURL()asset

如果存在自定义处理函数_customSourceTransformer,就返回它的执行结果。它的设置就是通过setCustomSourceTransformer来完成的。

否则就调用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,设置了三个参数: - serverUrl: 服务地址,格式为"http://www.xxx.com" - jsbundleUrl: bundle所在位置 - asset

里面包含了最终返回图片的逻辑:defaultAsset,我们分析之后可以得到:

bundle放在server

通过如下代码拼接图片地址,这里使用serverUrl要求bundle文件和图片在同级目录并且在域名下,中间不能有二级目录。

this.fromSource(
      this.serverUrl +
        getScaledAssetPath(this.asset) +
        '?platform=' +
        Platform.OS +
        '&hash=' +
        this.asset.hash,
    );
解决方案是通过 setCustomSourceTransformer替换 serverUrl,改为 jsbundleUrl

bundle内置在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();
    }
  }

f456a1b89673cf2c5a3b5973058736fd.png

3. 写在结尾

我们了解Image组件的图片逻辑之后,就可以按需调整了,通过调用setCustomSourceTransformer传入自定义函数来控制最终图片的访问地址。

我在项目中的处理是bundle部署在服务器上,这种方式会有两个问题:

  1. 图片资源是从域名开始查找,放置在多级目录后就无法访问到图片
  2. 安卓跳过了drawable-x目录

上面的问题都是图片无法显示,不知道看到文章的你是否也想到了解决办法?

本文同步发表于作者博客: React Native 图片资源那些事
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值