在Expo React Native中离线运行含.wasm的Stockfish国际象棋引擎
在Expo React Native中离线运行Stockfish WASM引擎的解决方案
核心问题分析
你的当前代码基于浏览器DOM API(document.createElement、document.body.appendChild),但React Native(包括Expo)没有浏览器环境的DOM对象,所以这段代码在RN原生环境中根本无法执行——这是导致失败的主要原因,而非库的选择问题。
库的适用性判断
react-native-react-bridge:不适用。它的作用是在RN与WebView之间桥接React组件,并非用于处理WASM文件或浏览器环境的JS代码。react-native-webassembly:适用。它专门用于在RN原生环境中加载和运行WASM模块,但需要处理Expo的资源路径问题。- 更推荐的方案:使用Expo WebView包裹现有HTML/JS代码。因为你已经有能在浏览器中正常运行的Stockfish实现,WebView提供了完整的浏览器环境,无需大幅修改代码,成本最低。
方案一:WebView快速迁移(推荐)
步骤1:整理资源文件
将Stockfish相关文件(stockfish.js、chess.min.js、stockfish.wasm)和你的HTML测试文件放到Expo项目的assets/stockfish目录下。
步骤2:修改HTML代码,添加RN通信逻辑
在HTML中,将原本的console.log输出替换为向RN发送消息的代码,以便在RN界面显示日志:
<!-- assets/stockfish/index.html --> <!DOCTYPE html> <html> <head> <script src="./chess.min.js"></script> <script src="./stockfish.js"></script> </head> <body> <script> const sf = Stockfish(); sf.onmessage = function(event) { // 将Stockfish的输出发送给RN window.ReactNativeWebView.postMessage(`Stockfish: ${event.data}`); }; sf.postMessage('uci'); // 初始化引擎 window.ReactNativeWebView.postMessage('Stockfish引擎已加载'); </script> </body> </html>
步骤3:RN组件中加载WebView并接收日志
先安装依赖:
npx expo install expo-webview expo-asset
然后编写RN组件:
import React, { useState } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { WebView } from 'expo-webview'; import { Asset } from 'expo-asset'; export default function StockfishScreen() { const [logMessages, setLogMessages] = useState([]); // 获取本地HTML文件的URI const htmlAsset = require('./assets/stockfish/index.html'); const htmlUri = Asset.fromModule(htmlAsset).uri; // 接收WebView传来的日志 const handleMessage = (event) => { const newLog = event.nativeEvent.data; setLogMessages(prev => [...prev, newLog]); }; return ( <View style={styles.container}> {/* 隐藏WebView,只显示日志;调试时可去掉hidden样式 */} <WebView source={{ uri: htmlUri }} onMessage={handleMessage} javaScriptEnabled={true} domStorageEnabled={true} style={styles.hiddenWebView} /> {/* 日志显示区域 */} <View style={styles.logContainer}> {logMessages.map((msg, idx) => ( <Text key={idx} style={styles.logText}>{msg}</Text> ))} </View> </View> ); } const styles = StyleSheet.create({ container: { flex: 1 }, hiddenWebView: { height: 0, width: 0 }, logContainer: { flex: 1, padding: 10, backgroundColor: '#f5f5f5' }, logText: { fontSize: 14, marginVertical: 2, color: '#333' } });
方案二:原生RN环境加载WASM
如果需要完全脱离WebView,可使用react-native-webassembly:
步骤1:安装依赖
npm install react-native-webassembly npx expo install expo-file-system expo-asset
步骤2:加载并运行WASM
import React, { useEffect, useState } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import * as FileSystem from 'expo-file-system'; import { Asset } from 'expo-asset'; import { load } from 'react-native-webassembly'; export default function StockfishScreen() { const [logMessages, setLogMessages] = useState([]); useEffect(() => { const loadStockfish = async () => { try { // 将WASM文件从assets复制到RN可访问的文档目录 const wasmAsset = require('./assets/stockfish/stockfish.wasm'); const wasmAssetUri = Asset.fromModule(wasmAsset).uri; const destUri = `${FileSystem.documentDirectory}stockfish.wasm`; await FileSystem.copyAsync({ from: wasmAssetUri, to: destUri }); // 加载WASM模块 const wasmInstance = await load(destUri); // 注意:Stockfish的WASM需要配合官方JS封装使用,需参考官方文档适配RN环境 setLogMessages(prev => [...prev, 'WASM模块已加载']); } catch (err) { setLogMessages(prev => [...prev, `加载失败:${err.message}`]); } }; loadStockfish(); }, []); return ( <View style={styles.container}> {logMessages.map((msg, idx) => ( <Text key={idx} style={styles.logText}>{msg}</Text> ))} </View> ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 10, backgroundColor: '#f5f5f5' }, logText: { fontSize: 14, marginVertical: 2, color: '#333' } });
关键注意事项
- Expo中访问assets文件必须通过
expo-asset获取正确的URI,不能直接使用相对路径(如/stockfish/stockfish.js)。 - RN原生环境没有浏览器的
window、document等对象,所有基于DOM的代码都无法直接运行。 - 调试时可使用Expo的Debug模式查看RN的console日志,或在WebView中长按选择"Inspect"打开调试工具。
内容的提问来源于stack exchange,提问作者Muhammad Hamza Latif
相关产品推荐
相关产品推荐

