因项目中有做与Unity对接相关的需求,完结后在此记载一下。主要记载怎么引进、两头怎么交互,以及碰到的问题解决。
先说一下原生工程怎么引进,现在有两种引进办法
一、项目工程引进
当Unity开发完结后,他们会依据渠道导出不同的项目工程文件,iOS便是xcodeproj;
首要,翻开你的项目
将Unity工程增加进来workspace来
add完结之后,就会
至此第一步完结,开端编译Unity, Command + B
选中Data文件夹,右侧勾选UnityFramework
找到NativeCallProxy.h文件,改成Public
这儿改成UnityFramwork,开端编译(能够在scheme中挑选debug和release)
编译成功后,能够在Xcode的DerivedData文件夹下找到,因为此时Unity工程现已被引进到原生项目,所以编译后的文件会在原生项目中
然后便是要到原生项目中引进这个UnityFramework
在原生的项目 找到增加framework的当地
点击加号增加
假如在你的增加的framework中能找到,即成功;之后就能够编译原生项目;
二、编译framework引进
考虑到原生项目需求的便是UnirtyFramework,所以只需求把编译成功的Unityframework导入进来即可;
这种办法好处在于,不影响其他同事,其他人拉取项目,不需求考虑编译Unity工程。
同办法一一样,
点击Data文件夹时右侧勾选framework, 点击NativeCallProxy时右侧挑选public ,
装备完结之后,挑选Target是Unity-iPhone,然后进行编译
(此时需求挑选签名账号,不选会编译报错,bundleID与账号能够与原生工程一样即可)
编译成功后,翻开Product文件夹
找到他show in Finder,然后将framework直接拖入到原生项目里去,不过要在导入的framework中检查一下是否导入,然后编译即可。
引进Unity经常见问题便是找不到UnityFrmework,能够编译原生工程,编译后看DerivedData文件夹下是否有UnityFrmework,假如没有,说明没有引进正确。
三、代码部分
能够参阅官方的demo : github.com/Unity-Techn…
这儿我建了一个管理类一致处理: HCUnityManager
首选在main.m
中,保存argc ,argv
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@(argc) forKey:@"argc"];
[userDefaults setObject:[NSString stringWithFormat:@"%p",argv] forKey:@"argv"];
[userDefaults synchronize];
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
在AppDelegate.m
中保存launchOptions
,除了didFinishLaunchingWithOptions
办法外,其他办法需求告诉UnityFramework
此时application的状态,否则会出现异常(如退到后台后,Unity页面无呼应了等等),
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
[HCUnityManager shareInstance].launchOptions = launchOptions;
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
[[[[HCUnityManager shareInstance] unityFramework] appController] applicationWillResignActive: application];
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[[[HCUnityManager shareInstance] unityFramework] appController] applicationDidEnterBackground: application];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[[[[HCUnityManager shareInstance] unityFramework] appController] applicationWillEnterForeground: application];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[[[HCUnityManager shareInstance] unityFramework] appController] applicationDidBecomeActive: application];
}
- (void)applicationWillTerminate:(UIApplication *)application {
[[[[HCUnityManager shareInstance] unityFramework] appController] applicationWillTerminate: application];
}
在HCUnityManager.h中,包括之前保存的数据,以及可供展现的unityView
#import <UnityFramework/UnityFramework.h>
#include <UnityFramework/NativeCallProxy.h>
@interface HCUnityManager : NSObject<UnityFrameworkListener,NativeCallsProtocol>
+ (HCUnityManager *)shareInstance;
@property (nonatomic, assign) int gArgc;
@property (nonatomic, assign) char **gArgv;
@property(nonatomic, strong) NSDictionary *launchOptions;
@property (nonatomic, strong) UnityFramework *unityFramework;
///用于展现Unity的View,可增加到自己需求展现页面的控制器上
@property (nonatomic, strong ) UIView *unityView;
///初始化
- (void)initUnity;
///是否现已初始化
- (BOOL)unityIsInitialized;
///发送音讯给Unity
- (void)sendMessageToGOWithName:(const char*)goName functionName:(const char*)name message:(const char*)msg;
在HCUnityManager.m中,做一些unity初始化操作,以及原生与Unity交互的办法
#pragma mark - Unity
//初始化 Unity 加载
- (UnityFramework *)loadUnityFramework {
NSString* bundlePath = nil;
bundlePath = [[NSBundle mainBundle] bundlePath];
bundlePath = [bundlePath stringByAppendingString: @"/Frameworks/UnityFramework.framework"];
NSBundle* bundle = [NSBundle bundleWithPath: bundlePath];
if ([bundle isLoaded] == false) {
[bundle load];
}
UnityFramework* ufw = [bundle.principalClass getInstance];
if (![ufw appController]) {
// unity is not initialized
[ufw setExecuteHeader: &_mh_execute_header];
}
return ufw;
}
// 判别Unity是否现已初始化
- (BOOL)unityIsInitialized {
return [self unityFramework] && [[self unityFramework] appController];
}
// 初始化Unity
- (void)initUnity {
// 判别Unity 是否现已初始化
if ([self unityIsInitialized]) return;
// 初始化Unity
self.unityFramework = [self loadUnityFramework];
[self.unityFramework setDataBundleId:"com.unity3d.framework"];
[self.unityFramework registerFrameworkListener:self];
//用于桥接运用
[NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self];
NSString *argvStr = [[NSUserDefaults standardUserDefaults] valueForKey:@"argv"];
char **argv;
sscanf([argvStr cStringUsingEncoding:NSUTF8StringEncoding], "%p",&argv);
int argc = [[[NSUserDefaults standardUserDefaults] valueForKey:@"argc"] intValue];
[self.unityFramework runEmbeddedWithArgc:argc argv:argv appLaunchOpts:self.launchOptions];
self.unityView = [[[self unityFramework] appController] rootView];
//隐藏 unity 自己的 window,否则会挡住 UIApplication 的 window
[[self unityFramework] appController].window.hidden = YES;
}
///展现Unity的view
- (void)showUnityView {
if (![self unityIsInitialized]){
NSLog(@"Unity 还未初始化");
}
[self.unityFramework showUnityWindow];
}
#pragma mark - UnityFrameworkListener
- (void)unityDidUnload:(NSNotification *)notification {
[[UIApplication sharedApplication].keyWindow makeKeyAndVisible];
[[self unityFramework] unregisterFrameworkListener: self];
self.unityFramework = nil;
}
- (void)unityDidQuit:(NSNotification *)notification {
NSLog(@"========== %s ============",__func__);
}
- (void)retryRegisterListener {
[self.unityFramework registerFrameworkListener:self];
}
///原生调用unity办法
- (void)sendMessageToGOWithName:(const char*)goName functionName:(const char*)name message:(const char*)msg {
[self.unityFramework sendMessageToGOWithName:goName functionName:name message:msg];
}
//MARK: -- NativeCallsProtocol
- (void) showHostMainWindow:(NSString*)color {
if(![self unityIsInitialized]) {
NSLog(@"Unity is not initialized, Initialize Unity first");
} else {
[self.unityFramework showUnityWindow];
}
}
///获取token
- (char *)getToken {
// 获取之前保存的token
NSString *token = [[HCUserManager sharedInstance] token];
char *cString = [token cStringUsingEncoding:NSUTF8StringEncoding];
return cString;
}
总结一下便是:
unity调用原生的办法,一致经过NativeCallsProtocol
协议完成;
原生调用unity办法,即一致是[self.unityFramework sendMessageToGOWithName:goName functionName:name message:msg];
NativeCallsProtocol
协议里边通常用C编写,unity那儿的C#能够调用的到
假如与unity有交互,需求在unity工程内增加代码后再编译引进;
在NativeCallsProtocol.h
中增加供unity调用的办法,showHostMainWindow
是Unity给的,仿照写即可
#import <Foundation/Foundation.h>
// NativeCallsProtocol defines protocol with methods you want to be called from managed
@protocol NativeCallsProtocol
@required
- (void) showHostMainWindow:(NSString*)color;
// other methods
- (char *)getToken;
@end
在NativeCallProxy.mm
中参加办法的完成
extern "C" {
void showHostMainWindow(const char* color) {
return [api showHostMainWindow:[NSString stringWithUTF8String:color]];
}
char* getToken(){
return strdup([api getToken]);
}
}
在此补充一下,假如要回来字符串给unity,需求加上strdup
函数,否则会报内存问题;
增加办法后,因为HCUnityManager
是恪守了NativeCallsProtocol,在HCUnityManager
中具体完成即可;
四:存在问题
1.内存问题
当unity初始化完结,我们用自己的控制器加载unityView时,内存会暴增,现在我的是300M;
优化点:UnityFramework 提供了unloadApplication
,quitApplication
,pause
办法
调用unloadApplication
,会使内存削减50M左右,仍是未能完全回收;重新进入页面时,需求重新init;
调用quitApplication
,会使使用直接退出,不建议运用;
调用pause
,仅暂停unity页面,无法继续动画,但内存未削减;
2.安装包大小问题,
现在我的增加200M左右,这儿只能靠unity开发同事优化;
其他问题待发现后再续写吧。