Unity嵌入Swift

前言
现在公司需要使用unity模型来展示数据。作为我本人使用的是Swift3.0语言。其中遇到了无数的坑。终于大致解决了问题。但是现在的办法并不是最好的,希望大家可以共同探讨。

参考

准备工作

  • 基于Swift的一个工程
  • Unity导出的Xcode工程
  • ios-unity5-master
  • 使用CocoaPods

1.在Swift工程文件下新建一个名为UnityFix文件夹(你可以使用其他的名字),用来存放Unity的文件。

Unity.png

2.将下载文件夹中的Unity.xconfig、UnityBridge.h、UnityUtils.h和UnityUtils.mm这4个文件拉入UnityFix中。桥接头文件选择不创建。因为在拉入的文件中已经有了桥接头文件。

拖配置.png
拖入配置.png
不创建桥接头文件.png

3.设置使用Unity.xcconfig配置。

修改配置.png
  • 修改BuildSetting配置,路径和Unity版本号
    这里科普一下$(SRCROOT)代表项目根目录,$(PROJECT_DIR)代表整个项目
修改BuildSetting配置.png
Header Search Paths.png
Library Search Paths.png
  • buildPhases中添加运行脚本,内容为最开始下载的UnityProjectRefresh.sh中的内容
脚本.png

4.修改UnityUtils.mm文件内容

extern "C" int custom_unity_init(int argc, char* argv[])
{
    @autoreleasepool
    {
        UnityInitTrampoline();
//        UnityParseCommandLine(argc, argv);
        UnityInitRuntime(argc, argv);
        
        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);
        
        //        UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String:"AppControllerClassName"]);
    }
    
    return 0;
}
UnityUtil.mm.png

5.把Unity导出的Xcode工程中Classes、Data、Libraries文件按照如下方式添加到Unity文件夹中

  • Classes和Libraries需要选择copy if needs、create groups(文件较多,需要等一会儿)
添加Classes和Libraries.png
  • Data需要选择Create folder references
Data.png

(PS:删除引用,libraries里面的libil2cpp文件夹,然后再删除Classes里面的Native文件夹里面的所有.h文件.这里都是删除引用,不要move to trash。这里也可以不删除,对程序本身的运行没有任何影响)

6.文件拖拽完成如图所示

最终配置形式.png

7.修改unity里的方法,引用。在UnityFix的Classes文件目录下找到main.mm,替换这个方法

//int main(int argc, char* argv[])
//{
//    signed long long startTime = mach_absolute_time();
//    @autoreleasepool
//    {
//        UnitySetStartupTime(startTime);
//        UnityInitTrampoline();
//        UnityInitRuntime(argc, argv);
//
//        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);
//
//        UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String: AppControllerClassName]);
//    }
//
//    return 0;
//}

int main_unity_default(int argc, char* argv[])
{
    @autoreleasepool
    {
        UnityInitTrampoline();
//        UnityParseCommandLine(argc, argv);
        UnityInitRuntime(argc, argv);
        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);
        
        //UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String:AppControllerClassName]);
        //        UIApplicationMain(argc, argv, nil, NSStringFromClass([UnitySubAppDelegate class]));
        UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String:AppControllerClassName]);
    }
    
    return 0;
}

在Classes文件目录下找到UnityAppController.h,添加:(如果你的.h本来有@class UnityViewControllerBase,就不需要再导入了)

#import <UIKit/UIKit.h>
@class UnityViewControllerBase;
UnityAPPController.h.png

在代码大概80行的位置替换如下方法:

//inline UnityAppController*  GetAppController()
//{
//    return (UnityAppController*)[UIApplication sharedApplication].delegate;
//}

NS_INLINE UnityAppController* GetAppController()
{
    NSObject<UIApplicationDelegate>* delegate = [UIApplication sharedApplication].delegate;
    UnityAppController* currentUnityController = (UnityAppController *)[delegate valueForKey:@"currentUnityController"];
    return currentUnityController;
}

8.修改Swift工程
新建一个main.swift,作为程序入口,注意m要小写,代码如下:

import Foundation
import UIKit
// overriding @UIApplicationMain
custom_unity_init(CommandLine.argc, CommandLine.unsafeArgv)
UIApplicationMain(
    CommandLine.argc,
    UnsafeMutableRawPointer(CommandLine.unsafeArgv)
        .bindMemory(
            to: UnsafeMutablePointer<Int8>.self,
            capacity: Int(CommandLine.argc)),
    nil,
    NSStringFromClass(AppDelegate.self)
)

