unity3d冷启动黑屏优化
问题分析
在 Unity 开屏的开发过程中,通常在 Unity 中编写是 Unity 的开屏页,在 Android 端运行时会额外添加unity_static_splash, 来保证Android 端展示时不是 黑屏,但是 unity_static_splash 只能使用 图片资源,如果涉及到需要根据屏幕尺寸进行动态适配的时候,一张图片就不能满足要求。 同时如果 Unity 开屏和unity_static_splash 展示相同内容的话,由于适配方式不一致,会出现界面抖动。
Static Splash Image 原理
在 Unity 中通常可以设置 Static Splash Image 来屏蔽黑屏,那么Static Splash Image 是如何实现的在 Android 端展示并且消失的?
将 Unity 项目导出 Android 项目之后,可以在drawable 文件夹中找到对应的图片
Android 端启动 Unity 的 Activity 是UnityPlayerActivity,分析源码过程
//UnityPlayerActivity
@Override protected void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity"));
getIntent().putExtra("unity", cmdLine);
mUnityPlayer = new UnityPlayer(this);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
UnityPlayer 是一个 FrameLayout, 具体实现
// UnityPlayer
public UnityPlayer(Context var1) {
super(var1);
if (var1 instanceof Activity) {
currentActivity = (Activity)var1;
this.c = currentActivity.getRequestedOrientation();
}
a(currentActivity);
this.q = var1;
if (currentActivity != null && this.k()) {
this.m = new l(this.q, com.unity3d.player.l.a.a()[this.getSplashMode()]);
this.addView(this.m);
}
....
...
}
分析代码,new l 添加到了布局里面,猜测应该是这个类
//l
public l(Context var1, int var2) {
super(var1);
this.a = var2;
this.b = this.getResources().getIdentifier("unity_static_splash", "drawable", this.getContext().getPackageName());
if (this.b != 0) {
this.forceLayout();
}
}
可以看到L 这个类也是个 View, 读取unity_static_splash,然后添加到父布局里面。 这样就了解了unity_static_splash 的原理
黑屏优化
出现黑屏的前提是不能使用unity_static_splash,可能是因为
需要根据屏幕适配调整布局 播放视频或者其他资源
添加自定义布局展示开屏
针对以上的情况,我们可以手动编写布局,然后同样添加到UnityPlayerActivityd的布局中实现开屏的展示
java复制代码//MyUnityPlayerActivity
@Override protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
ViewGroup layoutView = (FrameLayout) View.inflate(this, R.layout.activity_splash, null);
addContentView(layoutView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
添加自定义布局展示任意内容。同时需要将 Unity中 Static Splash Image 设置为空
关于添加布局消失
在添加了自定义展示的开屏之后 ,需要处理的就是 什么时机让自定义布局消失。两种方案
利用 AndroidJavaObject, 在 Unity 中调用 Android 端的函数,实现关闭布局。 利用延时机制,设置 1s 或者 0.5 s 之后关闭
以上两种方案都会有一些问题
方案一导致 Unity 开屏内容会有一部分遮挡 Unity 开屏展示时机不确定,延时可能短或者长,短就会出现黑屏(因为没有unity_static_splash),长就会遮挡 Unity 开屏。
分析unity_static_splash 的消失时机,找到合适的关闭自定义布局的时机
java复制代码//MyUnityPlayerActivity
private void a() {
this.a(new Runnable() {
public final void run() {
UnityPlayer.this.removeView(UnityPlayer.this.m);
UnityPlayer.f(UnityPlayer.this);
}
});
}
UnityPlayer 系统通过移除布局来实现关闭unity_static_splash 界面,那么可以监听父布局的子View 移除,如果是 L ,那么就代表unity_static_splash 被关闭,同时关闭我们自己的自定义布局就可以了
关闭自定义布局
java复制代码//MyUnityPlayerActivity @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); ... ... mUnityPlayer.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() { @Override public void onChildViewAdded(View parent, View child) {
}
@Override public void onChildViewRemoved(View parent, View child) {
//判断是l,关闭自定义布局
if (child instanceof com.unity3d.player.l) {
removeSplashLayout();
}
}
});
添加布局监听,判断类型,关闭自定义布局