标题看起来有点绕,大概场景如下:

  • 用一个父 SWF 来读取子 SWF,读取时的 ApplicationDomain 设置为系统子级(new ApplicationDomain(null))来完全分离加载方和被加载方。
  • 子 SWF 动态读取另一个含有嵌入字体的 assets.swf,读取时 ApplicationDomain 设置为父 SWF 所在域的子级。

以上场景发布后在公网运行会发现嵌入字体的文字完全不显示,注册和应用嵌入字体的代码如下:

var textFontClass:Class = ResLoader.getInstance().getClassByLinkName("S_TextFont");
Font.registerFont(textFontClass);
var textFont:Font = new textFontClass();

textFormat = new TextFormat();
textFormat.font = textFont.fontName;
textFormat.size = 30;
textFormat.color = 0xFFFFFF;
var text:TextField = new TextField();
text.defaultTextFormat = textFormat;
text.autoSize = TextFieldAutoSize.LEFT;
text.embedFonts = true;
text.text = levelString;
addChild(text);

经过测试发现,Font.registerFont(textFontClass); 注册字体时,只把字体注册在了当前域(子SWF)的全局字体列表中,而父 SWF 因为没有注册到这个字体,导致子 SWF 中使用嵌入字体的文字都无法正常显示。

解决这个问题的方法我所测试过的有如下几种:

  1. 最方便的解决方法,在父 SWF 读取子 SWF 时,将应用程序域设置为加载方(父SWF)的子级(new ApplicationDomain(ApplicationDomain.currentDomain) 也可以不设置这个参数,因为默认就是如此)。
  2. 将字体以 Embed 方式嵌入到子 SWF 中,这样就不会受应用程序域的影响了,具体方法可参考:嵌入字体的指定字符到AS项目中
  3. 在读取子 SWF 并调用时,将父 SWF 的当前域实例通过参数的形式传入调用函数中,这样子 SWF 在注册字体时,就可以用如下代码来注册字体,把字体注册到父 SWF 的全局字体列表中。
parentApplicationDomain.getDefinition("flash.text.Font").registerFont(textFontClass);

第一个方法虽然方便,但项目限制必须将加载方和被加载方的应用程序域完全分离,所以不能使用。第二个方法的缺点很明显,需要将字体直接嵌入到 SWF 中,增大了 SWF 的体积,而且在字符更新后,也要重新编译 SWF,虽然也可以另起一个项目单独编译,但终归很折腾。所以最终我选择了第三个方法,即保证了加载方和被加载方的分离,又可以让字体动态被载入。