當(dāng)前海外版本有硬性要求:Target API level必須升級到31贞盯,升級之后在Android 12機型上啟動游戲,Unity閃屏之后卡死沪饺,其他Android版本正常躏敢。
查了一下這個問題,是因為TelephonyManager的listen函數(shù)在Android 12過期了整葡,如果沒有授權(quán)READ_PHONE_STATE權(quán)限件余,此函數(shù)會拋出一個SecurityException。
而Unity在啟用了自帶的音頻系統(tǒng)的情況下遭居,恰巧在啟動時機會去調(diào)用這個方法以實現(xiàn)“在用戶接電話時游戲靜音”的功能啼器,拋出的異常影響了后續(xù)的流程導(dǎo)致卡死。
論壇上有人遇到了類似的問題俱萍,但是表現(xiàn)為崩潰:
https://forum.unity.com/threads/android-12-telephony-crash.1287986/
項目能升級引擎的話端壳,可以試試這里提到的修復(fù)的版本:
https://issuetracker.unity3d.com/issues/android-player-crashing-in-fmod-when-targetting-sdk-level-31
如果項目不能升級引擎,也有一個解決辦法:
重新寫一個android的啟動類枪蘑, 將這個問題繞過去
package com.xx.xxx
import android.content.Context;
import android.os.Build;
import com.unity3d.player.UnityPlayer;
public class UnityPlayerNew extends UnityPlayer
{
public UnityPlayerNew(Context context)
{
super(context);
}
@Override
protected void addPhoneCallListener()
{
if (Build.VERSION.SDK_INT >= 31)
{
return;
}
super.addPhoneCallListener();
}
}
package com.xx.xxx;
import com.unity3d.player.*;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class UnityPlayerActivity extends Activity
{
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
protected String updateUnityCommandLineArguments(String cmdLine)
{
return cmdLine;
}
// Setup activity layout
@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 UnityPlayerNew(this);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
@Override protected void onNewIntent(Intent intent)
{
// To support deep linking, we need to make sure that the client can get access to
// the last sent intent. The clients access this through a JNI api that allows them
// to get the intent set on launch. To update that after launch we have to manually
// replace the intent with the one caught here.
setIntent(intent);
}
// Quit Unity
@Override protected void onDestroy ()
{
mUnityPlayer.destroy();
super.onDestroy();
}
// Pause Unity
@Override protected void onPause()
{
super.onPause();
mUnityPlayer.pause();
}
// Resume Unity
@Override protected void onResume()
{
super.onResume();
mUnityPlayer.resume();
}
@Override protected void onStart()
{
super.onStart();
mUnityPlayer.start();
}
@Override protected void onStop()
{
super.onStop();
mUnityPlayer.stop();
}
// Low Memory Unity
@Override public void onLowMemory()
{
super.onLowMemory();
mUnityPlayer.lowMemory();
}
// Trim Memory Unity
@Override public void onTrimMemory(int level)
{
super.onTrimMemory(level);
if (level == TRIM_MEMORY_RUNNING_CRITICAL)
{
mUnityPlayer.lowMemory();
}
}
// This ensures the layout will be correct.
@Override public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
mUnityPlayer.configurationChanged(newConfig);
}
// Notify Unity of the focus change.
@Override public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
mUnityPlayer.windowFocusChanged(hasFocus);
}
// For some reason the multiple keyevent type is not supported by the ndk.
// Force event injection by overriding dispatchKeyEvent().
@Override public boolean dispatchKeyEvent(KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
return mUnityPlayer.injectEvent(event);
return super.dispatchKeyEvent(event);
}
// Pass any events not handled by (unfocused) views straight to UnityPlayer
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); }
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); }
@Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); }
/*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); }
}
<activity android:name="com.xx.xxx.UnityPlayerActivity" android:screenOrientation="landscape" android:exported="true" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>