找到appdelegate.swift,注释掉@UIApplicationMain(让我们新建的main.Swift作为程序入口),按图添加代码:

import UIKit

//@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var currentUnityController: UnityAppController!


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        currentUnityController = UnityAppController()
        currentUnityController.application(application,didFinishLaunchingWithOptions: launchOptions)
        
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        currentUnityController.applicationWillResignActive(application)
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        currentUnityController.applicationDidEnterBackground(application)
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        currentUnityController.applicationWillEnterForeground(application)
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        currentUnityController.applicationDidBecomeActive(application)
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        currentUnityController.applicationWillTerminate(application)
    }


}

9.添加依赖库,每个Unity版本需要的库可能都会不一样
需要的库均以Unity导出Xcode工程里面需要的依赖库为标准

dylib类型的库添加方法:
Build Phases -> Link Binary With Libraries —> + , 在对话框中点 Add Other, 然后在新的对话框用快捷键Command+Shift+G打开新的Folder对话框,输入/usr/lib/,然后点Go,在新弹出的dylib库目录选择libc++.dylib并添加。

这是我的依赖库.png

10.Unity.xcconfig修改
SWIFT_OBJC_BRIDGING_HEADER = UnityFix/UnityBridge.h;

如果你编译遇到如下错误

编译环境.png

11.编译器修改

感谢JingWang_48ec提供方法:
在Target -> Building Setting 选中 All,然后在搜索框里搜Compiler,更改下面两处的设置

Apple LLVM 8.0-Language -> C language dialect -> GNU99[-std=gnu99]
Apple LLVM 8.0-Language C++ -> C++ language dialect -> GNU++11[-std=gnu++11]

如果不用CocoaPods管理第三方库的话,到这里已经全部成功了

导入CocoaPods

1.在终端中cd 你的项目

  • pod init
  • pod install
Podfile警告.png
  • 按照黄色字体给出的提示在Unity.xcconfig里面添加如下代码:
#include "Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig"
#include "Pods/Target Support Files/Pods-Demo/Pods-Demo.release.xcconfig"
  • 导入一个第三库,编译不过
编译不过.png

结论按照黄色字体给出的提示不能解决CocoaPods的使用

  • 此处删除Unity.xccofig的引用
删除引用.png
  • 在重新一次pod install

  • 我们在Header Search Paths中添加如下:

添加.png
  • 此时我们在将这个Unity.xcconfig文件添加回来
加.png
  • 找到在Pod下的xcconfig文件:
Pods的xcconfig.png
  • 将里面的代码拷入Unity.xccofig(PS:里面有几处地方需要合并)
  • 最后在修改一下配置,到这里基本能编译成功了!
修改配置.png

结语

结合这个话了很多时间,也发现了很多有意思的东西,比如为什么需要合并,因为在Unity 的配置和Pods的配置有字段是冲突的。所以我们需要手动的将pod配置文件中的内容合并到Unity的配置文件中。当然这个方法并不是最好的,如果有朋友有更好的方法,希望提出~

5月18日更新

在Unity界面里面有按钮,点击按钮想要跳转新的界面。
直接调在Swift的方法执行,但没有效果。
解决办法:使用通知,调用方法。 原因:Unity和IOS之间只存在值传递

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,067评论 4 62
  • 前言 公司目前的项目是基于OC,融合了Unity做AR功能,目前已经比较稳定。swift现在已经趋向稳定,大家都在...
    Nothing_lu阅读 3,794评论 36 8
  • 这个主要是记录一下公司项目里面集成Unity时候遇到的一些问题。供后来的集成参考使用。 集成期间遇到了不少问题模板...
    韩大熊宝要姓张阅读 11,765评论 21 10
  • 卜算子 荷 婷婷伫水中, 丹青入画里。 泥淖污浊不染尘, 时有新篇咏。 咏者常自比, 难超《爱莲说》。 甚慰芙蓉应...
    冀泰来阅读 438评论 4 2
  • 这是时隔四年在家乡度过的第一个秋天。 也就前两天,门口那两株枇杷先一步响应季节更替的召唤开始退换新叶,硕大的树冠下...
    王家人宁阅读 298评论 0 0