找回密码
 立即注册
查看: 439|回复: 0

iOS项目集成Unity详细教程

[复制链接]
发表于 2021-10-22 13:32 | 显示全部楼层 |阅读模式
前言


Unity发布到iOS平台得到的是一个Xcode工程,这个Xcode工程可以直接编译运行,但是我们现在已经有个iOS项目了,Unity是作为项目的一部分,所以需要在已有的Xcode工程中集成Unity。
环境:Xcode 9 + Unity 2017。
Unity导出时设置图形API不要用Metal,因为我发现按我的集成方法使用Metal会崩,不知道什么原因。



下图为Unity发布得到的Xcode工程,红框中是我们要添加到自己的项目的文件夹。


步骤


1. 将Unity Xcode工程中的Classes和Libraries文件夹添加到工程中,注意勾选Copy items if needed,并选择Create groups。

(这里我把Unity相关的文件都放入了Unity逻辑文件夹下,便于管理,话说Xcode 9终于默认创建物理文件夹了,老版本默认创建的是逻辑文件夹,逻辑文件夹只在Xcode中显示,在Finder中是看不到的)


2. 将Unity Xcode工程中的Data文件夹添加到工程中,注意勾选Copy items if needed,并选择Create folder references。



3. 删除Libraries下的libil2cpp,注意删除选项选择Remove References。



4. 删除Classes下的main.mm,直接Move To Trash,因为我们使用自己的main文件,main.mm中有一些Unity初始化的代码,我将其放入了UnityController.mm中,下文会说到。

5. 接下来修改项目的Build Settings,建议从Unity导出的Xcode工程的Build Settings中复制,不容易出错。

    Other Linker Flags:
    $(inherited) -weak_framework CoreMotion -weak-lSystem


    Header Search Paths:
    $(inherited) “$(SRCROOT)/Classes” “$(SRCROOT)” $(SRCROOT)/Classes/Native $(SRCROOT)/Libraries/bdwgc/include $(SRCROOT)/Libraries/libil2cpp/include
    (如果你在第一步中建立的是物理文件夹,就把物理文件夹路径加进去)


    Other C Flags:
    $(inherited) -DINIT_SCRIPTING_BACKEND=1 -fno-strict-overflow -DRUNTIME_IL2CPP=1


    Precompile Prefix Header:YES
    Prefix Header:Classes/Prefix.pch


    在User-Defined添加以下属性,注意版本号换成自己的Unity版本号。
    GCC_THUMB_SUPPORT:NO
    GCC_USE_INDIRECT_FUNCTION_CALLS:NO
    UNITY_RUNTIME_VERSION:2017.1.0p5
    UNITY_SCRIPTING_BACKEND:il2cpp




    添加框架,建议按自己导出的Unity-Xcode工程来,不同人的可能不一样,注意Optional(弱引用)。


6. 创建类UnityController.mm继承自UnityAppController.mm

