前言
本内容讲解IOS、Unity项目通信的方式,以及IOS如何生成一个unitypager包,供Unity安装使用。
Demo: https://github.com/LSnumber1/UnityAndIOSMessageDemo
Unity调用IOS方法
-
创建一个Xcode工程
依次点击File->New->Project
选择 Cocoa Touch Static Libray
如果选择的Cocoa Touch Framework创建库也是可以的,本案例是演示静态库的创建,所以,如果选择了Cocoa Touch Framework 记得Mach-O Type属性设置为"Static Library"
如下:
-
创建一个本地类,提供要暴露的方法
创建的本地类,起名为:StudentStaticLibrary.h
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface StudentStaticLibrary : NSObject - (void) showMessage: (NSString *) content; @end
实现为:
#import "StudentStaticLibrary.h" #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @implementation StudentStaticLibrary - (void)showMessage:(NSString *)content { NSLog(@"Unity 传过来的参数为:%@",content); } @end
在此,我们构建了一个有参的函数,当unity调用后,会打印unity传递过来的数据。
-
创建桥接文件,供unity调用
桥接文件起名为:Bridge.h
#ifndef Bridge_h #define Bridge_h + (Bridge *)sharedInstance; @end #endif /* Bridge_h */
实现为:Bridge.mm
#import <Foundation/Foundation.h> #import "StudentStaticLibrary.h" #import "Bridge.h" @implementation Bridge //提供几个单例调用 + (Bridge *)sharedInstance { static dispatch_once_t oneceToken; dispatch_once(&oneceToken, ^{ object = [[Bridge alloc] init]; }); return object; } //下面定义的是C语言的代码,因为通信机制就是用C语言做的桥接 #if defined (__cplusplus) extern "C" { #endif // 获取StudentStaticLibrary对象的实例,调用方法,StudentStaticLibrary可以设置为单例模式,或者作为成员变量,避免每次创建实例。 void _showMessage(char* content){ NSLog(@"mm文件响应了"); StudentStaticLibrary *library = [[StudentStaticLibrary alloc] init]; NSString *string = [[NSString alloc] initWithUTF8String:content]; [library showMessage: string]; } #if defined (__cplusplus) } #endif @end
-
把头文件暴露出来
![image-20190331104234978](/Users/ls/Library/Application Support/typora-user-images/image-20190331104234978.png)
至此,IOS需要写的代码,就是这些,接下来是unity端的代码。
-
创建一个UnityToIOS.cs
此方法为Unity调用IOS的中介。
public static class UnityToIOS { [DllImport("__Internal")] private static extern void _showMessage(string str); public static void ShowMeeage() { _showMessage("调动IOS方法"); } }
DllImport声明的方法名称,要和 IOS中的方法名字完全一样,即"extern “C” "中声明的方法名字。
-
创建测试类进行测试
TestForIOS.cs
public class TestForIOS : MonoBehaviour { // Start is called before the first frame update void Start() { #if UNITY_IPHONE UnityToIOS.ShowMeeage(); #endif } // Update is called once per frame void Update() { } }
至此Unity调用IOS的步骤完成。
IOS调用Unity方法
IOS调用Unity的方法,通过UnitySendMessage方法实现。
-
在桥接文件中,声明一个UnitySendMessage方法
此类和上边介绍Unity调用IOS方法的类是同一个,所以这边为了简略,只写核心方法了。
#if defined (__cplusplus) extern "C" { #endif void UnitySendMessage( const char * className, const char * methodName, const char * param ); //此处,发送消息给Unity char *_lableName(char *str){ //第一个参数为gameobject的名字,第二个为捆绑在gameobject的方法,第三个为参数 UnitySendMessage("Main Camera","unityGet", str); return MakeStringCopy(str); } char *MakeStringCopy(const char *string) { if (NULL == string) { return NULL; } char *res = (char *)malloc(strlen(string) + 1); strcpy(res, string); return res; } #if defined (__cplusplus) } #endif
- Unity端对应的gameobject上有一个接受方法
public class TestForIOS : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } //ios 发送消息,unity端接受的方法。 public void unityGet(string s) { } }
回调方法的使用
存在一种需求,如果类调用了某个方法后,希望把结果通知桥接文件中,我们可以用回调的方法操作。
-
声明Deleaget
StudentStaticLibrary.h
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> /** * @protocol FAT_Delegate * @brief SDK接口回调协议 */ @protocol FAT_Delegate <NSObject> @required - (void)fat_CallBack:(id)response; @end @interface StudentStaticLibrary : NSObject //属性,接口 @property (nonatomic, assign) id <FAT_Delegate>delegate; - (void) showMessage: (NSString *) content; @end
StudentStaticLibrary.m
#import "StudentStaticLibrary.h" #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @implementation StudentStaticLibrary - (void)showMessage:(NSString *)content { NSLog(@"Unity 传过来的参数为:%@",content); //收到消息后,处理回调 if ([[self delegate] respondsToSelector:@selector(fat_CallBack:)]) { [[self delegate] fat_CallBack:@"回调"]; } } @end
-
在桥接文件中,实现回调
Bridge.h
#ifndef Bridge_h #define Bridge_h //实现接口 @interface Bridge : NSObject <FAT_Delegate> + (Bridge *)sharedInstance; @end #endif /* Bridge_h */
#import <Foundation/Foundation.h> #import "StudentStaticLibrary.h" #import "Bridge.h" //保存回调 static id object; @implementation Bridge + (Bridge *)sharedInstance { static dispatch_once_t oneceToken; dispatch_once(&oneceToken, ^{ object = [[Bridge alloc] init]; }); return object; } //实现回调 - (void)fat_CallBack:(id)response { NSLog(@"callback: %@",response); } //设置回到 - (void)setLinstener{ object = self; } @end #if defined (__cplusplus) extern "C" { #endif static Bridge *bridge; void UnitySendMessage( const char * className, const char * methodName, const char * param ); void _showMessage(char* content){ NSLog(@"mm文件响应了"); if(bridge==NULL) { bridge = [Bridge sharedInstance]; } //设置回调 [bridge setLinstener]; StudentStaticLibrary *library = [[StudentStaticLibrary alloc] init]; //赋值 library.delegate = object; NSString *string = [[NSString alloc] initWithUTF8String:content]; [library showMessage: string]; } #if defined (__cplusplus) } #endif
打unitypage包
考虑一种场景,采用上述产生的IOS包,Unity开发人员无法直接使用,需要写桥接文件去对应相应的方法,增加工作量,所以我们想有没有办法生成一个包,unity可以直接调用,不需要关系桥接文件等,只需要像我们在IOS中调用三方库一样的方便。
答案就是生成一个unitypage包,我们在编写完成IOS的包后,在unity端实现一个cube,cube中我们写好通信的方法,然后,提供一个单例供unity调用即可。
-
把所需的类都放在一个文件夹下
包括prefab文件、cs文件、ios的包、头文件等。
-
导出unitypage