一、布景
因为定义了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函数的两个参数
- (void)runEmbeddedWithArgc:(int)argc argv:(char*[])argv appLaunchOpts:(NSDictionary*)appLaunchOpts
启动unity引擎需求main进口函数的两个参数(int)argc 和 argv:(char*[])argv,一开始尝试让组件运用方在main函数里边将这两个参数传给组件。可是细想一下,发现这样不太美观(主要是即构也没这样搞,那么肯定是内部有办法去获取这两个参数的)。通过一顿牛逼的操作后,终于完成:
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;