1

My problem:

  • I have a zip file that contains a firmware update for my company's device
  • I want to be able to access it using react-native-fs with the code below

.

export function readAssetFile(name) {
  if(Platform.OS === 'ios') {
    return RNFS.readFile(`${RNFS.MainBundlePath}/assets/data/${name}`);
  } else {
    return RNFS.readFileAssets(`raw/${name}`, 'base64');
  }
}

My project structure looks like:

ProjectDir
  android
  data
    image1.png
    image2.png
    firmwarefile.zip
  ios

The android branch works, because I added a build step in my .gradle to copy firmwarefile.zip into ProjectDir/android/app/src/main/assets/raw. So I can call readAssetFile('firmwarefile.zip'), and it returns the data.

On iOS, all the image files (Image1.png, Image2.png) are included in MyProject.app/assets/data/ without me having to do anything, but the zip file that sits beside them is not.

Looking into the actual packager code (from the metro project), it seems (based on metro/src/defaults.js) that zip files aren't included by default by the packager, but the packager can be configured to include other file types. But I can't find any documentation for how I'd go about doing that configuring.

Sorry for what feels like a really simple question, but I've been trying to get this zip included in my bundle for ~4 hours now. I'm resorting to manually putting in console.logs and error-throws to trace things inside metro to try and find where I should be sending in my config.

Versions: React-native: 0.55.3 Metro: 0.30.2

ArtHare
  • 1,798
  • 20
  • 22
  • Getting mildly closer: in react-native/local-cli/cliEntry.js, there is evidence that there is a CLI command `--assetExts[list]`. Where that CLI command gets put in is still TBD. – ArtHare Jun 27 '18 at 15:05
  • Closer still: `react-native start --assetExts=zip` got 'zip' into the options objects getting passed into the various server/packager-related JS modules. Now to see if I can get XCode to modify its packager startup command... – ArtHare Jun 27 '18 at 15:11
  • Based on reading `react-native/react-native-xcode.sh`, it looks like I should be able to set envvar EXTRA_PACKAGER_ARGS=--assetExts=zip to cause xcode to launch its bundler with my desired extra arguments. – ArtHare Jun 27 '18 at 15:23
  • That last comment was unfortunately wrong. `react-native-xcode.sh` is seemingly about creating the .app, but doesn't deal with bundling. I'm going to try `react-native start --assetExts=zip` in my own console window to see if that makes a difference. I'm going to guess not. The React.xcodeproj project is where the packager is launched by xcode, but it doesn't seem to have any capability for me to inject additional arguments. React.xcodeproj launches `launchPackager.command` which launches `packager.sh`. `packager.sh` uses input args, but launchPackager.command doesn't sent it any. – ArtHare Jun 27 '18 at 16:29

1 Answers1

2

This is a hack, but it gets it done:

  • Convert your zip binary to a base64 string
  • Stick it in a .js file, a la module.exports = "<your base64 data goes here>"
  • In your file that needs the zip file, use import myZipFileAsBase64 from './hacky-base64-file.js';

Here's a quick script to make your base64 files:

var fs = require('fs');

function prepareZip(file, outJs) {
  const b64 = fs.readFileSync(file, 'base64');

  fs.writeFileSync(outJs, `module.exports = ${JSON.stringify(b64)};`);
}

prepareZip('./data/myFirmware.zip', './hacky-base64-file.js');
ArtHare
  • 1,798
  • 20
  • 22
  • Just want to thank you for documenting your process for solving this problem. No one else has commented on this, so wanted to let you know you're not alone! I'm looking for solution to same exact problem. – ososnilknarf Oct 27 '22 at 16:44
  • Thank you for this hack, I am confronted with the same problem - how did you then manage to convert the base64 string back to the zip file in your react native app? – user2968115 Nov 11 '22 at 20:47
  • @user2968115 You can use Buffer.from(b64, 'base64') to create a Buffer with the binary data. It's been a while since I was in react-native code though, so I forget specifically what format the DFU sender requires. – ArtHare Nov 12 '22 at 23:04
  • @user2968115 depending on if it needs a filename, you could also do fs.writeFileSync(filename, b64, 'base64'); to store it in storage, then hand the filename to the DFU system. – ArtHare Nov 12 '22 at 23:05