Unity发布预审:检查出调用苹果禁用api: [dlopen, dlsym]

表现:

打包出来的ipa在腾讯的wetest的ios预审中报以下错误。

最主要的就是这个【dlopen】【dlsym】,据公司的测试姐姐说这是苹果严打的对象。那么怎么从项目中找到问题代码并修改呢?

解决方案: 

1.首先确定空项目是否会报错。

可以看到空项目是没有这两个问题函数的。

2.下一步就是把项目中怀疑的文件拖到空项目中逐一去检测,导出的包是否有问题。如果没有什么重点怀疑对象,就采用二分法,一次拖一半的文件。

在这个过程中还比较顺利的,二分了多次,最后定位到一个插件上TextFX的具体一个脚本上【EffectManager】。下图就是我在空项目中添加文件的所有测试(PS:腾讯WeTest平台上用学校邮箱或者企业邮箱可以得到ios预审50次的额度)。最后一次是已经fix好的项目,不再报dlopen了。

也就是说连累整个项目报错的就是这个脚本了。那么具体是什么代码导致了dlopen呢?(当然不是可以直接搜索到函数名的)。这个EffectManager脚本由一千多行,怎么定位呢?想起测试姐姐好像说过dlopen是文件操作。此时看到脚本的头几行:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System;

咦,这个System.IO和System.Xml是什么????注释掉这两行看下脚本中哪里用到了。很好,找到了相应代码:

XmlTextReader reader = new XmlTextReader(new StringReader(m_font_data_file.text));

while (reader.Read())
{
    if (reader.IsStartElement())
    {
       if (reader.Name.Equals("common"))
       {
           texture_width = int.Parse(reader.GetAttribute("scaleW"));
           texture_height = int.Parse(reader.GetAttribute("scaleH"));
       }
       else if (reader.Name.Equals("char"))
       {
           uv_x = int.Parse(reader.GetAttribute("x"));
           uv_y = int.Parse(reader.GetAttribute("y"));
           width = float.Parse(reader.GetAttribute("width"));
           height = float.Parse(reader.GetAttribute("height"));
           xoffset = float.Parse(reader.GetAttribute("xoffset"));
           yoffset = float.Parse(reader.GetAttribute("yoffset"));
           xadvance = float.Parse(reader.GetAttribute("xadvance"));

           character_info = new CustomCharacterInfo();
           character_info.flipped = false;
           character_info.uv = new Rect((float)uv_x / (float)texture_width, 1 - ((float)uv_y / (float)texture_height) - (float)height / (float)texture_height(float)width/ (float)texture_width, (float)height /(float)texture_height);
           character_info.vert = new Rect(xoffset, -yoffset, width, -height);
           character_info.width = xadvance;
                               
           m_custom_font_data.m_character_infos.Add(int.Parse(reader.GetAttribute("id")), character_info);
        }
     }
}

先简单粗暴把它们注释掉。游戏竟然还能正常运行!随后测试一下单独注释掉这些代码的EffectManager脚本是否还报错,以及注释掉代码的原项目是否还报错。结果显示不报错了,问题解决。 

背后原理:

这个dlopen/dlsym到底是什么API呢?

可以查到:

“Linux提供了一套API来动态装载库。下面列出了这些API:

  • dlopen:该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。这种机制使得在系统中添加或者删除一个模块时,都不需要重新进行编译。
  • dlsym:在打开的动态库中查找符号的值。
  • dlclose:关闭动态库。dlerror:返回一个描述最后一次调用dlopen、dlsym,或dlclose的错误信息的字符串。

C语言用户需要包含头文件dlfcn.h才能使用上述API。”

所以dlopen是一个操作系统提供的API?Unity打包XCode项目时会编译成C++代码。在XCode中搜索dlfcn发现在“UnityAppController+Rendering.mm”这个文件中有

#include<dlfcn.h>

 在未修改前的EffectManager单独打包的Xcode工程和修改后的EffectManager的Xcode工程,分别搜索dlopen结果如下:

看来就是读取XML的代码导致编译为C++代码后包含了dlopen。感觉有点无辜,苹果爸爸打击调用动态库,可是调动XML并不是主观上要调用动态库啊。不过为了以防万一,还是先把这个预审错误消灭了吧。

再看看读取XML的这个是什么函数:C#读取XML文档使用XMLTextReader类浅析。感觉更无辜了。

感想

  1. 以后如果又出现了【dlopen】【dlsym】的错误,可以直接在项目中搜索“System.IO”,缩小目标范围。
  2. 使用外部的插件最好使用正版的最新版,TextFx是30美元,我看最新版有针对2018的build做修复,这可能也会解决问题。(如果用了旧版导致问题解决不了,这个成本可就高了....浪费了我好多天,甚至打算花钱找技术支持了,到时候就不是200块钱的事了)
发布了132 篇原创文章 · 获赞 40 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_36622009/article/details/103882854
今日推荐