AndroidReact-Native为Fresco的初始化提供自定义的Configuration

Posted Sodino

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AndroidReact-Native为Fresco的初始化提供自定义的Configuration相关的知识,希望对你有一定的参考价值。

具体调用栈如下:

这会导致原先的Fresco初始化的配置全部失效,比如缓存大小被改变图片可能过早被清除,失去自定义的NetworkFetcher导致图片下载失败(如果NetworkFetcher涉及添加自定义头信息的话)。

该问题在"react-native": "^0.40.0"中才得以解决。解决办法为MainReactPackage的构造函数中增加MainPackageConfig参数,该参数可指定FrescoImagePipelineConfig

应该是Fresco的坑(因为只要Fresco.initialize()判断避免重复初始化即),可却是React-Native来填(这也是机缘呀,因为该bug是反馈在React-Nativeissue上)。

填坑代码:

MyApplication.java

       
        1
       
       
        2
       
       
        3
       
       
        4
       
       
        5
       
       
        6
       
       
        7
       
       
        8
       
       
        9
       
       
        10
       
       
        11
       
       
        12
       
       
        13
       
       
        14
       
       
        15
       
       
        16
       
       
        17
       
       
        18
       
       
        19
       
       
        20
       
       
        21
       
       
        22
       
       
        23
       
       
        24
       
       
        25
       
       
        private ImagePipelineConfig imagePipelineConfig;   
       
          
       
       
        public 
        void 
        onCreate()    
       
           
        // .... do something ....   
       
       
            initFresco();   
       
       
            ....   
       
       
           
       
          
       
       
        public 
        void 
        initFresco()    
       
       
            DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder(
        this)   
       
       
                    .setBaseDirectoryPath(
        new File(MultiCard.getInstance(
        this).getRootDir()))   
       
       
                    .setBaseDirectoryName(MultiCard.FRESCO_IMAGE_CACHE)   
       
       
                    .setMaxCacheSize(
        50 * ByteConstants.MB)   
       
       
                    .setMaxCacheSizeOnLowDiskSpace(
        10 * ByteConstants.MB)   
       
       
                    .setMaxCacheSizeOnVeryLowDiskSpace(
        2 * ByteConstants.MB)   
       
       
                    .build();   
       
       
            imagePipelineConfig = ImagePipelineConfig.newBuilder(
        this)   
       
       
                    .setNetworkFetcher(
        new MyImageDownloaderFetcher())   
       
       
                    .setMainDiskCacheConfig(diskCacheConfig).build();   
       
       
            Fresco.initialize(
        this, imagePipelineConfig);   
       
       
           
       
          
       
       
        public ImagePipelineConfig 
        getImagePipelineConfig()    
       
           
        return imagePipelineConfig;   
       
       
        
       

ReactNativeBaseActivity.java

       
        1
       
       
        2
       
       
        3
       
       
        4
       
       
        5
       
       
        6
       
       
        7
       
       
        8
       
       
        9
       
       
        10
       
       
        11
       
       
        12
       
       
        13
       
       
        14
       
       
        15
       
       
        16
       
       
        17
       
       
        18
       
       
        19
       
       
        20
       
       
        21
       
       
        22
       
       
        23
       
       
        24
       
       
        25
       
       
        26
       
       
        27
       
       
        28
       
       
        29
       
       
        30
       
       
        @Override   
       
       
        protected 
        void 
        onCreate(Bundle savedInstanceState)    
       
           
        super.onCreate(savedInstanceState);   
       
       
            mReactRootView = 
        new ReactRootView(
        this);   
       
          
       
          
       
           
        // ↓↓↓ start custom config to fresco   
       
       
            MainPackageConfig.Builder configBuilder = 
        new MainPackageConfig.Builder();   
       
       
            configBuilder.setFrescoConfig(myApplication.getImagePipelineConfig());   
       
          
       
       
            mReactInstanceManager = ReactInstanceManager.builder()   
       
       
                    .setApplication(ElnApplication.getInstance())   
       
       
                    .setBundleAssetName(
        "index.android.bundle")   
       
       
                    .setJSMainModuleName(
        "index.android")   
       
       
                    .addPackage(
        new MainReactPackage(configBuilder.build()))   
       
       
                    .addPackage(
        new ModulePackage())   
       
       
                    .setUseDeveloperSupport(BuildConfig.DEBUG)   
       
       
                    .setInitialLifecycleState(LifecycleState.RESUMED)   
       
       
                    .build();   
       
           
        // ↑↑↑ end custom config to fresco   
       
          
       
       
            Bundle bundle = getExtra();   
       
           
        if(bundle == 
        null)   
       
       
                bundle = 
        new Bundle();   
       
       
               
       
          
       
       
            mReactRootView.startReactApplication(mReactInstanceManager, 
        "MyBoduleName", bundle);   
       
          
       
       
            setContentView(mReactRootView);   
       
       
        
       

填坑的前前后后

公司的App主体仍是原生开发的,但有部分界面使用了React-Native实现。

事情起因,测试同学提了个bug,说图片加载随机失败。
好吧,随机失败,尝试一下看能不能找出必定失败的步骤吧。

跟进步骤为:

  1. Charles抓包,查看图片请求详情。要在手机中安装SSL证书解决图片的https链接不可查看的现象。
  2. 抓包发现原本应该response code200,现在却返回302Location403 Forbidden的网页。
    由此,是被后台的防盗链识别为非法请求拒绝访问了。查看图片链接的请求头信息,发现User-AgentReferer都没有设置,才导致被判定为非法。

App使用的的图片框架是Fresco,为了自定义图片的请求头信息(User-AgentReferer)在Fresco初始化时设置了自定义的NetworkFetcherMyImageDownloaderFetcher
发现在抓包为403时,MyImageDownloaderFetcher类中相关的日志被没有被打印出来。
这时开始怀疑Fresco配置失效。
这时开始怀疑Fresco在某个未知时刻被修改了网络配置。
由于ImagePipelineConfig只在Fresco.initialize()才会被调用。
这时开始怀疑Fresco被重新初始化了。

使用Android StudioFind Usages功能,发现Fresco.initialize()除了在MyApplication中由自己主动调用外,还在React-Native中的FrescoModule被调用了一次。

则在Debug的编译环境下,对Fresco.initialize()设置断点,发现App启动时正常执行一次,打开React-Native界面时又执行一次。好了,原因就是这里了,后面的执行把老子的网络配置给冲掉了。

原因找到了,接下来是怎么解决。

第一个思路看有没有现成的接口可以自定义Configuration,没有!
第二个思路是那就使用Java Reflection再把被篡改的Configuration改回来吧!(死脑筋)
然后,lixiaowei同学说上github/react-native/issue找找,嗯,发现有人反馈了这个bug,得升级React-Native然后就可以按第一个思路来解决了。解决办法就如上了。(死开发,别闷着改代码,多聊天呀…)

Reference Link :
Android: Enable apps to provide a custom configuration to Fresco


About Sodino

以上是关于AndroidReact-Native为Fresco的初始化提供自定义的Configuration的主要内容,如果未能解决你的问题,请参考以下文章

Android react-native 中的 MainActivity 不存在错误

如何在 react-native android 应用程序中显示 GIF?

如何在android react-native中正确添加应用程序图标

React-Native Code-Push流程梳理

错误:无法确定当前字符,它不是 android react-native 中的字符串、数字、数组或对象

将 A 转换为 1 B 转换为 2 ... Z 转换为 26,然后将 AA 转换为 27 AB 转换为 28(Excel 中列引用的列索引)