react native 本地构建web服务器

677 阅读2分钟

通常如果我们想在react native项目中使用H5,会考虑使用webview引用本地assets文件夹中的html静态文件。但这样的使用方式限制很大,比如无法使用http下才能使用的一些方法,亦或者是被cross origin这样的跨域错误折磨得没脾气。

这个时候我们不得不考虑将web挂载到远程的网站上,直接让webview指向网站地址。但这样又会明显增加维护复杂度,同时用户体验也会极度依赖于网络的稳定和连接速度。

不妨考虑另一种思路,在本地host一个web server,就像服务器干的事情一样。刚好有一个能堪当此重任的库:react-native-http-bridge-refurbished

用法也很简单:

import {BridgeServer} from 'react-native-http-bridge-refurbished';

useEffect(() => {
    const server = new BridgeServer('http_service', true);
    server.get('/', async (req, res) => {
        // do something
        return {message: 'OK'}; // or res.json({message: 'OK'});
    });
    server.listen(3000);

    return () => {
        server.stop();
    };
}, []);

本仓库的官方例子过于简单,还无法基于此建立我们想要的web server。还需要引入react-native-fs 来读取html等文件。

针对Android,使用readFileAssets读取assets文件夹下的html文件,同时判断请求的res的类型来指定不同的header type,即可完整处理html关联文件。

const { url } = req;
let filePath="htmls/index.html", type = 'text/html';
if (!url.endsWith('html')) {
    filePath = "htmls" + url;
}
if (url.endsWith('css')) {
  type = 'text/css';
}
if (url.endsWith('js')) {
  type = 'text/javascript';
}
if (url.endsWith('png')) {
  type = 'image/png';
}
const format = url.endsWith('png') ? 'base64' : 'utf8';
let file= await RNFS.readFileAssets(filePath, format);
return  res.send(200, type, file);

ios稍有不同:

const { url } = req;
let filePath = RNFS.MainBundlePath+ "/htmls/index.html", type = 'text/html';
if (!url.endsWith('html')) {
     filePath = RNFS.MainBundlePath+ "/htmls" + url;
}
if(url == '/'){
     filePath = RNFS.MainBundlePath+ "/htmls/index.html"
}
if (url.endsWith('css')) {
     type = 'text/css';
}
if (url.endsWith('js')) {
  type = 'text/javascript';
}
if (url.endsWith('png')) {
  type = 'image/png';
}
const format = url.endsWith('png') ? 'base64' : 'utf8';
let file= await RNFS.readFile(filePath, format);
return  res.send(200, type, file);

对于设备的ip地址,刚好使用react-native-community/netinfo也能够获取。

import { fetch } from "@react-native-community/netinfo";

fetch().then(state => {
  console.log("ip address", state.details.ipAddress);
});

唯一要注意的是webview的引用url前缀必须加上http://