【Android】React-Native爲Fresco的初始化提供自定義的Configuration

 React-Native界面在啓動時會調用Fresco的初始化,即如果Fresco已經初始化過了,也會再重新執行初始化過程一次。

具體調用棧如下:
react_native_call_fresco_init_stack

這會導致原先的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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章