Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React-native: download and unzip large language file

Tags:

react-native

A multilingual react-native app. Each language bundle is ~50MB. It doesn't make sense to include all of them in a bundle. So, what do I do about it?

I assume the right way to go here is to download the respective language files upon language selection. What do I do with it next? Do I suppose to store it using AsyncStorage or what?

like image 294
stkvtflw Avatar asked Apr 22 '20 13:04

stkvtflw


1 Answers

Briefly explaining, you will:

  1. Store JSON as ZIP in Google Storage (save memory/bandwidth/time)

  2. Unzip file to JSON (in RN)

  3. Store JSON in AsyncStorage (in RN)

  4. Retrieve from AsyncStorage (in RN)

[Dependencies Summary] You can do this, using these deps:

  • react-native
  • react-native-async-storage
  • rn-fetch-blob
  • react-native-zip-archive

Tip: Always store big language json in zip format (this can save up to 90% of size).

I made a quick test here: one 3.52MB json file, turned out a 26KB zipped file!

Let's consider that yours stored zip file, can be accessed by using a public url, eg: https://storage.googleapis.com/bucket/folder/lang-file.zip.

Install and link all above RN deps, it's required to get this working.

Import the deps

import RNFetchBlob from 'rn-fetch-blob';
import { unzip } from 'react-native-zip-archive';
import AsyncStorage from '@react-native-community/async-storage';
  1. Download the file using rn-fetch-blob. This can be done using:
RNFetchBlob
.config({
  // add this option that makes response data to be stored as a file,
  // this is much more performant.
  fileCache : true,
})
.fetch('GET', 'http://www.example.com/file/example.zip', {
  //some headers ..
})
.then((res) => {
  // the temp file path
  console.log('The file saved to ', res.path())

  // Unzip will be called here!
  unzipDownloadFile(res.path(), (jsonFilePath) => {

    // Let's store this json.
    storeJSONtoAsyncStorage(jsonFilePath);

    // Done!
    // Now you can read the AsyncStorage everytime you need (using function bellow).
  });
});
  1. [function] Unzip the downloaded file, using react-native-zip-archive:
function unzipDownloadFile(target, cb) {
  const targetPath = target;
  const sourcePath = `${target}.json`;
  const charset = 'UTF-8';

  unzip(sourcePath, targetPath, charset)
  .then((path) => {
    console.log(`unzip completed at ${path}`)

    return cb(path);
  })
  .catch((error) => {
    console.error(error)
  });
}
  1. [function] Store JSON in AsyncStorage:
function storeJSONtoAsyncStorage (path) {
  RNFetchBlob.fs.readFile(path, 'utf-8')
  .then((data) => {
    AsyncStorage.setItem('myJSON', data);
  });
}
  1. Retrieve JSON data from AsyncStorage (everytime you want):
AsyncStorage.getItem('myJSON', (err, json) => {
  if (err) {
    console.log(err);
  } else {
    const myJSON = JSON.parse(json);

    // ... do what you need with you json lang file here...
  }
})

That's enough to get dynamic json lang files working in React Native.

I'm using this approach to give a similar feature to my i18n'ed project.

like image 96
Maycon Mesquita Avatar answered Nov 03 '22 23:11

Maycon Mesquita