iOS导出unityFramework历程

一、背景

由于定义了unity和原生之间交互的桥,因此在导出unity项目后,需要将桥源码加到unityFramework里面参与编译,编译出动态库。

二、问题及排查历程

符号未定义

在unity那个demo里面进行桥使用:

发现符号未定义的问题:

然后发现为什么库里面其他的符号可以被使用:

符号未定义原因

细看不同之处:

原来加了这个显示,符号默认对外界隐藏。查看动态库设置参数,果然如此:

于是乎我也在自定义的类加上这个参数不就解决了?(哈哈哈,只能说运气没有站在我这边,啪啪打脸):

在自定义的类声明前面,也加上了这个标识,再次编译,wtf还是报符号未定义的错误。然后开始反思为什么会出现这样的效果,明明是一样的。我甚至尝试把这个类定义到UnityFramework文件里面,以避免库单独对这个文件做了什么处理。结果还是不行(依然报错)。然后再次问:明明是一样的,为什么还会报这个问题????但是真的是一样的吗?(使用的时候还是有不一样的)请看:

会发现,没有报错的12行是通过bundle.principalclass去获取的class,查看静态库的info.plist可以发现,这个主要类设置的就是UnityFramework

那么至于为什么会出现符号未定义的问题也就显而易见了:因为这个动态库是懒加载的,并不是我们常用的系统自动加载的动态库。报符号未定义的错是因为在编译时,如果调用了[HostRouterApi sharedInstance].sendEventToHostBlock,编译器会去验证app的mach-o文件以及它依赖的动态库的mach-o文件中是否有这个类的定义。

由于在编译时,程序还没有加载动态库UnityFramework,而程序只包含了HostRouterApi类的头文件,并没有它对应的.m文件(编译器只会将.m文件编译到最终的mach-o文件中),所以编译器在app的mach-o文件以及它依赖的动态库中找不到HostRouterApi类的定义,然后编译器就报错了。所以如果我们把12行换成13行,也会出现同样的报错:

三、究竟设置了啥,让这个demo只能懒加载动态库

一开始以为是因为Link Binary With Libraries(构建阶段(Build Phase),用于指定要与你的应用程序一起链接的二进制文件。而且因为正常我们引入framework的时候,这里也会存在。但是Unity-iPhone这个demo是没有的)。

但是经过自己创建新的demo,去验证发现,动态库依然会主动被加载,并不需要手动去加载(没有模拟出Unity-iPhone这个demo的效果)。

这个问题还有待确定(为什么unity导出来的demo会出现使用类编译找不到符号的错误)。。。

四、修复措施

新建的类按照这个方法,让其符号是可见的,然后直接导入该动态库使用即可。

五、自定义组件

修改组件名称

不要直接修改target名称

直接修改target名称虽然可以达到修改组件名称的目的,但是后续unity项目无法继续导出项目(会因为路径问题导致导出出错)。

修改framework对应target的build settings里面的product name

更新bridge文件

bridge文件直接放在unityframework参与编译

bridge文件直接拖进unityframework里面参与编译,有更新的时候直接替换bridge文件即可。

unityframework依赖bridge组件

bridge作为一个单独的组件,unityframework依赖该组件:

注意要把use_frameworks!注释掉,否则unityframework里面不会有bridge组件里面的符号(也就达不到最终只提供一个framework给业务的目的)。

而且LZAvatarBridge需要支持bitcode(因为unityframework支持)

但是由于最新苹果要求关掉该配置,因此需要把unityframework默认的yes改成NO。LZAvatarBridge也不用开启bitcode。

自动获取main函数的两个参数

objectivec 复制代码
- (void)runEmbeddedWithArgc:(int)argc argv:(char*[])argv appLaunchOpts:(NSDictionary*)appLaunchOpts

启动unity引擎需要main入口函数的两个参数(int)argc 和 argv:(char*[])argv,一开始尝试让组件使用方在main函数里面将这两个参数传给组件。但是细想一下,发现这样不太美观(主要是即构也没这样搞,那么肯定是内部有办法去获取这两个参数的)。经过一顿牛逼的操作后,终于实现:

ini 复制代码
        NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments];
        // 创建一个 char ** 数组,长度为 arguments 数组的长度加一(用于存储 NULL 结束符)
        char **argv = (char **)malloc((arguments.count + 1) * sizeof(char *));
        // 遍历 arguments 数组,将每个 NSString 对象转换为对应的 C 字符串
        for (NSInteger i = 0; i < arguments.count; i++) {
            NSString *argument = arguments[i];
            const char *cString = [argument UTF8String];
            // 复制 C 字符串到动态分配的内存中
            argv[i] = strdup(cString);
        }
        // 最后一个元素设置为 NULL,表示参数列表的结束
        argv[arguments.count] = NULL;
        int argc = (int)arguments.count;
相关推荐
iFlyCai8 小时前
Xcode 16 pod init失败的解决方案
ios·xcode·swift
郝晨妤17 小时前
HarmonyOS和OpenHarmony区别是什么?鸿蒙和安卓IOS的区别是什么?
android·ios·harmonyos·鸿蒙
Hgc5588866617 小时前
iOS 18.1,未公开的新功能
ios
CocoaKier19 小时前
苹果商店下载链接如何获取
ios·apple
zhlx283521 小时前
【免越狱】iOS砸壳 可下载AppStore任意版本 旧版本IPA下载
macos·ios·cocoa
XZHOUMIN1 天前
网易博客旧文----编译用于IOS的zlib版本
ios
爱吃香菇的小白菜1 天前
H5跳转App 判断App是否安装
前端·ios
二流小码农2 天前
鸿蒙开发:ForEach中为什么键值生成函数很重要
android·ios·harmonyos
hxx2212 天前
iOS swift开发--- 加载PDF文件并显示内容
ios·pdf·swift
B.-2 天前
在 Flutter 应用中调用后端接口的方法
android·flutter·http·ios·https