From 51e016e18519f8ecef3be26e785538a8c8efcdc3 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Sun, 21 Jun 2026 09:23:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(xwebview):=20=E5=B0=86=20react-native-blob-?= =?UTF-8?q?util=20=E6=94=B9=E4=B8=BA=E6=87=92=E5=8A=A0=E8=BD=BD=E4=BB=A5?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=20RN=200.85=20Bridgeless=20=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 静态 import 会在模块评估时触发 fs.js:14 调用 ReactNativeBlobUtil.getConstants(), 在 Bridgeless 模式下 TurboModule 未注册时返回 null 导致崩溃。 改为在函数体内 require() 延迟至实际下载时才初始化。 Co-Authored-By: Claude Sonnet 4.6 --- packages/xwebview/src/XWebViewDownload.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/xwebview/src/XWebViewDownload.ts b/packages/xwebview/src/XWebViewDownload.ts index 6af349e..1a5d228 100644 --- a/packages/xwebview/src/XWebViewDownload.ts +++ b/packages/xwebview/src/XWebViewDownload.ts @@ -1,5 +1,4 @@ import { Platform } from 'react-native' -import RNFetchBlob from 'react-native-blob-util' import type { XWebViewDownloadDecision, @@ -8,6 +7,11 @@ import type { XWebViewDownloadResult, } from '@xuqm/rn-common' +// Lazy import: react-native-blob-util calls getConstants() at module evaluation time, +// which crashes in RN 0.85 Bridgeless mode. Defer the require until actual download use. +// eslint-disable-next-line @typescript-eslint/no-require-imports +const getRNFetchBlob = () => (require('react-native-blob-util') as { default: typeof import('react-native-blob-util').default }).default + function parseContentDispositionFilename(header: string): string | null { const rfc5987 = header.match(/filename\*=(?:[^']*'[^']*')?([^;\s]+)/i) if (rfc5987?.[1]) { @@ -70,7 +74,7 @@ async function resolveFilePath( const full = `${dir}/${filename}` if (conflict === 'overwrite') return full - const exists = await RNFetchBlob.fs.exists(full) + const exists = await getRNFetchBlob().fs.exists(full) if (!exists) return full const dot = filename.lastIndexOf('.') @@ -82,7 +86,7 @@ async function resolveFilePath( do { candidate = `${dir}/${base}(${n})${ext}` n++ - } while (await RNFetchBlob.fs.exists(candidate)) + } while (await getRNFetchBlob().fs.exists(candidate)) return candidate } @@ -93,14 +97,14 @@ export async function saveBase64File( savePath: string | undefined, conflict: 'rename' | 'overwrite', ): Promise { - const { dirs } = RNFetchBlob.fs + const { dirs } = getRNFetchBlob().fs const dir = savePath ?? (Platform.OS === 'android' ? (dirs.DownloadDir ?? dirs.DocumentDir) : dirs.DocumentDir) const filePath = await resolveFilePath(dir, filename, conflict) - await RNFetchBlob.fs.writeFile(filePath, base64, 'base64') + await getRNFetchBlob().fs.writeFile(filePath, base64, 'base64') return filePath } @@ -176,7 +180,7 @@ export function startDownload( onComplete: (r: XWebViewDownloadResult) => void, onError: (error: string) => void, ): DownloadHandle { - const { dirs } = RNFetchBlob.fs + const { dirs } = getRNFetchBlob().fs const dir = savePath ?? (Platform.OS === 'android' @@ -192,7 +196,7 @@ export function startDownload( .then(filePath => { if (cancelled) return - const task = RNFetchBlob.config({ path: filePath }).fetch('GET', url) + const task = getRNFetchBlob().config({ path: filePath }).fetch('GET', url) cancelFn = () => task.cancel() task.progress({ interval: 300 }, (received: number, total: number) => {