iOS 与 Unity 的交互

4,919 阅读3分钟

前言

今天听说了一个很有意思的需求,把Unity游戏打成一个包,嵌入到原生APP中

正好两种技术栈我都有过相关经验,所以手痒实现一下!

版本

Unity 2019.2.0f1

Xcode9.3.1

Show Me The Code

创建一个Unity工程

拖入一个Cube和Text控件

然后BuildSetting中切换到iOS

注意如果需要用模拟器调试 需要在Player Settings中把Other Settings中的Target SDK切换为Simulator SDK

Unity2019.2.0f中勾选Auto Graphics API并不会添加依赖 需要手动取消Auto Graphics API并在Graphics APIs中添加OpenGLES3

然后点击Build

iOS唤起Unity

Unity默认在iOS AppDelegate中的applicationDidBecomeActive调用一个startUnity:方法 如果要自定义唤起时间,则需要改变这个方法的调用时机

UnityAppController修改并添加以下代码


- (void)applicationDidBecomeActive:(UIApplication*)application
{
    ::printf("-> applicationDidBecomeActive()\n");

    [self removeSnapshotView];

    if (_unityAppReady)
    {
        if (UnityIsPaused() && _wasPausedExternal == false)
        {
            UnityWillResume();
            UnityPause(0);
        }
        if (_wasPausedExternal)
        {
            if (UnityIsFullScreenPlaying())
                TryResumeFullScreenVideo();
        }
        UnitySetPlayerFocus(1);
    }
    else if (!_startUnityScheduled)
    {
        _startUnityScheduled = true;
        // 替换startUnity:为startSelfIOSView
        [self performSelector: @selector(startSelfIOSView) withObject: application afterDelay: 0];
    }

    _didResignActive = false;
}
// 创建原生页面和控件,自己控制唤起Unity时机
- (void)startSelfIOSView
{
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view.frame = [UIScreen mainScreen].bounds;
    vc.view.backgroundColor = [UIColor whiteColor];
    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 200, 50)];
    btn.backgroundColor = [UIColor blueColor];
    [btn setTitle:@"跳转到Unity界面" forState:UIControlStateNormal];
    // 按钮被点击时唤起Unity项目
    [btn addTarget:self action:@selector(startUnity:) forControlEvents:UIControlEventTouchUpInside];
    [vc.view addSubview:btn];
    [_window addSubview:vc.view];
}

然后就可以通过我们的定义的时机唤起Unity了

Unity唤起iOS

因为Unity界面跳转到IOS界面涉及到了暂停Unity所以我们需要实现一个单例来判断Unity的暂停或启动

LARManager.h

#import <Foundation/Foundation.h>

@interface LARManager : NSObject
/** 是否暂停Unity */
@property (assign, nonatomic) BOOL unityIsPaused;
+ (instancetype)sharedInstance;
@end

LARManager.m

#import "LARManager.h"

@implementation LARManager

+ (instancetype)sharedInstance
{
    static LARManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc] init];
    });
    return manager;
}

- (instancetype)init
{
    if (self = [super init]) {
        self.unityIsPaused = NO;
        NSLog(@"单例初始化成功");
    }
    return self;
}
@end

然后在iOS中声明被Unity调用的方法

extern "C"
{
    // 对Unity中的unityToIOS方法进行实现
    void unityToIOS(char* str){
        // Unity传递过来的参数
        NSLog(@"%s",str);
        UnityPause(true);
        // 跳转到IOS界面,Unity界面暂停
        [LARManager sharedInstance].unityIsPaused = YES;
        // GetAppController()获取appController,相当于self
        // UnityGetGLView()获取UnityView,相当于_window
        // 点击按钮后跳转到IOS界面,设置界面为IOS界面
        GetAppController().window.rootViewController = GetAppController().vc;
    }
}

在Unity中调用

    [DllImport("__Internal")]
    private static extern void unityToIOS (string str);
    
    // 按钮点击后切换到iOS界面发送一个字符串
    public void ButtonClick()
    {
        unityToIOS("Hello iOS");
    } 

实现效果:

Unity向iOS传值

第一种方法

在上个例子中已经展示了Unity向iOS传值的方法 在iOS中在extern "C"中声明方法,然后在Unity中添加方法属性并添加标签[DllImport("__Internal")] 然后就可以直接调用了

第二种方法

在Unity项目中添加Test.h Test.m

Test.h
extern "C"
{
    extern void outputAppendString (char *str1, char *str2);
}

Test.m
#import <Foundation/Foundation.h>

void outputAppendString (char *str1, char *str2)
{
    NSString *string1 = [[NSString alloc] initWithUTF8String:str1];
    NSString *string2 = [[NSString alloc] initWithUTF8String:str2];
    
    NSLog(@"###%@", [NSString stringWithFormat:@"%@ %@", string1, string2]);
}

然后两个文件Include Platforms设置为iOS

然后添加一个按钮绑定事件

    // 导入OC文件
    [DllImport("__Internal")]
    static extern void outputAppendString (string str1, string str2);
    public void ButtonClickCalliOS()
    {
        #if UNITY_IPHONE    
        outputAppendString("Hello", "World");
        #endif
    }

就可以在不做任何iOS操作的情况下 把HelloWordl传入到iOS中啦~

实现效果:

iOS向Unity传值

iOS向Unity传值主要通过void UnitySendMessage(const char* obj, const char* method, const char* msg);这个方法 这个方法可以传入三个参数:

  • 参数一为unity脚本挂载的gameobject
  • 参数二为unity脚本中要调用的方法名
  • 参数三为传递的数据,*注意:传递的数据只能是char 类型

总结

总之就是删除Unity默认的启动时机

然后再通过自定义的时机跳转到Unity界面 或着跳回到原生界面

甚至可以用iOS的原生控件去操作Unity的对象

这样 iOS部分的开发 和 Unity部分的开发就可以同时进行了

其它

项目地址: github.com/Lafree317/i…

参考文章: iOS与Unity3d交互-Larrycal: www.jianshu.com/p/4c49655af…

iOS 与 unity3D 交互整合的那些事: juejin.cn/post/684490…


随缘更新RN/Week或其它移动端框架和Unity的交互