swift集成Unity项目及错误总结

前言

最近有个Unity游戏的项目,并且需要整合到现有iOS项目(swift)中,参考了很多大哥的分享,自己也遇到了不少很多坑,特来记录一下,希望能帮大家少走一些弯路。

涉及到的版本

  • Unity2019.2.6f1
  • Xcode 10.2.1
  • swift 4.2

Ready? Let's go~~

1、先确保Unity导出的Xcode项目能运行成功

我在拿到Unity导出的Xcode项目时,还是有几处报错的地方,待会下面会提到,我们还是先开始集成吧!

2.将Unity项目导入到自己的项目中

tip:(Unity导出的Xcode项目,后面都称Unity项目)

2.1 将Unity项目中的Classes、Library和data三个文件直接拖入到项目中。我这里自己创建了一个UnityGame的文件夹,关于Unity项目的东西,全都放在这个文件夹下面

2.1.1 Classes和Library拖入项目中的勾选


2.1.1.png

2.1.2 Data拖入项目中的勾选


2.1.2.png

2.1.3 拖入项目后,大概长这样,颜色对了就行啦!
2.1.3.png
2.2 添加UnityUtils.h UnityUtils.mm (UnityBridge.h)到项目

下载地址在这里
因为我自己的项目中又Bridge桥接文件了,所以我这里不需要再导入了;
2.2.1 如果原来没有桥接文件的话,就把UnityBridge.h文件拖进去好了,然后在Bulid Settings配置一下

2.2.1.png

2.2.2 拖入后,需要修改一些地方
UnityUtils.h

//
//  UnityUtils.h
//
//  Created by Adam Venturella on 10/28/15.
//

#ifndef UnityUtils_h
#define UnityUtils_h

void custom_unity_init(int argc, char* argv[]);

#endif /* UnityUtils_h */

UnityUtils.mm

//
//  UnityUtils.m
//
//  Created by Adam Venturella on 10/28/15.
//
// this is taken directly from the unity generated main.mm file.
// if they change that initialization, this will need to be updated
// as well.

#include "RegisterMonoModules.h"
#include "RegisterFeatures.h"
#include 

// Hack to work around iOS SDK 4.3 linker problem
// we need at least one __TEXT, __const section entry in main application .o files
// to get this section emitted at right time and so avoid LC_ENCRYPTION_INFO size miscalculation
static const int constsection = 0;

void UnityInitTrampoline();

// 原来的
//extern "C" void custom_unity_init(int argc, char* argv[])
//{
//    @autoreleasepool
//    {
//        UnityInitTrampoline();
////        UnityParseCommandLine(argc, argv); //Unity 5.3+
//        UnityInitRuntime(argc, argv); //Unity 5.6+
//
//        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);
//    }
//}
/// 修改后
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;
}

自己的Bridge桥接文件需要添加的内容(将UnityBridge.h拖进去的,已经写好了)

#import "UnityUtils.h"
#import "UnityAppController.h"
#import "UnityInterface.h"
2.3 添加工程配置

tip: 配置信息可以参考从Unity导出来的Xcode项目的配置,我在这里只是指点出来哪些地方
2.3.1 添加以下配置信息

UNITY_RUNTIME_VERSION = 2019.2.6f1;
UNITY_SCRIPTING_BACKEND = il2cpp;
GCC_THUMB_SUPPORT = NO;
GCC_USE_INDIRECT_FUNCTION_CALLS = NO
2.3.1.png

2.3.2 配置Language C++


2.3.2.png

2.3.3 配置Prefix Header,文件所在地址根据自己项目来发


2.3.3.jpg

2.3.4 配置Other C Flag
$(inherited)
-DINIT_SCRIPTING_BACKEND=1
-fno-strict-overflow
-DNET_4_0
-DRUNTIME_IL2CPP=1
2.3.4.png

2.3.5 配置Other C++ Flag

$(inherited)
$(OTHER_CFLAGS)
-DINIT_SCRIPTING_BACKEND=1
2.3.5.png

2.3.6 配置Header Search Paths

$(inherited)
"$(SRCROOT)/UnityGame/Classes"
"$(SRCROOT)"
$(SRCROOT)/UnityGame/Classes/Native
$(SRCROOT)/UnityGame/Libraries/bdwgc/include
$(SRCROOT)/UnityGame/Libraries/libil2cpp/include
2.3.6.png

2.3.7 配置Library Search Paths

$(inherited)
"$(SRCROOT)"
"$(SRCROOT)/UnityGame/Libraries"
2.3.7.png

2.3.8 配置Other Linker Flags

-weak_framework
CoreMotion
-weak-lSystem
image.png

2.3.9 EnableBitCode 设置为No


image.png
2.4 修改文件代码

2.4.1 UnityAppController.h文件
修改代码如下

// 修改前
//inline UnityAppController* GetAppController()
//{
//    return _UnityAppController;
//}
// 修改后
NS_INLINE UnityAppController* GetAppController()
{
    NSObject* delegate = [UIApplication sharedApplication].delegate;
    UnityAppController* currentUnityController = (UnityAppController *)[delegate valueForKey:@"currentUnityController"];
    return currentUnityController;
}

