如何在Next.js项目中定义供原生App调用的函数并解决构建问题
Next.js 全局挂载原生交互函数解决方案
核心思路
原生App(Android/iOS)只能通过window对象访问网页中的全局函数,Next.js的SSR/SSG特性会导致直接在页面中定义的函数被打包处理,无法被原生识别。因此需要将函数挂载到全局window对象,并确保代码仅在客户端执行(避免SSR时报错)。
方案一:在_app.js/_app.tsx中全局注入(推荐)
_app.js是Next.js所有页面的入口组件,在这里挂载函数可确保全项目全局可用。
JavaScript 项目示例
// pages/_app.js import React from 'react'; function MyApp({ Component, pageProps }) { React.useEffect(() => { // 1. 供原生调用的函数:Android/iOS可通过 window.nativeCallJs(data) 触发 window.nativeCallJs = (data) => { console.log('原生调用JS函数,接收数据:', data); // 这里添加你的业务逻辑 }; // 2. 调用原生的函数:JS端通过 window.invokeCSharpAction(action, params) 触发 window.invokeCSharpAction = (actionName, params) => { // 根据平台区分调用方式 if (window.webkit?.messageHandlers?.invokeCSharpAction) { // iOS 环境:通过WKScriptMessageHandler发送消息 window.webkit.messageHandlers.invokeCSharpAction.postMessage({ action: actionName, params: params }); } else if (window.android) { // Android 环境:通过addJavascriptInterface暴露的对象调用 window.android.invokeCSharpAction(actionName, JSON.stringify(params)); } }; // 组件卸载时清理全局函数,避免重复挂载 return () => { delete window.nativeCallJs; delete window.invokeCSharpAction; }; }, []); return <Component {...pageProps} />; } export default MyApp;
TypeScript 项目补充:声明Window类型
TypeScript项目需扩展Window接口,避免构建时出现“invokeCSharpAction未声明”的错误:
// types/global.d.ts(没有就新建这个文件) interface Window { nativeCallJs: (data: any) => void; invokeCSharpAction: (actionName: string, params: any) => void; // 声明原生可能暴露的对象 android?: { invokeCSharpAction: (actionName: string, params: string) => void; }; webkit?: { messageHandlers?: { invokeCSharpAction: { postMessage: (message: any) => void; }; }; }; }
方案二:用Next.js Script组件引入外部脚本
若你偏好将函数写在单独的JS文件中,可使用Next.js内置的Script组件(比普通script标签更可靠,适配SSR)。
步骤1:创建全局脚本文件
在public/static/script.js中编写函数并挂载到window:
// public/static/script.js // 供原生调用的函数 window.nativeCallJs = function(data) { console.log('原生调用JS函数:', data); }; // 调用原生的函数 window.invokeCSharpAction = function(actionName, params) { if (window.webkit?.messageHandlers?.invokeCSharpAction) { window.webkit.messageHandlers.invokeCSharpAction.postMessage({ action: actionName, params: params }); } else if (window.android) { window.android.invokeCSharpAction(actionName, JSON.stringify(params)); } };
步骤2:在_app.js中引入脚本
使用beforeInteractive策略确保脚本在页面初始化时加载:
// pages/_app.js import Script from 'next/script'; import React from 'react'; function MyApp({ Component, pageProps }) { return ( <> <Script src="/static/script.js" strategy="beforeInteractive" /> <Component {...pageProps} /> </> ); } export default MyApp;
关键注意事项
- 原生端配置:
- Android:需通过
addJavascriptInterface将原生对象暴露给WebView,或者使用evaluateJavascript调用JS函数。 - iOS:需通过
WKScriptMessageHandler注册invokeCSharpAction消息监听,才能接收JS发送的调用请求。
- Android:需通过
- 避免SSR报错:所有操作
window的代码必须在客户端执行(useEffect、Script组件都是客户端执行逻辑),不能在服务端渲染的代码中直接访问window。 - 测试验证:在浏览器控制台输入
window.nativeCallJs('测试数据')或window.invokeCSharpAction('testAction', {key: 'value'}),检查函数是否正常执行,再在原生App中测试交互。
内容的提问来源于stack exchange,提问作者Coolco
相关产品推荐
相关产品推荐

