思路
使用免费版的Unity开发Android端游戏时,在启动游戏时会展示Unity自带的Logo动画。那有没有办法在不花钱的前提下把Unity自带Logo替换成自己的Logo呢?有两个思路:
破解Unity编辑器,然后使用Unity自带功能替换Logo使用障眼法,在Unity的Logo之上添加自定义的View,盖住Unity自带Logo。
理论基础
我们选择第二种方案。该方案的原理也不难理解,Unity的Logo动画应该是在Android层实现的,它其实也是一个SplashView,最早展现给我们看。那么我们就可以在SplashView之上添加自定义的满屏CustomSplashView盖在原理的SplashView之上,用户自然只能看到自定义的CustomeSplashView了。
Android Apk都必须有一个AndroidManifest.xml文件,该文件会指定第一个启动的Activity,Unity2018版本使用的AndroidManifest.xml模板路径为Unity安装路径下的Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Apk\AndroidManifest.xml。
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="preferExternal">
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true"/>
<application
android:theme="@style/UnityThemeSelector"
android:icon="@mipmap/app_icon"
android:label="@string/app_name">
<activity android:name="com.unity3d.player.UnityPlayerActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>
</manifest>
以上配置文件可以看出,所有Unity Android游戏第一个被启动的Activity名字是UnityPlayerActivity,参考官方文档扩展UnityPlayerActivity Java代码,我们也扩展UnityPlayerActivity,在里面添加自定义的启动页CustomSplashView。
Android端实现
创建一个Module,在该Module下实现继承UnityPlayerActivity实现CustomSplashActivity,在SplashActivity 的onCreate方法中添加自定义SplashView,代码如下:
package com
.ccmm
.lib
;
import android
.content
.res
.Resources
;
import android
.os
.Bundle
;
import android
.util
.DisplayMetrics
;
import android
.util
.Log
;
import android
.view
.ViewGroup
;
import android
.widget
.ImageView
;
import com
.unity3d
.player
.UnityPlayerActivity
;
import androidx
.annotation
.Nullable
;
public class SplashActivity extends UnityPlayerActivity {
private ImageView bgView
;
private static String TAG
= "XJP";
@Override
public void onCreate(@Nullable Bundle savedInstanceState
) {
Log
.i(TAG
, "onCreate: start");
super.onCreate(savedInstanceState
);
WindowManager
.LayoutParams lp
= getWindow().getAttributes();
if (Build
.VERSION
.SDK_INT
>= Build
.VERSION_CODES
.P
) {
lp
.layoutInDisplayCutoutMode
= WindowManager
.LayoutParams
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
;
}
Log
.i(TAG
, "onCreate: end");
showSplashView();
}
public void showSplashView() {
Log
.i(TAG
, "showSplashView: start");
Resources r
= getResources();
bgView
= new ImageView(this);
int splash_bg
= r
.getIdentifier("splash", "drawable", getPackageName());
ViewGroup
.LayoutParams param
= new ViewGroup.LayoutParams(ViewGroup
.LayoutParams
.WRAP_CONTENT
, ViewGroup
.LayoutParams
.WRAP_CONTENT
);
DisplayMetrics displayMetrics
= r
.getDisplayMetrics();
param
.width
= displayMetrics
.widthPixels
;
bgView
.setScaleType(ImageView
.ScaleType
.CENTER_CROP
);
bgView
.setBackgroundResource(splash_bg
);
bgView
.setLayoutParams(param
);
mUnityPlayer
.addView(bgView
);
Log
.i(TAG
, "showSplashView: end");
}
public void removeSplashView() {
if (bgView
== null
) {
return;
}
runOnUiThread(new Runnable() {
@Override
public void run() {
Log
.i(TAG
, "removeSplashView: start");
mUnityPlayer
.removeView(bgView
);
bgView
= null
;
}
});
}
}
以上代码注释写的很清楚每一步都是干嘛的。
splash.png图片资源放在res/drawable/splash.png。将Module打包成aar包,提供给Unity使用。
Unity端实现
将Android打包成的aar放在Unity工程 Assets/Plugins/Android/ 目录下。修改上面的AndroidManifest.xml配置文件,使得Android apk第一个启动的Activity 为我们重写的SplashActivity ,代码如下:
<?xml version
="1.0" encoding
="utf-8"?>
<manifest
xmlns
:android
="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns
:tools
="http://schemas.android.com/tools"
android
:installLocation
="preferExternal">
<supports
-screens
android
:smallScreens
="true"
android
:normalScreens
="true"
android
:largeScreens
="true"
android
:xlargeScreens
="true"
android
:anyDensity
="true"/>
<application
android
:theme
="@style/UnityThemeSelector"
android
:icon
="@mipmap/app_icon"
android
:label
="@string/app_name">
<activity android
:name
="com.ccmm.lib.SplashActivity "
android
:label
="@string/app_name">
<intent
-filter
>
<action android
:name
="android.intent.action.MAIN" />
<category android
:name
="android.intent.category.LAUNCHER" />
</intent
-filter
>
<meta
-data android
:name
="unityplayer.UnityActivity" android
:value
="true" />
</activity
>
</application
>
</manifest
>
将修改过的AndroidManifest.xml文件放在Assets/Plugins/Android/ 目录下,Unity打包的使用就会使用这份配置文件。在Unity端找个合适的时机,当Unity的第一个场景加载完全可见时,移除自定义的启动页。Unity端代码如下:
public void RemoveSplashView() {
AndroidJavaClass ajc
= new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity
= ajc
.GetStatic<AndroidJavaObject>("currentActivity");
currentActivity
.Call("removeSplashView");
}
总结
1.以上方案并没有真正替换掉Unity logo,只是添加一个新的SplashView来盖住Unity Logo 2.测试发现并没有找到很好的做到Android端的启动页SplashView和Unity端的第一个场景无缝切换。 3.以上部分内容参考网络上资源。