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

转载地址:

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。所以共四种方法。

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

//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),注意不要重定义

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值