错误:ReactNative 不支持从“ArrayBuffer”和“ArrayBufferView”创建 blob

问题描述 投票:0回答:1

我在处理 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.
react-native arraybuffer react-native-cli
1个回答
0
投票

该功能可以在浏览器中使用,但不能在您当前的 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

    

© www.soinside.com 2019 - 2024. All rights reserved.