Abhishek
Abhishek

Reputation: 173

react-native How to open local file url using Linking?

I'm using the following code to download a file (can be a PDF or a DOC) and then opening it using Linking.

const { dirs } = RNFetchBlob.fs;
let config = {
    fileCache : true,
    appendExt : extension,
    addAndroidDownloads : {
        useDownloadManager : false,
        notification : false,
        title : 'File',
        description : 'A file.',
        path: `${dirs.DownloadDir}/file.${extension}`,
    },
};
RNFetchBlob.config(config)
    .fetch(
        method,
        remoteUrl,
        APIHelpers.getDefaultHeaders()
    )
    .then((res) => {
        let status = res.info().status;
        if (status == 200) {
            Linking.canOpenURL(res.path())
                .then((supported) => {
                    if (!supported) {
                        alert('Can\'t handle url: ' + res.path());
                    } else {
                        Linking.openURL(res.path())
                            .catch((err) => alert('An error occurred while opening the file. ' + err));
                    }
                })
                .catch((err) => alert('The file cannot be opened. ' + err));
        } else {
            alert('File was not found.')
        }
    })
    .catch((errorMessage, statusCode) => {
        alert('There was some error while downloading the file. ' + errorMessage);
    });

However, I'm getting the following error:

An error occurred while opening the file. Error: Unable to open URL: file:///Users/abhishekpokhriyal/Library/Developer/CoreSimulator/Devices/3E2A9C16-0222-40A6-8C1C-EC174B6EE9E8/data/Containers/Data/Application/A37B9D69-583D-4DC8-94B2-0F4AF8272310/Documents/RNFetchBlob_tmp/RNFetchBlobTmp_o259xexg7axbwq3fh6f4.pdf

I need to implement the solution for both iOS and Android.

Upvotes: 11

Views: 19231

Answers (4)

Atikur Rahman Sabuj
Atikur Rahman Sabuj

Reputation: 436

This can be done with 'rn-fetch-blob'

RNFetchBlob.android.actionViewIntent(fileLocation, mimeType);

Upvotes: 0

sangaloma
sangaloma

Reputation: 422

I think the easiest way to do so is by using react-native-file-viewer package.

It allows you to Prompt the user to choose an app to open the file with (if there are multiple installed apps that support the mimetype).

import FileViewer from 'react-native-file-viewer';

const path = // absolute-path-to-my-local-file.
FileViewer.open(path, { showOpenWithDialog: true })
.then(() => {
    // success
})
.catch(error => {
    // error
});

Upvotes: 5

Kira
Kira

Reputation: 1

Are you downloading it from the web? I can see the pdf path is attached at the end of the error path.
For web URLs, the protocol ("http://", "https://") must be set accordingly!

Try to append appropriate schemes to your path. Check it out from the link mentioned below.

Upvotes: 0

Abhishek
Abhishek

Reputation: 173

So, I finally did this by replacing Linking by the package react-native-file-viewer.

In my APIHelpers.js:

async getRemoteFile(filePath, extension, method = 'GET') {
    const remoteUrl = `${API_BASE_URL}/${encodeURIComponent(filePath)}`;
    const { dirs } = RNFetchBlob.fs;
    let config = {
        fileCache : true,
        appendExt : extension,
        addAndroidDownloads : {
            useDownloadManager : false,
            notification : false,
            title : 'File',
            description : 'A file.',
            path: `${dirs.DownloadDir}/file.${extension}`,
        },
    };

    return new Promise(async (next, error) => {
        try {
            let response = await RNFetchBlob.config(config)
                .fetch(
                    method,
                    remoteUrl,
                    this.getDefaultHeaders()
                );
            next(response);
        } catch (err) {
            error(err);
        }
    });
}

In my Actions.js

export function openDocument(docPath, ext) {
    return async (dispatch) => {
        dispatch(fetchingFile());
        APIHelpers.getRemoteFile(docPath, ext).then(async function(response) {
            dispatch(successFetchingFile());
            let status = response.info().status;
            if (status == 200) {
                const path = response.path();
                setTimeout(() => {
                    FileViewer.open(path, {
                        showOpenWithDialog: true,
                        showAppsSuggestions: true,
                        })
                        .catch(error => {
                            dispatch(errorOpeningFile(error));
                        });
                }, 100);
            } else {
                dispatch(invalidFile());
            }
            }).catch(function(err) {
                dispatch(errorFetchingFile(err));
            });
    }
}

In my Screen.js


import { openDocument } from 'path/to/Actions';

render() {
    return <Button
                title={'View file'}
                onPress={() => this.props.dispatchOpenDocument(doc.filepath, doc.extension)}
            />;
}
.
.
.
const mapDispatchToProps = {
    dispatchOpenDocument: (docPath, ext) => openDocument(docPath, ext),
}

Upvotes: 1

Related Questions