我在处理 React Native 应用程序时遇到错误。
当我尝试将页面的 HTML 内容转换为 PDF 以供导出和发送给客户电子邮件时,我收到以下错误:
Error: Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported.
后端API是在ASP.NET Core 8中构建的。我尝试转换为PDF的页面包含客户签名,该应用程序将在Android和iOS设备上使用。
这是我要导出的页面:
import {
View,
Text,
Image,
StyleSheet,
ScrollView,
TextInput,
Button,
Alert,
TouchableOpacity,
Modal,
Switch,
} from "react-native";
import { useNavigation } from "@react-navigation/native";
import { useAppContext } from "../../AppContext";
import { getCurrentDate } from "../helpers/DateHelper";
import SignatureSpace from "../components/SignatureSpace";
import { error } from "pdf-lib";
const DataScreen = () => {
const {
cardHolderName,
userID,
email,
phoneNumber,
address,
locality,
postalCode,
county,
barcodeData,
registrationType,
fiscalCode,
globalRegistrationType,
companyNameData,
} = useAppContext();
const navigation = useNavigation();
const pageRefAll = useRef(null);
const signatureRef = useRef(null);
const [signatureData, setSignatureData] = useState(null);
const [isButtonEnabled, setIsButtonEnabled] = useState(false);
const [isModalVisible, setIsModalVisible] = useState(false);
const [form, setForm] = useState({
date: "",
communicationChannel: [],
});
// .............
useEffect(() => {
const allFieldsCompleted = signatureData !== null;
setIsButtonEnabled(allFieldsCompleted);
}, [signatureData]);
const sendCardToEmail = async () => {
try {
let emailBody =
`Hello, ${cardHolderName}\nHere are your registration details:\n` +
`Email: ${email}\n` +
`Phone Number: ${phoneNumber}\n` +
`Address: ${address}, ${postalCode}, ${locality}, ${county}`;
if (registrationType === "business") {
emailBody += `\nFiscal Code: ${fiscalCode}`;
}
const emailDetails = {
name: cardHolderName,
fiscalCode: fiscalCode,
email: email,
phoneNumber: phoneNumber,
barcode: barcodeData,
registrationType: registrationType,
address: `${address}, ${postalCode}, ${locality}, ${county}`,
body: emailBody,
};
const response = await fetch(
"https://flowermarketapi.azurewebsites.net/Clients/send-email",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(emailDetails),
}
);
if (response.ok) {
console.log("Email sent successfully!");
} else {
console.error("Failed to send email. " + (await response.text()));
}
} catch (error) {
console.error("Error sending email", error);
}
};
const handleSubmit = async () => {
if (!isButtonEnabled) return;
// sendCardToEmail();
// navigation.navigate("Card");
const gdprHtmlString = `
<div class="dataScreen">
>! here is the text that will be sent to API in order to convert and send via email
</div>`;
console.log("GDPR " + { companyNameData } + ".pdf");
const blob = dataURItoBlob(signatureData);
console.log("signatureData", signatureData);
const formData = new FormData();
console.log("FormData", FormData);
try {
formData.append("model", gdprHtmlString);
console.log("model", gdprHtmlString); // here is stop the application and not move forward
formData.append("signature", blob);
console.log("signature", blob);
formData.append("userID", userID);
console.log("userID", userID);
formData.append("fileNameftp", companyNameData);
console.log("fileNameftp", companyNameData);
} catch (error) {
console.log("Error during creating PDF: ", error);
}
try {
// Send the request with both form data and JSON data
const response1 = await fetch(
"https://flowermarketapi.azurewebsites.net/api/fileupload/export",
{
method: "POST",
body: formData,
}
);
if (response1.ok) {
console.log("response ok");
}
} catch (error) {
console.log("Error during loading: ", error);
}
try {
sendCardToEmail();
navigation.navigate("Card");
} catch (error) {
console.error("Error during submission: ", error);
Alert.alert(
"Error",
"There was an error during submission: " + error.message
);
}
};
function dataURItoBlob(dataURI) {
const byteString = atob(dataURI.split(",")[1]);
const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
}
return (
<ScrollView contentContainerStyle={styles.dataScreen}>
<View style={styles.dataContainer} ref={pageRefAll}>
<View style={styles.dataHeader}>
<Image
source={require("../../assets/logo-dark 600.png")}
style={styles.dataLogo}
resizeMode="contain"
onError={(error) => console.log("Image load error: ", error)}
onLoad={() => console.log("Image loaded successfully")}
/>
<Text style={styles.companyName}>FLOWERS MARKET HOLLAND S.R.L.</Text>
>! ............. the text that will be sent to the client .................
>! ..........................
>! ..........................
<View style={styles.signatureContainer}>
<View style={styles.signatureSection}>
<Text style={styles.labelTop}>{getCurrentDate(".")}</Text>
<Text style={styles.labelTop}>{companyNameData}</Text>
<Text style={styles.labelTop}>{cardHolderName}</Text>
<TouchableOpacity
style={styles.clientSignature}
onPress={handleSignatureOpen}
>
{signatureData ? (
<Image
source={{ uri: signatureData }}
style={{ width: "100%", height: "100%" }}
/>
) : (
<Text>Sign Here</Text>
)}
</TouchableOpacity>
</View>
{signatureData && (
<View style={styles.signatureContainer}>
{/* <Text>Signature Captured:</Text> */}
<Image
source={{ uri: signatureData }}
style={styles.signatureImage}
/>
</View>
)}
<Modal
visible={isModalVisible}
animationType="slide"
onRequestClose={handleSignatureClose}
>
<SignatureSpace
ref={signatureRef}
onSave={handleSignatureSave}
onClose={handleSignatureClose}
/>
</Modal>
</View>
</View>
</View>
<TouchableOpacity
style={[
styles.acceptButton,
!isButtonEnabled && styles.disabledButton,
]}
onPress={handleSubmit}
disabled={!isButtonEnabled}
>
<Text style={styles.buttonText}>Accept and Continue</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
};
package-json 看起来像这样:
"name": "my-project",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@kichiyaki/react-native-barcode-generator": "^0.6.7",
"@react-native-masked-view/masked-view": "^0.3.1",
"@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/native": "^6.1.17",
"@react-navigation/stack": "^6.3.29",
"expo": "~51.0.9",
"expo-dev-client": "~4.0.15",
"expo-status-bar": "~1.12.1",
"pdf-lib": "^1.17.1",
"react": "18.2.0",
"react-native": "0.74.1",
"react-native-barcode-builder": "^2.0.0",
"react-native-barcode-creator": "^0.1.7",
"react-native-gesture-handler": "^2.16.2",
"react-native-image-picker": "^7.1.2",
"react-native-safe-area-context": "^4.10.3",
"react-native-screens": "^3.31.1",
"react-native-signature-canvas": "^4.7.2",
"react-native-svg": "^15.3.0",
"react-native-view-shot": "^3.8.0",
"react-native-webview": "^13.8.6"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true
}````
I try to put more console logs in order to see where it stop, and the handleSubmit function is stop here:
````console.log("model", gdprHtmlString);````
The app runs on a tablet emulator from Android Studio because the client requires this technology. I need help finding a solution to send the client the page's content in a PDF with his signature.
该功能可以在浏览器中使用,但不能在您当前的 javascript 引擎(可能是 Hermes)中使用。
为了解决这个问题,您需要导入 Blob 的 ponyfills,例如
react-native-blob-util
或 rn-fetch-blob
。
在
rn-fetch-blob
的情况下,如果您希望当前代码在不自己处理数据的情况下工作,您需要将其添加到全局范围并覆盖现有功能。
由于您正在使用 fetch,因此您还需要这个。在这种情况下,你可能只需要 fetch polyfill,我认为它可能显式地使用 blob 依赖项。
对于 Hermes,该代码将如下所示:
import RNFetchBlob from 'rn-fetch-blob';
global.fetch = new RNFetchBlob.polyfill.Fetch({}).build();
如果它没有显式使用 blob 依赖项,您还需要这个:
global.Blob = RNFetchBlob.polyfill.Blob;
这将有效地将 ponyfills(现在事实上的标准方法)转换为 polyfills,这可能对您来说更容易使用。
如果您想将它们用作 ponyfill,只需将 Fetch polyfill 存储在变量中并调用它,而不是全局
fetch
。