Cross-platform VR development: GearVR and Daydream

Hi all,

I’ve created a couple of projects for the GearVR. I’m looking to start a new project and I want to support both GearVR and Daydream. Before I start, I wanted to see if anyone had any tips, articles etc. on how to manage this.

What confuses me most is the UI systems. Oculus has a reference implementation for a gaze cursor and a custom InputModule. Unity’s VR samples provide the cross-platform “VRInteractiveItem” and associated classes, but it doesn’t seem to work as smoothly with the input system (there is no InputModule and events all have to be hooked up manually). The GoogleVR SDK for Unity has it’s own code and prefabs for gaze cursors. In addition, Daydream has a separate controller and in the GoogleVR samples, the pointing is done with the controller rather than the user’s gaze so there is a bit of a conceptual difference there.

So, should I

  • Use Unity’s VR sample code
  • Maintain two platform specific implementations, and have a switch at runtime depending on the platform?
  • Have a project for each platform?!

Basically any tips or stories you have about supporting and releasing to both of these platforms for the same project would be greatly appreciated!

Thanks

Use a Gaze Input Module- either your own, or the one from GoogleVR, etc. They are just scripts, so you can use the same ones for Cardboard, Daydream , GearVR, etc. Google VR’s is works nice:

If you have ‘VR Supported’ in build settings (daydream and gearvr), then you need to get center of screen slightly different than the default Gaze Input Module:

I have a Mobile VR Interaction Pack coming out soon to solve this problem:

Thanks for the reply. So if I used, say the Oculus GazeInputModule and then imported the Daydream SDK (or used the technical preview) then basic gaze pointing would work just fine on the Daydream?

My main problem is I don’t have a Daydream phone to test with right now, and I don’t want to find out later on down the track that I didn’t get my UI system right!

another problem I’ve seen is a camera: I’m very new here so I might miss something essential, but when I compile standard Google project Releases · googlevr/gvr-unity-sdk · GitHub, it looks different on the exact same phone Samsung Galaxy s8: there’s “eye fish” effect on the Gear VR. So I assume camera has to acquire headset specks during run time and it’s different for Gear VR and daydream headsets.

I’m working on GearVR/Daydream compatibility in my current project right now.

My goal is to have one project, that I can build for each target with minimal effort to set the build mode. I refuse to fork.

I want to just do this:

  • Set one VR platform in Unity VR list. (GearVR, Daydream or None)
  • Build.
  • Done.

Here’s some points I’ve discovered so far.

EDIT: best to just jump to this future post: Cross-platform VR development: GearVR and Daydream

Daydream: you can have a regular camera in scene and daydream “hooks” into that when Daydream is added to VR list. Just add GVREditorEmulator and GVRControllerInput to some scene object and you’re done, you can proceed to call all GVR static functions.

GearVR: you must place OVRCameraRig prefab into scene, there can be no regular cam in scene. I have yet to work out if this can be swapped out dynamically, I think not, I think OVRCameraRig has to be there at engine init?

Small fly in the ointment: When building daydream target: you should remove (maybe rename) the Assets/OVR/Plugins folder if you have one, if you fail to do this then the daydream game will cause any samsung phone with GearVR service running to popup “place phone in GearVR”, even if “GearVR” is not in unity VR list (and thus not referenced in manifest). Many samsung users are getting this issue when trying to play daydream games right now, their workaround is to disable oculus services, but that’s hardly conducive to a nice end user experience.

You can leave your Assets/Plugins/Android/assets/oculussig_xxxxx file where it is for daydream builds.

For daydream samsung S8/S8+ (and maybe other targets?) single pass rendering yields black at the moment, I set to multi pass for now.

I am using ETC2 texture compression for now, ASTC for final production build.

CAMERA:

