彻底解决unity universal media player PC平台打包报错问题


前言

UMP是个播放视频流的老插件了。由于其早已停止维护,在Unity较新版本中出现了致命Bug,导致其无法在PC包中正确获取Dll库(其他平台未测),经过我两天的断点调试和魔改,目前PC版本已正确运行。
本文主要能解决以下几个问题,如果你遇到的是其他问题也不妨看看,可能也会有所启发。
1、打PC包后运行时报错,找不到dll
2、打PC包后运行时报错,加载dll失败
3、在本机运行时完全没有报错,但只要放到其他机器上就报错
4、第一次打包时没有报错,但第二次及之后打包就报错
这些Bug的根源都指向同一个问题,应用本文的修复步骤后,理论上能一并解决。


一、解决找不到Dll

1.问题溯源

首先发现的问题就是,原本应该在打包时被放入Plugins根目录的三个dll——libvlc.dll、libvlccore.dll以及UniversalMediaPlayer.dll,被错误拷贝到Plugins/x86_64文件夹下了。

于是我尝试把三个dll移动出来,再次运行程序,报错就消失了。

然而至此,我只能通过每次手动移动dll的方式解决问题,这肯定是不妥的,得找出问题的根源。

经过一番比较后,我发现这三个文件的导入配置使用了Unity内置的插件导出逻辑,而plugins文件夹的则使用了插件自定义的PostBuild脚本,猜测Unity的插件导出逻辑会自动为dll增加父文件夹。

另外有人反馈用2019版本的Unity就没有这个bug,让我高度怀疑是2020版本增加的新特性引入了Bug,后来一查才知道,2020版本确实引入了新的Plugin文件规则

2.解决方案

首先就是将这三个dll的导入设置中的Standalond取消勾选,既然Unity自动导出的这么不靠谱,那么我们干脆不用它了!我们自己写代码把它们导出到正确位置就是了!
在这里插入图片描述
随后我们找到 UMPPostBuilds 脚本,这个就是插件在打包时拷贝 plugins文件夹 的脚本了,只需要在这里改一把,把那三个dll也一起拷贝到Plugins文件夹就行了。
我们先在脚本任意位置插入下面这段新的代码。这是因为以前的 CopyPlugins 方法比较局限,居然不能复制完整的文件结构,于是我只好用递归的方式重新写了一个,现在不管是根目录还是嵌套更多层文件夹都能通通复制出去了:

private static void CopyFullPlugins(string sourcePath, string targetPath)
    {
    
    
        string fileName = string.Empty;

        // CopyFiles
        var rootFiles = Directory.GetFiles(sourcePath);
        if (!Directory.Exists(targetPath))
            Directory.CreateDirectory(targetPath);
        foreach (var s in rootFiles)
        {
    
    
            if (Path.GetExtension(s).Equals(".meta"))
                continue;

            fileName = Path.GetFileName(s);
            CopyPluginFile(s,Path.Combine(targetPath, fileName));
        }

        string[] directories = Directory.GetDirectories(sourcePath);

        foreach (var d in directories)
        {
    
    
            CopyFullPlugins(d, Path.Combine(targetPath, Path.GetFileName(d)));
        }
    }

随后我们找到 BuildWindowsPlayer64 这个方法,里面有个CopyPlugins的方法,直接替换成我们的方法,顺便路径也要改一改,建议直接复制下面这行,替换掉原来的:

CopyFullPlugins(settings.AssetPath + "/Plugins/Win/x86_64/", dataPath + "/Plugins/");

最后就是开心的打包,运行程序,插件已正常运行起来了!
然而!事情到此还并没有完全结束。
此时你可以试着将包体放到一个中文目录下,再尝试运行。
哦吼,一个新的报错弹了出来,插件又JJ了!老外的插件不支持中文目录太常见了,不过这个也可以魔改。

二、解决加载Dll失败

原因其实就是加载Dll的方法不支持中文目录,其实已经有其他大佬写过了,我就不重复造车轮了,写得很细致,可以直接前往查看
解决完这一步之后,理论上所有的Bug及隐患就都排除了,看到这里可以点击关闭了,但如果对Bug3、4的成因很好奇,可以接着往下看。

三、第3、4种Bug的成因

这两条可以归结为一条,虽然根本原因是因为第一个Bug,但如此诡异的表现要归功于这个插件查找dll路径时坑爹的容错设计!

首先,UMPSettings 里有个开关_useExternalLibraries ,你可以通过它配置使用内置Dll还是外部Dll,如果打开它,你可以继续配置 _librariesPath 指定外部Dll路径,这个路径默认指向工程文件中的Dll的绝对路径。此时,如果你按这个配置打包,在自己的电脑上跑是不会报错的,但一旦复制到其他电脑上,马上就跑不起来了!因为别人电脑上可没有你的工程。

但是,我们默认不会打开这个开关啊,怎么还是会出现同样的问题呢——这时候它的容错设计就出场了。一般来说,如果我们设置了使用内置Dll,当打包后内置Dll的路径已经不对的情况下,程序应该立刻抛出错误了对吧,但实际上它又偷偷做了一件事,就是返回了默认的 _librariesPath。由于这个默认值指向了你的工程文件Dll,于是,你在自己电脑上无论怎么测试都没有报错,而把包体发给客户之后就翻了车,这插件的作者真TM是个人才!

而另一个问题,只有第一次打包正常,后面就报错,是它打包时有个自动搜索外部Dll的代码,这段代码只有在第一次打包时运转正常,后面的打包可能因为Unity会在C盘生成临时目录的缘故,最后检索到的都是C盘的一个不存在的路径。于是最后内置Dll没有找到,外部Dll路径也是错的,第一次打包之后的所有包都会报错。

但好在解决了Bug1之后,这两个问题也迎刃而解了,因此不再赘述。


总结

其实这个bug本来是个很好解决的问题,但因为它自以为是的容错设计,给我们查找问题带来了非常多的阻碍,因此在设计程序时,尽早地暴露问题,而不是尽力掩盖问题,是避免出现重大Bug的好习惯之一。

猜你喜欢

转载自blog.csdn.net/suibian19930828/article/details/127615976
今日推荐