React-Native WebView: Issue downloading and saving dynamically generated file - react-native

We are opening a Url (in WebView) which has a button that dynamically generates and downloads a file (e.g. PDF or Excel or any other type) based on user selected filters. This means that we do not have direct link to those files which can be downloaded using network request. In chrome, we can see downloaded file. However in WebView, we neither see download file (the way chrome shows at the bottom of window) nor we get any way to intercept/view the location where it is downloaded silently. Below is webview:
<WebView
ref={ref => (webview = ref)}
originWhitelist={['*']}
source={{ uri: pageURL }}
javaScriptEnabled={true}
startInLoadingState={true}
scalesPageToFit={true}
domStorageEnabled={true}
onError={(err) => console.log(err)}
onHttpError={(err) => console.log(err)}
allowFileAccess={true}
allowFileAccessFromFileURLs={true}
allowUniversalAccessFromFileURLs={true}
allowingReadAccessToURL={true}
mixedContentMode="always"
onFileDownload={({ nativeEvent }) => {
const { downloadUrl } = nativeEvent;
console.log(downloadUrl);
}}
onNavigationStateChange={handleWebViewNavigationStateChange}
onLoad={() => {
webview.injectJavaScript(jsCode);
}}
onMessage={event => {
const { data } = event.nativeEvent;
}}
/>
So, we have below queries:
How to know if WebView actually downloaded a file?
Is there a way to know where WebView downloads a file?
Is there a way to specify default location where WebView should download a file?
Environment:
Expo: 40.0.0,
React-native: 0.63,
react-native-webview: 11.0.0
We clicked on "Allow" when it asked for permission to download and store file on device. Also, onNavigationStateChange is not firing when button is clicked (may be because the file is downloaded on same page without navigating). We have onError and onHttpError which does not print anything so there does not seem to be any issue there.
Below is the code (C#) that gets executed when button is clicked to download file:
string attachment = "attachment; filename=temp.csv";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.AddHeader("Pragma", "public");
// Prepare file content
HttpContext.Current.Response.Write(fileContent.ToString());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.Close();

Related

How to only load/render custom rendered image when it comes into view (react-native-render-html)

I am using react-native-render-html to render content that has images in it via a custom renderer. The issue I'm running into is some pages have dozens of images, and I would like to only download/render the ones I need that are in or near the viewport. The way the custom renderer is set up currently (via the documentation) it downloads all of them at once (How would I go about Implementing the logic into a more flatlist-like render system?
Here's the image renderer (if it helps):
const ImgRenderer = useCallback((props: any) => {
console.log('imgRendererProps: ', props)
const { Renderer, rendererProps } = useInternalRenderer('img', props);
const uri = rendererProps.source.uri;
const imgSource = {
...rendererProps.source,
// You could change the uri here, for example to provide a thumbnail.
uri: `https://home.website.com${uri?.split('about://')[1]}`
};
return (
<TouchableWithoutFeedback onPress={() => setModalImage(uri?.split('about://')[1] ?? null)}>
<Renderer {...rendererProps} source={imgSource} style={{resizeMode: 'contain'}} />
</TouchableWithoutFeedback>
);
}, [props.tnode?.init.nodeIndex])

Download zip file in web view in react native

I'm trying to download file from a web view. I have used javascript inject to click on submit button.
I'm specifically trying this for offline aadhaar - https://resident.uidai.gov.in/offline-kyc
Reference Code -
<WebView
source={{ uri: "https://resident.uidai.gov.in/offline-kyc" }}
ref={webviewRef}
renderLoading={LoadingIndicatorView}
startInLoadingState={true}
injectedJavaScript={runFirst}
onMessage={onMessage}
renderError={loadError}
// onFileDownload={({ nativeEvent: { downloadUrl } }) => {
// console.log(downloadUrl);
// }}
/>
I have tried with api request by creating/replicating the browser behaviour for api call but it's not working. Any suggestions.
You can try react-native-fs
You can use downloadFile API to download and save the file to the device.

react native can't dynamically change Image component source uri

I'm facing a weird issue/bug with react native (0.61.5). I have a screen where a user can change his profile picture. The picture is fetched from redux.
const [pp, setPp] = useState(useSelector(state => state.profile.pp))
const ppChangeHandler = async () => {
try {
req = await fetch(...)
res = await req.json()
// res.url contains the url to the new uploaded image on the server
setPp(res.url)
} catch (e) {
console.log(e)
}
}
As you can see, I send a request to the server containing the new image (this is not included in the code, but it works), and as a response, I receive the newly generated url to the image. I want to update the profile picture on the screen to the new image once I receive the image url. But this does not work. The image dissapears and is not updated.
I'm thinking I'm facing this bug: Image Component will not update correctly when passing in new url #9195
I have tried the following things:
Adding a "key" prop to containing 'pp': <Image key={pp} source={{ uri: pp }} style={{ width: 100, height: 100 }} />
Adding "cache: reload" to the source: <Image source={{ uri: pp, cache: reload }} style={{ width: 100, height: 100 }} />
Does anyone has a tip/workaround for this problem? The "update" of the image works, when I refresh the app, the new profile picture is showed, but I want it to show immediately, not after refreshing the app.
Edit: I also tried it with FastImage (https://github.com/DylanVann/react-native-fast-image) but I get the same result.

Open link in a HTML in react native webview

I sucessfully render a HTML file to view using react-native-webview. And when I click on a link in a view, it loads perfectly on IOS at the same view. But the link doesn't work on Android. It shows 'Cannot download files as permission was denied. Please provide permisson to write to storage, in order to download files'
I've tried to add this line of code to AndroidManifest.xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> But it downloads as a file to the phone, not in a view of WebView. What did I miss?
<WebView
originWhitelist={['*']}
source={ Platform.OS === 'ios'
? this.renderHTML(content)
: this.renderHTMLAndroid(content)
}
domStorageEnabled
javaScriptEnabled
/>
I came to a solution. It doesn't render in a view of webview but open a link in a browser (for Android). It is not really what I want, but at least it works.
import { Linking } from 'react-native'
loading = (event) => {
if (event.url.slice(0,4) === 'http') {
Linking.openURL(event.url)
return false
}
return true
}
then in WebView, add
onShouldStartLoadWithRequest={ Platform.OS === 'ios'
? null
: this.loading
}

React Native Webview handle url change listener

it is possible to handle URL change on React Native web view.
I try to handle with onNavigationStateChange listener. But it only once time firing. When the page is load firing onNavigationStateChange. And when I navigate to another page, this event not firing.
Any idea?
With the reference to import { WebView } from 'react-native-webview' you may be using old version of webview please try updating or try following code/method to get current navigation path/url.
In your case onNavigationStateChange is not returning navigated path so you can try using onLoadProgress which return every change in url.
Instead of this
onNavigationStateChange={(state) => {
console.log("current_path",path);
}}
try this
This may get called multiple time please handle your condition accordingly.
onLoadProgress={({ path}) => {
console.log("current_path",path);
}}
This is how my WebView looks like
<WebView
source={{ uri: this.state.url }}
onLoadEnd={() => this.hideSpinner()}
onMessage={onMessage.bind(this)}
ref={WEBVIEW_REF => (this.WebViewRef = WEBVIEW_REF)}
startInLoadingState={true}
javaScriptEnabled={true}
domStorageEnabled={true}
onLoadProgress={({ nativeEvent }) => {
//your code goes here
}}
onNavigationStateChange={(state) => {
//your code goes here
}}
/>
Try upgrading your React Native (and React) version.
It should be fixed. Maybe was an old issue, because right now it's working OK.
Check this link: React Native webview get url
onNavigationStateChange={({ url, canGoBack }) => {
console.log("url>>>>>>>>",url);
}}
I load website link in react native WebView and its has button when i click that it navigate to default mobile browser.
Running application in react native android Current scenario: when i click button in website its navigate to default browser and am not getting the url i tried above suggestions.
Expected scenario: When i click that button in website it should not navigate to default browser and i want that url which is opened in default browser.
my react version: "react-native": "0.64.0",
onLoadProgress = {({ nativeEvent }) => {
//your code goes here
}}
onNavigationStateChange={navState => {
console.log("navState ", navState);
}}