I’m doing runtime VR mode detection once upon game startup like this, I wait for v.bInitialised to go true until the game then proceeds to load/build further scenery:

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //    INIT CAMERA FOR VR SYSTEM TYPE
        private void InitSystemType()
        {
            //  WAIT FOR MAIN CAM TO COME UP
            v.oCameraActive = Camera.main;
            if (!v.oCameraActive)
            {
                Invoke("InitSystemType", 0.1f);
                LOGW("NO Camera.main");
                return;
            }
            main.g.cLibMesh.ChildObjectToParent(v.oCameraActive.gameObject, this.gameObject);
            LOGM("FOUND Camera.main");

            //  WHAT CAM PREFAB
            string sCameraPrefab = "";

            //  GET VR SYSTEM NAMES INTO A LIST
            string[] asDevices = VRSettings.supportedDevices;
            List<string> lsDevices = new List<string>();
            for (int iDevice = 0; iDevice < asDevices.Length; iDevice++)
            {
                lsDevices.Add(asDevices[iDevice].ToUpper());
            }

            //    GEARVR
            if (lsDevices.Contains(K_S_VR_DEVICE_LIST_NAME_GEARVR))
            {
                v.eSystemType = E_SYSTEM_TYPE.GEARVR;
                sCameraPrefab = "vr_camera_gearvr";//OVRCameraRig and OVRManager in this prefab. And 2 OVRGearVRControllers are in the OVRCameraRig heirachy.

                if (v.oCameraActive)
                {
                    DestroyImmediate(v.oCameraActive.gameObject);
                }
#if(UNITY_EDITOR)
                v.bSynthesizeHMDRotation = true;
#else
                v.bSynthesizeHMDRotation = false;
#endif
            }

            //    DAYDREAM
            else if (lsDevices.Contains(K_S_VR_DEVICE_LIST_NAME_DAYDREAM))
            {
                v.eSystemType = E_SYSTEM_TYPE.DAYDREAM;
                sCameraPrefab = "vr_camera_daydream";//GVREditorEmulator and GVRControllerInput in this prefab.
            }

            //    NONE
            else
            {
                sCameraPrefab = "vr_camera_none";//just a dummy transform in this prefab.
                v.eSystemType = E_SYSTEM_TYPE.NONE;
                v.bSynthesizeHMDRotation = true;
            }

            //  LOAD RELEVANT PREFAB
            GameObject oCameraPrefab = main.g.cLibMesh.CreateObject("VR/Prefabs/" + sCameraPrefab);
            if (!oCameraPrefab)
            {
                LOGE("CANT LOAD CAMERA PREFAB " + sCameraPrefab);
                return;
            }

            v.tCameraPrefab = oCameraPrefab.transform;
            main.g.cLibMesh.ChildObjectToParent(v.tCameraPrefab, this.transform);
            v.tCameraPrefab.name = sCameraPrefab.ToUpper();

            //  SET CAM
            v.oCameraActive = Camera.main;
            main.g.cLibMesh.ChildObjectToParent(v.oCameraActive.gameObject, this.gameObject);
            v.oCameraActive.nearClipPlane = K_F_CAMERA_PLANE_NEAR;
            v.oCameraActive.farClipPlane = K_F_CAMERA_PLANE_FAR;
            v.oCameraActive.backgroundColor = Color.black;

            //  DONE
            v.bInitilised = true;
            LOGM("SYSTEM TYPE SET TO: " + v.eSystemType);
        }

My only issue is getting GearVR to init properly at runtime, I get 2 log warnings per frame:
ovrp_GetAppHasInputFocus return Failure_NotInitialized
ovrp_GetAppHasSystemOverlayPresent return Failure_NotInitialized

Searching google for either of these warnings gives zero results, so I’m obviously way out in the weeds here.

I’m not able to find docs on how to programattically instantiate Oculus in unity script, maybe the prefabs have to be in scene at start?

INPUT:

For input I am including both APIs and switching when polling like this. Then the relevant control state is stored in a superset abstraction class I made.

        public class C_BUTTON
        {
            public bool bDown;
            public bool bJustUp;
            public bool bJustDown;
            //  UPDATE
            public void Update(bool bDownNow)
            {
                bJustDown = (bDownNow && !bDown);
                bJustUp = (!bDownNow && bDown);
                bDown = bDownNow;
            }
        }

        public class C_BUTTONS
        {
            public bool bFresh;
            public C_BUTTON cBtn_App = new C_BUTTON();
            public C_BUTTON cBtn_PadClick = new C_BUTTON();
            public C_BUTTON cBtn_PadTouch = new C_BUTTON();
            public C_BUTTON cBtn_Trigger = new C_BUTTON();
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //    LATE UPDATE
        private void LateUpdate()
        {
            if (!v.bActive)
            {
                return;
            }

            //  DATA NOT FRESH FOR NEXT FRAME
            v.cButtons.bFresh = false;
            v.cTouchPad.bFresh = false;
            v.bBatterState_Fresh = false;
            v.bControllerRotation_Fresh = false;
        }
....
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //    GET STATE OF ALL BUTTONS
        public C_BUTTONS Controller_GetButtons()
        {
            //  NEED TO GET FRESH DATA?
            if (!v.cButtons.bFresh)
            {
                //---------------------------------------------------------------------------------------------------------------------
                //    DAY DREAM
                if (v.eSystemType == E_SYSTEM_TYPE.DAYDREAM)
                {
                    v.cButtons.cBtn_App.Update(GvrControllerInput.AppButton);
                    v.cButtons.cBtn_PadClick.Update(GvrControllerInput.ClickButton);
                    v.cButtons.cBtn_PadTouch.Update(GvrControllerInput.IsTouching);
                    //v.cButtons.cBtn_Trigger.Update(false); NO TRIGGER ON DAYDREAM
                }
                //---------------------------------------------------------------------------------------------------------------------
                //    GEAR VR
                else if (v.eSystemType == E_SYSTEM_TYPE.GEARVR)
                {
                    v.cButtons.cBtn_App.Update(OVRInput.Get(OVRInput.Button.Back));
                    v.cButtons.cBtn_PadClick.Update(OVRInput.Get(OVRInput.Button.PrimaryTouchpad));
                    v.cButtons.cBtn_PadTouch.Update(OVRInput.Get(OVRInput.Touch.PrimaryTouchpad));
                    v.cButtons.cBtn_Trigger.Update(OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger));
                }
                //---------------------------------------------------------------------------------------------------------------------
                //    NONE
                else if (v.eSystemType == E_SYSTEM_TYPE.NONE)
                {
                    v.cButtons.cBtn_App.Update(Input.GetKey(KeyCode.X));
                    v.cButtons.cBtn_PadClick.Update(Input.GetKey(KeyCode.Space) || Input.GetMouseButton(0));
                    v.cButtons.cBtn_PadTouch.Update(v.cNone.vTouchpadPos_Raw.magnitude > 0.0f);
                    v.cButtons.cBtn_Trigger.Update(Input.GetKey(KeyCode.RightAlt));
                }

                //  NOW FRESH
                v.cButtons.bFresh = true;
            }

            //  DONE
            return v.cButtons;
        }....

Above is basically what unity will have to do if it wants to “unite” all VR APIs.

Unity will have to employ some even more general abstraction under the hood, because it will have to handle extra buttons/pads/sticks/orientations found on any potential future input devices. It should allow the unity user to query any systems control state through the same UnityEngine.VR API. A wide problem for sure.

Your daydream build must not include any oculus plugins or phones oculus service will wake up. So to build daydream (that will work on a gearVR equipped phone): just have daydream in VR list and remove (temporarily move outside project scope) Assets/OVR/Plugins folder from your project.

See updated post below for 2017.1.2f1

RE pure script useage of these VR APIs
i.e. choosing and using relevant API at runtime game start:
More stuff I’ve discovered using Unity 2017.1.0p4:
Best to use the built in GearVR plugin, do not import Assets/OVR/Plugins.
Just import these from Oculus package:
Assets/OVR/Editor
Assets/OVR/Prefabs
Assets/OVR/Scripts
This way Unity does not include any Oculus plugins if Oculus is not in the VR list.

