背景
unity需要调用其没有实现的原生功能。
unity使用C#开发,可以与c++混编。
iOS使用Objective-c开发,可以与C++和C混编。
例如:
- 支付,分享,音视频,但只提供了 iOS 平台 SDK。
- 优秀插件
- 需要通过 Objective-C 调用 iOS 原生类库代码。
交互方式
Unity 通过 C 与 iOS 进行交互。
Unity 不能直接调用 C++ 的原因是 C++ 编译会有 Name mangling 问题。
Objective-C 可以与 C/C++ 进行混编。使用 C 代码封装对应的 Objective-C 代码,提供给 Unity 使用。
unity主动调用链:unity(C#) -> C -> iOS(Objective-C)
iOS调用链: unity(C#) -> 注册回调到iOS -> iOS(Objective-C) -> 通过注册的回调,调用C -> 调用unity(C#)
注意:建议 C 函数名加有特定意义的前缀,避免函数名冲突。
unity交互部分
核心文件上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices; // 必须导入
using System
public class MonoPInvokeCallbackAttribute : Attribute // 用于定义C语音回调的类
{
public MonoPInvokeCallbackAttribute(Type type)
{
}
}
public class BridgeUnityToNative // 定义了一个类,用以做桥,可自定义
{
protected static BridgeUnityToNative _manager = null;
public static BridgeUnityToNative Instance
{
get
{
if(_manager == null)
{
_manager = new BridgeUnityToNative();
}
return _manager;
}
}
public delegate void CallBack(int res); // 定义回调,如果定义的方法需要有回调,则必须先定义delegate,才能核心交互代码中使用
// 核心交互代码
#if UNITY_IOS
[DllImport("__Internal")] // 固定形式,注册TestCallback方法为可调用的C函数
private static extern void TestCallback(); // 封装必须为private, extern需要定义的方法,不然会报错
[DllImport("__Internal")]
private static extern void RegistCallback(CallBack callBack); // 封装必须为private, extern需要定义的方法,不然会报错
[AOT.MonoPInvokeCallback(typeof(CallBack))] // 将LogCallback方法,注册为回调
static void LogCallback(int res)
{
Debug.Log("调用了c# callback" + res);
}
public void TestCallbackFunc(int retCode) // 对外接口方法,,外部文件调用此方法验证demo
{
Debug.Log("调用了TestCallbackFunc" + retCode);
TestCallback();
RegistCallback(BridgeUnityToNative.LogCallback);
}
#endif
}
上述代码,一共定义了两个交互函数。
无回调方法TestCallback
和 有回调方法RegistCallback
由于作用域的问题,两个方法都只能private。所以对外接口需要用c#包一层
[AOT.MonoPInvokeCallback(typeof(CallBack))]
的下一个函数,可以用于回调代理。其函数类类型必须与代理完全一致,否则会报错
这里函数名和回调类型,必须要跟iOS(Objective-C)的类型完全一致。不然会报错,无法调用整个函数。
注意事项:
TestCallback
和'RegistCallback'方法。只在此处extern了方法名,所以不会有任何检查机制,C#或iOS改了方法,对方完全察觉不到,验证也很费劲。所以精心维护一份交互文档是很重要的。
iOS交互部分
因为要混C++ , 所有.m文件的后缀要改成.mm
.h文件:
//
// IOSToUnity.h
// Unity-iPhone
//
// Created by yangda on 2019/1/12.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#ifndef ConnectUnityToiOS_h
#define ConnectUnityToiOS_h
#endif /* ConnectUnityToiOS_h */
@interface ConnectUnityToiOS : NSObject
typedef void(*CallBack)(int retCode);
+ (ConnectUnityToiOS *)sharedInstance;
extern "C"
{
void TestCallback();
void RegistCallback(CallBack callBack);
}
@end
其中:typedef void(*CallBack)(int retCode);
对应C#代码中的代理public delegate void CallBack(int res);
定义
核心代码为:
extern "C"
{
void TestCallback();
void RegistCallback(CallBack callBack);
}
extern "C"
可以扩展C函数,用于交互
.m文件:
//
// IOSToUnity.m
// Unity-iPhone
//
// Created by yangda on 2019/1/12.
//
#import "ConnectUnityToiOS.h"
@interface ConnectUnityToiOS()
@property(atomic, assign)CallBack callBack;
@end
@implementation ConnectUnityToiOS
// MARK:- OC部分
static ConnectUnityToiOS *instance = nil;
+ (ConnectUnityToiOS *)sharedInstance{
@synchronized(self) {
if(instance == nil) {
instance = [[[self class] alloc] init];
}
}
return instance;
}
- (void)registTestCallBack:(CallBack)callBack {
_callBack = callBack;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_callBack(1);
NSLog(@"iOS registTestCallBack");
});
}
// MARK:- C++部分
void TestCallback()
{
NSLog(@"TestCallback");
}
void RegistCallback(CallBack callBack)
{
NSLog(@"iOS RegistCallback");
[ConnectUnityToiOS.sharedInstance registTestCallBack:callBack];
}
@end
如果有错误的地方欢迎指正
网友评论