01 Splash Screen
对Unity Splash Screen使用进行简单记录,主要是针对安卓的。
第一点,只设置Static Splash Image,效果非常好,就是显示该启动图片:
第二点,用Splash Screen,启用的话就能用Preview直接预览启动效果,可以选择是否显示Unity的logo,可以设置动画模式,可以添加多个logo,设置持续时间等。这里注意,logo就是小的图片,它需要在背景图之上,且动画效果控制其变大淡入淡出效果。而且为了凸显logo,清晰背景图会被unity模糊化,如果想以此来替代Static Splash Image则会得到模糊化的启动图效果。
第三点,我开发的VR应用,开启unity的xr支持,sdk选择一个Cardboard甚至None,就会发现Splash无效了。然后我注意到Virtual Reality Splash Image,对其进行设置,并取消Splash Screen和Static Splash Image,还是未得到启动图效果。这可能很少有人用到过,我觉得可能我设置不正确或者Unity有bug,这里unity是2017.4版本。因此,对于安卓VR应用的Splash,我用了第二点中的做法,背景被自动模糊了,其实并不是我想要的,我想要的是VR应用Splash像普通应用Static Splash Image那样。
02 Unity序列化代码.NET4.6运行时安卓平台kernel32报错问题
这里记录一个少见的问题,有关于安卓平台序列化kernel32.dll找不到的问题。
首先是示例代码:
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using UnityEngine;
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
[XmlIgnore] //此属性不被序列化,System.Xml.Serialization.XmlIgnoreAttribute
public bool Gender { get; set; }
}
public class TestSer2 : MonoBehaviour
{
void Start ()
{
Serializer(Application.persistentDataPath + "/test.xml");
List<Person> people = Deserializer(Application.persistentDataPath + "/test.xml");
Debug.Log(people[0].Age);
}
public List<Person> Deserializer(string path)
{
List<Person> list = new List<Person>();
XmlSerializer xmlSer = new XmlSerializer(typeof(List<Person>));
using (System.IO.FileStream fs = System.IO.File.OpenRead(path))
{
list = (List<Person>)xmlSer.Deserialize(fs);
}
return list;
}
public void Serializer(string path)
{
List<Person> list = new List<Person>();
Person p1 = new Person() { ID = 1, Name = "张三", Age = 18 };
Person p2 = new Person() { ID = 2, Name = "李四", Age = 20 };
list.Add(p1);
list.Add(p2);
//xml序列化,System.Xml.Serialization.XmlSerializer
XmlSerializer xmlSer = new XmlSerializer(typeof(List<Person>));
using (System.IO.FileStream fs = System.IO.File.OpenWrite(path))
{
xmlSer.Serialize(fs, list);
}
}
}
这个代码直接创建简单的xml并写入两个人的信息,如下:
<?xml version="1.0"?>
<ArrayOfPerson xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Person>
<ID>1</ID>
<Name>张三</Name>
<Age>18</Age>
</Person>
<Person>
<ID>2</ID>
<Name>李四</Name>
<Age>20</Age>
</Person>
</ArrayOfPerson>
然后反序列化读取第一个人的年龄信息。
Windows上没有任何问题,而安卓上则出现了问题。首先Unity版本是2.17.4.15f1,编译安卓的时候,选择Scripting Runtime Version未Stable(.NET 3.5 Equivalent),编译运行没有问题。出问题的是在选择4.6的时候,手机上就报错:
Unable to find kernel32.dll
不过不得不说,这个报错虽然有,但是解析还是解析出来了,让人疑惑。
接着,由于我Unity2019.1正式版已经出来了,它的4.6运行时已经不是实验版了,我用它做了同样的测试,报错依旧(Api Compatibility Level选的是.NET 4.x)。不过我继续尝试,发现2019版本Unity选择4.6的运行时版本的时候,仍然可以选择Api Compatibility Level为.NET Standard 2.0,用该版本进行编译,发现不会报错。这边说的都是Mono后端,没涉及IL2CPP。
因此序列化的操作考虑跨平台问题,还是需要2.0的Api兼容等级。如果用了异步等操作,还需要4.x的运行时,那么二者都要,可能就不得不用2019版本的Unity了(2018.3在选择了4.x运行时的情况下也可以选择2.0的Api兼容等级,而不像2017.4长期支持版那样选择了4.x后就只能用4.x的Api兼容等级,毕竟这里的4.x还是实验版本)。
03 Unity DLL平台设置
前面的一篇博客记录了VS添加条件编译符号的操作,这里还有一些别的设置需要Unity中完成,记录如下。
创建Plugins目录,下面根据平台创建Android和x86目录,如下:
分别放入VS编译的DLL,安卓下的dll已经自动默认平台为Android,且没有其他设置:
x86下面的则默认为全平台,这里设置为Windows:
且可以继续设置CPU和OS类型,且可以区分Editor和Standalone模式。
根据测试,Editor模式中,切换平台为Windows,那么自然调用的是x86下面的dll。切换为安卓,发现仍然调用x86下面的dll。真正编译运行在安卓平台上的时候,则调用了Android目录下的dll。所以说,要编译一个安卓平台的dll,想要调用的话,还需要一个Windows版本的dll,这样Edito模式中才能运行起来不报错。
04 Unity Movie Texture报错问题
本来的一个工程写了www.GetMovieTexture()的代码,虽然没用到,但是这也导致安卓平台上报错
Windows平台则是可以的,也不报错。为了测试,我写了下面的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestGetMovieTexture : MonoBehaviour
{
void Start ()
{
StartCoroutine(TestMovieTexture(Application.persistentDataPath + "test.txt"));
}
IEnumerator TestMovieTexture(string path)
{
string prefix = "file://";
UnityEngine.Object obj;
WWW www = new WWW(prefix + path);
while(!www.isDone)
{
yield return null;
}
if(path.Contains("mp4"))
{
obj = www.GetMovieTexture();
}
else
{
Debug.Log("Not supported");
}
www.Dispose();
}
}
Windows平台则能输出我预设的“Not supported”,切换到安卓平台编译,本来还想重现原来的问题,这次居然编译不过了:
error CS1061: Type `UnityEngine.WWW' does not contain a definition for `GetMovieTexture' and no extension method `GetMovieTexture' of type `UnityEngine.WWW' could be found. Are you missing an assembly reference?
真是怪事。网上也有关于安卓上movie texture的问题,且unity已经不太支持用这个了:
而且我本来也用不到,只是一行代码写道了GetMovieTexture(),反而让我浪费许多时间查找问题。
05 Awake函数执行时机
再强调一下,Awake执行与自身脚本激活状态无关,但是与其所在游戏对象激活状态有关。一般都知道,如果脚本不激活,运行的时候Awake也会自动执行。但是要注意,如果其所在游戏对象一开始就是非激活状态,那么Awake是要等到启用该游戏对象的时候才会执行的。
06 Unity使用AVPro的时候进行Application.Quit()问题
Unity使用Application.Quit()可以退出应用,回到前一个activity,而不是回到主界面。比如,用下面的启动器来拉起一个Unity应用:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView)this.findViewById(R.id.textView);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date date = new Date(System.currentTimeMillis());
textView.append(simpleDateFormat.format(date));
Button button = (Button)this.findViewById(R.id.button);
button.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = getPackageManager().getLaunchIntentForPackage("com.hu.sic");
if (intent != null) {
{
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
}
);
}
那么在Application.Quit()后,unity应用关闭了,回到了该启动器界面,该启动器界面上的时间字符串还是一开始的时间,证明启动器没有被关闭。
但是,如果unity中用:
System.Diagnostics.Process.GetCurrentProcess().Kill();
来结束程序,那么会关闭应用,并回到主界面,而无法回到启动器一开始的activity。
所以用quit的方式是比较好的,但是由于我工程中用了avpro这个视频播放插件,它有点bug。quit的时候,程序实际并没有完全关闭,继续启动它的时候会发现它的进程id没变。当然,如果是kill的方式,那就完全清掉了进程。所以quit这种方式,导致avpro不会再次初始化,无法播放视频,就一直黑屏,具体问题如下:
https://github.com/RenderHeads/UnityPlugin-AVProVideo/issues/37
所以用下面的方法来改进:
public static void QuitApp()
{
#if UNITY_ANDROID
AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject androidActivity = player.GetStatic<AndroidJavaObject>("currentActivity");
if (androidActivity != null)
{
androidActivity.Call("finishAffinity");
AndroidJavaClass system = new AndroidJavaClass("java.lang.System");
system.CallStatic("exit", new object[] { 0 });
}
#else
Application.Quit();
#endif
}
这样,程序会正常关闭,关闭的时候会回到上一个activity而不是退到主界面;另外,它也可以避免avpro初始化问题,不会再黑屏。