For hybrid project:
always start scene[0] with just one vanilla unity cam.
Then duing your init phase: swap out for any VR_SDK specific cam with any required VR_SDK scripts on it.
When game starts, if you find Daydream in unity VR list: DestroyImmediate your oculus_prefab and instantiate new gearvr_prefab: with Camera, GVREditorEmulator and GVRControllerInput on it.
Best to have a seperate object that holds your audio listener, instantiate it at (0,0,0) on game start and child it to your VR camera once you’ve got it up and running.
Build with only one VR platform in unity list: Oculus or daydream. Unity will moan with log error that “android VR builds require cardboard or daydream in the list”, but it will continue and build fine with just Oculus in the list (as it should).

Result:
I can now build daydream or GearVR simply by selecting relevant platform in Unity VR list and hitting “Build”, no other steps needed, no #if directives needed.
Both work correctly on a GalaxyS8 with Oculus service running, i.e. daydream works fine without activating GearVR service.
If we want newer Oculus plugin version: I think best to wait until it is bundled with a stable unity release.

Note:
If any other mobile VR SDK comes out that’s as finnicky and particular as Oculus then it will be a problem, thank goodness daydream is more forgiving.

See updated post below for 2017.1.2f1

Same here, did you find anything about this warning?

Not much info about warning, to get around it: follow my below post.

GearVR/Daydream one project, easy build switch:

Unity 2017.1.2f1

Import latest VR SDK asset packages:
GoogleVRForUnity_1-7.unitypackage
ovr_unity_utilities_1.18.1

I chose to use the plugins bundled with unity, that is: I only imported the required .cs declaration scripts for each SDK, you may want to try the latest plugins included with the relevant github download. However if you do: be sure to remove them from project scope when you build, otherwise they will find their way into your APK and interfere with each other.

Note: I did have to include the google audio plugin for X86 (to get GVRAudio working in editor), this daydream related plugin can stay in project scope when building for GearVR.

To easily target build platform: Put one entry into your Unity PlayerSettings VR list, the entry you select will determine your build target.

Make your game scene[0] have a straight vanilla unity camera in it.

During game init: ascertain which VR SDK you are running by enumerating VRSettings.supportedDevices.

Then swap out the vanilla camera for a camera set up for the relevant VR platform (with the required VR_SDK scripts on it for input etc). Can swap by calling DestroyImmediate on vanilla cam and then loading relevant cam prefab.

NOTES: If using single pass rendering, have at least 2xMSAA enabled and set your cameras “Clear Flags” to “Solid Color”.

All other build/quality settings can be the same for both platforms.

For production build: Obey the Oculus lint tool, and apply those settings to the project for both GearVR and Daydream: ASTC, IL2CPP etc.

1 Like

GearVR/Daydream one project, NOTE!

I just discovered this after hours of poking around:

Make sure you have different package identifier names for GearVR and DayDream builds.

If you don’t then your phone remembers the package name is associated with daydream, and then if you install the same APK built for oculus: you get wrong final render texture width, this happens even if you uninstall daydream version first. (EDIT uninstalling and restarting phone will cure it).

Set it in:
File / BuildSettings / PlayerSettings / AndroidTab / OtherSettings / Identification / PackageName

Of course we will be having different package names (for Oculus and GooglePlay stores) when finally publishing, but if you forget to change it during development testing, just once, then your target phone will never render the game correctly in gearvr again.

3 Likes

Thanks for sharing. Are you using the GearVR controller? Any tips for supporting both controllers easily? I have to port soon and I’m not sure what approach to take.

One idea I had was to write one single InputModule which would switch in the relevant Google/Oculus input module, and a simple wrapper class to do something similar in the case where the controller values might need to be accessed directly (get last raycast result, etc).

1 Like

@jmitcheson , yes i’m using both daydream/gearvr controllers.

I’m running a custom rig, swap out controller 3d models on init:
screenshot

So I don’t use any prefab controller helpers etc. I only need to get low level hardware info:

  • Left/Right handed user.
  • Controller rotation.
  • Touchpad state.
  • Button states.
  • Battery state.

I did as you allude to and wrote a general VR input class, it calls the static methods of the relevant API.

I dont need to #ifdef anything out, you can have all OVR/GVR scripts in your project together.

