fix(xwebview): 将 react-native-blob-util 改为懒加载以兼容 RN 0.85 Bridgeless 模式
静态 import 会在模块评估时触发 fs.js:14 调用 ReactNativeBlobUtil.getConstants(), 在 Bridgeless 模式下 TurboModule 未注册时返回 null 导致崩溃。 改为在函数体内 require() 延迟至实际下载时才初始化。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
ff8f34e5a4
当前提交
51e016e185
@ -1,5 +1,4 @@
|
|||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
import RNFetchBlob from 'react-native-blob-util'
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
XWebViewDownloadDecision,
|
XWebViewDownloadDecision,
|
||||||
@ -8,6 +7,11 @@ import type {
|
|||||||
XWebViewDownloadResult,
|
XWebViewDownloadResult,
|
||||||
} from '@xuqm/rn-common'
|
} 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 {
|
function parseContentDispositionFilename(header: string): string | null {
|
||||||
const rfc5987 = header.match(/filename\*=(?:[^']*'[^']*')?([^;\s]+)/i)
|
const rfc5987 = header.match(/filename\*=(?:[^']*'[^']*')?([^;\s]+)/i)
|
||||||
if (rfc5987?.[1]) {
|
if (rfc5987?.[1]) {
|
||||||
@ -70,7 +74,7 @@ async function resolveFilePath(
|
|||||||
const full = `${dir}/${filename}`
|
const full = `${dir}/${filename}`
|
||||||
if (conflict === 'overwrite') return full
|
if (conflict === 'overwrite') return full
|
||||||
|
|
||||||
const exists = await RNFetchBlob.fs.exists(full)
|
const exists = await getRNFetchBlob().fs.exists(full)
|
||||||
if (!exists) return full
|
if (!exists) return full
|
||||||
|
|
||||||
const dot = filename.lastIndexOf('.')
|
const dot = filename.lastIndexOf('.')
|
||||||
@ -82,7 +86,7 @@ async function resolveFilePath(
|
|||||||
do {
|
do {
|
||||||
candidate = `${dir}/${base}(${n})${ext}`
|
candidate = `${dir}/${base}(${n})${ext}`
|
||||||
n++
|
n++
|
||||||
} while (await RNFetchBlob.fs.exists(candidate))
|
} while (await getRNFetchBlob().fs.exists(candidate))
|
||||||
|
|
||||||
return candidate
|
return candidate
|
||||||
}
|
}
|
||||||
@ -93,14 +97,14 @@ export async function saveBase64File(
|
|||||||
savePath: string | undefined,
|
savePath: string | undefined,
|
||||||
conflict: 'rename' | 'overwrite',
|
conflict: 'rename' | 'overwrite',
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const { dirs } = RNFetchBlob.fs
|
const { dirs } = getRNFetchBlob().fs
|
||||||
const dir =
|
const dir =
|
||||||
savePath ??
|
savePath ??
|
||||||
(Platform.OS === 'android'
|
(Platform.OS === 'android'
|
||||||
? (dirs.DownloadDir ?? dirs.DocumentDir)
|
? (dirs.DownloadDir ?? dirs.DocumentDir)
|
||||||
: dirs.DocumentDir)
|
: dirs.DocumentDir)
|
||||||
const filePath = await resolveFilePath(dir, filename, conflict)
|
const filePath = await resolveFilePath(dir, filename, conflict)
|
||||||
await RNFetchBlob.fs.writeFile(filePath, base64, 'base64')
|
await getRNFetchBlob().fs.writeFile(filePath, base64, 'base64')
|
||||||
return filePath
|
return filePath
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +180,7 @@ export function startDownload(
|
|||||||
onComplete: (r: XWebViewDownloadResult) => void,
|
onComplete: (r: XWebViewDownloadResult) => void,
|
||||||
onError: (error: string) => void,
|
onError: (error: string) => void,
|
||||||
): DownloadHandle {
|
): DownloadHandle {
|
||||||
const { dirs } = RNFetchBlob.fs
|
const { dirs } = getRNFetchBlob().fs
|
||||||
const dir =
|
const dir =
|
||||||
savePath ??
|
savePath ??
|
||||||
(Platform.OS === 'android'
|
(Platform.OS === 'android'
|
||||||
@ -192,7 +196,7 @@ export function startDownload(
|
|||||||
.then(filePath => {
|
.then(filePath => {
|
||||||
if (cancelled) return
|
if (cancelled) return
|
||||||
|
|
||||||
const task = RNFetchBlob.config({ path: filePath }).fetch('GET', url)
|
const task = getRNFetchBlob().config({ path: filePath }).fetch('GET', url)
|
||||||
cancelFn = () => task.cancel()
|
cancelFn = () => task.cancel()
|
||||||
|
|
||||||
task.progress({ interval: 300 }, (received: number, total: number) => {
|
task.progress({ interval: 300 }, (received: number, total: number) => {
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户