感谢您的访问。此页面目前仅提供英语版本。我们正在开发中文版本。谢谢您的理解。

Fire OS 7 for Fire Tablets

Fire OS 7 is based on Android 9 Pie. You can ensure your app's compatibility with Fire OS 7 by following these guidelines.

Devices Running Fire OS 7 and Previous Fire OS Releases

Fire OS 7 is based on Android 9 Pie (API level 28). Fire OS 7 will be released for Fire Tablet devices in 2019.

Most of the Fire Tablet devices run Fire OS 5 (Android 5.1, level 22). The Fire 7 (2019) Tablet device runs Fire OS 6, which is based on Android Nougat (Android 7.1.2, level 25). Some older Fire Tablet devices remain on Fire OS 4 or earlier releases.

For a detailed list of Fire Tablet devices and versions, see Tablet Device Specs.

Android Changes in Fire OS 7

The upgrade from Fire OS 6 to Fire OS 7 requires a transition from Nougat (Android 7.1.2) through Oreo (Android 8.0) to Pie (Android 9).

Changes introduced in Android 8.0 and Android 9 require you to make code changes in your app before the app will work correctly on Fire OS 7 devices.

Android 8.0 Changes

Major changes in Android 8.0 include the following:

  • Notification Channels: All notifications (which includes recommendations and partner-managed recommendations) must be associated with a channel. For information about channels, see Android training for Notification Channels. For sample code and additional details, see the Notifications in Fire OS 7 section below.

  • Background Services: Android 8.0 limits the use of background services. As a result, any apps using background services to refresh their recommendations will fail to refresh the recommendations on FOS 7. Android recommends using JobSchedulers as a workaround for the limitation with background services. See Background Services.

  • Native Libraries: Native libraries no longer load if they contain any load segment that is both writable and executable.

  • Permissions: Apps need to explicitly request each permission, even within the same permission group.

  • MediaSession events: Your app needs to use MediaSession correctly to handle audio. See the Android 8.0 documentation on Finding a media session. When Android handles events, if the foreground activity doesn't have an active media session to handle the event, Android will look for other media sessions. See also Requirements for Multimedia Apps on Fire TV.

You can read about most of these changes in Android 8.0 Behavior Changes.

Android 9 Changes

Major changes in Android 9 include only the following:

  • Privacy changes: Apps will have restricted access to wifi. Apps will have limited access to user inputs and sensor data while running in the background.

You can read about these changes in Behavior changes: all apps (Pie).

Fire OS 7 Parity with Android 9

All features implemented in FOS 7 are at feature parity with Android 9. This doesn't necessarily mean that everything in Android 9 is available in FOS 7, but for those Android 9 features implemented in FOS 7, they have parity. Some Android 9 features, such as split-Screen, notification dots, and adaptive icons, aren't supported in FOS 7.

Also, remember that although Fire OS 7 has parity with Android 9, you can't use Google services on Amazon Fire devices. Instead, you must use the Apps & Games Services SDKs for the services you need (such as in-app purchasing).

Targeting Your App for Fire OS 7 Devices

Users might run your app on a Fire OS 5, Fire OS 6, or Fire OS 7 device. To maximize your app compatibility with the Fire OS version on the device, we recommend that you target the device based on the SDK level.

In your code, you can check whether the Build.VERSION.SDK_INT is greater than or equal to 28 (The Android 9 API level) to target Fire OS 7 devices.

Also see Supporting Different Platform Versions in the Android documentation.

Testing your App's Compatibility on Fire OS 7 Devices

Currently, you can test your app's compatibility with Fire OS 7 by connecting to an actual device. The App Testing Service, which provides only minimal compatibility testing, won't tell you if your app is compatible with Fire OS 7 devices.

What to Set for minSdkVersion and targetSdkVersion

In general, set your minSdkVersion to 22 or lower (set it to the minimum API level your app needs). This will make your app available to all Amazon Fire TV devices (including older devices running Fire OS 5) and most Fire Tablet devices. Set the targetSdkVersion to the highest API level that you've tested your app against.

Understanding How minSdkVersion Affects Supported Devices

In your app manifest (or build.gradle file), the minSdkVersion attribute sets the minimum SDK level that your app needs in order to function properly. (Devices that don't support that API level won't allow the app to be installed 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). Fire OS 7 devices are based on API level 28 (Android 9). By setting the minSdkVersion to 22, you're saying that your app requires the device to have at least API level 22 for it to function properly.

By setting the minSdkVersion to 22, your app will also install on any devices that have a higher API level (such as 28), because Android levels are backwards-compatible. API level 28 usually includes all the APIs for levels 1 through 28 (each release adds to the previous).

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

targetSdkVersion

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

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

