2015-11-06 199 views
13

我正在構建一個包含Unity 3d交互體驗的Android應用程序。Android UnityPlayerActivity操作欄

我已經將Unity項目導入到Android Studio中,但啓動時該活動是全屏顯示並且不顯示Android操作欄。

我該怎麼做?

整合步伐

  • 創建新的統一的項目。
  • 從Unity導出「Google Android Project」。
  • 將項目導入Android Studio。

嘗試的解決方案

  • 更改清單中的主題。
  • 在UnityPlayerActivity Java類中設置主題。
  • 通過將具有更新主題的清單放置在Unity目錄/ Assets/Plugins/Android中,覆蓋Unity Manifest。
  • 更改UnityPlayerActivity以擴展AppCompatActivity。這將顯示操作欄,但它與狀態欄之間存在白色間隙。
  • 設置「Screen.fullScreen = false;」在Unity SceneManager中。這將刪除沉浸式模式,以便Android狀態欄可見。
  • 在播放器設置中關閉「狀態欄隱藏」。似乎沒有效果。
  • 在FrameLayout中包裝UnityPlayer。這使我可以將Unity作爲視圖調整大小。

AndroidManifest.xml中

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.company.unity.test" 
    android:installLocation="preferExternal" 
    android:versionCode="1" 
    android:versionName="1.0"> 

    <supports-screens 
     android:anyDensity="true" 
     android:largeScreens="true" 
     android:normalScreens="true" 
     android:smallScreens="true" 
     android:xlargeScreens="true" /> 

    <application 
     android:banner="@drawable/app_banner" 
     android:debuggable="false" 
     android:icon="@drawable/app_icon" 
     android:isGame="true" 
     android:label="@string/app_name" 
     android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> 
     <activity 
      android:name="com.company.unity.test.UnityPlayerActivity" 
      android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale" 
      android:label="@string/app_name" 
      android:launchMode="singleTask" 
      android:screenOrientation="fullSensor"> 
      <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> 
      <meta-data 
       android:name="unityplayer.UnityActivity" 
       android:value="true" /> 
     </activity> 
    </application> 

    <uses-sdk 
     android:minSdkVersion="9" 
     android:targetSdkVersion="23" /> 

    <uses-feature android:glEsVersion="0x00020000" /> 
    <uses-feature 
     android:name="android.hardware.sensor.accelerometer" 
     android:required="false" /> 
    <uses-feature 
     android:name="android.hardware.touchscreen" 
     android:required="false" /> 
    <uses-feature 
     android:name="android.hardware.touchscreen.multitouch" 
     android:required="false" /> 
    <uses-feature 
     android:name="android.hardware.touchscreen.multitouch.distinct" 
     android:required="false" /> 
</manifest> 

UnityPlayerActivity.java

package com.company.unity.test; 

import android.app.Activity; 
import android.content.res.Configuration; 
import android.graphics.PixelFormat; 
import android.os.Bundle; 
import android.view.KeyEvent; 
import android.view.MotionEvent; 
import android.view.Window; 

import com.unity3d.player.UnityPlayer; 

public class UnityPlayerActivity extends Activity 
{ 
    protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code 

    // Setup activity layout 
    @Override protected void onCreate (Bundle savedInstanceState) 
    { 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     super.onCreate(savedInstanceState); 

     getWindow().setFormat(PixelFormat.RGBX_8888); // <--- This makes xperia play happy 

     mUnityPlayer = new UnityPlayer(this); 
     setContentView(mUnityPlayer); 
     mUnityPlayer.requestFocus(); 
    } 

    // Quit Unity 
    @Override protected void onDestroy() 
    { 
     mUnityPlayer.quit(); 
     super.onDestroy(); 
    } 

    // Pause Unity 
    @Override protected void onPause() 
    { 
     super.onPause(); 
     mUnityPlayer.pause(); 
    } 

    // Resume Unity 
    @Override protected void onResume() 
    { 
     super.onResume(); 
     mUnityPlayer.resume(); 
    } 

    // 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); } 
} 
+0

我寫給你的表現改變了主題,但例如在一個有@android:風格/ Theme.NoTitleBar.Fullscreen。這是你改變的主題嗎?如果不是,那麼它是什麼? – Lingviston

+0

@Lingviston我發佈的代碼顯示了原始集成。我嘗試在應用程序和活動標籤上將主題更改爲'android:theme =「@ android:style/Theme.Material.Light.DarkActionBar」',但都沒有使操作欄可見。 – Morepork

