由于我生成的 PDF 的大小,无法进行 Base64 转换,我必须使用离屏功能。
基于这个答案->https://stackoverflow.com/a/75539867/8016254
我尝试下载一个 PDF 文件,该文件将在我的自定义 Chrome 扩展中重新读取。
背景.js
import './pdf-lib.min.js';
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
(async () => {
if (message.pdfUrls && message.pdfUrls.length > 0) {
// Debug PDF
const urls = ["https://www.africau.edu/images/default/sample.pdf"];
await mergeAllPDFs(urls, "Test");
}
})();
return true;
});
async function mergeAllPDFs(urls, filename) {
const numDocs = urls.length;
const pdfDoc = await PDFLib.PDFDocument.create();
for (let i = 0; i < numDocs; i++) {
console.log(`Fetching ${urls[i]}`)
const donorPdf = await fetch(urls[i]);
const donorPdfBytes = await donorPdf.arrayBuffer();
const donorPdfDoc = await PDFLib.PDFDocument.load(donorPdfBytes);
const copiedPages = await pdfDoc.copyPages(donorPdfDoc, donorPdfDoc.getPageIndices());
copiedPages.forEach((page) => pdfDoc.addPage(page));
}
const pdfDocBytes = await pdfDoc.save();
const waiting = await chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: ['BLOBS'],
justification: 'reason for needing the document',
});
chrome.runtime.sendMessage({
data: pdfDocBytes
}, (response) => {
console.log(response);
const url = response.url;
console.log(url);
chrome.downloads.download({
url: url,
filename: filename + ".pdf"
});
});
}
离屏.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const blob = new Blob([message.data], { type: "application/pdf" });
const url = URL.createObjectURL(blob);
sendResponse({ url: url });
return true;
});
生成的 PDF 似乎已损坏并且比预期小得多。有什么想法吗?
问题:chrome.runtime.sendMessage 无法在 Chrome 中发送二进制数据。
解决方案:使用标准网络消息传递。
//背景.js
async function main() {
const blob = new Blob(['foo']);
const blobUrl = await getBlobUrl(blob);
chrome.downloads.download({url: blobUrl, filename: filename + '.pdf'});
}
async function getBlobUrl(blob) {
const url = chrome.runtime.getURL('offscreen.html');
try {
await chrome.offscreen.createDocument({
url,
reasons: ['BLOBS'],
justification: 'MV3 requirement',
});
} catch (err) {
if (!err.message.startsWith('Only a single offscreen')) throw err;
}
const client = (await clients.matchAll({includeUncontrolled: true}))
.find(c => c.url === url);
const mc = new MessageChannel();
client.postMessage(blob, [mc.port2]);
const res = await new Promise(cb => (mc.port1.onmessage = cb));
return res.data;
}
//offscreen.html
<script src="offscreen.js"></script>
//offscreen.js
let timeout;
navigator.serviceWorker.onmessage = e => {
clearTimeout(timeout);
e.ports[0].postMessage(URL.createObjectURL(e.data));
timeout = setTimeout(close, 60e3);
};
navigator.serviceWorker.startMessages();
不要忘记将“offscreen”添加到manifest.json中的“permissions”。