├── .gitignore ├── test └── test.js ├── img └── react-native-webview-callback_01.png ├── src ├── baseH5Api.ts ├── baseReactNativeApi.ts ├── index.ts └── events.ts ├── tsconfig.types.json ├── babel.config.js ├── LICENSE ├── tsconfig.json ├── package.json ├── rollup.config.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /dist 3 | .DS_Store 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | // const { sayHelloWorld } = require('../dist/index.js') 2 | 3 | console.log('helo'); -------------------------------------------------------------------------------- /img/react-native-webview-callback_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liutaohz/react-native-webview-callback/HEAD/img/react-native-webview-callback_01.png -------------------------------------------------------------------------------- /src/baseH5Api.ts: -------------------------------------------------------------------------------- 1 | // 测试React Native 自定义基础API 2 | const echoH5Test = (res: any) => { 3 | return new Promise((resolve, reject) => { 4 | if (res === 'hello world H5') { 5 | resolve(res) // 成功 6 | } else { 7 | reject(res) // 失败 8 | } 9 | }) 10 | }; 11 | 12 | export default { 13 | echoH5Test: echoH5Test, 14 | } -------------------------------------------------------------------------------- /src/baseReactNativeApi.ts: -------------------------------------------------------------------------------- 1 | // 测试React Native 自定义基础API 2 | const echoReactNativeTest = (res: any) => { 3 | return new Promise((resolve, reject) => { 4 | if (res === 'hello world react-native') { 5 | resolve(res) // 成功 6 | } else { 7 | reject(res) // 失败 8 | } 9 | }) 10 | }; 11 | 12 | export default { 13 | echoReactNativeTest: echoReactNativeTest, 14 | } -------------------------------------------------------------------------------- /tsconfig.types.json: -------------------------------------------------------------------------------- 1 | { 2 | // 继承 tsconfig.json 中的通用配置 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "declaration": true, /* 生成相应的 '.d.ts' file. */ 6 | "declarationDir": "./dist/types", /* 类型声明文件输出目录 */ 7 | "emitDeclarationOnly": true, /* 只生成声明文件,不生成 js 文件*/ 8 | "rootDir": "./src", /* 指定输出文件目录(用于输出),用于控制输出目录结构 */ 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | /* Babel 会在 Rollup 有机会做处理之前,将我们的模块转成 CommonJS,导致 Rollup 的一些处理失败 */ 7 | "modules": false 8 | } 9 | ] 10 | ], 11 | "plugins": [ 12 | [ 13 | // 与 babelHelpers: 'runtime' 配合使用 14 | "@babel/plugin-transform-runtime" 15 | ] 16 | ] 17 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import baseH5Api from './baseH5Api'; 2 | import baseReactNativeApi from './baseReactNativeApi'; 3 | import { 4 | useH5AddListener, 5 | h5CallreactNative, 6 | useReactNativeAddListener, 7 | reactNativeCallH5, 8 | } from './events'; 9 | // 合并基础方法,将合并的方法返回到应用端,用户方法监听调用 10 | const mergeReactNativeApi = (userApi = {}) => { 11 | return { 12 | ...baseReactNativeApi, 13 | ...userApi, // 用户定义APP接口 14 | }; 15 | }; 16 | // 合并基础方法,将合并的方法返回到应用端,用户方法监听调用 17 | const mergeH5Api = (userApi = {}) => { 18 | return { 19 | ...baseH5Api, 20 | ...userApi, // 用户定义H5接口 21 | }; 22 | }; 23 | export { 24 | mergeH5Api, 25 | useH5AddListener, 26 | h5CallreactNative, 27 | mergeReactNativeApi, 28 | useReactNativeAddListener, 29 | reactNativeCallH5, 30 | }; 31 | export default { 32 | mergeH5Api, 33 | useH5AddListener, // 只需要在入口文件初始化一次。初始化,将合并后的API作为参数传进去 34 | h5CallreactNative, // 在任何页面都可以直接调用 35 | mergeReactNativeApi, 36 | useReactNativeAddListener, // react native 初始化 37 | reactNativeCallH5, // react native 调用H5接口 38 | }; 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 liutao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* 基础选项 */ 4 | "target": "esnext", /* 指定 ECMAScript 目标版本:'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "esnext", /* 输出的代码使用什么方式进行模块化: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | "lib": [ /* 指定引用的标准库 */ 7 | "esnext", 8 | "dom", 9 | "dom.iterable", 10 | ], 11 | "allowJs": true, /* 允许编译 js 文件 */ 12 | "removeComments": true, /* 输出不包含注释 */ 13 | /* 严格类型检查选项 */ 14 | "strict": true, /* 启用所有严格类型检查选项 */ 15 | "noImplicitAny": false, /* 检查隐含 any 类型的表达式和声明 */ 16 | "strictNullChecks": false, /* 严格空检查. */ 17 | /* 额外检查 */ 18 | "noUnusedLocals": false, /* 检查无用的变量. */ 19 | /* Module Resolution Options */ 20 | "moduleResolution": "node", /* 指定模块查找策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6) */ 21 | "baseUrl": "./", /* 查找模块的基础目录 */ 22 | "paths": { 23 | "@/*": [ 24 | "src/*" 25 | ] 26 | }, /* 记录 baseUrl 的模块路径查找别名 */ 27 | "types": [], /* 类型声明文件 */ 28 | }, 29 | "include": [ /* 指定编译处理的文件列表 */ 30 | "src/*.ts" 31 | ], 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-webview-callback", 3 | "version": "0.0.5", 4 | "description": "A lightweight tool library for connecting React Native and webview, providing communication and success and failure callback methods", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.esm.js", 7 | "umd": "./dist/index.umd.js", 8 | "types": "./dist/types/index.d.ts", 9 | "scripts": { 10 | "clean:dist": "rimraf dist", 11 | "build:types": "npm run clean:dist && tsc -b ./tsconfig.types.json", 12 | "build": "npm run build:types && rollup -c", 13 | "test": "node test/test.js", 14 | "pretest": "npm run build" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/liutaohz/react-native-webview-callback.git" 19 | }, 20 | "keywords": [ 21 | "React", 22 | "Native", 23 | "webview", 24 | "callback", 25 | "promise", 26 | "h5", 27 | "communication" 28 | ], 29 | "author": "liutaohangzhou@163.com", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/liutaohz/react-native-webview-callback/issues" 33 | }, 34 | "homepage": "https://github.com/liutaohz/react-native-webview-callback#readme", 35 | "devDependencies": { 36 | "@babel/plugin-transform-runtime": "^7.22.15", 37 | "@babel/preset-env": "^7.22.20", 38 | "@rollup/plugin-babel": "^6.0.4", 39 | "@rollup/plugin-commonjs": "^25.0.5", 40 | "@rollup/plugin-node-resolve": "^15.2.3", 41 | "@types/events": "^3.0.1", 42 | "@types/react": "^18.2.27", 43 | "rimraf": "^5.0.5", 44 | "rollup": "^2.79.1", 45 | "rollup-plugin-terser": "^7.0.2", 46 | "rollup-plugin-typescript2": "^0.36.0", 47 | "typescript": "^5.2.2" 48 | }, 49 | "files": [ 50 | "dist" 51 | ], 52 | "dependencies": { 53 | "events": "^3.3.0" 54 | }, 55 | "peerDependencies": { 56 | "react": ">16.8.3" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import resolve from '@rollup/plugin-node-resolve' 3 | import commonjs from '@rollup/plugin-commonjs' 4 | import rollupTypescript from 'rollup-plugin-typescript2' 5 | import babel from '@rollup/plugin-babel' 6 | import { DEFAULT_EXTENSIONS } from '@babel/core' 7 | import { terser } from 'rollup-plugin-terser' 8 | 9 | // 读取 package.json 配置 10 | import pkg from './package.json' 11 | // 当前运行环境,可通过 cross-env 命令行设置 12 | const env = process.env.NODE_ENV 13 | // umd 模式的编译结果文件输出的全局变量名称 14 | const name = 'ReactNativeWebViewCallback' 15 | const config = { 16 | // 入口文件,src/index.ts 17 | input: path.resolve(__dirname, 'src/index.ts'), 18 | // 输出文件 19 | output: [ 20 | // commonjs 21 | // { 22 | // // package.json 配置的 main 属性 23 | // file: pkg.main, 24 | // format: 'cjs', 25 | // }, 26 | // index 打一个UMD包,不打CJS 27 | { 28 | // umd 导出文件的全局变量 29 | name, 30 | // package.json 配置的 umd 属性 31 | file: pkg.main, 32 | format: 'umd' 33 | }, 34 | // es module 35 | { 36 | // package.json 配置的 module 属性 37 | file: pkg.module, 38 | format: 'es', 39 | }, 40 | // umd 41 | { 42 | // umd 导出文件的全局变量 43 | name, 44 | // package.json 配置的 umd 属性 45 | file: pkg.umd, 46 | format: 'umd' 47 | } 48 | ], 49 | plugins: [ 50 | // 解析第三方依赖 51 | resolve(), 52 | // 识别 commonjs 模式第三方依赖 53 | commonjs(), 54 | // rollup 编译 typescript 55 | rollupTypescript(), 56 | // babel 配置 57 | babel({ 58 | // 编译库使用 runtime 59 | babelHelpers: 'runtime', 60 | // 只转换源代码,不转换外部依赖 61 | exclude: 'node_modules/**', 62 | // babel 默认不支持 ts 需要手动添加 63 | extensions: [ 64 | ...DEFAULT_EXTENSIONS, 65 | '.ts', 66 | ], 67 | }), 68 | ] 69 | } 70 | 71 | // 若打包正式环境,压缩代码 72 | if (env === 'production') { 73 | config.plugins.push(terser({ 74 | compress: { 75 | pure_getters: true, 76 | unsafe: true, 77 | unsafe_comps: true, 78 | warnings: false 79 | } 80 | })) 81 | } 82 | export default config -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-webview-callback 2 | 3 | [![NPM version](https://img.shields.io/npm/v/react-native-webview-callback.svg?style=flat)](https://npmjs.org/package/react-native-webview-callback) 4 | [![NPM downloads](http://img.shields.io/npm/dm/react-native-webview-callback.svg?style=flat)](https://npmjs.org/package/react-native-webview-callback) 5 | 6 | A lightweight tool library for connecting React Native and webview, providing communication and success and failure callback methods 7 | 8 | 我的博文:[实现React Native与内嵌H5相互通信](https://juejin.cn/post/7297144566251454502) 9 | 10 | ![react-native-webview-callback_01.png](./img/react-native-webview-callback_01.png) 11 | 12 | 13 | 14 | 15 | ## Usage 16 | 17 | ### Import Dependency Package 18 | 19 | ``` 20 | npm install react-native-webview-callback 21 | 22 | ``` 23 | 24 | ### Configure and use on H5 end 25 | 26 | #### Define your own methods to provide for React Native calls 27 | 28 | You can define your own event API and incorporate it during subsequent initialization. eg(myEvent.ts) 29 | 30 | 31 | 32 | 33 | ``` js 34 | // customH5Api.ts 35 | 36 | // Define your own methods to provide for React Native calls 37 | const getWebToken = () => { 38 | return new Promise((resolve, reject) => { 39 | try { 40 | const token = window.localStorage.getItem('token')||'hello'; 41 | resolve(token) // Successful callback 42 | } catch (error) { 43 | reject(error) // Failed callback 44 | } 45 | }) 46 | }; 47 | // other methods 48 | 49 | export default { 50 | getWebToken: getWebToken, 51 | // other methods 52 | } 53 | ``` 54 | 55 | #### Initialize listening in the entry file && Use and get callback 56 | 57 | Initialize listening methods in the entry file 58 | 59 | ``` js 60 | import { useEffect, useState } from 'react' 61 | import { 62 | mergeReactNativeApi, 63 | useReactNativeAddListener, 64 | reactNativeCallH5, 65 | } from 'react-native-webview-callback'; 66 | import myEvent from './customH5Api'; 67 | import './App.css'; 68 | function App() { 69 | useH5AddListener(mergeH5Api(myEvent)) // just need init once ,Entry file 70 | useEffect(() => { 71 | window.localStorage.setItem('token', 'mytokenStrXXXXX');// mock data 72 | },[]) 73 | const [result, setResult] = useState('--'); 74 | const testFn = () => { 75 | h5CallreactNative({ 76 | methodName: "getAppInfo", // Or other interface functions that you customize on the React Native end, eg:“myReactNativeMethod” 77 | data: "", // Object data can also be passed, and the specific parameter format depends on the defined interface parameters 78 | }) 79 | .then((data) => { 80 | if (typeof data === 'object') { 81 | setResult(JSON.stringify(data)) 82 | } else if (typeof data === 'string') { 83 | setResult(data) 84 | } 85 | console.log("Successful data:", data); 86 | }) 87 | .catch((error) => { 88 | alert("Failed from React Native callback"); 89 | console.error("Failed data:", error); 90 | }); 91 | } 92 | return ( 93 | <> 94 |

