1. Introduction
In this codelab, you will learn how to optimize a Unity Android game for large screen and foldable devices. You will use the Lost Crypt sample project to implement aspect ratio support, expand full screen utilization, and respond to foldable states.
Prerequisites
- Basic understanding of Unity and Android development.
- Large screen Android devices like tablets or foldable phones.
What you learn
- How to implement support for various aspect ratios.
- How to use anchors in your game's UI and camera settings to automatically adjust to the screen size.
- How to use Android's Jetpack Window Manager to detect the device's folding posture and adjust layout.
What you need
- Unity Hub and Editor: Unity 2020 LTS or Unity 2022 installed, with Android build support.
- Hardware: Large screen Android devices like tablets or foldable phones.
- Agentic development platform such as Google Antigravity if you plan to to use the skill.
2. Agent Skill
Optionally, an agent skill is available to evaluate your Unity game project. This skill helps you add support for resizability and support for large screen and foldable devices. For more information, see: GitHub
To use this skill:
- Copy the SKILL.md file to your agent directory. For more information about how to add a skill, see Getting Started with Google Antigravity.
- Prompt your agent in your Agentic IDE, such as Antigravity, with questions about large screens, foldables, or resizability.
- Ask the agent to add support for large screens and foldables.
3. Aspect Ratio Support
To ensure your game appears correctly across different screen sizes, start by implementing support for various aspect ratios. You might consider adjusting the camera or canvas aspect ratio to better fit different screens.
- Ensure your application utilizes the full screen resizable setting.
- In your
AndroidManifest.xml(located atAssets/Plugins/Android/AndroidManifest.xml):- Set
android:resizeableActivity="true". - Set
android:screenOrientation="fullSensor".
- Set
For example:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unity3d.player"
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity android:name="com.unity.lostcryptlargescreenexample.LargeScreenPlayableActivity"
android:theme="@style/UnityThemeSelector"
android:screenOrientation="fullSensor"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
android:hardwareAccelerated="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>
</manifest>
- Check your Build Settings in Unity for Android platform configurations.
Note: Supporting various aspect ratios is the first step to making your game look great on tablets and foldables.
4. Full Screen Utilization
After adapting to different aspect ratios, ensure your game uses the entire screen to make gameplay more immersive.
To use the entire screen:
- Use anchors in your game's UI and camera settings. This lets UI elements automatically adjust their positions relative to the screen size.
- Open the Anchoring scene in the example project to see how UI canvas anchoring is set up.
- In the Anchoring scene, the canvas is updated to be safe-frame aware, and the movement controls are anchored to the corners of the screen.
To maintain the aspect ratio for your main camera, dynamically adjust the camera's pixelRect. The CameraAspectLock.cs script demonstrates how to respond to orientation changes and letterbox the camera view:
[SerializeField]
private float minAspectRatio = 4f / 3f;
[SerializeField]
private float maxAspectRatio = 21f / 9f;
public void MaintainAspectRatio() {
int viewWidth = Display.main.systemWidth;
int viewHeight = Display.main.systemHeight;
// 1. Calculate screen aspect ratio
float scaleScreen = viewWidth / (float)viewHeight;
Rect rect = _camera.pixelRect;
// 2. Scale to the fullest of the lower between width or height
if (scaleScreen > maxAspectRatio) {
// use height, lock width to max at aspect scale
rect.width = viewHeight * maxAspectRatio;
rect.height = viewHeight;
} else if (scaleScreen < minAspectRatio) {
// use width, lock height to min at aspect scale
rect.width = viewWidth;
rect.height = viewWidth / minAspectRatio;
} else {
// within allowed aspect ratio range, use full screen
rect.width = viewWidth;
rect.height = viewHeight;
}
// make sure to center the rect within the window
rect.x = Mathf.Floor((viewWidth - rect.width) * 0.5f);
rect.y = Mathf.Floor((viewHeight - rect.height) * 0.5f);
Debug.Log("camera view width = " + rect.width +
" height = " + rect.height +
" x = " + rect.x +
" y = " + rect.y);
// 3. Commit the new size to the camera so that it takes effect
_camera.pixelRect = rect;
}
5. Foldable devices support
With foldable devices, you should adjust your game's layout based on the device's folding posture (For example, HALF_OPENED, FLAT) and screen size on the fly.
- Use Android's Jetpack Window Manager to detect the device's state.
- In the example project, open the HingeAware scene.
- This scene contains a
ConfigurationManagerMonoBehaviour which bridges Android's Jetpack WindowManager events to Unity and responds to folding states viaUnityEventcallbacks. - The
HingeSensor.csreads the hinge angle using thecom.unity.lostcryptlargescreenexample.HingeAngleSensorJava plugin.
Using ConfigurationManager
ConfigurationManager.cs communicates with a custom Android activity and parses JSON strings representing the state. It listens for onConfigurationChanged and onFoldChanged callbacks from the Android Activity.
[System.Serializable]
public class FoldInfo {
public string orientation;
public string state;
public int isSeparating;
public int boundsLeft;
public int boundsTop;
public int boundsRight;
public int boundsBottom;
}
public void onFoldChanged(string strFoldInfo) {
FoldInfo info = JsonUtility.FromJson<FoldInfo>(strFoldInfo);
// Always call the refresh from the main Unity thread
StartCoroutine(ExecuteOnMainUnityThread(ActionOnFoldChange, info));
}
You can also query the state synchronously using the getFoldableState property:
public static string getFoldableState {
get {
if (Application.platform == RuntimePlatform.Android) {
var foldingFeatureObject = foldablePlayerActivity.Call<AndroidJavaObject>("getFoldingFeature");
if (foldingFeatureObject != null) {
var state = foldingFeatureObject.Call<AndroidJavaObject>("getState");
return state.Call<string>("toString");
}
}
return "NONE";
}
}
6. Utilize the HingeSensor
Some foldable devices have a physical hinge sensor that provides the exact angle of the fold (0 to 360 degrees). You can use this to drive gameplay mechanics or adjust the camera.
In HingeSensor.cs, an Android plugin is initialized to read the hardware sensor. You can also check if the hinge is enabled:
public class HingeSensor : IDisposable {
AndroidJavaObject plugin;
public static HingeSensor Start() {
if (Application.platform == RuntimePlatform.Android) {
return OnPlayer.Run(p => {
var context = p.GetStatic<AndroidJavaObject>("currentActivity");
var plugin = new AndroidJavaClass("com.unity.lostcryptlargescreenexample.HingeAngleSensor")
.CallStatic<AndroidJavaObject>("getInstance", context);
if (plugin != null) {
plugin.Call("setupSensor");
return new HingeSensor(plugin);
}
return null;
});
}
return null;
}
public float GetHingeAngle() {
return (Application.platform == RuntimePlatform.Android && plugin != null) ? plugin.Call<float>("getHingeAngle") : -1.0f;
}
public bool IsHingeEnabled() {
return Application.platform == RuntimePlatform.Android && plugin != null && plugin.Call<int>("isHingeEnabled") > 0;
}
}
Note: Make sure to call Dispose() or StopSensing() on your HingeSensor instance when your application pauses or is destroyed to prevent battery drain.
7. Create an AAB file
To create an AAB file in Unity Editor, follow these steps:
- In the Unity Editor, click File > Build settings.
- Select Build App Bundle ( Google Play ).For more information, see Android Build Settings reference.
- Click Build.
- Download the AAB file from the Unity Editor.
Create an internal testing release
To create an internal testing release and add testers in Play Console, perform the following steps:
- In the Google Play Console, select a game.
- Navigate to the Test and release page (Testing > Internal testing).
- Click Upload and select the AAB file.
- In the Release details field, enter a name.
- Click Next and review the release details.
- Click Save and publish.
8. Build and run the project
Now you are ready to build the project and test it on your device.
- Make sure you have the game open.
- In the Play Console, go to File > Build Profile (or Build Settings).
- Ensure Build App Bundle (Google Play) is checked if you want to upload to Play Console, or click Build and Run to deploy directly to your connected device.
- Verify the foldable devices, you should adjust your game's layout based on the device's folding posture (For example, HALF_OPENED, FLAT) and screen size on the fly.
9. Congratulations
You have successfully learned the principles of adapting a Unity Android game for large screens and foldables!
Survey
Your feedback on this codelab is highly valued. Consider taking a few minutes to complete our survey.