If you are using the supplied prefabs for controllers, laser pointer with raycast etc. then you should be able to handle that as well; just spawn the prefab you need during init.

1 Like

@SiliconDroid Thanks for the info. Nice use of the arm model and controller. Your game looks great.

Slightly OT but do many / most mobile VR games fully embody the player like this? Mine is disembodied at the moment.

1 Like

@jmitcheson I think most mobile VR games are not implementing full body avatars. I guess it’s a lot of extra work and also mobile triangle budget is tight.

I do like having a body and I think it helps ground users and reduce sim sickness. In GearVR (with wider FOV), when I’m settled and only moving my neck muscles and controller hand: I still manage to get that magical feeling of presence (as strong as 6DOF tracking), I can’t get it without a body avatar, but maybe that’s just me?

My avatar only has bones in the arms and to help with the triangle budget I performed a laborious hand culling of all unseen triangles from my avatar and cockpit model; similar to what googles new Seurat tool will do automatically.

screenshot

HI @SiliconDroid ,

I’ve been trying to make a cross-platform build,
Wanted to know how you manage the AndroidManifest.xml?
Do you manually change the parameters before build, or is there an Automated way to handle this.

If possible have AndoridManifest.xml for each platform.

We’ve already uploaded a test build to Daydream(Play store) and ran into issues while uploading to GearVR(Oculus) store.
(worried that if we manually make changes necessary for Oculus It might cause errors while updating the Daydream version in the future.)

Thanks a lot.

@vivalavida I’ve not tried publishing to daydream or gearvr yet, but I will be and will need to understand this (as do you).

So we can see what manifest is getting bundled like this:

For checking what’s in an actual APK: I like ClassyShark because its a fast small standalone .jar and formats the XML to be very readable.

So here are my currently generated APKS:

OCULUS

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.1" package="com.silicondroid.cmwo" android:installLocation="auto">
  <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:theme="@style/UnityThemeSelector" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner">
    <activity android:label="@string/app_name" android:name="com.unity3d.player.UnityPlayerActivity" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density">
      <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>
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:name="com.unity.purchasing.googleplay.PurchaseActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:name="com.unity.purchasing.googleplay.VRPurchaseActivity" android:theme="@style/VrActivityTheme">
      <intent-filter>
        <action android:name="com.google.vr.vrcore.ACTION_NONE" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <!-- For enableVrMode use the value vs. the string so Unity can build it. -->
    <activity android:configChanges="orientation|screenSize" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:exported="false" android:label="@string/app_name" android:name="com.google.gvr.keyboardsupport.TransitionVRActivity" android:resizeableActivity="false">
      <intent-filter>
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <!-- For enableVrMode use the value vs. the string so Unity can build it. -->
    <activity android:configChanges="orientation|screenSize" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:exported="false" android:label="@string/app_name" android:name="com.google.gvr.permissionsupport.TransitionVRActivity" android:theme="@android:style/Theme.Dialog">
      <intent-filter>
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only" />
    <meta-data android:name="unity.build-id" android:value="40e3d1a4-b5e7-478e-803c-669266dc5147" />
    <meta-data android:name="unity.splash-mode" android:value="0" />
    <meta-data android:name="unity.splash-enable" android:value="False" />
    <meta-data android:name="android.max_aspect" android:value="2.1" />
  </application>
  <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="25" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="com.android.vending.BILLING" />
  <!-- Indicates use of Android's VR-mode, available only on Android N+ -->
  <uses-feature android:name="android.software.vr.mode" android:required="false" />
  <!-- Indicates use of VR features that are available only on official "VR-ready" devices -->
  <uses-feature android:name="android.software.vr.high_performance" android:required="false" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-feature android:name="android.hardware.vulkan" android:required="false" />
  <uses-feature android:name="android.hardware.gamepad" 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>