H5

95 |
96 | 99 |

100 | {result} 101 |

102 |
103 | 104 | ) 105 | } 106 | 107 | export default App 108 | 109 | ``` 110 | 111 | 112 | 113 | ### Configure and use on the React Native end 114 | 115 | #### Define your own methods to provide for H5 calls 116 | 117 | You can define your own event API and incorporate it during subsequent initialization. eg(myEvent.ts) 118 | 119 | ``` js 120 | // customNativeApi.tsx 121 | import { 122 | Platform, 123 | // Share, 124 | } from 'react-native'; 125 | // Define your own methods to provide for H5 calls 126 | const getAppInfo = () => { 127 | return new Promise((resolve, reject) => { 128 | try { 129 | const result = { 130 | os: Platform.OS, 131 | version: Platform.Version, 132 | }; 133 | resolve(result); // Successful callback 134 | } catch (error) { 135 | reject(error); // Failed callback 136 | } 137 | }); 138 | }; 139 | // other methods 140 | // const appShare = () => { 141 | // return new Promise((resolve, reject) => { 142 | // Share.share({ 143 | // message: 144 | // 'React Native | A framework for building native apps using React', 145 | // }).then(result => { 146 | // resolve(result); // Successful callback 147 | // }).catch(error => { 148 | // reject(error); // Failed callback 149 | // }) 150 | // }); 151 | // }; 152 | 153 | export default { 154 | getAppInfo: getAppInfo, 155 | // other methods 156 | }; 157 | ``` 158 | 159 | 160 | #### Initialize listening in the entry file & Use and get callback 161 | 162 | ``` js 163 | // App.tsx 164 | 165 | import React, {useRef} from 'react'; 166 | import { 167 | SafeAreaView, 168 | ScrollView, 169 | Alert, 170 | StyleSheet, 171 | Text, 172 | useColorScheme, 173 | View, 174 | } from 'react-native'; 175 | import {WebView} from 'react-native-webview'; 176 | import myEvent from './customNativeApi'; 177 | import { 178 | mergeReactNativeApi, 179 | useReactNativeAddListener, 180 | reactNativeCallH5 181 | } from 'react-native-webview-callback'; 182 | const {alert} = Alert; 183 | 184 | function App(): JSX.Element { 185 | const webViewRef: any = useRef(null); 186 | // 收到消息 187 | const onMessage = (event: any) => { 188 | // eslint-disable-next-line react-hooks/rules-of-hooks 189 | useReactNativeAddListener({ 190 | bridgeReactNativeApi: mergeReactNativeApi(myEvent), // Merge into custom methods on listening objects 191 | webViewRef, 192 | event, 193 | }); 194 | }; 195 | const handleLoadEnd = () => { 196 | reactNativeCallH5({ 197 | dataParms: { 198 | methodName: 'getWebToken', // 199 | data: '', 200 | }, 201 | webViewRef: webViewRef, 202 | }) 203 | .then((data: any) => { 204 | alert(data || 'Successful data:'); 205 | console.log('Successful data:', data); 206 | }) 207 | .catch(error => { 208 | console.log('Failed data:', error); 209 | alert('Failed from H5 callback'); 210 | }); 211 | }; 212 | 213 | return ( 214 | 227 | ); 228 | } 229 | 230 | export default App; 231 | 232 | ``` 233 | 234 | ## examples 235 | You can take a look at the usage examples in [react-native-webview-callback-demo](https://github.com/liutaohz/react-native-webview-callback-demo) 236 | 237 | 238 | ## Development 239 | 240 | ```bash 241 | # install dependencies 242 | $ yarn install 243 | 244 | # develop library by docs demo 245 | $ yarn start 246 | 247 | # build library source code 248 | $ yarn run build 249 | 250 | ``` 251 | 252 | ## LICENSE 253 | 254 | MIT 255 | 256 | Copyright (c) 2023 liutao 257 | -------------------------------------------------------------------------------- /src/events.ts: -------------------------------------------------------------------------------- 1 | import {EventEmitter} from 'events'; 2 | export const eventEmiter = new EventEmitter(); 3 | export enum CallType { 4 | call = 'call', // 调用 5 | callBack = 'callBack', // 回调 6 | } 7 | declare global { 8 | interface Window { 9 | ReactNativeWebView: any 10 | } 11 | } 12 | export const defaultChannelName = 'ReactNativeWebView'; // 默认渠道名称 13 | 14 | export interface MethodArgs { 15 | channelName?: string; // 渠道名称,默认'ReactNativeWebView',一般都使用同一个渠道,不同业务或者应用可以使用不同的渠道名,避免通信污染 16 | methodType?: CallType; // 当前是调用还是响应调用即【回调】 17 | methodName: string; // 方法名称,用户自定义,一般是一个有意义并且唯一的字符串 18 | data?: any; // 传输的数据,any类型 19 | } 20 | 21 | export interface MethodCallArgs extends MethodArgs { 22 | timeStr: string; // 时间戳 23 | sourceMethodName: string; // 保留原始方法名 24 | successKey: string; // 成功回调的key值 25 | errorKey: string; // 失败回调的key值 26 | } 27 | // H5初始化监听 28 | export const useH5AddListener = (bridgeH5Api: any = {}) => { 29 | // 可以传进来一个meargeApi进来 30 | const messageFn = event => { 31 | try { 32 | let dataSource = event?.data; 33 | if (dataSource && dataSource !== 'undefined') { 34 | const messageData: MethodCallArgs = dataSource && JSON.parse(dataSource) || {}; 35 | const { 36 | channelName, 37 | methodType, 38 | methodName, 39 | data, 40 | sourceMethodName, 41 | successKey, 42 | errorKey, 43 | } = messageData; 44 | if (channelName === defaultChannelName) { 45 | if (methodType === CallType.callBack) { 46 | // react native 回调到H5 47 | eventEmiter.emit(methodName, data); 48 | eventEmiter.off(successKey, () => {}); 49 | eventEmiter.off(errorKey, () => {}); 50 | } else if (methodType === CallType.call) { 51 | // react native 调用H5的方法 52 | if ( 53 | bridgeH5Api.hasOwnProperty(sourceMethodName) && 54 | typeof bridgeH5Api[sourceMethodName] === 'function' 55 | ) { 56 | bridgeH5Api[sourceMethodName](data) 57 | .then((res: any) => { 58 | const successObj = { 59 | ...messageData, 60 | data: res, 61 | methodType: CallType.callBack, 62 | methodName: successKey, 63 | }; 64 | window?.ReactNativeWebView?.postMessage( 65 | JSON.stringify(successObj), 66 | ); 67 | }) 68 | .catch(err => { 69 | const errObj = { 70 | ...messageData, 71 | data: err, 72 | methodType: CallType.callBack, 73 | methodName: errorKey, 74 | }; 75 | window?.ReactNativeWebView?.postMessage( 76 | JSON.stringify(errObj), 77 | ); 78 | }); 79 | } 80 | } 81 | } 82 | } 83 | } catch (error) { 84 | console.error(error); 85 | } 86 | }; 87 | window?.addEventListener('message', messageFn, { 88 | capture: true, 89 | passive: true, 90 | }); 91 | window.addEventListener('beforeunload', ()=>{ 92 | window?.removeEventListener('message', messageFn); 93 | }); 94 | }; 95 | 96 | export interface useReactNativeAddListenerArgs { 97 | bridgeReactNativeApi: any; 98 | webViewRef: any; 99 | event: any; 100 | } 101 | export const useReactNativeAddListener = ( 102 | messageProps: useReactNativeAddListenerArgs, 103 | ) => { 104 | const {bridgeReactNativeApi, webViewRef, event} = messageProps; 105 | const dataSource = event?.nativeEvent?.data; 106 | try { 107 | if (dataSource && dataSource !== 'undefined') { 108 | const messageData: MethodCallArgs = dataSource && JSON.parse(dataSource) || {}; 109 | const { 110 | channelName, 111 | methodType, 112 | methodName, 113 | data, 114 | sourceMethodName, 115 | successKey, 116 | errorKey, 117 | } = messageData; 118 | if (channelName === defaultChannelName) { 119 | if (methodType === CallType.callBack) { 120 | // H5 回调到react native 121 | eventEmiter.emit(methodName, data); 122 | eventEmiter.off(successKey, () => {}); 123 | eventEmiter.off(errorKey, () => {}); 124 | } else if (methodType === CallType.call) { 125 | // H5调用react native的方法 126 | if ( 127 | bridgeReactNativeApi.hasOwnProperty(sourceMethodName) && 128 | typeof bridgeReactNativeApi[sourceMethodName] === 'function' 129 | ) { 130 | bridgeReactNativeApi[sourceMethodName](data) 131 | .then((res: any) => { 132 | const successObj = { 133 | ...messageData, 134 | data: res, 135 | methodType: CallType.callBack, 136 | methodName: successKey, 137 | }; 138 | webViewRef?.current?.postMessage(JSON.stringify(successObj), '*'); 139 | }) 140 | .catch(err => { 141 | const errObj = { 142 | ...messageData, 143 | data: err, 144 | methodType: CallType.callBack, 145 | methodName: errorKey, 146 | }; 147 | webViewRef?.current?.postMessage(JSON.stringify(errObj), '*'); 148 | }); 149 | } 150 | } 151 | } 152 | } 153 | } catch (error) { 154 | console.error(error); 155 | } 156 | }; 157 | 158 | // 统一封装H5调用react native 及回调返回,通过promise的方式 159 | export const h5CallreactNative = (dataParms: MethodArgs) => { 160 | return new Promise((resolve, reject) => { 161 | const { 162 | channelName = defaultChannelName, 163 | methodType = CallType.call, 164 | methodName = 'methodName', 165 | data = '', 166 | } = dataParms; 167 | const timeStr = `${new Date().getTime()}`; 168 | const successKey = `${methodName}_${timeStr}_success`; 169 | const errorKey = `${methodName}_${timeStr}_error`; 170 | const obj: MethodCallArgs = { 171 | channelName, 172 | methodType, 173 | methodName, 174 | sourceMethodName: methodName, 175 | data, 176 | timeStr, 177 | successKey, 178 | errorKey, 179 | }; 180 | // 挂载成功的回调 181 | eventEmiter.on(successKey, res => { 182 | resolve(res); 183 | }); 184 | // 挂载失败的回调 185 | eventEmiter.on(errorKey, err => { 186 | reject(err); 187 | }); 188 | window?.ReactNativeWebView?.postMessage(JSON.stringify(obj)); 189 | }); 190 | }; 191 | 192 | export interface reactNativeCallH5Args { 193 | dataParms: MethodArgs; 194 | webViewRef: any; 195 | } 196 | // 统一封装react native调用H5及回调返回,通过promise的方式 197 | export const reactNativeCallH5 = ( 198 | reactNativeCallH5Props: reactNativeCallH5Args, 199 | ) => { 200 | const {dataParms, webViewRef} = reactNativeCallH5Props; 201 | return new Promise((resolve, reject) => { 202 | const { 203 | channelName = defaultChannelName, 204 | methodType = CallType.call, 205 | methodName = 'methodName', 206 | data = '', 207 | } = dataParms; 208 | const timeStr = `${new Date().getTime()}`; 209 | const successKey = `${methodName}_${timeStr}_success`; 210 | const errorKey = `${methodName}_${timeStr}_error`; 211 | const obj: MethodCallArgs = { 212 | channelName, 213 | methodType, 214 | methodName, 215 | sourceMethodName: methodName, 216 | data, 217 | timeStr, 218 | successKey, 219 | errorKey, 220 | }; 221 | // 挂载成功的回调 222 | eventEmiter.on(successKey, res => { 223 | resolve(res); 224 | }); 225 | // 挂载失败的回调 226 | eventEmiter.on(errorKey, err => { 227 | reject(err); 228 | }); 229 | webViewRef?.current?.postMessage(JSON.stringify(obj), '*'); 230 | }); 231 | }; 232 | --------------------------------------------------------------------------------