Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-native下载pdf文件 #6

Open
gwl002 opened this issue Jun 22, 2021 · 0 comments
Open

react-native下载pdf文件 #6

gwl002 opened this issue Jun 22, 2021 · 0 comments

Comments

@gwl002
Copy link
Owner

gwl002 commented Jun 22, 2021

很久就实现过的功能,今天又遇到了,竟然无从下手,只好去翻翻旧代码并在这里记录一下也方便日后查看。

需求分析

  • ajax请求pdf文件
  • 转成base64
  • 下载到手机,需要能从外部App打开

1. 首先获取pdf文件二进制

async function getPdfBinary(url) {
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", url, true);
        xhr.responseType = "arraybuffer"; // get the binary 
        xhr.setRequestHeader('content-type', 'application/json');
        xhr.onload = function (event) {
            var arrayBuffer = xhr.response;
            var byteArray = new Uint8Array(arrayBuffer);
            var len = byteArray.byteLength;
            var binary = ""
            for (var i = 0; i < len; i++) {
                binary += String.fromCharCode(byteArray[i]);
            }
            resolve(binary);
        }
        xhr.send();
    })
}

2. 转成base64字符串

//react-native 并没有btoa和atob方法 需要自己实现
function base64_encode(str) {
    var c1, c2, c3;
    var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var i = 0,
        len = str.length,
        string = '';

    while (i < len) {
        c1 = str.charCodeAt(i++) & 0xff;
        if (i == len) {
            string += base64EncodeChars.charAt(c1 >> 2);
            string += base64EncodeChars.charAt((c1 & 0x3) << 4);
            string += "==";
            break;
        }
        c2 = str.charCodeAt(i++);
        if (i == len) {
            string += base64EncodeChars.charAt(c1 >> 2);
            string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
            string += base64EncodeChars.charAt((c2 & 0xF) << 2);
            string += "=";
            break;
        }
        c3 = str.charCodeAt(i++);
        string += base64EncodeChars.charAt(c1 >> 2);
        string += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
        string += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
        string += base64EncodeChars.charAt(c3 & 0x3F)
    }
    return string
}

3. 下载到android手机

今天刚好在stackoverflow上回答别人的问题,他需要的是expo,所以写了个expo版本的。Base64 String to pdf JavaScript React Native then download
For expo

const downloadForAos = async (pdfBase64Str) => {
    const folder = FileSystem.StorageAccessFramework.getUriForDirectoryInRoot("test");
    const permissions = await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync(folder);
    if (!permissions.granted) return;

    let filePath = await FileSystem.StorageAccessFramework.createFileAsync(permissions.directoryUri, "test.pdf", "application/pdf");
    // let filePath = "content://com.android.externalstorage.documents/tree/primary%3Atest/document/primary%3Atest%2Ftest.txt";
    console.log(pdfBase64Str, "====");
    try {
        await FileSystem.StorageAccessFramework.writeAsStringAsync(filePath, pdfBase64Str, { encoding: FileSystem.EncodingType.Base64 });
        alert("download success!")
    } catch (err) {
        console.log(err);
    }
}

For android

const downloadForAos = async (pdfBase64Str) => {
    const fileName = `/${Date.now()}_report.pdf`;
    const path = RNFS.DownloadDirectoryPath + fileName;
    try {
        const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
        );
        if (granted) {
            RNFS.writeFile(path, pdfBase64Str, "base64").then(res => {
                ToastAndroid.show(I18n.t("myHealth.Downloaded"), ToastAndroid.SHORT);
            }).catch(error => {
                ToastAndroid.show(I18n.t("myHealth.DownloadFailed"), ToastAndroid.SHORT);
            })
        }
    } catch (err) {
        console.warn(err);
    }
}

4. 下载到ios手机

ios不能直接下载文件到外部app,只能通过分享到file app实现。找了很久没找到其他办法,有其他办法的大神请多多指教。

const downloadPdfForIos = async (pdf) => {
    const url = "data:application/pdf;base64," + pdf;
    const shareOptions = {
        title: 'image report',
        failOnCancel: false,
        saveToFiles: true,
        url: url, // base64 with mimeType or path to local file
    };
    try {
        const ShareResponse = await Share.open(shareOptions);
        Alert.alert(
            null,
            I18n.t("myHealth.Downloaded"),
            [
                {
                    text: I18n.t("common.OK"),
                    onPress: () => null
                }
            ]
        );
    } catch (error) {
        if (error.error && error.error.code === "ECANCELLED500") {
            console.warn("canceled");
        } else {
            Alert.alert(
                null,
                I18n.t("myHealth.DownloadFailed"),
                [
                    {
                        text: I18n.t("common.OK"),
                        onPress: () => null
                    }
                ]
            );
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant