You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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;

关键注意事项

  1. 原生端配置:
    • Android:需通过addJavascriptInterface将原生对象暴露给WebView,或者使用evaluateJavascript调用JS函数。
    • iOS:需通过WKScriptMessageHandler注册invokeCSharpAction消息监听,才能接收JS发送的调用请求。
  2. 避免SSR报错:所有操作window的代码必须在客户端执行(useEffect、Script组件都是客户端执行逻辑),不能在服务端渲染的代码中直接访问window。
  3. 测试验证:在浏览器控制台输入window.nativeCallJs('测试数据')或window.invokeCSharpAction('testAction', {key: 'value'}),检查函数是否正常执行,再在原生App中测试交互。

内容的提问来源于stack exchange,提问作者Coolco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 16:40:02