Xcode 项目中嵌入Unity后的使用,互调方法和展示(Unity与SSZipArchive框架不兼容的问题处理)

1,661 阅读3分钟

在上一篇文章中,已经将unity框架嵌入到我们的xcode项目中了传送门
接下来,就要在项目中跑起来Unity里面的东西了。其实,如果交互不多的话,我们需要做的东西很少,基本上Unity已经全部做好了,但是安装包会增大很多,如果长期嵌入的话,需要再对安装包做一下处理,让安装包小一些。

正题(添加Unity的代码):

  • 在AppDelegate.h里添加

    // Unity文件
    #import "UnityAppController.h"
    
    //----------------- 以下参数仅仅用于Unity -----------------//
    
    /// Unity 的 AppDelegate
    @property (strong, nonatomic) UnityAppController *unityController;
    
    /// Unity 显示视图
    @property (strong, nonatomic) UIWindow *unityWindow;
    
    - (void)showUnityWindow;
    - (void)hideUnityWindow;
    
    //----------------- 以上参数仅仅用于Unity -----------------//
    
    
  • 在AppDelegate.m里添加

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    {
        // Unity
        _unityController = [[UnityAppController alloc] init];
        [_unityController application:application didFinishLaunchingWithOptions:launchOptions];
    }
        
    }
    
    //程序进入前台并处于活动状态时调用
    - (void)applicationDidBecomeActive:(UIApplication *)application {
    	 [self.unityController applicationDidBecomeActive:application];
    }
    
    // APP从后台进入前台
    - (void)applicationWillEnterForeground:(UIApplication *)application{
    	[self.unityController applicationWillEnterForeground:application];
    }
    
    /**
    	APP从前台进入后台
     */
     
    -(void)applicationDidEnterBackground:(UIApplication *)application {
      	[self.unityController applicationDidEnterBackground:application];
    
    }
    
    	#pragma mark 应用终止
    -(void)applicationWillTerminate:(UIApplication *)application {
    	[self.unityController applicationWillTerminate:application];
    }
    		#pragma mark =================== Unity ===================
    
    -(void)applicationWillResignActive:(UIApplication *)application {
    	[_unityController applicationWillResignActive:application];
    }
    
    /// 显示AR页面
    -(void)showUnityWindow{
    	[self.unityWindow makeKeyAndVisible];
    }
    -(void)hideUnityWindow{
    	[self.window makeKeyAndVisible];
    }
    
    
    -(UIWindow *)unityWindow{
    
     return  UnityGetMainWindow();
    }
    
    
    
    
  • 调用方法,进入和退出Unity Windows

    -(void)go {
    	//进入unity界面
    	[(AppDelegate *)[UIApplication sharedApplication].delegate showUnityWindow];
    	UnityPause(false);
    }
    
    - (void)quit{
        //退出unity界面
        UnityPause(true);
        [(AppDelegate *)[UIApplication sharedApplication].delegate hideUnityWindow];
    }
    
    

Unity调用iOS方法

RegisterMonoModules.h 文件里填写相应的方法

void getLevelAndCoin();

  1. 如果需要调用传递返回值的方法,也需要写成void类型 RegisterMonoModules.mm 不需要写对一个的方法

  2. UnityAppController.mm里边填写对应的方法实现

extern "C"
{
    const char* getLevelAndCoin(){
        // do something
        return strdup([@"Test" UTF8String]);
    }
}

返回类型要通过strdup封装一下,直接return “Test” 会运行时崩溃

iOS调用Unity方法 iOS调用Unity方法,比较简单,直接让他们提供相应的方法即可
如果通过Swift调用,需要在桥接文件里导入一下#import <Classes/Unity/UnityInterface.h>

接入Unity后,SSZipArchive会在解压时崩溃

现象是会在解压时,这个方法会报内存错误:
unzOpenCurrentFile

Thread 39: EXC_BAD_ACCESS (code=1, address=0x1177140)

找了一些资料,和很多种解决办法,都无法解决,原因应该和负责Unity同事的说法差不多

因为引入的多个库中都有结构体unz_file_info,但是他们的定义不一样(一个库是ZipArchive一个是Zip,还有是引入的.a中也存在这个结构体,我们在继续看为啥没报符号表冲突的问题)。在实际运行的时候,变量directoriesModificationDates被污染了。找了一下原因,是因为实际使用的unz_file_info的定义不是ZipArchive库中的,而是其他的。在Runtime时unz_file_info与ZipArchive中的定义的内部布局不一致。于是污染了堆栈,于是directoriesModificationDates指针就意外的被换成了脏数据。这也就是为什么,在调用之前加了一个没有啥用的fileInfoFake,就能正常使用的原因。 fileInfoFake所在的内部被污染了,防止了其他变量被污染。 造成这个问题的原因,是库冲突导致的。看了一下Zip、ZipArchive都直接源码引用了minizip的代码。为了避免这种冲突的问题,还是建议要么直接把minizip抽成一个库。要么重命名一下使用到的minizip符号。避免这种隐藏极深的问题。

我将ZipArchive封装成一个framework或者.a的静态库都会造成崩
最后不得不换了一个解压框架 ——_—— ZipZap

如果有人知道这个框架冲突的问题怎么解决,劳烦解惑一下