DAYDREAM

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.1" package="com.silicondroid.cmwo" android:installLocation="auto">
  <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner" android:theme="@style/VrActivityTheme">
    <activity android:label="@string/app_name" android:name="com.unity3d.player.UnityPlayerActivity" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" android:enableVrMode="@string/gvr_vr_mode_component" android:resizeableActivity="false">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
      <meta-data android:name="com.google.android.vr.icon" android:resource="@drawable/vr_icon_front" />
      <meta-data android:name="com.google.android.vr.icon_background" android:resource="@drawable/vr_icon_back" />
    </activity>
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:name="com.unity.purchasing.googleplay.PurchaseActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:name="com.unity.purchasing.googleplay.VRPurchaseActivity" android:theme="@style/VrActivityTheme">
      <intent-filter>
        <action android:name="com.google.vr.vrcore.ACTION_NONE" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <!-- For enableVrMode use the value vs. the string so Unity can build it. -->
    <activity android:configChanges="orientation|screenSize" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:exported="false" android:label="@string/app_name" android:name="com.google.gvr.keyboardsupport.TransitionVRActivity" android:resizeableActivity="false">
      <intent-filter>
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <!-- For enableVrMode use the value vs. the string so Unity can build it. -->
    <activity android:configChanges="orientation|screenSize" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:exported="false" android:label="@string/app_name" android:name="com.google.gvr.permissionsupport.TransitionVRActivity" android:theme="@android:style/Theme.Dialog">
      <intent-filter>
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
    <meta-data android:name="unity.build-id" android:value="727e1c15-b3d0-4dd1-ab43-d088edc91e26" />
    <meta-data android:name="unity.splash-mode" android:value="0" />
    <meta-data android:name="unity.splash-enable" android:value="False" />
    <meta-data android:name="android.max_aspect" android:value="2.1" />
  </application>
  <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="25" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="com.android.vending.BILLING" />
  <!-- Indicates use of Android's VR-mode, available only on Android N+ -->
  <uses-feature android:name="android.software.vr.mode" android:required="false" />
  <!-- Indicates use of VR features that are available only on official "VR-ready" devices -->
  <uses-feature android:name="android.software.vr.high_performance" android:required="false" />
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-feature android:name="android.hardware.vulkan" android:required="false" />
  <uses-feature android:name="android.hardware.gamepad" android:required="false" />
  <uses-feature android:name="android.hardware.vr.high_performance" />
  <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>

My oculus manifest has lots of daydream pollution in it, but currently I have imported the GoogleVR unity package and have it’s newer plugins in my project path, that may be causing this pollution (will investigate).

My daydream manifest seems OK.

It’s possible to over ride the unity generated manifest and supply our own, which could be a hand edited version of the auto generated one, so whatever happens, it’s possible to get correct manifests. But that’s really painful when it comes to future app updates, it’s better if unity just does the correct manifest. Simply select Oculus or Daydream in the XR list and build, that’s what we need.

EDIT: I built an oculus APK after removing the GoogleVR package imported plugins. I still have the unity included GoogleVR plugins, those supplied with unity under the hood.

Daydream pollution in Oculus manifest is reduced:
OCULUS2

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.1" package="com.silicondroid.cmwo" android:installLocation="auto">
  <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:theme="@style/UnityThemeSelector" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner">
    <activity android:label="@string/app_name" android:name="com.unity3d.player.UnityPlayerActivity" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density">
      <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>
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:name="com.unity.purchasing.googleplay.PurchaseActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:name="com.unity.purchasing.googleplay.VRPurchaseActivity" android:theme="@style/VrActivityTheme">
      <intent-filter>
        <action android:name="com.google.vr.vrcore.ACTION_NONE" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only" />
    <meta-data android:name="unity.build-id" android:value="2bd03ba5-55d8-479a-8ff8-544af6f07f41" />
    <meta-data android:name="unity.splash-mode" android:value="0" />
    <meta-data android:name="unity.splash-enable" android:value="False" />
    <meta-data android:name="android.max_aspect" android:value="2.1" />
  </application>
  <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="25" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="com.android.vending.BILLING" />
  <!-- Indicates use of Android's VR-mode, available only on Android N+ -->
  <uses-feature android:name="android.software.vr.mode" android:required="false" />
  <!-- Indicates use of VR features that are available only on official "VR-ready" devices -->
  <uses-feature android:name="android.software.vr.high_performance" android:required="false" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-feature android:name="android.hardware.vulkan" android:required="false" />
  <uses-feature android:name="android.hardware.gamepad" 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>

