iOS项目集成Unity详细教程

前言


Unity发布到iOS平台得到的是一个Xcode工程,这个Xcode工程可以直接编译运行,但是我们现在已经有个iOS项目了,Unity是作为项目的一部分,所以需要在已有的Xcode工程中集成Unity。
环境:Xcode 9 + Unity 2017。

Unity导出时设置图形API不要用Metal,因为我发现按我的集成方法使用Metal会崩,不知道什么原因。
api设置

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

需要添加的文件夹

步骤


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

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

Create groups

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

Create folder references

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

libil2cpp

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

Other Linker Flags

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

Header Search Paths

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

Other C Flags

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

Prefix

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

添加User-Defined

添加完成

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

framework

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

Classes下的UnityAppController类就是用于启动、显示Unity界面的类,不过它创建的是全屏界面,而我们需要的是让Unity只占整个界面的一部分,所以需要修改;我的方法是自己建一个类继承它,从而自定义自己的方法,代码如下:

//
//  UnityController.h
//

#import "UnityAppController.h"

@interface UnityController : 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>

@interface UnityController()

@property (nonatomic, assign) BOOL isInitUnity;

@end



@implementation UnityController

+ (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];
        
    }
    return self;
}

- (UIView *)playView {
    
    return self.unityView;
    
}

static const int 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) {
        return YES;
    }
    else {
        return NO;
    }
}

- (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]];
}

@end

7. 打开AppDelegate.m文件,添加UnityController属性,并在应用程序加载完成后创建对象。

AppDelegate.m

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"

@interface ViewController ()

@end

@implementation ViewController

- (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显示的View
    UIView *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的运行效果如下:

Demo

后记


  • 网上有些教程说还要添加MapFileParser.sh文件,我看了这个文件是用于Unity托管堆栈跟踪的,暂时用不到,就不添加了。
  • 启动Unity后只能暂停/运行Unity,没有找到让Unity完全销毁的方法,这样的话内存占用肯定是不会减少了,CPU在暂停的时候还是占用很小的,如果有人有让Unity完全销毁的办法,欢迎指教。
  • Demo工程下载链接:
    https://download.csdn.net/download/suwk1009/10351477
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
Unity是一种跨平台的游戏开发引擎,可以用于开发iOS、Android、Windows等多种平台的游戏。而阿里云则是阿里巴巴集团提供的云计算服务平台,该平台提供了各种云服务器、存储、数据库等服务,方便开发者部署和管理应用程序。 Unity与阿里云之间的接口主要包括以下几个方面: 1. 阿里云云服务器(ECS)集成Unity可以使用阿里云提供的API和SDK进行与ECS实例的交互,包括创建、删除、管理云服务器等。 2. 阿里云对象存储(OSS)集成:通过阿里云的OSS服务,Unity可以实现游戏素材的存储和管理,包括上传、下载、删除等操作。 3. 阿里云消息服务(MNS)集成Unity可以通过阿里云的消息服务,实现游戏之间的消息传递和通信,方便实现多人游戏或在线功能。 4. 阿里云数据库服务(RDS)集成Unity可以使用阿里云提供的数据库服务,如MySQL、SQL Server等,在游戏中存储和管理用户数据、排行榜等信息。 要实现Unity与阿里云的接口,首先要根据阿里云提供的开发文档和教程了解相关的API和SDK的使用方法。然后,在Unity项目中导入相应的SDK,并根据文档进行配置和设置。最后,在代码中调用相应的API和方法,实现与阿里云的交互。 总之,Unity与阿里云的接口集成可以为游戏开发者提供强大的云计算能力和存储服务,使得游戏开发和部署更加便捷和灵活。通过学习和掌握相关的教程和文档,开发者可以使用Unity开发出更具有丰富性和可扩展性的游戏应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值