Skip to main content

Hello 互操作

本篇假定已完成 安装。目标:在 Editor Play 时同时看到 C# 调 JSJS 调 C#。更短的 Demo 对照见 快速开始;本篇是使用指南主线的正式起点。

Canonical:zts-demojs-demo(纯 JS)或 ts-demo(TypeScript)。

1. 注册 loader 并 Initialize

using System.IO;
using System.Text;
using UnityEngine;
using ZTS;

public class Bootstrap : MonoBehaviour
{
private static object LoadJsModule(string module)
{
#if UNITY_EDITOR
string path = Path.Combine(Application.dataPath, "..", "JsScripts", module + ".js");
#else
string path = Path.Combine(Application.streamingAssetsPath, "Js", module + ".js");
#endif
return File.Exists(path) ? File.ReadAllText(path, Encoding.UTF8) : null;
}

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void InitZtsOnStartup()
{
TsAppDomain.Initialize(LoadJsModule);
}
}
  • modulecanonical specifier(无路径、无 .js / .ts),如 "app"
  • loader 返回 UTF-8 ES module 源码字符串;找不到返回 null(或抛明确异常)
  • csharp: 由运行时在 loader 之前拦截,不要把该前缀交给业务 loader
  • 不需要手动创建 JSContext / 注册 Wrap

TypeScript 工程则让 loader 读 TsProject/out/{canonical}.js,见 TypeScript 工作流

2. 最简 C# → JS

模块须使用 named export(不要指望 export default 自动映射到 GetFunction):

// JsScripts/app.js
export function main() {
console.log("js main start");
}

export function add(a, b) {
return a + b;
}
Action AppMain;
Func<int, int, int> AppAdd;

void Awake()
{
// 须在 Initialize 之后;勿放在与 RuntimeInitializeOnLoadMethod 同类型的 static 字段初始化器里
AppMain = TsAppDomain.GetFunction<Action>("app", "main");
AppAdd = TsAppDomain.GetFunction<Func<int, int, int>>("app", "add");
}

void Start()
{
AppMain();
Debug.Log(AppAdd(10, 20)); // 30
}

热路径请自行缓存 Delegate;GetFunction 不保证返回同一实例。详解见 C# 调用 JS

3. 最简 JS → C#

// Assets/Demo.cs(示意)
public class Demo
{
public static int Add(int a, int b) => a + b;
public int x;
public void SetX(int v) => x = v;
public int GetX() => x;
}

全局 CSharp(低层权威路径):

CSharp['AC'] = CSharp['Assembly-CSharp'];

console.log(CSharp.AC.Demo.Add(3, 5)); // 8 静态方法

const demo = new CSharp.AC.Demo(); // 构造须 new
demo.SetX(10); // 实例方法:点号调用,无冒号
console.log(demo.x); // 10 字段 / 无参 Property

推荐脚本写法(与上式 identity 相同):

import { Demo } from "csharp:Assembly-CSharp";

console.log(Demo.Add(3, 5));
const demo = new Demo();
demo.SetX(10);
console.log(demo.x);

含 namespace 时:import { Panel } from "csharp:Assembly-CSharp/MyGame.UI",或 CSharp.AC['MyGame.UI.Panel']。日常用法见 JS 调用 C#

与 Lua / 旧习惯的差异
  • 实例方法用 demo.SetX(10)没有 demo:SetX(10) 冒号语法
  • 构造用 new Demo()
  • 未知成员 strict missthrow Error('zts: …'),不是 undefined

预期输出(Editor Play)

js main start
...
30

若无输出:确认 BeforeSceneLoad 已执行、LoadJsModule("app") 非 null、Console 未过滤日志。更多排查见 排障

下一步

学习路径

上一篇安装
下一篇JS 调用 C#

相关文档