前提
推荐一个Native C++开发工具。
默认Unity Native插件开发,C#用[DllImport("dll名称")]标注,存在一个问题是,如果想要重新编译Plugin,需要先将UnityEditor关闭,不然原有的dll还被占用,无法将新编译的dll动态库更新到Unity工程。
一种修复方法是,使用LoadLibrary手动加载、管理dll而不是让Unity管理,已有工具UnityNativeTool能做到这一点。
使用方法
1. 到relase中下载UnityPackage导入到项目中。
2. 场景中加一个空物体挂在DllManipulatorScript用来配置。
看一些常用选项:
①Enable in Edit Mode
不需要游戏运行也能让工具生效
②Only Assembly-CSharp(-Editor)
默认只在Assembly-CSharp、Assembly-CSharp-Editor生效,如果你的Plugin的C#交互接口有自己的asmdef,就需要取消勾选并添加自己的程序集名称。
注: 有一个坑,较新版本的编辑器,程序集名称还有Assembly-CSharp-Editor-firstpass,你可以在Inspector面板添加,也可以去DllManipulator.cs中添加。
③Dll Path pattern
名称的匹配模式,默认是{assets}/Plugins/__{name}.dll
工作方法是这样:如果你的接口声明是:
public class MyPluginClass
{
[DllImport("MyPlugin")]
private static extern bool MyPluginFunction(
}
原本Unity会去寻找MyPlugin.dll,现在被工具拦截后,会替换上述pattern,{assets}会替换成你的Assets的全路径,{name}会替换你的dll名称,这个例子里,整体会替换成Assets/Plugins/__MyPlugin.dll,也因此你需要将编译好的dll定义成这个名字,然后拷贝到这个路径下。
你也可以根据你的喜好自定义路径,例如写成{assets}/Plugins/mocks/__{name}.dll等等。
添加好上述选项后,Mocked Dlls检测到生效的dll和路径,会在Inspector中显示出来,当需要更新Plugin时,点Inspector的Unload all DLLs即可(或者Alt+D快捷键)。

这些dll就会被解除占用,此时更新dll文件,下次extern函数调用时,就会是更新过后的方法。
配合使用方式
拷贝dll依旧是一步手动操作,可以生成构建时,自动拷贝dll,例如VS中是项目属性>生成事件>生成后事件,参考UnityNativeRenderPlugin:
<PostBuildEvent>
<Command>SETLOCAL
if "$(PlatformShortName)" == "x86" (
set TARGET_PLUGIN_PATH=$(SolutionDir)..\..\..\UnityProject\Assets\Plugins\x86
) else (
set TARGET_PLUGIN_PATH=$(SolutionDir)..\..\..\UnityProject\Assets\Plugins\x86_64
)
echo Target Plugin Path is %TARGET_PLUGIN_PATH%
copy /Y "$(TargetPath)" "%TARGET_PLUGIN_PATH%\$(TargetFileName)"
ENDLOCAL
</Command>
</PostBuildEvent>
我是xmake组织的C++项目,在target中可以加入after_build,这样xmake导出的VS工程生成时也能照常执行:
after_build(function (target)
local target_base_path
if target:is_arch("x86") then
target_base_path = path.join("../GPUDrivenPlayergroundUnityProject/Assets/Plugins/x86")
else
target_base_path = path.join("../GPUDrivenPlayergroundUnityProject/Assets/Plugins/x86_64")
end
local target_plugin_path
if is_mode("debug") then
target_plugin_path = target_base_path
elseif is_mode("release") then
target_plugin_path = path.join(target_base_path, "GPUDrivenPlugin/RenderingPlugin")
end
print("Target Plugin Path is " .. target_plugin_path)
os.mkdir(target_plugin_path)
if is_mode("debug") then
os.cp(target:targetfile(), path.join(target_plugin_path, "__" .. path.filename(target:targetfile())))
elseif is_mode("release") then
os.cp(target:targetfile(), path.join(target_plugin_path, path.filename(target:targetfile())))
end
end)
经过上述配置后,更新插件我只需要Alt+D,生成dll两步即可更新dll,而无需重启编辑器。
