84e5cead08
WKWebView blocks HTTP requests (ATS) even when NSAllowsLocalNetworking is set for the app's own networking — so fetch(http://192.168.x.x/api/wheel/download) inside the WebView always fails with 'Load failed' on iOS. - extractActivity.ts: rename wheelUrl param to wheelBase64; WebView now receives the wheel as pre-fetched base64 bytes rather than a URL to fetch itself - PyodideWebView.tsx: decode wheelBase64 → Uint8Array → Blob → blob URL for micropip.install; fix baseUrl '' → 'https://localhost' (null origin blocks fetch on iOS) - import.tsx: add fetchWheelBase64() that resolves the wheel URL via /api/wheel/version then fetches with native networking (HTTP works); caches result in memory so repeated imports in one session don't re-download
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { createRef } from 'react';
|
|
import type WebView from 'react-native-webview';
|
|
import type { WebViewMessageEvent } from 'react-native-webview';
|
|
|
|
export type ExtractionResult = {
|
|
id: string;
|
|
detail: object;
|
|
timeseries: object | null;
|
|
geojson: object | null;
|
|
sourceHash: string;
|
|
};
|
|
|
|
type Pending = {
|
|
resolve: (r: ExtractionResult) => void;
|
|
reject: (e: Error) => void;
|
|
onStatus: (msg: string) => void;
|
|
};
|
|
|
|
export const pyodideRef = createRef<WebView>();
|
|
|
|
const pending = new Map<string, Pending>();
|
|
let reqCounter = 0;
|
|
let isExtracting = false;
|
|
|
|
export function handleWebViewMessage(e: WebViewMessageEvent): void {
|
|
let msg: Record<string, unknown>;
|
|
try { msg = JSON.parse(e.nativeEvent.data); } catch { return; }
|
|
|
|
const reqId = msg.reqId as string | undefined;
|
|
const p = reqId ? pending.get(reqId) : undefined;
|
|
|
|
switch (msg.type) {
|
|
case 'result':
|
|
if (p) {
|
|
pending.delete(reqId!);
|
|
p.resolve({
|
|
id: msg.id as string,
|
|
detail: msg.detail as object,
|
|
timeseries: (msg.timeseries as object | null) ?? null,
|
|
geojson: (msg.geojson as object | null) ?? null,
|
|
sourceHash: msg.sourceHash as string,
|
|
});
|
|
}
|
|
break;
|
|
case 'error':
|
|
if (p) {
|
|
pending.delete(reqId!);
|
|
p.reject(new Error(msg.message as string));
|
|
}
|
|
break;
|
|
case 'progress':
|
|
p?.onStatus(msg.msg as string);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// wheelBase64 is the bincio .whl file pre-fetched by the React Native side
|
|
// (native networking supports HTTP on local network; WKWebView does not).
|
|
export function extractFile(
|
|
filename: string,
|
|
base64: string,
|
|
wheelBase64: string,
|
|
onStatus: (msg: string) => void = () => {},
|
|
): Promise<ExtractionResult> {
|
|
if (isExtracting) return Promise.reject(new Error('Another extraction is already in progress'));
|
|
|
|
const webview = pyodideRef.current;
|
|
if (!webview) return Promise.reject(new Error('Extraction engine not ready — restart the app'));
|
|
|
|
isExtracting = true;
|
|
const reqId = String(++reqCounter);
|
|
const args = JSON.stringify({ reqId, filename, base64, wheelBase64 });
|
|
|
|
return new Promise<ExtractionResult>((resolve, reject) => {
|
|
pending.set(reqId, {
|
|
resolve: (r) => { isExtracting = false; resolve(r); },
|
|
reject: (e) => { isExtracting = false; reject(e); },
|
|
onStatus,
|
|
});
|
|
webview.injectJavaScript(`window._bincioExtract(${args}); true;`);
|
|
});
|
|
}
|