iOS&&Unity简单融合

1,817 阅读2分钟
  1. 创建空白Unity工程,导出iOS项目(UnityiOSDemo)
  2. 创建空白iOS项目(iOSUnityDemo)
  3. 打开Xcode,新建xcworkspace(iOS&&Unity)
  4. 把UnityiOSDemo和iOSUnityDemo导入iOS&&Unity
  5. 选择UnityiOSDemo scheme 进行编译,这一步是为了获得UnityFramework.framework
  6. 选中UnityiOSDemo工程中的Data目录,将Target Membership更改为UnityFramework
  7. 选中iOSUnityDemo工程,在General-Frameworks,Libraries,and Embedded Content 添加UnityFramework.framework
  8. 选中iOSUnityDemo工程,在Build-Phases-Link Binary With Libraries 中删除UnityFramework.framework
  9. 此时准备工作已就绪

如何切换iOS原生页面和Unity页面

//

//  AppDelegate.h

//  iOSUnityDemo

//

//  Created by YueQu on 2021/8/31.

//

#import <UIKit/UIKit.h>

#include <UnityFramework/UnityFramework.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, UnityFrameworkListener>

@property (nonatomic, strong) UIWindow *window;

@property (nonatomic, strong) UnityFramework *ufw;

- (void)initUnity;

- (void)showUnityMainWindow;

- (void)showNativeMainWindow;

@end
#import "AppDelegate.h"

#import "ViewController.h"

#import <UnityFramework/UnityFramework.h>

/* UnityFrameworkLoad */

UIKIT_STATIC_INLINE UnityFramework* UnityFrameworkLoad() {

    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;

}

@interface AppDelegate ()

@property (nonatomic, strong) UIViewController *nativeRootVC;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Override point for customization after application launch.

    /* 保存参数 */
    [[NSUserDefaults standardUserDefaults] setValue:launchOptions forKey:@"launchOptions"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    self.nativeRootVC = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
    self.window.rootViewController = self.nativeRootVC;
    return YES;

}

- (void)applicationWillResignActive:(UIApplication *)application {

    [[[self ufw] appController] applicationWillResignActive: application];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {

    [[[self ufw] appController] applicationDidEnterBackground: application];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {

    [[[self ufw] appController] applicationWillEnterForeground: application];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {

    [[[self ufw] appController] applicationDidBecomeActive: application];
}

- (void)applicationWillTerminate:(UIApplication *)application {

    [[[self ufw] appController] applicationWillTerminate: application];
}

#pragma mark - Unity


- (BOOL)unityIsInitialized {

    return [self ufw] && [[self ufw] appController];
}

- (void)initUnity {

    /* 判断Unity 是否已经初始化 */
    if ([self unityIsInitialized]) return;

    /* 初始化Unity */
    self.ufw = UnityFrameworkLoad();
    [self.ufw setDataBundleId:"com.unity3d.framework"];
    [self.ufw 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];
    NSDictionary *launchOptions = [[NSUserDefaults standardUserDefaults] valueForKey:@"launchOptions"];

    /* 初始化 */
    [self.ufw runEmbeddedWithArgc:argc argv:argv appLaunchOpts:launchOptions];

}

/// unity页面添加导航栏

- (void)unityRootVCAddNavgationController {
    UIViewController *rootVC = [[self ufw] appController].rootViewController;
    [[self ufw] appController].window.rootViewController = nil;
    [[self ufw] appController].window.rootViewController = [[UINavigationController alloc] initWithRootViewController:rootVC];
    [rootVC.navigationController setNavigationBarHidden:true];

}

/// 显示unity页面

- (void)showUnityMainWindow {

    self.window.hidden = YES;
    [self.ufw appController].window.hidden = NO;

    if (![self unityIsInitialized]){
        NSLog(@"Unity 还未初始化");
        return;
    }

    [self.ufw showUnityWindow];
    [self.ufw pause:false];

    // 为unity页面添加导航栏
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self unityRootVCAddNavgationController];
    });

    // iOS调用Unity
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.ufw sendMessageToGOWithName:"Canvas" functionName:"outputStr" message:"Hello, Message from iOS Native."];
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self unityRootVCPushVC];
    });
}

/// 显示原生页面

- (void)showNativeMainWindow {
    self.window.hidden = NO;
    [self.ufw appController].window.hidden = YES;
    self.window.rootViewController = self.nativeRootVC;
    [self.window makeKeyAndVisible];
}

/// 模拟从unity页面push

- (void)unityRootVCPushVC {
    UIViewController *foo = [[UIViewController alloc] init];
    foo.view.backgroundColor = [UIColor whiteColor];
    [[[self ufw] appController].rootViewController.navigationController pushViewController:foo animated:YES];
}

#pragma mark - UnityFrameworkListener

- (void)unityDidUnload:(NSNotification *)notification {

    NSLog(@"========== %s ============",__func__);
    [self.ufw unregisterFrameworkListener:self];
    [self setUfw:nil];
    [self.window makeKeyAndVisible];
}

- (void)unityDidQuit:(NSNotification *)notification {
    NSLog(@"========== %s ============",__func__);
}

@end

iOS调用Unity方法

// obj:GameObject名称, method:Unity脚本函数名称 msg:函数参数,如果是多个函数,可以转成JSON字符串
void UnitySendMessage(const char* obj, const char* method, const char* msg);

Unity调用iOS方法

1、在Unity项目Plugins中添加插件文件,例如Test.mm

//
//  Test.m
//  Unity-iPhone
//
//  Created by YueQu on 2021/8/31.
//

#import <Foundation/Foundation.h>

extern "C" {

    void iOSLog(const char * message);
}

void iOSLog(const char * message) {

    NSLog(@"%@", [NSString stringWithUTF8String:message]);
}

2、在Unity项目脚本中,调用iOS方法,例如

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class CallObjC : MonoBehaviour
{

    public InputField input;

#if UNITY_IPHONE
    // 声明iOS方法
    [DllImport("__Internal")]
    static extern void iOSLog(string message);

    [DllImport("__Internal")]
    static extern void iOSLog2(string message);

#endif

    public void onButtonClick()
    {
        outputStr("test");
        // 调用iOS方法
        iOSLog(input.text);
	iOSLog2(input.text);
    }

    public void outputStr(string resultStr)
    {
        Debug.LogFormat("result string = {0}", resultStr);
    }
}