Unity3D在IOS、Android上使用C++并回调的究极解决方案

来源:互联网 发布:游戏代练网站源码 编辑:程序博客网 时间:2024/05/03 09:59

转载地址:

http://blog.csdn.net/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。所以共四种方法。

直接看我将四种方法汇总在一块的代码吧:

//C#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;    // Use this for initialization      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.");    }      // Update is called once per frame      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
//C++ 直接用.cpp#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
//C++ 编译成.a  与上面几乎一样#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),注意不要重定义

要是官方文档能更详细一点就好了…

原创粉丝点击