likes
comments
collection
share

React native中嵌入H5---学习记录目前公司的 RN 项目规模较大,然而,RN 环境的安装流程颇为复杂,学习

作者站长头像
站长
· 阅读数 17

需求:

       目前公司的 RN 项目规模较大,然而,RN 环境的安装流程颇为复杂,学习成本曲线较高。要参与该项目,人员必须具备一定的 RN 基础,这一硬性要求致使 RN 功能重构的任务被迫搁置。相较而言,掌握 React 的人员数量相对更多,对 React 的熟练程度也更高。基于此,在针对 APP 功能进行重构时,公司计划采用 H5 嵌入的方式,以实现参与人员的自由化,提升整体的参与度与开发进程!

RN和H5的优缺点:

rn的优点

  1. **性能较好:能够提供接近原生应用的性能体验。**例如,一些对性能要求较高的移动游戏,使用 RN 开发能够保证流畅的运行效果。
  2. **代码复用性高:可以在不同的移动平台(如 iOS 和 Android)上复用大部分代码。**像一些跨平台的办公应用,一次开发就能在多个平台发布,节省了开发成本和时间。
  3. **开发效率较高:利用 JavaScript 和 React 框架,开发者可以更快速地构建应用。**很多新兴的创业公司,借助 RN 快速推出产品的原型进行市场验证。

rn的缺点

  1. 学习曲线较陡峭:需要开发者同时掌握 JavaScript、React 以及原生移动开发的知识。对于新手开发者来说,可能需要花费较多的时间和精力去学习和适应。
  2. 调试复杂:在调试过程中可能会遇到一些难以排查的问题。

H5的优点

  1. **开发成本低:无需针对不同平台进行单独开发。**比如简单的宣传页面,用 H5 开发能快速上线。
  2. **传播方便:可以通过链接轻松分享和访问。**常见的活动推广页面,通过社交媒体分享就能快速传播。
  3. **更新及时:无需经过应用商店的审核流程,可随时更新内容。**对于一些时效性强的信息展示,如新闻资讯,能及时推送最新内容。

H5的缺点

  1. **性能相对较差:尤其是在处理复杂交互和大量数据时。**比如复杂的电商购物流程,可能会出现卡顿。
  2. **功能受限:某些硬件相关的功能(如摄像头、蓝牙等)调用不如原生应用方便。**像一些需要高精度定位的应用,H5 实现起来较为困难。

方法:

       使用webview在RN中嵌入H5以及实现RN与webview之间的通信

使用:

1.安装并引用webview:

import WebView, { WebViewMessageEvent } from 'react-native-webview'

2.在RN中使用Webview,(这里是写了一个WebviewPage组件,做了一些封装,参数随业务需要,一般用不着配置那么多)

<SafeAreaView>
        <WebView
          ref={webviewRef}
          source={{
            uri: url,   //h5地址
          }}
          onMessage={(e) => reciveH5Message(e)}  //接收h5的消息
          thirdPartyCookiesEnabled={true} //在webview中启用第三方cookie
          mixedContentMode="always"  //WebView将允许安全源从任何其他源加载内容
          cacheEnabled={false} //webvie是否使用浏览器缓存
          overScrollMode="never"  //滚动模式
          bounces={false} //网页视图在到达内容边缘时是否反弹
          showsHorizontalScrollIndicator={false}  //是否展示水平滚动条
          showsVerticalScrollIndicator={false} //是否展示垂直滚动条
          automaticallyAdjustContentInsets={false} //控制是否为放置在导航栏、标签栏或工具栏后面的网页视图调整内容插入
          startInLoadingState={true} //强制WebView在首次加载时显示加载视图
          injectedJavaScript={`(() => {
            localStorage.setItem('access_token', '${JSON.stringify(authModel?.state?.userInfos?.access_token)}');
            localStorage.setItem('userInfos', '${JSON.stringify(authModel?.state?.userInfos)}');
            localStorage.setItem('isApp', 'true');
            true;
          })();`}   //在webview加载完页面后执行的js(传入的是字符串)
          onContentProcessDidTerminate={(syntheticEvent) => {
            webviewRef.current?.reload();
          }}   //当WebView内容进程终止时调用
          onLoadProgress={e => {
            setCurrentH5(e?.nativeEvent)
          }}  //webview加载时执行
          renderLoading={() => (
            <View style={styles.container}>
              <FastImage style={cs.loadingBox} source={require('@xlb/common/src/assets/gif/loading.gif')} resizeMode={FastImage.resizeMode.contain} />
            </View>
          )}   //返回加载函数
          renderError={() => (
            <View>
              <Text>加载失败,请返回后重新打开</Text>
            </View>
          )}  //加载失败返回函数
        />
      </SafeAreaView>

3.使用WebViewPage组件:

<WebViewPage 
  url={routes.dateCheck} 
  onMessage={reciveH5Message}   //当前业务功能接收到H5消息时做处理
  ref={webviewRef}>  //每个webview都有单独的ref
</WebViewPage> 

4.H5(Webview)中发送消息给RN(这里写了一个需要用到的功能对象):

const NativeBridge = {
  postMessage: (method: string, data?: any) => {
    let params = {
      method: method,
      ...(data && {
        data: data,
      }),
    };
    window.ReactNativeWebView?.postMessage(JSON.stringify(params));   //发送消息给RN
  },
  /**
   * 跳转到登录页面
   */
  logout: () => {
    NativeBridge.postMessage('logout');
  },

  /**
   * 返回原生上一页
   */
  goBack: () => {
    NativeBridge.postMessage('backRN');
  },

   /**
   * 选择门店
   */
  selectStore: (data: any) => {
    NativeBridge.postMessage('selectStore', data);
  },
  ...
};

export default NativeBridge;

5.RN接收到消息(按照获取到的请求资源方法做相对应的处理):

const reciveH5Message = async (e: any) => {
        let params = JSON.parse(e.nativeEvent.data)
        if (params.method === 'selectStores') {
            //TODO.....
            changeStore()
        } else if (params.method === 'changeOrientation') {
            //TODO.....
            changeOrientation()
        }else if (params.method === 'backRN') {
            //退出当前网页
            navigation.goBack()
        }
          ...
    }

6.RN发消息给H5:

const sendMessageToH5 = (method: any, result?: any) => {
    let data = {
      method: method,
      data: result,
    }
    webviewRef.current?.postMessage(JSON.stringify(data))
  }

7.H5收到消息后存储数据(这里写了一个通用Hook)

const useJsb = (onHandleMessage: (method: string, result: object) => {}) => {
  const [jsbData, setJsbData] = useState({});

  // JSB通信
  const handleMessage = (event: any) => {
    const data = event.data;
    if (typeof data === 'string') {
      console.log('收到消息了', event.data, jsbData);
      try {
        const result = JSON.parse(data);
        const method = result.method;
         if (method === 'selectStoreMultiple') {  //监听到的消息类别做处理
          console.log('收到多选门店消息了', result?.data);
          setJsbData({   //塞数据
            ...jsbData,
            multipleStore: result?.data,
          });
        }else if .....
        } else {
          // 自己处理 msg
          onHandleMessage && onHandleMessage(method, result);
        }
      } catch (e) {
        console.error('消息数据解析错误');
      }
    }
  };
  useEffect(() => {
    window.addEventListener('message', handleMessage, true);   //监听message
    return () => {
      window.removeEventListener('message', handleMessage, true);
    };
  }, []);

  return [jsbData, setJsbData];
};

export default useJsb;
转载自:https://juejin.cn/post/7397025359532703744
评论
请登录