I was working recently on a GoogleVR Cardboard project where they printed their own custom Cardboard headsets and bulk mailed them out to invited guests.
As you may or may not know, each Google cardboard physcial headset could be manufactured with different specifications but still obtain the “”Works with Google Cardboard” compatibility via a custom profile (with specs embedded into a URL and QR Code) using the Viewer Profile Generator. This profile can be scanned in by the user in the Cardboard app to set the correct viewer settings.
If the user has not paired a hardware Cardboard Viewer with your app (using the settings QR Code scanner) then you can set the default to be a different viewer – and that default will stay in effect unless the user decides to scan in a different one.
Note: GoogleVR Cardboard stores the viewer linked to the provisioning profile of your app, so if you re-install the app the pairing will still be valid. If you want to specifically lose that pairing you will need to change your provisioning profile (a bundle id change is not enough).
To set the default profile you will need to install the GoogleVR Cardboard SDK for Unity. You have to do this because the generic VR settings in Unity do not have a concept of profiles. When you use the GoogleVR Cardboard SDK it will communicate directly to the cardboard native library that Unity has embedded in it.
For full details, watch my tutorial video:
In SDK we want:
GvrCardboardHelpers.SetViewerProfile(profileURI)
Broken on GVR Unity SDK v1.60
Important Note: This method is currently broken in GVR Unity SDK v1.60.0 (Jun 7, 2017). Please follow this work-around to fix it:
Pull Request #622: GvrSettings and GvrCardboardHelpers on ios should use [DllImport(“__Internal”)]
SetViewerProfile SDK method
Lets create a c# script to set the default profile URI. SetupCardboard.cs:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.VR; public class SetupCardboard : MonoBehaviour { public string CardboardProfileUri; void Awake () { if (VRSettings.loadedDeviceName == "cardboard") { GvrCardboardHelpers.SetViewerProfile (CardboardProfileUri); } } }
Add that script to a game object in the scene and build your app.
On that component, enter a URI for CardboardProfileUri property. eg:
URI for 2015 Cardboard Viewer V2
http://google.com/cardboard/cfg?p=CgZHb29nbGUSEkNhcmRib2FyZCBJL08gMjAxNR0rGBU9JQHegj0qEAAASEIAAEhCAABIQgAASEJYADUpXA89OggeZnc-Ej6aPlAAYAM
If the user has not already paired a viewer with your app then the app will now be pre-configured for the viewer you setup.
If you have your own viewer profile called “My Viewer” then it will appear like this:
A useful full list of QRCodes for Google Cardboard headsets is here:
LIST OF VR HEADSET QR CODES
Only call when Cardboard is enabled
An important gotcha is you can’t make this call when Cardboard is not the currently enabled VR module in Unity.
The reason is that SetViewerProfile() obtains an internal pointer to the native code library via VRDevice.GetNativePtr() and there is not checking around which module that is getting the pointer on. So if your current VR module is set to “None” or some other one, then the call will attempt to use an invalid pointer and your app will crash or do something unexpected.
Checking if the default was applied
The method SetViewerProfile() returns void, but internally the SDK function returns a boolean, which will be True if it changed the device to the one you requested, otherwise False (if the user already was paired to a device). I verified this works, by changing the void return type to bool and making sure the call in the DLLImport returns the result.
This is useful if you do want to know if they user has paired or not.
Getting the profile (aka cfg url)
So above I fed in a URI into CardboardProfileUri(). Just how did I get that URI? You probably just have a fancy QR Code.
To get your config URI, here are the steps I used:
1. Download a copy of your QR Code
2. Decode it by upload it to https://zxing.org/w/decode.jspx
3. You’ll get a parsed result, such as: https://goo.gl/4JRn3b
4. We want to go to that URL *BUT* not in a web browser (which redirects to a fancy user page), instead, use a command line tool such as curl. So open up terminal and enter:
$ curl https://goo.gl/4JRn3b
5 Examine the response and it will contain the cfg URI
eg:
<HTML> <HEAD> <TITLE>Moved Permanently</TITLE> </HEAD> <BODY BGCOLOR="#FFFFFF" TEXT="#000000"> <H1>Moved Permanently</H1> The document has moved <A HREF="http://google.com/cardboard/cfg?p=CglBZHNoZWwgVlISAB0xCCw9JbgehT0qEAAASEIAAEhCAABIQgAASEJYADXjpRs9OgjNzEw-mpmZP1AAYAA">here</A>. </BODY> </HTML> 6. Copy the URL from that and use it in your profile setup!
March 15, 2018 at 2:57 am
Hi Peter,
This guide has been very helpful to me, thank you. I managed to reproduce everything here to make this work for iOS.
Have you tried the same steps for an Android build? I can’t seem to have any luck there. I figure the Android VR Settings strong-arm the viewer choice or something similar, but I’m not entirely sure.
Would you have any pointers?
Cheers
February 20, 2019 at 11:55 am
Hi Peter,
It worked perfectly for me when I follow your post, thank you. But I have a problem, for example:
1. My default viewer is viewer A.
2. Switch to another viewer (viewer B) of cardboard.
2. Uninstall app on my device.
3. Reinstall app on my device.
=> Then the previous profile (viewer B) is loaded.
Can I force my default viewer (viewer A) when I uninstall app on device ?
Thank you so much.