Developer Console

Developing for Amazon Fire TV Devices Running Android 14

Android 14-based Fire TV is based on API level 34. The following sections explain some of important changes that you should consider when you build apps for Android 14-based Fire TV. The migration to standard Android components in the following sections will help reduce the risk of compatibility issues and provide ease of maintenance for your app.

Devices that run Android 14-based Fire TV and previous Fire OS versions

Android 14-based Fire TV incorporates updates from Android 12 (API 31), Android 12L (API 32), Android 13 (API 33), and Android 14 (API 34). Some older Fire TV devices remain on earlier versions of Fire OS.

For a detailed list of Fire TV devices and versions, see Fire OS Versions.

Android updates

See the following topics to learn about important updates through Android 14:

PendingIntent mutability flag

Before the Android 12 release, you could assume PendingIntent is mutable by default unless you set FLAG_IMMUTABLE. Starting with Android 12, you are required to explicitly specify the mutability of PendingIntent when you create it with FLAG_IMMUTABLE or FLAG_MUTABLE.

Solution

Use FLAG_IMMUTABLE when you create a PendingIntent and only use FLAG_MUTABLE when some functionality relies on modifying the underlying intent. The following example shows how to apply FLAG_MUTABLE to a PendingIntent that you need to use with inline reply or bubbles.

Copied to clipboard.


PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_MUTABLE);

Copied to clipboard.


val pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_MUTABLE)


Here is some sample code for a mutability flag.

Here's what you might have used in the past.

Copied to clipboard.

PendingIntent pendingIntent =
        PendingIntent.getBroadcast(
            context,
            requestCode,
            intent, 
            /* flags= */ 0);

Copied to clipboard.

val pendingIntent =
      PendingIntent.getBroadcast(
          context,
          requestCode,
          intent,
          /* flags= */ 0)

Here's what an updated code sample may look like.

Copied to clipboard.

PendingIntent pendingIntent =
        PendingIntent.getBroadcast(
            context,
            requestCode,
            intent, 
            /* flags= */ PendingIntent.FLAG_MUTABLE);

Copied to clipboard.

val pendingIntent =
      PendingIntent.getBroadcast(
          context,
          requestCode,
          intent,
          /* flags= */ PendingIntent.FLAG_MUTABLE)

For more details, see FLAG_IMMUTABLE and PendingIntent.

Safer component export intent

Starting with Android 12, if an app uses the <intent-filter> element on its activities, services, or broadcast receivers, you must have an explicit attribute declaration (android:exported) on the manifest file to declare that the activity can be accessed by any app. If apps don’t have a value set for android:exported, they can't be installed on a Android 14-based Fire TV device. To comply with these new guidelines, update your app's AndroidManifest.xml file with the following attribute declaration.

Copied to clipboard.

<activity android:name="ShareActivity" android:exported="false">

If you set the declaration to true, any app can access the activity and launch it by its exact class name. If you set the declaration to false, only components of the same app, apps with the same user ID, or privileged system components can launch the activity.

Additionally, starting with Android 14, any apps you target to API 34 must also specify the RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flags for context-registered receivers. Without RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED flags, the apps will crash at runtime.

Solution

You can prevent a crash at runtime by updating all calls to Context.registerReceiver to include these flags.

For more details, see Receiving an implicit intent and Runtime-registered broadcasts receivers must specify export behavior.

targetSdkVersion constraints

For apps with targetSdkVersion between 23 and 27, the user sees a onetime compatibility warning. Although the user can dismiss the warning and the app continues to run, this results in a degraded experience for the user. If you submitted or updated your app after April 1, 2022, and it is already available on Fire OS 7 (or later), the targetSdkVersion is already be above 27.

Starting with Android 14, users can't install apps that have a targetSdkVersion lower than 23. The requirement to meet this minimum target API level improves security and privacy for users.

For more details, see Ensure compatibility with Android 14.

DEX files - uplevel

If you encounter the "Writable dex file is not allowed" error while developing your Android app, it's likely due to compatibility issues with the latest version of the Android operating system.

This error typically occurs when the dex files (compiled code files in Android apps) have their permissions set to writable. In Android 14, Android introduced more strict security measures that prevent apps from having writable dex files, since it poses a potential security risk.

