转载地址:
http://blog.youkuaiyun.com/IceTeaSet/article/details/53142929
各种调用C++的方法在各种平台下的总结如下(可能会有出入):
1、在VS中使用CLR C++工程,编译产生.dll,放入Plugins
✔ Android、Editor、Windows、OSX
✘ IOS (报的错貌似与il2cpp有关)
2、直接在Plugins中放入.cpp文件(不支持子目录)
✔ IOS
✘ Editor、Windows、OSX、Android
3、编译出目标移动平台的库(.a或.so等),放入Plugins
✔ IOS、Android
✘ Editor、Windows、OSX
4、编译出PC平台的库,放入Plugins
✔ Windows(.dll)、Linux(.so)、OSX(Bundle)
✘ iOS、Android
? Editor
我的目标主要是IOS,所以下面以IOS、C++为例介绍一下各种解决方案,我的Unity版本是5.4.2f2。(后因为build时崩溃换成5.5.0f3)
无论用哪种方法,都需要在Unity工程中Assets中新建一个Plugins文件夹,再新建一个iOS文件夹。
第一种方案的话,CLR C++的语法与正常C++稍有不同,要改C++代码,而且还不能在iOS上使用,就直接否决了。第四种也不用说,应该行不通。
第二、三种方案根据回调方法的不同每种又可以分为两种方法:使用官方手册上的UnitySendMessage;使用MonoPInvokeCallBack。所以共四种方法。
直接看我将四种方法汇总在一块的代码吧:
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
using AOT;
public class MonoCB : MonoBehaviour {
[StructLayout(LayoutKind.Sequential)]
struct Parameter {
public int a;
public int b;
}
delegate void CallBack(IntPtr param);
[DllImport ("__Internal")]
static extern void TestFunc(int a,int b,CallBack cb);
[DllImport ("__Internal")]
static extern void TestFunc2(int a,int b);
[DllImport ("__Internal")]
static extern void TestFunc3(int a,int b,CallBack cb);
[DllImport ("__Internal")]
static extern void TestFunc4(int a,int b);
const int CallBackByMonoPInvokeFromCpp = 1;
const int CallBackByUnitySendMessageFromCpp = 1;
const int CallBackByMonoPInvokeFromLib = 1;
const int CallBackByUnitySendMessageFromLib = 1;
void Start () {
RuntimePlatform rp = Application.platform;
Debug.Log ("[DQC]:" + rp.ToString ());
if (rp == RuntimePlatform.IPhonePlayer) {
if (CallBackByMonoPInvokeFromCpp>0) {
Debug.Log ("[DQC]:start accessing cpp TestFunc. ");
TestFunc (1,0,CallBackFunc);
Debug.Log ("[DQC]:End accessing cpp TestFunc. ");
}
if (CallBackByUnitySendMessageFromCpp>0) {
Debug.Log ("[DQC]:start accessing cpp TestFunc2. ");
TestFunc2 (2,0);
Debug.Log ("[DQC]:End accessing cpp TestFunc2. ");
}
if (CallBackByMonoPInvokeFromLib>0) {
Debug.Log ("[DQC]:start accessing cpp TestFunc3. ");
TestFunc3 (3,0,CallBackFunc3);
Debug.Log ("[DQC]:End accessing cpp TestFunc3. ");
}
if (CallBackByUnitySendMessageFromLib>0) {
Debug.Log ("[DQC]:start accessing cpp TestFunc4. ");
TestFunc4 (4,0);
Debug.Log ("[DQC]:End accessing cpp TestFunc4. ");
}
}
else if (rp == RuntimePlatform.OSXEditor || rp == RuntimePlatform.OSXPlayer)
Debug.Log ("[DQC]:need to run in a real iphone to access cpp.");
}
void Update () {
}
[MonoPInvokeCallback(typeof(CallBack))]
static void CallBackFunc(IntPtr param) {
var p = (Parameter)Marshal.PtrToStructure(param, typeof(Parameter));
Debug.Log("[DQC]:CallBackFunc. a:" + p.a + " b:" + p.b);
}
void CallBackFunc2(string message)
{
Debug.Log("[DQC]:CallBackFunc2. Message is:"+ message);
}
[MonoPInvokeCallback(typeof(CallBack))]
static void CallBackFunc3(IntPtr param) {
var p = (Parameter)Marshal.PtrToStructure(param, typeof(Parameter));
Debug.Log("[DQC]:CallBackFunc3. a:" + p.a + " b:" + p.b);
}
void CallBackFunc4(string message)
{
Debug.Log("[DQC]:CallBackFunc4. Message is:"+ message);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
#include <iostream>
using namespace std;
extern "C" {
typedef struct Parameter {
int a;
int b;
} Param;
typedef void(*CallBack)(Param* p);
void TestFunc(int a,int b,CallBack cb) {
cout<<"[DQC]:in TestFunc.a:"<<a<<" b:"<<b<<endl;
Param p;
p.a = a;
p.b = b;
cb(&p);
}
void TestFunc2(int a,int b)
{
cout<<"[DQC]:in TestFunc2.a:"<<a<<" b:"<<b<<endl;
UnitySendMessage("Main Camera","CallBackFunc2","[DQC]:success from TestFunc2");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
#include <iostream>
using namespace std;
extern "C" {
typedef struct Parameter {
int a;
int b;
} Param;
typedef void(*CallBack)(Param* p);
namespace IvesTest{
void TestFunc3(int a,int b,CallBack cb) {
cout<<"[DQC]:in TestFunc3.a:"<<a<<" b:"<<b<<endl;
Param p;
p.a = a;
p.b = b;
cb(&p);
}
}
extern void UnitySendMessage(const char* obj, const char* method, const char* msg);
void TestFunc4(int a,int b)
{
cout<<"[DQC]:in TestFunc4.a:"<<a<<" b:"<<b<<endl;
UnitySendMessage("Main Camera","CallBackFunc4","[DQC]:success from TestFunc4");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
将最后一个代码片用CocoaTouchStaticLibrary工程编译成.a后,与第二个代码片的.cpp一起放到Plugins/iOS文件夹中。Unity在Build时会将Plugins复制到Xcode工程里的Libraries文件夹下。
几个注意事项:
1、尽量不要在XCode里的Libraries/Plugins中直接修改.cpp,因为很容易就被Unity覆盖或者删除了……别问我怎么知道的。如果要在XCode中修改.cpp,那么要么干脆把Unity工程里的Plugins删除,要么可以放到XCode下的Classes文件夹中(官方文档推荐的,说是不会被覆盖)。
2、官方文档说UnitySendMessage是异步的,可能会慢一帧,MonoPInvokeCallBack未知。
3、如果是在Android,可能要将dllimport中的“__Internal”改成“库文件名”。
4、[重要]CocoaTouchStaticLibrary工程的IOS deployment target要设置成和Unity Xcode工程一样,不然链接时会报错。Unity生成的Xcode默认是7.0,郁闷的是现在最低只能选8.0了,只好都改成8.0或者更高。
5、用了extern “C”后namespace就失效了(如上例TestFunc3),注意不要重定义
要是官方文档能更详细一点就好了…