By default, if the targetSdkVersion is not specified, it uses the same value as the minSdkVersion. The 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 your targetSdkVersion to 23 or higher (Marshmallow's release), Android will apply the runtime permission checking features included in Marshmallow. But if targetSdkVersion is lower than 23 (prior to the runtime permission checking release in Marshmallow), Android will not apply this behavior to your app.

The maxSdkVersion attribute isn't recommended, but if you wanted to make your app available only on on Fire OS 5 devices, you could set the maxSdkVersion to 22. If you wanted to make your app available only on Fire OS 7 devices, you could set your minSdkVersion to 28.

For more information, see the following:

Support

If you notice any issues with your app on Fire OS 7, note the issue in the Fire Tablets forums.

Notifications in Fire OS 7

As of Android Level 8.0 (API level 26), notifications that your app sends must be assigned to a channel. (Recommendations are a kind of notification.) If your app sends notifications or recommendations, you must create a channel and associate the channel with the notification. A notification without a channel ID will be dropped.

At a high-level, to add a channel to a notification, you do the following:

  1. Step 1: Create the notification channel and register it with the notification manager.
  2. Step 2: Set the channel ID for the notification, using one of the following methods:

The following sections provide more detail and code samples.

Step 1: Create the notification channel and register it with the notification manager

The following is from Create a notification channel in the Android documentation:

Create a notification channel

To create a notification channel, follow these steps:

  1. Construct a NotificationChannel object with a unique channel ID, a user-visible name, and an importance level.
  2. Optionally, specify the description that the user sees in the system settings with setDescription.
  3. Register the notification channel by passing it to createNotificationChannel.

    private void createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = getString(R.string.channel_name);
            String description = getString(R.string.channel_description);
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
    

Step 2: Set the Channel ID for the Notification

You have two options for setting the channel ID for the notification. You can either use ContentRecommendation and use reflection to set the channel ID, or you can use Notification.Builder.

Option 1: Use createContentRecommendation and use reflection to set the channel ID

Notification notification = createContentRecommendation(largeIcon, notificationId);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    Log.d(TAG, "SDK version is >= Android O");

    try {
        Field channel = notification.getClass().getDeclaredField("mChannelId");
        channel.setAccessible(true);
        channel.set(notification, StringTerms.CHANNEL_ID);
    }
    catch (Exception e) {
        Log.d(TAG, "Can't set ChannelId", e);
    }
}

Option 2: Use Notification.Builder with channel ID

Note that the following code is adapted from the Android Open Source Project on Google Git.

public Notification getNotificationObject(Context context) {
    Notification.Builder builder = new Notification.Builder(context, "channelId");
    RecommendationExtender recExtender = new RecommendationExtender();

    // Encode all the content recommendation data in a Notification object

    builder.setCategory(Notification.CATEGORY_RECOMMENDATION);
    builder.setContentTitle(mTitle);
    builder.setContentText(mText);
    builder.setContentInfo(mSourceName);
    builder.setLargeIcon(mContentImage);
    builder.setSmallIcon(mBadgeIconId);
    if (mBackgroundImageUri != null) {
        builder.getExtras().putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, mBackgroundImageUri);
    }
    builder.setColor(mColor);
    builder.setGroup(mGroup);
    builder.setSortKey(mSortKey);
    builder.setProgress(mProgressMax, mProgressAmount, false);
    builder.setAutoCancel(mAutoDismiss);

    if (mContentIntentData != null) {
        PendingIntent contentPending;
        if (mContentIntentData.mType == INTENT_TYPE_ACTIVITY) {
            contentPending = PendingIntent.getActivity(context, mContentIntentData.mRequestCode,
            mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT,
            mContentIntentData.mOptions);
        }
        else if (mContentIntentData.mType == INTENT_TYPE_SERVICE) {
            contentPending = PendingIntent.getService(context, mContentIntentData.mRequestCode,
            mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
            else { // Default:INTENT_TYPE_BROADCAST{
            contentPending = PendingIntent.getBroadcast(context,
            mContentIntentData.mRequestCode,
            mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
        builder.setContentIntent(contentPending);
    }

    if (mDismissIntentData != null) {
        PendingIntent dismissPending;
        if (mDismissIntentData.mType == INTENT_TYPE_ACTIVITY) {
            dismissPending = PendingIntent.getActivity(context, mDismissIntentData.mRequestCode,
            mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT,
            mDismissIntentData.mOptions);
        }
        else if (mDismissIntentData.mType == INTENT_TYPE_SERVICE) {
            dismissPending = PendingIntent.getService(context, mDismissIntentData.mRequestCode,
            mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
            else { // Default:INTENT_TYPE_BROADCAST{
                dismissPending = PendingIntent.getBroadcast(context,
                mDismissIntentData.mRequestCode,
                mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
        builder.setDeleteIntent(dismissPending);
    }

    recExtender.setContentTypes(mContentTypes);
    recExtender.setGenres(mContentGenres);
    recExtender.setPricingInformation(mPriceType, mPriceValue);
    recExtender.setStatus(mStatus);
    recExtender.setMaturityRating(mMaturityRating);
    recExtender.setRunningTime(mRunningTime);

    builder.extend(recExtender);
    Notification notif = builder.build();
    return notif;
}

For more details, consult the Android documentation on Create and Manage Notification Channels.