2.4.2 main.mm

// 修改前
//int main(int argc, char* argv[])
//{
//#if UNITY_USES_DYNAMIC_PLAYER_LIB
//    SetAllUnityFunctionsForDynamicPlayerLib();
//#endif
//
//    @autoreleasepool
//    {
//        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;
}

2.4.3 添加一个新的main.swift文件到项目

//
//  main.swift
//  DDog
//
//  Created by leesum on 2019/11/10.
//  Copyright © 2019 Lgsc. All rights reserved.
//

import Foundation
import UIKit

custom_unity_init(CommandLine.argc, CommandLine.unsafeArgv)
UIApplicationMain(
   CommandLine.argc,
   UnsafeMutableRawPointer(CommandLine.unsafeArgv)
       .bindMemory(
           to: UnsafeMutablePointer.self,
           capacity: Int(CommandLine.argc)),
   nil,
   NSStringFromClass(AppDelegate.self)
)

2.4.4 添加依赖库,我懒,是直接从Unity项目中拖进来的


image.png

差不多了 运行一下看吧;

3.下面来解决问题
  • 问题1


    image.png

    解决:直接把@UIApplicationMain注销掉

//@UIApplicationMain
  • 问题2


    image.png

解决:在开始我都说了,我的文件在UnityGame下存放,所以从Unity项目中拖过来的时候,路径已经变了;

方法一:路径写完整
#include "UnityGame/Classes/iPhone_Sensors.h"
方法二:不要路径
#include "iPhone_Sensors.h"

其实这个文件在下一个问题中,我们是需要把他删掉的,但是不解决问题就暴露不出来,尴尬。。

  • 问题3


    image.png

    看到这么多错,不要慌
    解决:可以看到都是这个DynamicLibEngineAPI.o搞的鬼
    去 Build Phases 搜索 DynamicLibEngineAPI ,搜索到一个DynamicLibEngineAPI.mm文件,删掉! 搞定!

  • 问题4
    刚拿到Unity导出的Xcode项目时,运行报错,如下


    image.png

解决:打开终端,在终端中输入

chmod +x 文件目录/MapFileParser.sh
MapFileParser.sh文件就在你的项目里,自己配置路径
  • 问题5
    刚拿到Unity导出的Xcode项目,运行报错


    image.png

    分析:报错的原因是因为Unity游戏在加载的时候需要我这边把游戏ID等参数传过去,Unity已经发起了调用我这边传值的方法,但是我这边没有写,故报错;
    解决:创建一个.h和.m文件,名称随便,在.m文件中加上相应的方法;方法名和返回参数需和Unity游戏的代码一致,这里也有提示,缺的几个方法,但是参数的类型需要和游戏开发去核对;
    我的解决如下:

//
//  MyGamePlayer.m
//  Unity-iPhone
//
//  Created by leesum on 2019/11/13.
//

#import "MyGamePlayer.h"

@implementation MyGamePlayer
    int GetRoomID() {
        return 1;
    }
    void hideSplash() {
        NSLog(@"退出");
    }
    int GetGameType() {
        return 1;
    }
    int GetJoinCM() {
        return 100;
    }
    int GameReturn() {
        return 1;
    }
    int GetUnitId() {
        return 9;
    }
    int GetJoinMinUser() {
        return 1;
    }
    int GetJoinMaxTime() {
        return 1;
    }
    int GetUserID() {
        return 1;
    }
    int GetGameID() {
        return 1;
    }
    int GetLevel() {
        return 1;
    }
@end

我暂时只有这么多问题,后续有问题会及时更新

4.用起来

4.1 在AppDelegate中初始化代码


image.png

注意:这里定义的currentUnityController要和UnityAppController中替换的方法中的Key对应


image.png

这个时候运行一下,运行成功后,发现已经有游戏的声音了!
这就说明,肯定是已经启动了游戏;游戏启动暂停,开始这些方法,基本上都封装在UnityAppController类中,那么我们就去UnityAppController.mm的实现文件中去找;既然是启动后就有声音,那么先重点找application开头的方法,你会发现确实有启动的方法,把方法注销掉,问题就解决了


image.png

4.2 添加游戏开始方法


image.png

添加之后,运行成功->点击开始游戏
当点击开始后,并没有来到游戏界面,而是直接崩掉来到了main.swift文件中


image.png

打开打印台分析一下报错原因
image.png

这里显示是currentUnityController的问题;
解决:因为Unity的代码是OC,故找到AppDelegate,加上@objc,问题就解决了


image.png

我差不多就好了,有啥问题,可以留言哦!

参考

https://www.jianshu.com/p/ca693626d00a?open_source=weibo_search
https://www.jianshu.com/p/184f3d1e01f6
https://www.jianshu.com/p/3bf2902bf2f0
https://www.jianshu.com/p/a3df2922d98d
https://www.cnblogs.com/willbin/p/3370412.html
https://www.jianshu.com/p/ec514261e569
https://www.jianshu.com/p/51b7b4bb6748

你可能感兴趣的:(swift集成Unity项目及错误总结)