Unity Native Plugin C#和C++互相调用

官方链接

1.DLL的方式:

C++代码:编译成DLL,导入Unity

#pragma once
#include 
#include 

//导出宏定义
#define _DllExport _declspec(dllexport)

//函数指针
typedef void (*NativeCallback)(const char*);

extern "C"
{
	//注意这里字符串不能用C++的std::string,和C#的string不等价,等价的是char*,即字符数组
	_DllExport void RegisterNativeCallback(const char* functionName, NativeCallback callback);
	_DllExport void UpdateNative();
}

//缓存C#函数的地址
std::map<std::string, NativeCallback> _callbackMap;

//导出让C#调用,注册C#端的函数,注册后就可以在C++端调用C#的函数,本质就职把C#函数的地址给到C++,C++调用。
_DllExport void RegisterNativeCallback(const char* functionName, NativeCallback callback)
{
	_callbackMap[std::string(functionName)] = callback;
}

//导出让C#调用
_DllExport void UpdateNative()
{
	//调用C#端的函数,可以在Unity性能分析界面看到Native update,用此方法可以在Unity界面查看C++代码的耗时
	_callbackMap[std::string("BeginSample")]("Native update");
	_callbackMap[std::string("Log")]("Native Log");
	_callbackMap[std::string("EndSample")]("Native update");
}

C#代码:

using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;

namespace Haha
{
    public class TestCPPLib : MonoBehaviour
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        delegate void NativeCallback(string args);

        [DllImport("CPPLib")]
        static extern void RegisterNativeCallback(string functionName, IntPtr callback);

        [DllImport("CPPLib")]
        static extern void UpdateNative();

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackLog(string args)
        {
            Debug.Log(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackBeginSample(string args)
        {
            Profiler.BeginSample(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackEndSample(string args)
        {
            Profiler.EndSample();
        }

        void Start()
        {
        	//调用C++函数,注册C#函数
            RegisterNativeCallback("Log", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackLog)));
            RegisterNativeCallback("BeginSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackBeginSample)));
            RegisterNativeCallback("EndSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackEndSample)));
        }

        private void Update()
        {
        	//调用C++函数
            UpdateNative();
        }
    }
}

2.还有一种是C++源码作为插件,只支持il2cpp。

C++代码:直接放到Unity的Assets目录下

C#源文件:区别只在导入时不写具体的文件名,写:__Internal即可,因为用IL2CPP 后端的方式,会把C++源文件放到工程内部一块编译。

using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;

namespace Haha
{
    public class TestCPPLib : MonoBehaviour
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        delegate void NativeCallback(string args);
		
		//区别在这里:
        [DllImport("__Internal")]
        static extern void RegisterNativeCallback(string functionName, IntPtr callback);

        [DllImport("__Internal")]
        static extern void UpdateNative();

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackLog(string args)
        {
            Debug.Log(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackBeginSample(string args)
        {
            Profiler.BeginSample(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackEndSample(string args)
        {
            Profiler.EndSample();
        }

        void Start()
        {
            RegisterNativeCallback("Log", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackLog)));
            RegisterNativeCallback("BeginSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackBeginSample)));
            RegisterNativeCallback("EndSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackEndSample)));
        }

        private void Update()
        {
            UpdateNative();
        }
    }
}

如果只是查看C++代码的耗时,unity提供了C++的接口,更加方便,视频最后有介绍。
Unity官方手册

//使用这两个原生接口,需要在C++项目属性配置:VC++目录->包含目录 或 C/C++->常规->附加包含目录,添加Unity这两个文件的文件路径
#include 
#include 

static IUnityProfiler* s_UnityProfiler = NULL;
static const UnityProfilerMarkerDesc* s_MyPluginMarker = NULL;
static bool s_IsDevelopmentBuild = false;

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces * unityInterfaces)
{
	s_UnityProfiler = unityInterfaces->Get<IUnityProfiler>();
	if (s_UnityProfiler == NULL)
		return;
	s_IsDevelopmentBuild = s_UnityProfiler->IsAvailable() != 0;
	s_UnityProfiler->CreateMarker(&s_MyPluginMarker, "MyCustomMethod", kUnityProfilerCategoryOther, kUnityProfilerMarkerFlagDefault, 0);
}

extern "C"  void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
	s_UnityProfiler = NULL;
}

extern "C" void UNITY_INTERFACE_EXPORT InterfaceUpdate()
{
	if (s_IsDevelopmentBuild)
	{
		s_UnityProfiler->BeginSample(s_MyPluginMarker);
	}

	//测试耗时代码
	for (int i = 0; i < 100000; i++)
	{

	}

	if (s_IsDevelopmentBuild)
	{
		s_UnityProfiler->EndSample(s_MyPluginMarker);
	}
}

关于IL2CPP打包的测试:
1.直接通过Unity构建,结构如下:如下:大小313M
Unity Native Plugin C#和C++互相调用_第1张图片
2.通过创建VS解决方案(可以在VS里设置断点,修改调试C++代码),在VS里构建,在构建界面设置:
Unity Native Plugin C#和C++互相调用_第2张图片
结构如下:bin目录包含软件的data目录,具体生成的exe在各自的平台下:
Unity Native Plugin C#和C++互相调用_第3张图片Unity Native Plugin C#和C++互相调用_第4张图片

Unity Native Plugin C#和C++互相调用_第5张图片
最终把bin目录的data文件夹和对应平台的exe何在一起,如下:大小162M
Unity Native Plugin C#和C++互相调用_第6张图片
上面的lib、pdb、exp可以删除,测试不影响运行,精简后的目录:大小50.8M
Unity Native Plugin C#和C++互相调用_第7张图片
结论:用vs构建的体积更小。

你可能感兴趣的:(Unity,C++,c#,unity,c++)