Follow Android's recommendations. The latest version of Android Studio will also help you detect this issue.

Error log example

08-21 01:43:58.189  8222  8554 E AndroidRuntime: java.lang.SecurityException: Writable dex file '/data/user/0/com.kptv.ott/cache/1664557424545.jar' is not allowed.

Toast usage

When migrating apps to Android 14, the following runtime exception may occur when using Toast.

Caused by: java.lang.IllegalStateException: Text provided for custom toast, remove previous setView() calls if you want a text toast instead.

In previous versions of Android, it was possible to set both a custom view and text on the same Toast. Android 14 enforces a stricter separation, so you can either display a text-based Toast or a custom view, but not both simultaneously. IllegalStateException appears when attempting to use both methods.

Solution

Use a Text-Only Toast to avoid the IllegalStateException in Android 14.

Bluetooth permissions

The updated Bluetooth permissions is designed to enhance user privacy and provide a more streamlined Bluetooth connection experience. Now an issue arises when attempting to retrieve the Bluetooth name or establish a Bluetooth connection, which results in the following error logs.

java.lang.SecurityException: Settings key: <bluetooth_name> is only readable to apps with targetSdkVersion lower than or equal to: 31
08-20 11:34:26.175 10079 10152 W cr_media: BLUETOOTH_CONNECT permission is missing.08-20 11:34:26.189 10079 10152 W cr_media: registerBluetoothIntentsIfNeeded: Requires BLUETOOTH permission

Solution

To address this issue, update your app's Bluetooth permission declarations in the manifest file to align with the latest Android guidelines. If your app targets Android 12 (API level 31) or higher, declare the following permissions.

  1. BLUETOOTH_SCAN: If your app looks for Bluetooth devices, such as BLE peripherals.
  2. BLUETOOTH_ADVERTISE: If your app makes the current device discoverable to other Bluetooth devices.
  3. BLUETOOTH_CONNECT: If your app communicates with already-paired Bluetooth devices.

For more information, see Bluetooth permissions.

Foreground services

The issue manifests as a java.lang.SecurityException when attempting to start a foreground service without the necessary permission:

java.lang.SecurityException: Permission Denial: startForeground from pid=1824, uid=10479 requires android.permission.FOREGROUND_SERVICE

Solution

Android 9 introduced the FOREGROUND_SERVICE permission. Apps running on Android 9 or above that use foreground services must include that permission.

If apps that target Android 14 use a foreground service, they must declare a specific permission based on the foreground service type. See Foreground service types are required to select what's appropriate for your use case.

To see all the changes to the foreground service across API levels, see Changes to foreground services.

Updating the Exoplayer version

There are video fluidity issues with Exoplayer 2.x versions, resulting in a degraded experience for the user.

Solution

Follow the steps mentioned in the AndroidX Media3 migration guide to update your app’s ExoPlayer to Media3 and force the DefaultRenderersFactory component to MediaCodec asynchronous queueing.

Alarm Scheduling

The SCHEDULE_EXACT_ALARM permission is a security-sensitive permission introduced in Android 12 (API level 31) to allow apps to schedule exact alarms. This permission has changed in recent Android versions.

Solution

Declare the permissions in your app's manifest file with something like this.

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />

However, in Android 14 (API level 34), the SCHEDULE_EXACT_ALARM permission is no longer granted by default, even if your app declares it in the manifest file. This means you need to check if the permission is granted at runtime and request it from the user if it's not.

Check and request the SCHEDULE_EXACT_ALARM permission in your app using the following.

Copied to clipboard.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    AlarmManager alarmManager = ContextCompat.getSystemService(context, AlarmManager.class);
    if (alarmManager != null && !alarmManager.canScheduleExactAlarms()) {
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
        context.startActivity(intent);
    }
}

Copied to clipboard.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    val alarmManager = ContextCompat.getSystemService(context, AlarmManager::class.java)
    if (alarmManager?.canScheduleExactAlarms() == false) {
        Intent().also { intent ->
            intent.action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
            context.startActivity(intent)
        }
    }
}

Evaluate your use cases and determine if exact alarms are needed. For more information, see Use cases that might not require exact alarms.

Package visibility filtering

