记一次Unity TextMeshPro迁移打AB包的坑

2026/07 25 09:07

起因

TextMeshPro的资源放在了Resources中,其TMP Setting会引用Font

这样就会导致字体也需要放在Resources目录中,而且也会导致字体无法更新。

改造

将TextMeshPro/Resources中所有的资源,移到外部目录中,自行打一个AB包

打包方法使用的是

UnityEditor.Build.Pipeline.CompatibilityBuildPipeline.BuildAssetBundles

问题1

  • AB无法加载,因为加载路径要区分大小写
  • 解决:将加载出来的AB,拿出GetAllAssetNames,然后与传入的loadPath,进行 忽略大小写对比,如果相同,则使用 GetAllAssetNames中的路径进行加载

问题2

  • TextMeshPro是属于底层组件,它现在要依赖外部加载系统,需要替代内部Resources.Load代码
  • 解决:采用注入式
public interface IResLoad 
{
    T Load<T>(string path) where T : UnityEngine.Object;
}

TMP_Text.cs中
private static BaseModule.IResLoad s_ResLoad;
public static void SetResLoad(BaseModule.IResLoad resLoad)
{
    s_ResLoad = resLoad;
}
然后逐个将Resources.Load修改 s_ResLoad.Load

问题3

  • 如果处理运行时与编辑时
  • 解决:增加2个加载器
public class EditorPreloadLoader : IResLoad
{
    private static string[] exts = new string[] { ".asset", ".prefab", ".mat", ".png", ".jpg", ".txt", };

    public T Load<T>(string path) where T : UnityEngine.Object
    {
        var currExt = System.IO.Path.GetExtension(path);
        var assetPath0 = $"Assets/MyResources/{path}";
        if (!string.IsNullOrEmpty(currExt))
        {
            if(System.IO.File.Exists(assetPath0))
            {
                return AssetDatabase.LoadAssetAtPath<T>(assetPath0);
            }
        }
        else
        {
            // 不自带扩展名的资源, 逐个尝试
            foreach(var ext in exts)
            {
                var assetPath1 = $"{assetPath0}{ext}";
                if(System.IO.File.Exists(assetPath1))
                {
                    return AssetDatabase.LoadAssetAtPath<T>(assetPath1);
                }
            }
        }
        return null;
    }
    private static EditorPreloadLoader _Loader;
    public static EditorPreloadLoader Ins => _Loader;
    [InitializeOnLoadMethod]
    public static void Install()
    {
        _Loader = new EditorPreloadLoader();

        TMPro.TMP_Text.SetResLoad(_Loader);
    }
}

以上代码,在编辑器(没有运行的时候),自动使用 EditorPreloadLoader


再加一个运行时

public class RuntimePreloadLoader : IResLoad
{
    public T Load<T>(string path) where T : UnityEngine.Object
    {
        // 自己的加载系统
    }

    private static RuntimePreloadLoader sLoader = null;
    public static void Install()
    {
        if (sLoader != null)
        {
            return;
        }
        var loader = new RuntimePreloadLoader();
        TMPro.TMP_Text.SetResLoad(loader);
        sLoader = loader;
    }
}

在游戏启动后,先加载MyResources的资源,然后再跑 RuntimePrellloadLoader.Install

问题4

  • 问题:打出来的包,Android可正常显示TMP文字,但在编辑器中加载此AB,文字不显示
  • 解决:使用Windows平台重新打包,Android不兼容