We want to include zip file on react native project, for example in project/src/assets/zip folder, include it in the build and extract it to local phone storage on initial App run.
What we want to achieve is, suppose we have a web page that we want to show on react native app. We can decrease the loading time by including the asset for the web page on the project, then told the web page to search for the assets file locally.
We have successfully showing web page with local assets downloaded from internet, in zip format. But We haven’t found on how to achieve the same using zip file on local project.
We have try to import the asset file, then unzip it directly like below with no luck
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
unzip(zipFile, destination)
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
We have try to use react-native-local-resource to get the file with several combinations without luck too
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import loadLocalResource from 'react-native-local-resource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
loadLocalResource(assetsZip)
.then((fileContent) => unzip(fileContent, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import loadLocalResource from 'react-native-local-resource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
const fileName = 'file.zip'
loadLocalResource(assetsZip)
.then((fileContent) => RNFS.writeFile(destination + fileName, fileContent))
.then(() => unzip(destination + fileName, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
How can We extract zip file on project folder into Phone Storage?
EDIT:
while the previous answer was working on debug version of the app, it seems to break on production, because on production resource.uri return file:// uri instead of http:// as in debug version.
to fix the problem we need to check whether it was file uri or http url. then use copy function on react-native-fs instead of download function, if it was file uri.
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
const filename = 'file.zip'
const resource = resolveAssetSource(zipFile)
const fileUri = resource.uri
this.loadZipFile(fileUri, destination + filename)
.then((result) => unzip(destination + filename, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
}
loadZipFile = (fileUri, destinationFile) = {
if (fileUri.startWith('file://')) {
return RNFS.copyFile(fileUri, destinationFile)
} else {
const downloadOptions = {
fromUrl: fileUri,
toFile: destinationFile
}
return RNFS.downloadFile(downloadOptions).promise
}
}
this should work on both production and debug version, even sending zip file using code push was working fine on our case.
OLD ANSWER:
After looking on react-native-local-resource source code, We come up with some Idea.
The problem with react-native-local-resource in our case is, that the final result was text, but zip file is not a text. So we try to intercept the code in the middle to get zip file as we want.
After some experiment, we follow react-native-local-resource code until we got the uri of the file, then use react-native-fs to download the file into local storage folder, then unzip those file.
Here is sample of working code on our case
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
const filename = 'file.zip'
const resource = resolveAssetSource(zipFile)
const fileUri = resource.uri
const downloadOptions = {
fromUrl: fileUri,
toFile: destination + filename
}
RNFS.downloadFile(downloadOptions).promise
.then((result) => unzip(destination + filename, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
Hope it can help anyone who have meet the same problem
Related
The following code works up to Android 10, it is creating a csv file in the DCIM folder:
import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
export async function saveCSV() {
const permission = await MediaLibrary.requestPermissionsAsync();
if (permission.status != 'granted') {
console.log("Permission not Granted!")
return;
}
// CSVLocation
const directoryUri = FileSystem.documentDirectory;
const fileUri = directoryUri + `formData.csv`;
// Save to DCIM folder
const asset = await MediaLibrary.createAssetAsync(fileUri);
try {
const album = await MediaLibrary.getAlbumAsync('album');
if (album == null) {
console.log("ASSET", asset)
await MediaLibrary.createAlbumAsync('album', asset, true);
} else {
await MediaLibrary.addAssetsToAlbumAsync([asset], album, true)
.then(() => {
console.log('File Saved Successfully!');
})
.catch((err: string) => {
console.log('Error In Saving File!', err);
});
}
} catch (e) {
console.log(e);
}
}
Previously this line of code was executed in another function to create a file in the fileUri used above:
await FileSystem.writeAsStringAsync(fileUri, CSVheader + newInfo);
This issue has been described here: https://github.com/expo/expo/issues/12060
In short: Expo Media library is able to save image/video/audio assets so it will fail with other file types. Weirdly enough it was working fine with .pdf and .csv up to Android 10.
In the link above, and also on stackoverflow there are solutions using StorageAccessFramework. However, the user needs to create a subdirectory inside Downloads every time a file needs to be saved. I would like to make it automatically without any popups (after permission is granted).
The destination folder doesn't matter as long as it is accessible by the user later.
I want to download the image file from web. This is my code :
import React from 'react'
import * as Sharing from "expo-sharing";
import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import { getCurrentDateTime } from './UtilityHelper';
import { messageBoxOK } from './AlertHelper';
export const downloadFileIOS = async (url, ticker) => {
let filename = ticker + "_" + getCurrentDateTime() + ".png";
MediaLibrary.requestPermissionsAsync();
if (filename !== null) {
FileSystem.downloadAsync(
url,
FileSystem.documentDirectory + filename
).then(async ({uri}) => {
console.log('Finished downloading to ', uri);
MediaLibrary.createAssetAsync(uri).then(asset => {
console.log('asset', asset);
MediaLibrary.createAlbumAsync('My Gallery', asset, false)
.then(() => {
messageBoxOK("Download", "Success");
})
.catch(error => {
messageBoxOK("Download", "Failed");
});
});
}).catch(error => {
console.error(error);
});
}
};
It worked well on Android but not for IOS.
For IOS I got this error :
[Error: Directory for
'file:///Users/dennisliu/Library/Developer/CoreSimulator/Devices/632FD441-0040-4E1A-AA4E-52A5C015C304/data/Containers/Data/Application/EBFB20FF-EAD8-40FE-BE4D-1D1719A633D2/Documents/ASII_2022-09-07
07:37:36.png' doesn't exist. Please make sure directory '(null)'
exists before calling downloadAsync.]
I have allow the permission in IOS.
What could be the problem ?
I found the problem.
The problem is the filename : ASII_2022-09-07 07:37:36.png is not valid and causing the error.
When I change the filename to : AAA.png it worked.
i am working with react native project i have a task to doawnload files and store them in local so use RNFS but i have links like this .../api/v1/files/5e6f831588b03d4ba3d9f69c/download where i use it in chrome it start the download but with in react native it didn't download anything
here is my code
const localFile = `${RNFS.DocumentDirectoryPath}/test2.pdf`;
const options = {
fromUrl:
'.../api/v1/files/5e6f831588b03d4ba3d9f69c/download', //... means the server base url the link is totaly right
toFile: localFile,
};
RNFS.downloadFile(options)
.promise.then(() => FileViewer.open(localFile))
.then(() => {
// success
})
.catch(error => {
// error
});
}
In a react-native project,I have a zipped file which is in android_assets folder. I want to unzip this folder and copy it into the DocumentDirectoryPath. I have imported react-native-zip-archive and used unzipAssets,but it doesn't seem to work. I have used the following code but I get Error: "./ICF-Package" could not be opened.
const assetPath = './ICF-Package.zip'
const targetPath = ${DocumentDirectoryPath}/ICF-Package.zip
copyfile() {
unzipAssets(assetPath, targetPath)
.then(() => {
console.log('unzip completed!')
})
.catch((error) => {
console.log(error)
})
}
You can install it and try to fix the problem.
$ npm install react-native-fetch-blob
$ react-native link react-native-fetch-blob
import RNFetchBlob from 'react-native-fetch-blob';
import { unzip } from 'react-native-zip-archive';
let dirs = RNFetchBlob.fs.dirs
const documentPath = dirs.DocumentDir
const resourceUrl = 'file:///android_asset/target.zip'
downloadResource = () => {
// Set the path to store on the device
const dirs = RNFetchBlob.fs.dirs.DocumentDir
const homePath = dirs + '/target.zip'
RNFetchBlob
.config({
path: homePath
})
.fetch('GET', resourceUrl)
.progress((received, total) => {
const percentage = Math.floor(received / total * 10000) / 100 + '%'
console.log(percentage)
})
.then(resourceFile => {
console.log('target.zip file download success')
this.unzip(resourceFile);
})
.catch((errorMessage, statusCode) => {
console.log(errorMessage);
})
}
unzip = resourceFile => {
const resourcePath = resourceFile.path()
unzip(resourcePath, documentPath)
.then(path => {
console.log(`unzip sucess: ${path}`)
})
}
I am developing a React Native project. What I am trying to do now is that I am downloading and saving the downloaded file to the device. I am using this package, https://www.npmjs.com/package/rn-fetch-blob for downloading the file.
This is my code
RNFetchBlob.config({
fileCache: true,
})
.fetch('GET', 'https://static.standard.co.uk/s3fs-public/thumbnails/image/2016/05/22/11/davidbeckham.jpg?w968', {
})
.then((res) => {
Alert.alert(res.path());
})
After download, res.path returns the path like this.
I am trying to convert it to the URI to be displayed using the Image component. I tried binding the following state object to the Image component.
{
uri: res.path()
}
It did not work. That is why as a next attempt, I am trying to convert the path into URI and display the uri. How can I do that?
Try providing the path of the file where you want to download it,
const directoryFile = RNFS.ExternalStorageDirectoryPath + "/FolderName/";
RNFS.mkdir(directoryFile);
const urlDownload = input.url;
let fileName;
fileName = "filename.zip";
let dirs = directoryFile + fileName;
RNFetchBlob.config({
// response data will be saved to this path if it has access right.
path: dirs
}).fetch("GET", urlDownload, {
//some headers ..
})
.then(res => {
console.log("The file saved to ", res.path());
//RNFS.moveFile(dirs, directoryFile + fileName); // -> uncomment this line if it still does not store at your desired path
alert("File Downloaded At Folder");
})
.catch(err => {
console.log("Error: " + err);
});