+0

@Morepork你找到解決方案嗎? – Piotr

回答

4

我想我已經找到了解決方案。
更改了該行:

mUnityPlayer = new UnityPlayer(this); 

因此它會創建自己的UnityPlayer子類,它覆蓋setFullscreen方法(有點哈克):

public class UnityPlayerWrapper extends UnityPlayer { 
    public UnityPlayerWrapper(ContextWrapper contextWrapper) { 
     super(contextWrapper); 
    } 

    @Override 
    protected void setFullscreen(boolean b) { 
     super.setFullscreen(false); 
    } 
} 

另外,請刪除該行:requestWindowFeature(Window.FEATURE_NO_TITLE);

+0

我在我的項目中試過這個,但我沒有看到一個操作欄。在運行Android 5.1的三星Galaxy S6上測試.1 – Morepork

+0

是否禁用了該行 - requestWindowFeature(Window.FEATURE_NO_TITLE);? – Piotr

+1

禁用無標題功能後工作。謝謝@Piotr。 – Morepork

6

適用於Unity版本5.5避免Android中Immersive Mode的最好方法是在構造函數中傳遞Activity而不是將ApplicationContext轉換爲Wrapper Context。

mUnityPlayer = new UnityPlayer((ContextWrapper) getApplicationContext()); 

,由於在混淆UnityPlayer.class工程(團結-classes.jar)有實例的檢查。

private void h() { 
    if(this.h instanceof Activity) { 
     ((Activity)this.h).getWindow().setFlags(1024, 1024); 
    } 
} 

所以,如果它不是一個活動UnityPlayer.class不設置標誌。

+0

它顯示工具欄後,更改爲ContextWrapper現在,但問題是,現在相機視圖不呈現,請你給一些建議? –

+0

您可以使用kotlin擴展函數來覆蓋此方法嗎? –

+0

不幸的是不可能e覆蓋該方法,因爲它是私人的。你可以用一個骯髒的解決方案來做:使用反射。 –

0

彼得回答正在爲舊版本和洛倫佐DM的回答也是有效的,但

mUnityPlayer = new UnityPlayer((ContextWrapper) getApplicationContext());

在某些設備不工作。所以,最後我在這裏修改UnityPlayerActivity是新的解決方案



public class UnityPlayerActivity extends AppCompatActivity 
{ 
    protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code 
    ActionBar actionBar; 
    private Toolbar toolbar; 
    private FrameLayout unityContainer; 

    // Setup activity layout 
    @Override protected void onCreate (Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     mUnityPlayer = new UnityPlayer(this); 
     setContentView(R.layout.activity_unity_player); 
     mappingWidgets(); 
     init(); 

    } 

    void mappingWidgets(){ 
     toolbar = (Toolbar) findViewById(R.id.toolbar); 
     unityContainer = (FrameLayout) findViewById(R.id.unity_container); 
     FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); 
     unityContainer.addView(mUnityPlayer.getView(), 0, layoutParams); 
     mUnityPlayer.requestFocus(); 

    } 
    void init(){ 
     setSupportActionBar(toolbar); 
     actionBar = getSupportActionBar(); 
     if (actionBar != null) 
      actionBar.setDisplayHomeAsUpEnabled(true); 
     toolbar.setNavigationOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       finish(); 
       onDestroy(); 
      } 
     }); 
     setTitle(getString(R.string.app_name)); 


    } 


    @Override protected void onNewIntent(Intent intent) 
    { 
     setIntent(intent); 
    } 

    // Quit Unity 
    @Override protected void onDestroy() 
    { 
     mUnityPlayer.quit(); 
     super.onDestroy(); 
    } 

    // Pause Unity 
    @Override protected void onPause() 
    { 
     super.onPause(); 
     mUnityPlayer.pause(); 
    } 

    // Resume Unity 
    @Override protected void onResume() 
    { 
     super.onResume(); 
     mUnityPlayer.resume(); 
    } 

    // 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); } 
    // Pass any events not handled by (unfocused) views straight to UnityPlayer 
    @Override public boolean onKeyUp(int keyCode, KeyEvent event)  { 
     if(keyCode == KeyEvent.KEYCODE_BACK) { 
      finish(); 
      onDestroy(); 
      return true; 
     } 
     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); } 
}