Classes下的UnityAppController类就是用于启动、显示Unity界面的类,不过它创建的是全屏界面,而我们需要的是让Unity只占整个界面的一部分,所以需要修改;我的方法是自己建一个类继承它,从而自定义自己的方法,代码如下:
////  UnityController.h//#import "UnityAppController.h"@interfaceUnityController : UnityAppController@property (nonatomic, readonly, weak) UIView *playView;  /* 展示Unity的view */+ (instancetype)instance;- (void)initUnity;- (void)pauseUnity;- (void)startUnity;- (BOOL)isPaused;@end////  UnityController.mm//#import "UnityController.h"#import "UnityAppController.h"#import "UnityAppController+ViewHandling.h"#import "UnityAppController+Rendering.h"#import "DisplayManager.h"#import "UnityView.h"#include "RegisterMonoModules.h"#include "RegisterFeatures.h"#include <csignal>@interfaceUnityController()@property (nonatomic, assign) BOOL isInitUnity;@end@implementationUnityController+ (instancetype)instance {    return (UnityController *)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityController"];}- (instancetype)init{    self = [super init];    if (self) {        self.isInitUnity = NO;        // 注册Unity的事件        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];    }    returnself;}- (UIView *)playView {    returnself.unityView;}staticconstint constsection = 0;void UnityInitTrampoline();void initMain() {    @autoreleasepool    {        UnityInitStartupTime();        UnityInitTrampoline();        UnityInitRuntime(0, NULL);        RegisterMonoModules();        NSLog(@"-> registered mono modules %p\n", &constsection);        RegisterFeatures();        // iOS terminates open sockets when an application enters background mode.// The next write to any of such socket causes SIGPIPE signal being raised,// even if the request has been done from scripting side. This disables the// signal and allows Mono to throw a proper C# exception.        std::signal(SIGPIPE, SIG_IGN);    }}- (void)initUnity {    if (!self.isInitUnity) {        initMain();        if ([UIDevice currentDevice].generatesDeviceOrientationNotifications == NO)            [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];        UnityInitApplicationNoGraphics([[[NSBundle mainBundle] bundlePath] UTF8String]);        [self selectRenderingAPI];        [UnityRenderingView InitializeForAPI: self.renderingAPI];        _window = nil;        _unityView      = [self createUnityView];        [DisplayManager Initialize];        _mainDisplay    = [DisplayManager Instance].mainDisplay;        [_mainDisplay createWithWindow: _window andView: _unityView];        [super applicationDidBecomeActive:[UIApplication sharedApplication]];        self.isInitUnity = YES;    }}- (void)pauseUnity {    //[self applicationWillResignActive:[UIApplication sharedApplication]];    UnityPause(1);}- (void)startUnity {    //[self applicationDidBecomeActive:[UIApplication sharedApplication]];    UnityPause(0);}- (BOOL)isPaused {    if (UnityIsPaused() == 1) {        returnYES;    }    else {        returnNO;    }}- (void)appWillEnterForeground:(NSNotification *)notification {    [self applicationWillEnterForeground:[UIApplication sharedApplication]];}- (void)appDidBecomeActive:(NSNotification *)notification {    if (nil == self.unityView) {        return;    }    [self applicationDidBecomeActive:[UIApplication sharedApplication]];}- (void)appWillResignActive:(NSNotification *)notification {    [self applicationWillResignActive:[UIApplication sharedApplication]];}- (void)appWillTerminate:(NSNotification *)notification {    [self applicationWillTerminate:[UIApplication sharedApplication]];}- (void)appDidReceiveMemoryWarning:(NSNotification *)notification {    [self applicationDidReceiveMemoryWarning:[UIApplication sharedApplication]];}@end7. 打开AppDelegate.m文件,添加UnityController属性,并在应用程序加载完成后创建对象。



8. 打开Classes下的UnityAppController.h文件,修改GetAppController()函数。

inline UnityAppController*  GetAppController(){//    return (UnityAppController*)[UIApplication sharedApplication].delegate;    return (UnityAppController *)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityController"];}9. 为ViewController.m添加代码。

////  ViewController.m//  #import "ViewController.h"#import "UnityController.h"@interfaceViewController ()@end@implementationViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];    button.frame = CGRectMake(60, 60, 80, 40);    [button setTitle:@"开启Unity" forState:UIControlStateNormal];    [self.view addSubview:button];    [button addTarget:self action:@selector(clickHandler:) forControlEvents:UIControlEventTouchUpInside];    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];    button1.frame = CGRectMake(160, 60, 80, 40);    [button1 setTitle:@"暂停Unity" forState:UIControlStateNormal];    [self.view addSubview:button1];    [button1 addTarget:self action:@selector(clickHandler1:) forControlEvents:UIControlEventTouchUpInside];    // 供Unity显示的ViewUIView *view = [[UIView alloc] initWithFrame:CGRectMake(10, 150, 300, 300)];    [view setBackgroundColor:[UIColor grayColor]];    [view setTag:22];    [self.view addSubview:view];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}- (void) clickHandler:(id)sender{    [[UnityController instance] initUnity];    [UnityController instance].playView.frame = [self.view viewWithTag:22].bounds;    [[self.view viewWithTag:22] addSubview:[UnityController instance].playView];}- (void) clickHandler1:(id)sender{    if ([[UnityController instance] isPaused]) {        [[UnityController instance] startUnity];    }    else {        [[UnityController instance] pauseUnity];    }}@end好了,大功告成!Demo的运行效果如下:



后记



    网上有些教程说还要添加MapFileParser.sh文件,我看了这个文件是用于Unity托管堆栈跟踪的,暂时用不到,就不添加了。启动Unity后只能暂停/运行Unity,没有找到让Unity完全销毁的方法,这样的话内存占用肯定是不会减少了,CPU在暂停的时候还是占用很小的,如果有人有让Unity完全销毁的办法,欢迎指教。Demo工程下载链接:
    https://download.csdn.net/download/suwk1009/10351477

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 20:05 , Processed in 0.094422 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表