Trying to download pdf from react native webview - react-native

I can't seem to get this to work i know. the "onFileDownload={ ( { nativeEvent: { downloadUrl } } ) => {" has been added and i need my own code to make this work. I tried to use expo file system and expo sharing to get this to download but it's not working. all i want is that when they download a pdf instead of a preview they can share the document or save it. Any help would be greatly appreciated.
Below is the code i tried to make it work but failed (the alert function works but then nothing happens):
import React, { Component } from 'react';
import { StyleSheet, ActivityIndicator, View, Platform, PermissionsAndroid, Alert } from 'react-native';
import * as Permissions from 'expo-permissions';
import { WebView } from 'react-native-webview';
//sharing and download
import * as Sharing from 'expo-sharing';
import * as FileSystem from 'expo-file-system';
import { Image, Text, TouchableOpacity, } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
export default function App() {
let [selectedImage, setSelectedImage] = React.useState(null);
let openImagePickerAsync = async () => {
const downloadResumable = FileSystem.createDownloadResumable(
{downloadUrl},
${FileSystem.documentDirectory}/pdf.pdf,
{},
);
const { uri, status } = await downloadResumable.downloadAsync();
// setSelectedImage({ localUri: uri });
Sharing.shareAsync(uri);
};
let openShareDialogAsync = async () => {
if (!(await Sharing.isAvailableAsync())) {
alert(Uh oh, sharing isn't available on your platform);
return;
}
Sharing.shareAsync(selectedImage.localUri);
};
// if (selectedImage !== null) {
// return (
//
//
// Share this
//
//
// );
// }
return (
<View style={{ flex: 1 }}>
<WebView
style={{ flex: 1 }}
source={{ uri: 'http://www.pdf995.com/' }}
onFileDownload={ ( { nativeEvent: { downloadUrl } } ) => {
Alert.alert(
"Documents",
"Do you wish to download and share this document",
[
{
text: "Download",
onPress: () => {openImagePickerAsync}
},
{
text: "Cancel",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
],
{ cancelable: false }
);}
} />
</View>
);
}
I took the code from expo snack: https://snack.expo.io/#trinet/sharing
Any help would be greatly appreciated. I'm really stuck

I had the same experience, in my case, it was due to some wrong header config, Content-Disposition inline instead of an attachment, so what happened is that inline attribute makes it render the content in the web page whereas attachment sees a file and tries to download it without previewing.
Add this in the header config of the file on the server and you will be file.
Credits to this SO answer and this

Related

How to download a pdf file in a react-native iOS webview?

Just developing a simple react-native app using expo and react-native-webview library.
The problem is that when users try to download an invoice in pdf format, iOS shows the preview and it's not possible to go back to the app.
Here attached the main app screen component:
import React, { useState } from "react";
import { ActivityIndicator, Share, StyleSheet } from "react-native";
import * as FileSystem from 'expo-file-system';
const { downloadAsync, documentDirectory } = FileSystem;
import { SafeAreaView } from 'react-native-safe-area-context';
import { WebView } from 'react-native-webview';
const HomeScreen = ({ navigation }) => {
const [loading, setLoading] = useState(true);
let downloadDocument = async (downloadUrl) => {
alert('downloadUrl 2: ', downloadUrl);
let fileURI = await downloadAsync(
downloadUrl,
`${documentDirectory}/invoice.pdf`,
{}
);
await onShare(fileURI.uri);
}
const onShare = async (url) => {
try {
return Share.share({
message: 'Select storage location',
url: url
});
} catch (error) {
alert('error: ', error);
return error;
}
};
return (
<SafeAreaView style={styles.container}>
<WebView
source={{ uri: '<url>' }}
onError={() =>
navigation.navigate('Error')
}
setSupportMultipleWindows={false}
startInLoadingState={true}
renderLoading={() =>
<ActivityIndicator
style={styles.spinner}
size='large'
color='#0098D4'
/>
}
domStorageEnabled={true}
// iOS
onFileDownload={({ nativeEvent: { downloadUrl } }) => {
alert('downloadUrl: ', downloadUrl);
downloadDocument(downloadUrl);
}}
/>
</SafeAreaView>
);
}
We added some alerts, but the're never fired.
In the html code, there is an tag with href property pointing to the file's url and the download option set.
Any solution?

React native package #homee/react-native-mapbox-navigation not showing map (ANDROID)

I am trying to implement a turn by turn navigation in react native, I have used the package '#homee/react-native-mapbox-navigation'. I have used these instructions (https://reactnativeexample.com/smart-mapbox-turn-by-turn-routing-based-on-real-time-traffic-for-react-native/) to set all the gradle.properties / gradle.build and the manifest setting. This is how my app.js looks like:
import React from 'react';
import type {Node} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import MapboxNavigation from '#homee/react-native-mapbox-navigation';
const App: () => Node = () => {
// const isDarkMode = useColorScheme() === 'dark';
// const backgroundStyle = {
// backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
// };
return (
<View style={styles.container}>
<MapboxNavigation
origin={[-97.760288, 30.273566]}
destination={[-97.918842, 30.494466]}
shouldSimulateRoute={true}
onLocationChange={(event) => {
const { latitude, longitude } = event.nativeEvent;
}}
onRouteProgressChange={(event) => {
const {
distanceTraveled,
durationRemaining,
fractionTraveled,
distanceRemaining,
} = event.nativeEvent;
}}
onError={(event) => {
const { message } = event.nativeEvent;
console.log('error', event)
}}
onCancelNavigation={() => {
// User tapped the "X" cancel button in the nav UI
// or canceled via the OS system tray on android.
// Do whatever you need to here.
}}
onArrive={() => {
// Called when you arrive at the destination.
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default App;
This is what my simulator is showing:
Is there someone who knows why I am getting an empty screen and how to fix this?
Thx guys!
The code works fine the mistake was that I put the meta-data tag in the wrong section
of the androidManifest.xml. I fixed this and it worked

Uhandled atob variable on screen rendering

The error I get is [Unhandled promise rejection: ReferenceError: Can't find variable: atob].
And my screen code:
import React, { Component } from "react";
import { View, StatusBar, Text } from "react-native";
import firebase from "firebase";
import "firebase/firestore";
import { RowItem } from "../components/RowItem";
import { Header, Left, Right, Icon } from "native-base";
const styles = {
container: {
flexDirection: "row",
flexWrap: "wrap",
padding: 20
}
};
class QuizIndex extends Component {
constructor(props) {
super(props);
this.state = {
docs: []
};
}
async componentDidMount() {
await this.quizes();
}
quizes = async () => {
let result = await firebase
.firestore()
.collection("quiz")
.where("parentId", "==", "")
.get()
.then(r => {
console.log("fine");
})
.catch(e => {
console.log("Not fine");
});
const docs = result.docs.map(doc => {
return { uid: doc.id, ...doc.data() };
});
return this.setState({ docs });
};
render() {
return (
<View style={styles.container}>
<StatusBar barStyle="dark-content" />
{this.state.docs.map(doc => (
<RowItem
key={doc.uid}
parentId={doc.parentId}
name={doc.title}
color={doc.color}
icon={doc.icon}
onPress={() =>
this.props.navigation.navigate("QuizSub", {
title: doc.title,
color: doc.color,
parentId: doc.uid
})
}
/>
))}
</View>
);
}
}
export default QuizIndex;
I don't get it where this problem occur because the things were working fine. Do you have any suggestion about this ? I googled it but none of the solutions helped me.
It's an issue in firebase dependency
Try to use version 7.9.0, this version will work fine.
yarn add firebase#7.9.0
I think if you install the base-64 npm package it will solve, but don't quite know why this is happening.
yarn add base-64
#or
npm install base-64
At App.js add:
import {decode, encode} from 'base-64'
if (!global.btoa) { global.btoa = encode }
if (!global.atob) { global.atob = decode }

React Native: How to take ScreenShot Programmatically and save it to the gallery

I am not able to find any documents that explain this feature.
I would like to know how to take screenshot programmatically and save it to the gallery.
I tried the react-native-view-show gallery but it doesn't work.
Any help would be appreciated
Current Code :
import React, { Component } from "react";
import { View, Text, Button, Image, ScrollView, StatusBar } from "react-native";
import { captureScreen } from "react-native-view-shot";
import CameraRollExtended from "react-native-store-photos-album";
export default class App extends Component {
componentDidMount() {
StatusBar.setHidden(true, "none");
}
render() {
return (
<View>
<Button
title="Click"
onPress={() => {
captureScreen({
format: "jpg",
quality: 0.8
}).then(
uri => {
CameraRollExtended.saveToCameraRoll(
{
uri: uri,
album: "Name"
},
"photo"
);
},
error => console.error("Oops, snapshot failed", error)
);
}}
/>
</View>
);
}
}

Is it possible to encrypt the images of android device using react native?

I am developing an app where I take photos using react-native-image-picker and upload those to the AWS server. Once after uploading those I want to encrypt those taken images in the Android device i.e in saved folder. Is it possible to do? If yes, How can I do that using react-native?
My code is,
I am able to capture images and uploading to the AWS s3.
import React, { Component } from "react";
import {
Platform,
StyleSheet,
Alert,
Text,
TouchableOpacity,
View,
Picker,
Animated,
Easing,
Image
} from "react-native";
import ImagePicker from "react-native-image-picker";
import { RNS3 } from "react-native-aws3";
export default class SecondScreen extends Component<Props> {
constructor(props) {
super(props);
this.state = {
file: "",
saveImages: []
};
}
takePic() {
ImagePicker.launchCamera({}, responce => {
const file = {
uri: responce.uri,
name: responce.fileName,
method: "POST",
path: responce.path,
type: responce.type,
notification: {
enabled: true
}
};
this.state.saveImages.push(file);
});
}
_upload = saveImages => {
const config = {
keyPrefix: "uploads/",
bucket: "s3merahkee",
region: "us-east-2",
accessKey: "***",
secretKey: "***",
successActionStatus: 201
};
this.state.saveImages.map(image => {
RNS3.put(image, config).then(responce => {
console.log(saveImages);
});
});
};
render() {
return (
<View style={styles.container}>
<View style={styles.Camera}>
<TouchableOpacity onPress={this.takePic.bind(this)}>
<Text>Take Picture</Text>
</TouchableOpacity>
</View>
<View style={styles.Send}>
<TouchableOpacity onPress={() => this._upload()}>
<Text>Send</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
I am using two methods here, one the for capturing images and once the user clicks on send it to upload the file to AWS s3.
I hope I can encrypt the image If possible tell me how can I implement it. Or if not possible suggest me the other way that I can do it. (EX: deleting, etc..)
I have done this using converting image to base64. Using react-native-fs library, I am able to achieve this. Here, Once I captured the images I convert them to a base64 string and delete the real image from the folder.
My code is,
takePic = () => {
// create a path you want to write to
var pictureFolder = RNFetchBlob.fs.dirs.SDCardDir+'/Schoolapp';
ImagePicker.launchCamera(options,(responce)=>{
const file ={
uri : responce.uri,
name : responce.fileName,
method: 'POST',
path : responce.path,
type : responce.type,
notification: {
enabled: true
}
}
//convert image into base64
const base64 = RNFS.writeFile(responce.uri, responce.data);
return base64;
//delete the original image
RNFS.unlink(responce.path)
.then(() => {
console.log('deleted');
RNFS.scanFile(responce.path)
.then(() => {
console.log('scanned');
})
.catch(err => {
console.log(err);
});
})
.catch((err) => {
console.log(err);
})
});
}