2016-12-09

Forcing a device-orientation per scene in Unity3D

Unity3D has a Screen class with an orientation property that allows you to force orientation in code, which lets you have different scenes with different orientations (useful in mini-games). this works fine for Android but crashes on iOS.
The problem is the file UnityViewControllerBaseiOS.mm that gets generated during the build for iOS has an assert in it which inadvertently prevents this property from being used. It is possible to create a post-build class that runs after the iOS build files have been generated that can alter the generated code before you compile it in XCode.
Just create a C# script named iOSScreenOrientationFix.cs and paste in the following code - adapted from this Unity3D forum post.
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;

namespace Holovis
{
    public class iOSScreenOrientationFix : MonoBehaviour
    {
#if UNITY_CLOUD_BUILD
    // This method is added in the Advanced Features Settings on UCB
    // PostBuildProcessor.OnPostprocessBuildiOS
    public static void OnPostprocessBuildiOS (string exportPath)
    {
        Debug.Log("OnPostprocessBuildiOS");
        ProcessPostBuild(BuildTarget.iPhone,exportPath);
    }
#endif

        [PostProcessBuild]
        public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
        {
#if !UNITY_CLOUD_BUILD
            ProcessPostBuild(buildTarget, path);
#endif
        }

        private static void ProcessPostBuild(BuildTarget buildTarget, string path)
        {
            if (buildTarget == BuildTarget.iOS)
            {
#if !UNITY_CLOUD_BUILD
                Debug.Log("Patching iOS to allow setting orientation");
#endif
                string filePath = Path.Combine(path, "Classes");
                filePath = Path.Combine(filePath, "UI");
                filePath = Path.Combine(filePath, "UnityViewControllerBaseiOS.mm");

                Debug.Log("File Path for View Controller Class: " + filePath);

                string classFile = File.ReadAllText(filePath);

                string newClassFile = classFile.Replace("NSAssert(UnityShouldAutorotate()", "//NSAssert(UnityShouldAutorotate()");

                File.WriteAllText(filePath, newClassFile);
            }
        }
    }
}
You can set it in a scene by attaching the following MonoBehaviour to a game object
using UnityEngine;

namespace Holovis
{
    public class SetDeviceOrientation : MonoBehaviour
    {
        public ScreenOrientation orientation = ScreenOrientation.AutoRotation;

        void Awake()
        {
            Screen.orientation = orientation;
        }
    }
}

No comments: