Develop games for all screens

When developing a game for Android, it's important to anticipate the variety of possible player experiences and remain adaptive to a player's real-time interaction needs. By supporting different player experiences, you increase gameplay flexibility, helping you expand your game's reach.

Specific differences in player experience include the following:

  • Device form factors: Although phones provide the traditional Android device experience, it's possible to interact with games on other form factors. ChromeOS devices can run an Android container that displays your game. Tablets that can run Android support several different levels of fidelity. Android TV devices support more detail-rich and more immersive experiences. Players can simulate a multi-window environment by using a display extension tool. And when using foldables, players can change the size of the screen during a gameplay session.
  • Interaction methods: Players can provide input by touching a device's screen, but they can also use a mouse, touchpad, keyboard, or controller instead. In addition, the availability of display extension tools and foldable devices allows players to experience your game on a larger screen, making longer gameplay sessions and more complex interfaces more feasible.
  • Hardware support: Some Android-powered devices don't have hardware that is more typical in a handheld device, such as a rear-facing camera, a GPS, and network connectivity. Your game should adapt to the hardware that's available and gracefully handle situations where certain features aren't available.

This guide presents best practices related to developing your game for different types of screens and user interactions. This guide also provides suggestions on designing your game and developing an effective testing strategy.

Game design best practices

When planning your game's design and architecture, follow the best practices described in the following sections.

Respond to configuration changes manually

When the Android system detects a configuration change, such as a change in screen size, screen orientation, or input method, the system by default restarts the current activity. To preserve state within an app or game, the activity by default calls onSaveInstanceState() before it restarts and onRestoreInstanceState() after it restarts. This process, however, requires the activity to reload all associated services and resources. To learn more about this default behavior, see the guide on handling configuration changes.

A typical gameplay session undergoes several configuration changes. If your game lets the system handle each configuration change, your game's scene is destroyed and restarted over and over, reducing your game's performance. For this reason, we highly encourage you to handle these configuration changes yourself in your game.

To learn how to add this configuration change logic to your game, see the section on how to create custom configuration change handlers.

Create a flexible architecture

To add support for your game on as many devices as possible, follow these best practices:

  • Deploy Android App Bundles instead of individual APKs. Android App Bundles allow you to package artifacts of different resolutions and different architecture models, such as x86, ARM, into a single artifact. Better still, Android App Bundles support higher size limits for your game; each base APK can be as large as 150 MB, and the bundle itself can be many gigabytes in size.
  • Add support for x86 architectures. This step improves your game's performance on devices that don't support ARM, because these devices can now execute instructions without having to translate them first.

Add support for Vulkan

By supporting Vulkan, your game can achieve higher graphics performance. Most devices support this graphics API.

Create custom configuration change handlers

To declare the types of configuration changes that your game handles itself, add the android:configChanges attribute to each <activity> element in your manifest that represents a screen or complex interface.

The following code snippet demonstrates how to declare that your game takes care of screen size, screen orientation, and input method changes:

<activity ...
    android:configChanges="screenSize|orientation|keyboard|keyboardHidden">
</activity>

When the declared configuration changes occur, the system now invokes a different method, onConfigurationChanged(). Within this method, add logic to update your game's UI:

  • Update the scale factor and orientation of the screen. Keep in mind that, for performance purposes, it's sometimes better to scale your game's UI along only one dimension.
  • Identify the optimal input method for the player to use.

Handle screen configuration changes

Your game handles screen size and screen orientation changes manually whenever you include the screenSize and orientation values, respectively, in an android:configChanges attribute. You can use these new values to update your scene's content and player input areas. For guidance on how to design your game's layout to make it easier to update, see the guide on supporting different screen sizes.

In your game's implementation of onConfigurationChanged(), use the passed-in Configuration object and the window manager's Display object to determine the updated values for screen size and screen orientation, respectively.

The following code snippet shows how to obtain your game's updated screen size and orientation:

Kotlin

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    val density: Float = resources.displayMetrics.density
    val newScreenWidthPixels = (newConfig.screenWidthDp * density).toInt()
    val newScreenHeightPixels = (newConfig.screenHeightDp * density).toInt()

    // Get general orientation; either Configuration.ORIENTATION_PORTRAIT or
    // Configuration.ORIENTATION_LANDSCAPE.
    val newScreenOrientation: Int = newConfig.orientation

    // Get general rotation; one of: ROTATION_0, ROTATION_90, ROTATION_180,
    // or ROTATION_270.
    val newScreenRotation: Int = windowManager.defaultDisplay.rotation
}

Java

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    float density = getResources().getDisplayMetrics().density;
    int newScreenWidthPixels = (int) (newConfig.screenWidthDp * density);
    int newScreenHeightPixels = (int) (newConfig.screenHeightDp * density);

    // Get general orientation; either Configuration.ORIENTATION_PORTRAIT or
    // Configuration.ORIENTATION_LANDSCAPE.
    int newScreenOrientation = newConfig.orientation;

    // Get general rotation; one of: ROTATION_0, ROTATION_90, ROTATION_180,
    // or ROTATION_270.
    int newScreenRotation = getWindowManager().getDefaultDisplay()
            .getRotation();
}

Note that changing the pose of a foldable device changes the configuration, even if your app runs in fullscreen mode. As a result, your app might have to handle changes to screen size or pixel density if the user folds or unfolds the device while your game is running.

Game-specific screen qualities

The following sections describe how to adjust how your game reacts to screen size or screen orientation changes, depending on your game's qualities:

Fullscreen mode

On some platforms, such as ChromeOS, Android apps and games can be windowed and resizeable by default. If your game should always run in fullscreen mode, you can set the android:resizeableActivity attribute to false in one of your <activity> elements, as shown in the following code snippet:

<activity ...
    android:resizeableActivity="false">
</activity>

You can also set android:resizeableActivity attribute to false to prevent size-based configuration changes from occurring. Unless your game always runs in fullscreen mode, however, you should add this attribute only as a temporary fix for testing purposes.

Screen orientation

If your game depends on a device's sensors having a specific orientation, specify a value for android:screenOrientation in your game's activity, as shown in the following code snippet. This setting helps prevent a scene in your game from flipping upside down unexpectedly.

<activity ...
    android:screenOrientation="landscape">
</activity>

Device-specific screen qualities

The following sections describe how to handle screen-based configuration changes given specific qualities that some devices have.

Aspect ratio

Some devices support different aspect ratios. For example, foldable devices are designed to support an aspect ratio of 21:9 when in the folded state. To handle this potential variety in aspect ratio, do at least one of the following:

  • Target Android 8.0 (API level 26) or higher.
  • Make your game's scene and interface resizeable. Set android:resizeableActivity to true on devices running Android 7.0 (API level 24) and higher.
  • Declare a maximum supported aspect ratio. In a <meta-data> attribute associated with your game, set android.max_aspect to 2.4, as shown in the following code snippet. Keep in mind, however, that aspect ratios larger than the one you've specified cause the game to appear letterboxed within a display.

    <application>
    <meta-data android:name="android.max_aspect"
               android:value="2.4" />
    </application>

Multiple activities visible simultaneously

Many modern devices support a variety of screen layouts, including split-screen, picture-in-picture, and large display areas. When using one of these layouts, the system can make multiple activities visible at the same time.

On devices running Android 9 (API level 28) or higher, it's possible for all top visible activities to be resumed at the same time. In order for this behavior to work, however, both your game and the device's OEM need to opt into the functionality. You can add support within your game by setting android.allow_multiple_resumed_activities to true in your game's manifest, as shown in the following snippet:

<application>
    <meta-data android:name="android.allow_multiple_resumed_activities"
               android:value="true" />
</application>

You can then test your game on different devices to see which of them provide the OEM support necessary for multi-resume to function properly.

For more information on configuring your game to appear as part of a multi-window display, see the guide on how to add multi-window support.

Handle different types of interaction models

Your game handles keyboard presence and keyboard availability manually whenever you include the keyboard and keyboardHidden values, respectively, in an android:configChanges attribute. You can use these new values to update your game's primary input method.

When configuring your game for supporting multiple types of user input, keep the following in mind:

  • Detect input methods rather than individual devices. This mindset makes it easier to improve the player experience without focusing too much on the specific device that the player might have.
  • Include the keyboardHidden attribute in your list of manually-handled configuration changes. That way, your game can keep track of when a keyboard is physically attached to the device but unusable.
  • Determine input methods that are currently available. To do so, call getInputDeviceIds() on game startup and after each configuration change.

    You can often determine how the player plans to interact with your game based on their preferred input device:

    • Players typically use a keyboard or game controller to perform rapid button sequences.
    • Players typically use a touchscreen or touchpad to perform more complex gestures.
    • Players typically use a mouse to perform higher-precision input.

The following sections provide best practices for specific types of input devices.

Keyboard

When creating a keyboard layout for your game, consider how the player navigates through a given scene as well as how they interact with your game's settings.

The WASD keys or arrow keys are usually best for controlling character movement. It's also best to assign a particular key for each important action or skill that a controllable character can perform within your game. To maximize the player experience, consider adding support for custom key bindings in your game.

Players should also be able to open your game's menus and navigate through them using the keyboard. The Esc key is a common mapping for pausing a scene and showing the game's menu.

For more information on supporting keyboard input in your game, see the guide on how to support keyboard navigation as well as the guide on how to handle keyboard actions.

Game controller

For more information on handling controller input in your game, see the guide on how to support game controllers.

Mouse or touchpad

If your game supports player input from a mouse or touchpad, keep in mind that players interact with the device in ways other than playing your game. It's important to be aware that, by requesting pointer capture, all mouse input is directed to your game. Therefore, after your game has the information it needs, release pointer capture so that players regain standard mouse control of their device.

On devices running Android 8.0 (API level 26) and higher, you can use the Mouse Capture API to assist with the pointer capture process. In games that react to high-precision input, you can get the pointer's current coordinates by calling the getX() and getY() methods.

For additional information on adding support for mouse input and touchpad input in your game, see the guide on how to track touch and pointer movements as well as the guide on how to handle multi-touch gestures.

Test your game

Before launching your game, test how it responds to configuration changes by completing the steps described in the following sections.

Update your test plan

When validating your game's functionality, include the following test cases:

  • Minimize and maximize the window that contains your game. (Doesn't apply if your game is always in fullscreen mode.)
  • Change screen size.
  • Change screen orientation. (Doesn't apply if your game has a fixed orientation.)
  • Connect and disconnect input devices, such as keyboards and mice.
  • Perform multi-resume, if your game supports it.

Also, consider updating your game's quality control system so that you can optimize for a wider variety of player experiences.

For best practices related to testing your game, see the Fundamentals of Testing guide.

Use testing and debugging tools

You can perform tests using a variety of tools that the platform supports: