Expo.FileSystem.downloadAsync do not show download notification
I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.
The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.
FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});
react-native expo
add a comment |
I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.
The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.
FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});
react-native expo
Do you consider both Android and iOS? Which file types will be allowed for download?
– Siavas
Jan 21 at 23:35
@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt
– Charanor
Jan 24 at 19:23
@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.
– Siavas
Jan 24 at 22:45
@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)
– Charanor
Jan 24 at 22:49
@Charanor have added a solution to your use-case. Let me know how this goes for you.
– Siavas
Jan 26 at 14:27
add a comment |
I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.
The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.
FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});
react-native expo
I am using expo FileSystem to download the pdf file. The API response lands into success function. However, I am not able to show the downloaded file to the user.
The expected behaviour should be like we usually see notification icon on the status bar and on click on icon its opens your file.
FileSystem.downloadAsync(
'https://bitcoin.org/bitcoin.pdf',
FileSystem.documentDirectory + 'Stay_Overview.xlsx'
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
})
.catch(error => {
console.error(error);
});
react-native expo
react-native expo
asked Dec 26 '17 at 14:26
CarlosCarlos
2,4881757124
2,4881757124
Do you consider both Android and iOS? Which file types will be allowed for download?
– Siavas
Jan 21 at 23:35
@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt
– Charanor
Jan 24 at 19:23
@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.
– Siavas
Jan 24 at 22:45
@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)
– Charanor
Jan 24 at 22:49
@Charanor have added a solution to your use-case. Let me know how this goes for you.
– Siavas
Jan 26 at 14:27
add a comment |
Do you consider both Android and iOS? Which file types will be allowed for download?
– Siavas
Jan 21 at 23:35
@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt
– Charanor
Jan 24 at 19:23
@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.
– Siavas
Jan 24 at 22:45
@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)
– Charanor
Jan 24 at 22:49
@Charanor have added a solution to your use-case. Let me know how this goes for you.
– Siavas
Jan 26 at 14:27
Do you consider both Android and iOS? Which file types will be allowed for download?
– Siavas
Jan 21 at 23:35
Do you consider both Android and iOS? Which file types will be allowed for download?
– Siavas
Jan 21 at 23:35
@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt
– Charanor
Jan 24 at 19:23
@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt
– Charanor
Jan 24 at 19:23
@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.
– Siavas
Jan 24 at 22:45
@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.
– Siavas
Jan 24 at 22:45
@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)
– Charanor
Jan 24 at 22:49
@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)
– Charanor
Jan 24 at 22:49
@Charanor have added a solution to your use-case. Let me know how this goes for you.
– Siavas
Jan 26 at 14:27
@Charanor have added a solution to your use-case. Let me know how this goes for you.
– Siavas
Jan 26 at 14:27
add a comment |
2 Answers
2
active
oldest
votes
DownloadManager
I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.
However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:
Each app only has read and write access to locations under the following directories:
- Expo.FileSystem.documentDirectory
- Expo.FileSystem.cacheDirectory
https://docs.expo.io/versions/latest/sdk/filesystem
So there would be no way to access the file in Expo once it was downloaded.
Possible Solution
A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support
Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.
However, that would mean ejecting your application from Expo.
add a comment |
This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.
In a new Expo project, amend the following two files:
- App.js
import React, { Component } from 'react';
import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
import { FileSystem, Constants, Notifications, Permissions } from 'expo';
import Toast, {DURATION} from 'react-native-easy-toast';
async function getiOSNotificationPermission() {
const { status } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
if (status !== 'granted') {
await Permissions.askAsync(Permissions.NOTIFICATIONS);
}
}
export default class App extends Component {
constructor(props) {
super(props);
// this.toast = null;
this.listenForNotifications = this.listenForNotifications.bind(this);
// this.openFile = this.openFile.bind(this);
this.state = {
filePreviewText: ''
}
}
_handleButtonPress = () => {
let fileName = 'document.txt';
let fileUri = FileSystem.documentDirectory + fileName;
FileSystem.downloadAsync(
"https://raw.githubusercontent.com/expo/expo/master/README.md",
fileUri
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
const localnotification = {
title: 'Download has finished',
body: fileName + " has been downloaded. Tap to open file.",
android: {
sound: true,
},
ios: {
sound: true,
},
data: {
fileUri: uri
},
};
localnotification.data.title = localnotification.title;
localnotification.data.body = localnotification.body;
let sendAfterFiveSeconds = Date.now();
sendAfterFiveSeconds += 3000;
const schedulingOptions = { time: sendAfterFiveSeconds };
Notifications.scheduleLocalNotificationAsync(
localnotification,
schedulingOptions
);
})
.catch(error => {
console.error(error);
Alert.alert(error);
});
};
listenForNotifications = () => {
const _this = this;
Notifications.addListener(notification => {
if (notification.origin === 'received') {
// We could also make our own design for the toast
// _this.refs.toast.show(<View><Text>hello world!</Text></View>);
const toastDOM =
<TouchableWithoutFeedback
onPress={() => {this.openFile(notification.data.fileUri)}}
style={{padding: '10', backgroundColor: 'green'}}>
<Text style={styles.toastText}>{notification.data.body}</Text>
</TouchableWithoutFeedback>;
_this.toast.show(toastDOM, DURATION.FOREVER);
} else if (notification.origin === 'selected') {
this.openFile(notification.data.fileUri);
}
// Expo.Notifications.setBadgeNumberAsync(number);
// Notifications.setBadgeNumberAsync(10);
// Notifications.presentLocalNotificationAsync(notification);
// Alert.alert(notification.title, notification.body);
});
};
componentWillMount() {
getiOSNotificationPermission();
this.listenForNotifications();
}
componentDidMount() {
// let asset = Asset.fromModule(md);
// Toast.show('Hello World');
}
openFile = (fileUri) => {
this.toast.close(40);
console.log('Opening file ' + fileUri);
FileSystem.readAsStringAsync(fileUri)
.then((fileContents) => {
// Get file contents in binary and convert to text
// let fileTextContent = parseInt(fileContents, 2);
this.setState({filePreviewText: fileContents});
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<Button style={styles.button}
title={"Download text file"}
onPress={this._handleButtonPress}
/>
<Button style={styles.button}
title={"Clear File Preview"}
onPress={() => {this.setState({filePreviewText: ""})}}
/>
</View>
<ScrollView style={styles.filePreview}>
<Text>{this.state.filePreviewText}</Text>
</ScrollView>
<Toast ref={ (ref) => this.toast=ref }/>
</View>
);
// <Toast
// ref={ (ref) => this.toast=ref }
// style={{backgroundColor:'green'}}
// textStyle={{color:'white'}}
// position={'bottom'}
// positionValue={100}
// opacity={0.8}
// />
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
buttonsContainer: {
flexDirection: 'row',
},
button: {
flex: 1
},
filePreview: {
flex: 1,
padding: 10,
},
toastText: {
color: 'white',
padding: 5,
justifyContent: 'flex-start',
},
});
- package.json: Add the following dependency (fork of react-native-easy-toast)
"react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"
There are a couple of important notes about this solution:
Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.
Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the
<Text>component.The
crazycodeboy/react-native-easy-toastrepo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.Although this project is also available in Snack, it will not run due to the need of using a git repository in
package.jsonas mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.
The toast (internal notification) is created with a
TouchableWithoutFeedbackcomponent, although there are other similar ones in React Native with various differences. This component can be customised in the code (search fortoastDOM), but might even be replaceable in the future by internal notifications available in Expo.Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.
And that's it! I think this gives a good starting point for file downloading and previewing with Expo.
Codebase also available on GitHub.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47979921%2fexpo-filesystem-downloadasync-do-not-show-download-notification%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
DownloadManager
I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.
However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:
Each app only has read and write access to locations under the following directories:
- Expo.FileSystem.documentDirectory
- Expo.FileSystem.cacheDirectory
https://docs.expo.io/versions/latest/sdk/filesystem
So there would be no way to access the file in Expo once it was downloaded.
Possible Solution
A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support
Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.
However, that would mean ejecting your application from Expo.
add a comment |
DownloadManager
I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.
However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:
Each app only has read and write access to locations under the following directories:
- Expo.FileSystem.documentDirectory
- Expo.FileSystem.cacheDirectory
https://docs.expo.io/versions/latest/sdk/filesystem
So there would be no way to access the file in Expo once it was downloaded.
Possible Solution
A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support
Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.
However, that would mean ejecting your application from Expo.
add a comment |
DownloadManager
I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.
However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:
Each app only has read and write access to locations under the following directories:
- Expo.FileSystem.documentDirectory
- Expo.FileSystem.cacheDirectory
https://docs.expo.io/versions/latest/sdk/filesystem
So there would be no way to access the file in Expo once it was downloaded.
Possible Solution
A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support
Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.
However, that would mean ejecting your application from Expo.
DownloadManager
I believe that you are looking to use the DownloadManager for handling your downloads on Android (be aware there is no DownloadManager for iOS so you would have to handle this differently) The DownloadManager either savse the file to a shared system cache or it would save it to external storage.
However, at this time I do not believe that Expo allows you to use the DownloadManager, instead handling all the downloads itself. The reason could be that Expo doesn't allow you access to external storage, as it states in the documentation:
Each app only has read and write access to locations under the following directories:
- Expo.FileSystem.documentDirectory
- Expo.FileSystem.cacheDirectory
https://docs.expo.io/versions/latest/sdk/filesystem
So there would be no way to access the file in Expo once it was downloaded.
Possible Solution
A possible solution would be to use React-Native Fetch Blob. It does allow you to use the DownloadManager.
https://github.com/joltup/rn-fetch-blob#android-media-scanner-and-download-manager-support
Using the DownloadManager can be achieved in rn-fetch-blob by setting the addAndroidDownloads with the useDownloadManager key set to true.
However, that would mean ejecting your application from Expo.
answered Jan 20 at 11:35
AndrewAndrew
3,54911026
3,54911026
add a comment |
add a comment |
This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.
In a new Expo project, amend the following two files:
- App.js
import React, { Component } from 'react';
import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
import { FileSystem, Constants, Notifications, Permissions } from 'expo';
import Toast, {DURATION} from 'react-native-easy-toast';
async function getiOSNotificationPermission() {
const { status } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
if (status !== 'granted') {
await Permissions.askAsync(Permissions.NOTIFICATIONS);
}
}
export default class App extends Component {
constructor(props) {
super(props);
// this.toast = null;
this.listenForNotifications = this.listenForNotifications.bind(this);
// this.openFile = this.openFile.bind(this);
this.state = {
filePreviewText: ''
}
}
_handleButtonPress = () => {
let fileName = 'document.txt';
let fileUri = FileSystem.documentDirectory + fileName;
FileSystem.downloadAsync(
"https://raw.githubusercontent.com/expo/expo/master/README.md",
fileUri
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
const localnotification = {
title: 'Download has finished',
body: fileName + " has been downloaded. Tap to open file.",
android: {
sound: true,
},
ios: {
sound: true,
},
data: {
fileUri: uri
},
};
localnotification.data.title = localnotification.title;
localnotification.data.body = localnotification.body;
let sendAfterFiveSeconds = Date.now();
sendAfterFiveSeconds += 3000;
const schedulingOptions = { time: sendAfterFiveSeconds };
Notifications.scheduleLocalNotificationAsync(
localnotification,
schedulingOptions
);
})
.catch(error => {
console.error(error);
Alert.alert(error);
});
};
listenForNotifications = () => {
const _this = this;
Notifications.addListener(notification => {
if (notification.origin === 'received') {
// We could also make our own design for the toast
// _this.refs.toast.show(<View><Text>hello world!</Text></View>);
const toastDOM =
<TouchableWithoutFeedback
onPress={() => {this.openFile(notification.data.fileUri)}}
style={{padding: '10', backgroundColor: 'green'}}>
<Text style={styles.toastText}>{notification.data.body}</Text>
</TouchableWithoutFeedback>;
_this.toast.show(toastDOM, DURATION.FOREVER);
} else if (notification.origin === 'selected') {
this.openFile(notification.data.fileUri);
}
// Expo.Notifications.setBadgeNumberAsync(number);
// Notifications.setBadgeNumberAsync(10);
// Notifications.presentLocalNotificationAsync(notification);
// Alert.alert(notification.title, notification.body);
});
};
componentWillMount() {
getiOSNotificationPermission();
this.listenForNotifications();
}
componentDidMount() {
// let asset = Asset.fromModule(md);
// Toast.show('Hello World');
}
openFile = (fileUri) => {
this.toast.close(40);
console.log('Opening file ' + fileUri);
FileSystem.readAsStringAsync(fileUri)
.then((fileContents) => {
// Get file contents in binary and convert to text
// let fileTextContent = parseInt(fileContents, 2);
this.setState({filePreviewText: fileContents});
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<Button style={styles.button}
title={"Download text file"}
onPress={this._handleButtonPress}
/>
<Button style={styles.button}
title={"Clear File Preview"}
onPress={() => {this.setState({filePreviewText: ""})}}
/>
</View>
<ScrollView style={styles.filePreview}>
<Text>{this.state.filePreviewText}</Text>
</ScrollView>
<Toast ref={ (ref) => this.toast=ref }/>
</View>
);
// <Toast
// ref={ (ref) => this.toast=ref }
// style={{backgroundColor:'green'}}
// textStyle={{color:'white'}}
// position={'bottom'}
// positionValue={100}
// opacity={0.8}
// />
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
buttonsContainer: {
flexDirection: 'row',
},
button: {
flex: 1
},
filePreview: {
flex: 1,
padding: 10,
},
toastText: {
color: 'white',
padding: 5,
justifyContent: 'flex-start',
},
});
- package.json: Add the following dependency (fork of react-native-easy-toast)
"react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"
There are a couple of important notes about this solution:
Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.
Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the
<Text>component.The
crazycodeboy/react-native-easy-toastrepo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.Although this project is also available in Snack, it will not run due to the need of using a git repository in
package.jsonas mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.
The toast (internal notification) is created with a
TouchableWithoutFeedbackcomponent, although there are other similar ones in React Native with various differences. This component can be customised in the code (search fortoastDOM), but might even be replaceable in the future by internal notifications available in Expo.Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.
And that's it! I think this gives a good starting point for file downloading and previewing with Expo.
Codebase also available on GitHub.
add a comment |
This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.
In a new Expo project, amend the following two files:
- App.js
import React, { Component } from 'react';
import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
import { FileSystem, Constants, Notifications, Permissions } from 'expo';
import Toast, {DURATION} from 'react-native-easy-toast';
async function getiOSNotificationPermission() {
const { status } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
if (status !== 'granted') {
await Permissions.askAsync(Permissions.NOTIFICATIONS);
}
}
export default class App extends Component {
constructor(props) {
super(props);
// this.toast = null;
this.listenForNotifications = this.listenForNotifications.bind(this);
// this.openFile = this.openFile.bind(this);
this.state = {
filePreviewText: ''
}
}
_handleButtonPress = () => {
let fileName = 'document.txt';
let fileUri = FileSystem.documentDirectory + fileName;
FileSystem.downloadAsync(
"https://raw.githubusercontent.com/expo/expo/master/README.md",
fileUri
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
const localnotification = {
title: 'Download has finished',
body: fileName + " has been downloaded. Tap to open file.",
android: {
sound: true,
},
ios: {
sound: true,
},
data: {
fileUri: uri
},
};
localnotification.data.title = localnotification.title;
localnotification.data.body = localnotification.body;
let sendAfterFiveSeconds = Date.now();
sendAfterFiveSeconds += 3000;
const schedulingOptions = { time: sendAfterFiveSeconds };
Notifications.scheduleLocalNotificationAsync(
localnotification,
schedulingOptions
);
})
.catch(error => {
console.error(error);
Alert.alert(error);
});
};
listenForNotifications = () => {
const _this = this;
Notifications.addListener(notification => {
if (notification.origin === 'received') {
// We could also make our own design for the toast
// _this.refs.toast.show(<View><Text>hello world!</Text></View>);
const toastDOM =
<TouchableWithoutFeedback
onPress={() => {this.openFile(notification.data.fileUri)}}
style={{padding: '10', backgroundColor: 'green'}}>
<Text style={styles.toastText}>{notification.data.body}</Text>
</TouchableWithoutFeedback>;
_this.toast.show(toastDOM, DURATION.FOREVER);
} else if (notification.origin === 'selected') {
this.openFile(notification.data.fileUri);
}
// Expo.Notifications.setBadgeNumberAsync(number);
// Notifications.setBadgeNumberAsync(10);
// Notifications.presentLocalNotificationAsync(notification);
// Alert.alert(notification.title, notification.body);
});
};
componentWillMount() {
getiOSNotificationPermission();
this.listenForNotifications();
}
componentDidMount() {
// let asset = Asset.fromModule(md);
// Toast.show('Hello World');
}
openFile = (fileUri) => {
this.toast.close(40);
console.log('Opening file ' + fileUri);
FileSystem.readAsStringAsync(fileUri)
.then((fileContents) => {
// Get file contents in binary and convert to text
// let fileTextContent = parseInt(fileContents, 2);
this.setState({filePreviewText: fileContents});
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<Button style={styles.button}
title={"Download text file"}
onPress={this._handleButtonPress}
/>
<Button style={styles.button}
title={"Clear File Preview"}
onPress={() => {this.setState({filePreviewText: ""})}}
/>
</View>
<ScrollView style={styles.filePreview}>
<Text>{this.state.filePreviewText}</Text>
</ScrollView>
<Toast ref={ (ref) => this.toast=ref }/>
</View>
);
// <Toast
// ref={ (ref) => this.toast=ref }
// style={{backgroundColor:'green'}}
// textStyle={{color:'white'}}
// position={'bottom'}
// positionValue={100}
// opacity={0.8}
// />
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
buttonsContainer: {
flexDirection: 'row',
},
button: {
flex: 1
},
filePreview: {
flex: 1,
padding: 10,
},
toastText: {
color: 'white',
padding: 5,
justifyContent: 'flex-start',
},
});
- package.json: Add the following dependency (fork of react-native-easy-toast)
"react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"
There are a couple of important notes about this solution:
Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.
Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the
<Text>component.The
crazycodeboy/react-native-easy-toastrepo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.Although this project is also available in Snack, it will not run due to the need of using a git repository in
package.jsonas mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.
The toast (internal notification) is created with a
TouchableWithoutFeedbackcomponent, although there are other similar ones in React Native with various differences. This component can be customised in the code (search fortoastDOM), but might even be replaceable in the future by internal notifications available in Expo.Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.
And that's it! I think this gives a good starting point for file downloading and previewing with Expo.
Codebase also available on GitHub.
add a comment |
This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.
In a new Expo project, amend the following two files:
- App.js
import React, { Component } from 'react';
import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
import { FileSystem, Constants, Notifications, Permissions } from 'expo';
import Toast, {DURATION} from 'react-native-easy-toast';
async function getiOSNotificationPermission() {
const { status } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
if (status !== 'granted') {
await Permissions.askAsync(Permissions.NOTIFICATIONS);
}
}
export default class App extends Component {
constructor(props) {
super(props);
// this.toast = null;
this.listenForNotifications = this.listenForNotifications.bind(this);
// this.openFile = this.openFile.bind(this);
this.state = {
filePreviewText: ''
}
}
_handleButtonPress = () => {
let fileName = 'document.txt';
let fileUri = FileSystem.documentDirectory + fileName;
FileSystem.downloadAsync(
"https://raw.githubusercontent.com/expo/expo/master/README.md",
fileUri
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
const localnotification = {
title: 'Download has finished',
body: fileName + " has been downloaded. Tap to open file.",
android: {
sound: true,
},
ios: {
sound: true,
},
data: {
fileUri: uri
},
};
localnotification.data.title = localnotification.title;
localnotification.data.body = localnotification.body;
let sendAfterFiveSeconds = Date.now();
sendAfterFiveSeconds += 3000;
const schedulingOptions = { time: sendAfterFiveSeconds };
Notifications.scheduleLocalNotificationAsync(
localnotification,
schedulingOptions
);
})
.catch(error => {
console.error(error);
Alert.alert(error);
});
};
listenForNotifications = () => {
const _this = this;
Notifications.addListener(notification => {
if (notification.origin === 'received') {
// We could also make our own design for the toast
// _this.refs.toast.show(<View><Text>hello world!</Text></View>);
const toastDOM =
<TouchableWithoutFeedback
onPress={() => {this.openFile(notification.data.fileUri)}}
style={{padding: '10', backgroundColor: 'green'}}>
<Text style={styles.toastText}>{notification.data.body}</Text>
</TouchableWithoutFeedback>;
_this.toast.show(toastDOM, DURATION.FOREVER);
} else if (notification.origin === 'selected') {
this.openFile(notification.data.fileUri);
}
// Expo.Notifications.setBadgeNumberAsync(number);
// Notifications.setBadgeNumberAsync(10);
// Notifications.presentLocalNotificationAsync(notification);
// Alert.alert(notification.title, notification.body);
});
};
componentWillMount() {
getiOSNotificationPermission();
this.listenForNotifications();
}
componentDidMount() {
// let asset = Asset.fromModule(md);
// Toast.show('Hello World');
}
openFile = (fileUri) => {
this.toast.close(40);
console.log('Opening file ' + fileUri);
FileSystem.readAsStringAsync(fileUri)
.then((fileContents) => {
// Get file contents in binary and convert to text
// let fileTextContent = parseInt(fileContents, 2);
this.setState({filePreviewText: fileContents});
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<Button style={styles.button}
title={"Download text file"}
onPress={this._handleButtonPress}
/>
<Button style={styles.button}
title={"Clear File Preview"}
onPress={() => {this.setState({filePreviewText: ""})}}
/>
</View>
<ScrollView style={styles.filePreview}>
<Text>{this.state.filePreviewText}</Text>
</ScrollView>
<Toast ref={ (ref) => this.toast=ref }/>
</View>
);
// <Toast
// ref={ (ref) => this.toast=ref }
// style={{backgroundColor:'green'}}
// textStyle={{color:'white'}}
// position={'bottom'}
// positionValue={100}
// opacity={0.8}
// />
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
buttonsContainer: {
flexDirection: 'row',
},
button: {
flex: 1
},
filePreview: {
flex: 1,
padding: 10,
},
toastText: {
color: 'white',
padding: 5,
justifyContent: 'flex-start',
},
});
- package.json: Add the following dependency (fork of react-native-easy-toast)
"react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"
There are a couple of important notes about this solution:
Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.
Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the
<Text>component.The
crazycodeboy/react-native-easy-toastrepo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.Although this project is also available in Snack, it will not run due to the need of using a git repository in
package.jsonas mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.
The toast (internal notification) is created with a
TouchableWithoutFeedbackcomponent, although there are other similar ones in React Native with various differences. This component can be customised in the code (search fortoastDOM), but might even be replaceable in the future by internal notifications available in Expo.Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.
And that's it! I think this gives a good starting point for file downloading and previewing with Expo.
Codebase also available on GitHub.
This one had one or two tricks, but here is a solution to this using Expo that works on both iOS and Android.
In a new Expo project, amend the following two files:
- App.js
import React, { Component } from 'react';
import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
import { FileSystem, Constants, Notifications, Permissions } from 'expo';
import Toast, {DURATION} from 'react-native-easy-toast';
async function getiOSNotificationPermission() {
const { status } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
if (status !== 'granted') {
await Permissions.askAsync(Permissions.NOTIFICATIONS);
}
}
export default class App extends Component {
constructor(props) {
super(props);
// this.toast = null;
this.listenForNotifications = this.listenForNotifications.bind(this);
// this.openFile = this.openFile.bind(this);
this.state = {
filePreviewText: ''
}
}
_handleButtonPress = () => {
let fileName = 'document.txt';
let fileUri = FileSystem.documentDirectory + fileName;
FileSystem.downloadAsync(
"https://raw.githubusercontent.com/expo/expo/master/README.md",
fileUri
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
const localnotification = {
title: 'Download has finished',
body: fileName + " has been downloaded. Tap to open file.",
android: {
sound: true,
},
ios: {
sound: true,
},
data: {
fileUri: uri
},
};
localnotification.data.title = localnotification.title;
localnotification.data.body = localnotification.body;
let sendAfterFiveSeconds = Date.now();
sendAfterFiveSeconds += 3000;
const schedulingOptions = { time: sendAfterFiveSeconds };
Notifications.scheduleLocalNotificationAsync(
localnotification,
schedulingOptions
);
})
.catch(error => {
console.error(error);
Alert.alert(error);
});
};
listenForNotifications = () => {
const _this = this;
Notifications.addListener(notification => {
if (notification.origin === 'received') {
// We could also make our own design for the toast
// _this.refs.toast.show(<View><Text>hello world!</Text></View>);
const toastDOM =
<TouchableWithoutFeedback
onPress={() => {this.openFile(notification.data.fileUri)}}
style={{padding: '10', backgroundColor: 'green'}}>
<Text style={styles.toastText}>{notification.data.body}</Text>
</TouchableWithoutFeedback>;
_this.toast.show(toastDOM, DURATION.FOREVER);
} else if (notification.origin === 'selected') {
this.openFile(notification.data.fileUri);
}
// Expo.Notifications.setBadgeNumberAsync(number);
// Notifications.setBadgeNumberAsync(10);
// Notifications.presentLocalNotificationAsync(notification);
// Alert.alert(notification.title, notification.body);
});
};
componentWillMount() {
getiOSNotificationPermission();
this.listenForNotifications();
}
componentDidMount() {
// let asset = Asset.fromModule(md);
// Toast.show('Hello World');
}
openFile = (fileUri) => {
this.toast.close(40);
console.log('Opening file ' + fileUri);
FileSystem.readAsStringAsync(fileUri)
.then((fileContents) => {
// Get file contents in binary and convert to text
// let fileTextContent = parseInt(fileContents, 2);
this.setState({filePreviewText: fileContents});
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<Button style={styles.button}
title={"Download text file"}
onPress={this._handleButtonPress}
/>
<Button style={styles.button}
title={"Clear File Preview"}
onPress={() => {this.setState({filePreviewText: ""})}}
/>
</View>
<ScrollView style={styles.filePreview}>
<Text>{this.state.filePreviewText}</Text>
</ScrollView>
<Toast ref={ (ref) => this.toast=ref }/>
</View>
);
// <Toast
// ref={ (ref) => this.toast=ref }
// style={{backgroundColor:'green'}}
// textStyle={{color:'white'}}
// position={'bottom'}
// positionValue={100}
// opacity={0.8}
// />
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
buttonsContainer: {
flexDirection: 'row',
},
button: {
flex: 1
},
filePreview: {
flex: 1,
padding: 10,
},
toastText: {
color: 'white',
padding: 5,
justifyContent: 'flex-start',
},
});
- package.json: Add the following dependency (fork of react-native-easy-toast)
"react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git"
There are a couple of important notes about this solution:
Uses Expo API the most, for external local notifications and writing to / reading from files, which limits the current solution to being unable to write to other locations than Expo's own directory.
Once the file is downloaded, either a customisable toast is shown to the user if the app is active (Expo currently does not support foreground notifications), or sends a local Push Notification to let the user know the download has finished. Clicking on any of these two will show the contents of the file in a View, using the
<Text>component.The
crazycodeboy/react-native-easy-toastrepo has not been used directly due to a limitation of the toast, which is that the touch events are currently disregarded. The forked repo makes this functionality available before the merge request is implemented in the original. I recommend switching back to the original one once it gets patched as I will likely not maintain mine.Although this project is also available in Snack, it will not run due to the need of using a git repository in
package.jsonas mentioned above, and other apparent inconsistencies in variable scoping. This would be fixed by either the merge request or the new feature in Snack.Other file types may be supported, either by Expo itself or via external packages, such as this PDF viewer. However, the code will have to be further adapted.
The toast (internal notification) is created with a
TouchableWithoutFeedbackcomponent, although there are other similar ones in React Native with various differences. This component can be customised in the code (search fortoastDOM), but might even be replaceable in the future by internal notifications available in Expo.Lastly, an intentional three-second delay is applied to the notification once the file is downloaded – this allows us to test the notification when the app is in background. Feel free to remove the delay and trigger the notification immediately.
And that's it! I think this gives a good starting point for file downloading and previewing with Expo.
Codebase also available on GitHub.
answered Jan 26 at 1:31
SiavasSiavas
1,77111023
1,77111023
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f47979921%2fexpo-filesystem-downloadasync-do-not-show-download-notification%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Do you consider both Android and iOS? Which file types will be allowed for download?
– Siavas
Jan 21 at 23:35
@Siavas (Bounty giver) For me, both. In my case it's a simple *.txt
– Charanor
Jan 24 at 19:23
@Charanor, OP, in this case how do you envision the download notification to take action? Should it just allow opening the file from its own directory? Otherwise being able to select where to download the file might not be feasible in Expo.
– Siavas
Jan 24 at 22:45
@Siavas just a simple notification that allows you to open the file when pressed. This is possible to do with "normal" notifications on android but not iOS from what I can tell (iOS does not allow to open arbitrary links with notifications) (notification example)
– Charanor
Jan 24 at 22:49
@Charanor have added a solution to your use-case. Let me know how this goes for you.
– Siavas
Jan 26 at 14:27