Daydream manifest smaller, less redundancy:
DAYDREAM2

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.1" package="com.silicondroid.cmwo" android:installLocation="auto">
  <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner" android:theme="@style/VrActivityTheme">
    <activity android:label="@string/app_name" android:name="com.unity3d.player.UnityPlayerActivity" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" android:enableVrMode="@string/gvr_vr_mode_component" android:resizeableActivity="false">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
      <meta-data android:name="com.google.android.vr.icon" android:resource="@drawable/vr_icon_front" />
      <meta-data android:name="com.google.android.vr.icon_background" android:resource="@drawable/vr_icon_back" />
    </activity>
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:name="com.unity.purchasing.googleplay.PurchaseActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
    <activity android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService" android:name="com.unity.purchasing.googleplay.VRPurchaseActivity" android:theme="@style/VrActivityTheme">
      <intent-filter>
        <action android:name="com.google.vr.vrcore.ACTION_NONE" />
        <category android:name="com.google.intent.category.DAYDREAM" />
      </intent-filter>
    </activity>
    <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
    <meta-data android:name="unity.build-id" android:value="f4e3550d-122c-46c4-a1e5-96f52d051a7d" />
    <meta-data android:name="unity.splash-mode" android:value="0" />
    <meta-data android:name="unity.splash-enable" android:value="False" />
    <meta-data android:name="android.max_aspect" android:value="2.1" />
  </application>
  <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="25" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="com.android.vending.BILLING" />
  <!-- Indicates use of Android's VR-mode, available only on Android N+ -->
  <uses-feature android:name="android.software.vr.mode" android:required="false" />
  <!-- Indicates use of VR features that are available only on official "VR-ready" devices -->
  <uses-feature android:name="android.software.vr.high_performance" android:required="false" />
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-feature android:name="android.hardware.vulkan" android:required="false" />
  <uses-feature android:name="android.hardware.gamepad" android:required="false" />
  <uses-feature android:name="android.hardware.vr.high_performance" />
  <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>

Again this is proving: Try not to import any VR plugins, use those bundled with unity. The unity manifest generator must search entire project directory tree for any plugins suitable for Android.

There will be some time in the future when we just write game using unity XR api and wont need to bother importing various SDKs, that will be cool. Until then we will have to muddle through ourselves.

1 Like

I had made a cross platform input plugin for both platforms that never got released because the daydream sales were a lot less than gear vr (tiny fraction, enough over it’s life where it wouldn’t justify support). In the end the daydream version was deprecated and the cross platform one I stopped work on, to concentrate on just the gear vr product.

The cross platform piece of it was complete and I tried a few things, but in the end what seemed to work the best was to do everything pre build. That way you had complete control over the pipeline and could change any settings, manifests, etc. that you wanted automatically. Basically, you’d just create a few entries in your own custom menu dropdown in the editor, one for “build gear vr” and one for “build daydream”. This would be the hook you need to do things pre build and then build. That way building for the various platforms is as simple as just selecting the right menu item, similar to how “build” and “build and run” are separate items. You could even extend this to 4 items one pair for debug builds and another pair for publishing builds.

Obviously there are many ways to approach it, but this worked best for me. It’s a shame daydream doesn’t seem to be gaining much traction, and with go around the corner, I’m not sure it’s going to get better. Hope it does though, it’s a nice platform (and I’ve played with them all). Lack of sales was one thing, but google seems to have a bad habit of introducing breaking changes in their API (happened once at 1.4 and again at 1.6). Eventually that will be mute when Unity inputtracking and VR camera options are complete but that’s a ways off.

1 Like

@SiliconDroid

What do you mean by this?

He meant it would be awesome if Unity’s auto generated manifest actually took into account the appropriate entries for daydream or gear vr based on which sdk’s were selected or at the top of your xr sdk list. That way you wouldn’t have to provide your own to use instead of the one Unity normally includes.