Android 11 made changes to package visibility when making intents to other apps. When an app targets Android 11 (API level 30) or higher and queries for information about the other installed apps on a device, the system filters this information by default. This causes the intent to fail silently, with no error shown.

Solution

Some packages are visible automatically, so your app can automatically detect visible packages in its queries for other installed apps. To view other packages, declare your app's need for increased package visibility using the <queries> element. For more information, see Package visibility filtering on Android.

Amazon SDKs

If you depend on Amazon SDKs, you need to update your apps AndroidManifest.xml file and replace the amazon:enable-feature element with uses-library. This change is backward compatible with previous Fire OS versions.

The following example is for Amazon Device Messaging (ADM).

<uses-library
    android:name="com.amazon.device.messaging"
android:required="false"/>

For more details, see Integrate Your App.

64-bit compatibility

To avoid a warning that your 32-bit app is not compatible with the latest Android version, make sure to add 64-bit support.

For more details, see Support 64-bit architectures.

Target your app for Android 14-based Fire TV devices

Users might run your app on a Fire OS 5, Fire OS 6, Fire OS 7, Fire OS 8, or Android 14-based Fire TV. To maximize your app’s compatibility with the Fire OS version on the device, Amazon recommends that you target the device based on the SDK level.

In your code, you can check whether Build.VERSION.SDK_INT is greater than or equal to 34 (Android 14 API level) to target Android 14-based Fire TV devices.

For more details, see Supporting Different Platform Versions.

Test your app

In order to test your app, see Understanding Live App Testing

What to set for minSdkVersion and targetSdkVersion

Set targetSdkVersion to the highest API level that you're targeting. For Android 14-based Fire TV, Amazon recommends that you set targetSdkVersion for 34. You can still support older devices by setting minSdkVersion to the API level you want.

The following table shows the API level based on the Fire OS version.

Fire OS Version API Level
Fire OS 5 22
Fire OS 7 28
Fire OS 8 30
Android 14-based Fire TV 34

For more details, see Device Filtering and Compatibility.

How minSdkVersion affects supported devices and backwards compatibility

In your app manifest (or build.gradle file), minSdkVersion sets the minimum SDK level that your app needs in order to function properly. Devices that don't support that API level prevent users from installing the app on that device — this is how device filtering and compatibility works with the Appstore.

Fire OS 5 devices are based on API level 22 (Lollipop 5.1). Android 14-based Fire TV devices are based on API level 34 (Android 14). When you set minSdkVersion to 22, you've decided that your app requires the device to have at least API level 22 for it to function properly.

When you set minSdkVersion to 22, your app also installs on any devices that have a higher API level (such as 34), because Android levels are backwards-compatible. API level 34 usually includes all the APIs for levels 1 through 34. Each release adds an API level to the previous levels.

However, suppose you want to take advantage of APIs in Android 14 (API level 34). If you set minSdkVersion to 22, your app installs on Fire OS 5 devices that don't have level 34 APIs. Therefore, you must code in a defensive way to check the device API level and fall back to alternatives if the device doesn't support that API level. Your code might look like the following code example.

if (Build.VERSION.SDK_INT >= 34) {
 Log.v(TAG, "Yes, this is an API level 34 or higher device");
} else {
 Log.v(TAG, "No, this is not an API level 34 or higher device");
}

In the previous example, the code checks whether the device's API level is greater than or equal to 34, and if so, runs the code. If not, the code falls back on the else logic.

By default, if targetSdkVersion is not specified, Android uses the same value as minSdkVersion. Specifically, targetSdkVersion lets you set the latest API level that you have tested your app against. Based on this value, Android will ensure proper behavior on devices at this level.

For example, if you set targetSdkVersion to 25 or higher (Nougat’s release), Android applies the runtime permission checking features included in Nougat. But if targetSdkVersion is lower than 25 (prior to the runtime permission checking release in Nougat), Android doesn't apply this behavior to your app.

Although not recommended, if you need to prevent older apps from appearing on Android 14-based Fire TV devices, you can set maxSdkVersion to Fire OS 8 (30).

For more details, see the following resources:

Support

If you notice any issues with your app on Android 14-based Fire TV, note the issue in the Amazon Fire TV and Fire TV Stick forums.


Last updated: Jan 28, 2025