当前位置:   article > 正文

iOS项目集成Unity详细教程_ios开发 unity工程运行

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
//
//  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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
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"];
}
  • 1
  • 2
  • 3
  • 4
  • 5
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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
好了,大功告成!Demo的运行效果如下:

Demo

后记


  • 网上有些教程说还要添加MapFileParser.sh文件,我看了这个文件是用于Unity托管堆栈跟踪的,暂时用不到,就不添加了。
  • 启动Unity后只能暂停/运行Unity,没有找到让Unity完全销毁的方法,这样的话内存占用肯定是不会减少了,CPU在暂停的时候还是占用很小的,如果有人有让Unity完全销毁的办法,欢迎指教。
  • Demo工程下载链接:
    https://download.csdn.net/download/suwk1009/10351477
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/748783
推荐阅读
相关标签
  

闽ICP备14008679号