Fire TV app development already comes with a long list of things to consider. You’re dealing with Fire TV remote control navigation, UI layouts that need to look good from across the room, and UX behaviors which are fundamentally different from mobile apps.
You can't afford to lose time on things like wiring up authentication, managing backend data, or figuring out how to store and serve media assets. If you could offload all of those to a service that’s developer-friendly and easy to integrate, you’d save yourself a lot of time and unnecessary complexity.
That’s exactly what AWS Amplify offers. AWS Amplify helps developers quickly build, deploy, and scale full-stack web and mobile apps using AWS services with minimal backend configuration. Amplify can help you handle all of the backend pieces: authentication, cloud storage, and data persistence. That way, you can stay focused on building an experience that works seamlessly on Fire TV.
To follow along with this Fire TV app tutorial, you’ll need a few things set up:
Keep in mind that this is a demo focused on highlighting Amplify alongside Fire OS app development—it's not meant to be a production-level app, so it does not incorporate security best practices.
Fire TV app development has its own set of UX challenges—D-pad navigation, TV-optimized layouts, and audio focus handling. Add backend infrastructure to that mix, and it’s easy to lose momentum before your UI is even working.
Amplify gives you a shortcut. It lets you skip the boilerplate and get straight to shipping your app:
The app you’ll create by following this guide will focus on the above three features, but Amplify also gives you serverless functions, letting you add Lambda functions for background processing without managing infrastructure.
That means you’ll also learn about serverless app development, so you can focus on building your Fire TV experience—not wiring up cloud services from scratch.
The first step is to set up the Amplify backend that will power authentication, storage, and data for our app.
Before using the Amplify CLI to provision resources, you'll need credentials for an IAM Identity Center with sufficient permissions. Start by signing into the AWS Console and creating a new user in the IAM Identity Center.
After creating the user, you will see the access portal URL, username, and one-time password for the new user.
Follow the remaining instructions here to complete the setup of your user, along with a local AWS profile which you'll use when making Amplify-related calls from the command line. For the remainder of this guide, we'll assume that a local AWS profile named amplify-app-developer exists, and that profile has arn:aws:iam::aws:policy/service-role/AmplifyBackendDeployFullAccess permissions.
From your project folder, run the following command:
~/project$ $ npm create amplify@latest
Need to install the following packages:
create-amplify@1.2.0
Ok to proceed? (y) y
> npx
> create-amplify
✔ Where should we create your project? .
Installing devDependencies:
- @aws-amplify/backend
- @aws-amplify/backend-cli
- aws-cdk-lib@2.189.1
...
Welcome to AWS Amplify!
- Get started by running npx ampx sandbox.
- Run npx ampx help for a list of available commands.
This will create a subfolder called amplify.
Use the AWS profile you created to create the Amplify sandbox. This will provision resources (such as S3 for storage, managed GraphQL for data, and Cognito for authentication) which you can use for development. As the process runs, it detects changes you may make to files in the amplify subfolder, and it will update your sandbox accordingly.
$ npx ampx sandbox --profile amplify-app-developer
The region us-east-1 has not been bootstrapped. Sign in to the AWS console as a Root user or Admin to complete the bootstrap process, then restart the sandbox.
If this is not the region you are expecting to bootstrap, check for any AWS environment variables that may be set in your shell or use --profile <profile-name> to specify a profile with the correct region.
If this is your first time using Amplify, then your browser will open to walk you through the process of bootstrapping your environment for Amplify. Click through the steps to complete this setup.
Ultimately, this bootstrapping process uses AWS CloudFormation to provision resources used by AWS Cloud Development Kit. The CloudFormation stack will touch resources in S3, ECR, and IAM.
After bootstrapping has completed, run the sandbox command again.
$ npx ampx sandbox --profile amplify-app-developer
Amplify Sandbox
Identifier: firedev
Stack: amplify-project-firedev-sandbox-c212f661f8
Region: us-east-1
To specify a different sandbox identifier, use --identifier
WARNING: Schema is using an @auth directive with deprecated provider 'iam'. Replace 'iam' provider with 'identityPool' provider.
✔ Backend synthesized in 1.47 seconds
✔ Type checks completed in 3.38 seconds
✔ Built and published assets
✔ Deployment completed in 210.98 seconds
AppSync API endpoint = https://hw734z3v7bhknhxjpvxf4xrnvu.appsync-api.us-east-1.amazonaws.com/graphql
[Sandbox] Watching for file changes...
You can leave your Amplify sandbox process running in this terminal.
Now that Amplify is up and running, let's build our Android project.
Open Android Studio (installation instructions). Go to File > New > New Project.
Select a Television template with Empty Activity.
Specify a Package name (for example com.example.amplifyfiretv). Set the Save Location to your project root folder. Choose a minimum SDK. For this example, we will use API 29.
This will initialize your new project, creating many new files. Once Android Studio opens your project for the first time, it will spend a few minutes downloading dependencies.
To test our application, we'll use an Android emulator. You can find more detailed information about Android TV emulators and Fire TV apps on this page.
In Android Studio, go to the Device Manager. Click to Create Virtual Device. Create a New Hardware Profile. Create a profile with the following settings:
Specify a name for your virtual device. In this example, the device will be named "Fire TV Emulator", but you can give it any name of your choosing.
Click Finish. Then, select the newly created profile and click Next. Select a system image with an API level of 23 or higher. For this guide, we will use Q (29). Download the image and select it for this virtual device.
Finish creating the virtual device. Then, start the emulator.
With our initial project set up, we can test it in the emulator.
The initial setup from Android Studio for Android TV app uses Jetpack Compose for Android TV. Jetpack Compose is the default toolkit used in Android Studio for building UI. However, for our Fire TV app, we will use Android's Leanback library because Fire TV has strong support for Leanback's UI components and features. So, you'll modify your app/build.gradle.kts file to look like this:
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.example.amplifyfiretv"
compileSdk = 35
defaultConfig {
applicationId = "com.example.amplifyfiretv"
minSdk = 29
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
lint {
abortOnError = false
checkReleaseBuilds = false
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation("androidx.leanback:leanback:1.0.0")
implementation("com.github.bumptech.glide:glide:4.12.0")
implementation(libs.androidx.lifecycle.runtime.ktx)
// Testing dependencies
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
Then, modify app/src/main/java/com/example/amplifyfiretv/MainActivity.kt to use Leanback and present a very simple "Hello Android" text to start.
package com.example.amplifyfiretv
import android.os.Bundle
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.FragmentActivity
import androidx.leanback.app.BrowseSupportFragment
import androidx.leanback.widget.*
class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.main_browse_fragment, MainFragment())
.commit()
}
}
}
class MainFragment : BrowseSupportFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupUIElements()
loadContent()
}
private fun setupUIElements() {
title = "Amplify Fire TV"
headersState = HEADERS_DISABLED
}
private fun loadContent() {
val textView = TextView(requireContext()).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
text = "Hello Android"
textSize = 24f
}
val container = requireActivity().findViewById<ViewGroup>(R.id.main_browse_fragment)
container.addView(textView)
}
}
Next, we'll add cards to our main activity page, with each one representing a video. For now, we'll hardcode references to all of the videos and thumbnails in a local JSON file called cards.json. This way, we can ensure video playback and navigation works as it ought to.
Our JSON card data is read in at real time by CardDataProvider, defined in a file called CardData.kt:
package com.example.amplifyfiretv.data
import android.content.Context
import android.util.Log
import com.google.gson.Gson
data class CardData(
val title: String,
val subtitle: String,
val imageUrl: String,
val videoUrl: String
)
data class CardDataResponse(
val cards: List<CardData>
)
object CardDataProvider {
private const val TAG = "CardDataProvider"
private var cards: List<CardData> = emptyList()
fun initialize(context: Context) {
try {
val jsonString = context
.assets
.open("cards.json")
.bufferedReader()
.use { it.readText() }
val response = Gson()
.fromJson(jsonString, CardDataResponse::class.java)
cards = response.cards
} catch (e: Exception) {
cards = emptyList()
}
}
fun getCards(): List<CardData> {
return cards
}
}
We will use the Media3 ExoPlayer for video playback. All the functionality for creating the video player and loading the video is found in VideoPlayerActivity.kt.
Tested in the emulator, our app currently looks like this:
We have Amplify set up, but we need to add it to our project.
Start by adding the Amplify dependencies to app/build.gradle.kts:
implementation("com.amplifyframework:aws-api:2.24.0")
implementation("com.amplifyframework:aws-datastore:2.24.0")
implementation("com.amplifyframework:aws-storage-s3:2.24.0")
implementation("com.amplifyframework:aws-auth-cognito:2.24.0")
Then, create a new file called AmplifyApp.kt. Its contents are as follows:
package com.example.amplifyfiretv
import android.app.Application
import android.util.Log
import com.amplifyframework.AmplifyException
import com.amplifyframework.api.aws.AWSApiPlugin
import com.amplifyframework.auth.cognito.AWSCognitoAuthPlugin
import com.amplifyframework.core.Amplify
import com.amplifyframework.datastore.AWSDataStorePlugin
import com.amplifyframework.storage.s3.AWSS3StoragePlugin
import com.example.amplifyfiretv.data.CardDataProvider
class AmplifyApp : Application() {
companion object {
private const val TAG = "AmplifyApp"
}
override fun onCreate() {
super.onCreate()
CardDataProvider.initialize(applicationContext)
try {
Amplify.addPlugin(AWSApiPlugin())
Amplify.configure(applicationContext)
} catch (error: AmplifyException) {
Log.e(TAG, "Error initializing Amplify", error)
} catch (error: Exception) {
Log.e(TAG, "Unexpected error during initialization", error)
}
}
}
Then, modify app/src/main/AndroidManifest.xml to tell Android to use your AmplifyApp class as the Application class.
<application
android:name=".AmplifyApp"
One of the benefits of using Amplify is that you can store and retrieve assets in AWS S3. As a simple test of this, move your cards.json file to an S3 bucket. Instead of having the app reference this file locally at compile time, it will retrieve data for the cards from S3 in real time.
Documentation for using Amplify to set up storage in an Android project can be found here.
Go ahead and create amplify/storage/resource.ts:
import { defineStorage } from '@aws-amplify/backend';
export const storage = defineStorage({
name: 'my-bucket',
access: (allow) => ({
'data/*': [
allow.guest.to(['get']),
allow.authenticated.to(['get'])
]
})
});
You will be uploading the cards.json file to the data subfolder of your S3 bucket, allowing access by both non-authenticated (guests) and authenticated users.
In this walkthrough, you will also add auth for Amplify (which uses Cognito), as that is necessary for using storage.
In amplify/auth/resource.ts, you have:
import { defineAuth } from '@aws-amplify/backend';
export const auth = defineAuth({
loginWith: {
email: true,
},
});
Then, create amplify/backend.ts, specifying that you will use your auth and storage definitions.
import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { storage } from './storage/resource';
defineBackend({
auth,
storage,
});
After you create these files, the running Amplify sandbox process will update the AWS resources to handle your needs for auth and storage.
The Amplify Sandbox process generates a client configuration file (amplify_outputs.json), which your app will use when connecting to the various resources that Amplify spins up for you. The file is automatically updated whenever the running process detects changes to your Amplify configuration (such as the changes we made above).
By default, amplify_outputs.json is written directly into the directory where the Amplify Sandbox process is run. However, your Fire TV app will need the file available in app/src/main/res/raw/amplify_outputs.json. Restart the Amplify Sandbox process, explicitly specifying the path where it should write the file from now on:
$ npx ampx sandbox \
--profile amplify-app-developer \
--outputs-out-dir app/src/main/res/raw/
Amplify Sandbox
Identifier: firedev
Stack: amplify-project-firedev-sandbox-c212f661f8
Region: us-east-1
To specify a different sandbox identifier, use --identifier
WARNING: Schema is using an @auth directive with deprecated provider 'iam'. Replace 'iam' provider with 'identityPool' provider.
✔ Backend synthesized in 1.47 seconds
✔ Type checks completed in 3.38 seconds
✔ Built and published assets
✔ Deployment completed in 210.98 seconds
AppSync API endpoint = https://hw734z3v7bhknhxjpvxf4xrnvu.appsync-api.us-east-1.amazonaws.com/graphql
[Sandbox] Watching for file changes…
File written: app/src/main/res/raw/amplify_outputs.json
In the amplify_outputs.json file generated above, you can see the name of the S3 bucket that has been created for your Amplify project.
"storage": {
"aws_region": "us-east-1",
"bucket_name": "amplify-project-firedev-sandb-mybucket-ovpsejk2htya",
...
In the AWS console, navigate to that S3 bucket, create a subfolder called data, and then upload your cards.json to the folder. The resulting S3 URI for the file is:
s3://amplify-project-firedev-sandb-mybucket-ovpsejk2htya/data/cards.json
Next, modify your code in CardData.kt. Instead of reading from cards.json locally, it will look in amplify_outputs.json for the S3 bucket name, and then call Amplify resources to download the remote file and save it to local cache. Key lines of code from the initialize function are shown below:
// Set up local file for downloading
val localFile = File(cacheDir, FILE_NAME)
// Get bucket name from AmplifyOutputs
val outputs = AmplifyOutputs.fromResource(R.raw.amplify_outputs)
val jsonString = context
.resources
.openRawResource(R.raw.amplify_outputs)
.bufferedReader()
.use { it.readText() }
val jsonObject = Gson().fromJson(jsonString, JsonObject::class.java)
val storageObject = jsonObject.getAsJsonObject("storage")
val bucketName = storageObject.get("bucket_name").asString
// Set up S3 path - using data/ prefix to match permissions
val s3Path = StoragePath.fromString("$DATA_SUBFOLDER/$FILE_NAME")
val options = StorageDownloadFileOptions.builder().build()
Amplify.Storage.downloadFile(
s3Path,
localFile,
options,
{ result ->
try {
val jsonString = localFile.readText()
val response = Gson()
.fromJson(jsonString, CardDataResponse::class.java)
cards = response.cards
onCardsLoaded?.invoke()
} catch (e: Exception) {
e.printStackTrace()
throw e
}
},
{ error ->
error.printStackTrace()
throw error
}
)
Then, update MainActivity.kt to listen for when cards have been loaded and then call updateContent() accordingly.
CardDataProvider.setOnCardsLoadedListener {
updateContent()
}
Finally, update AmplifyApp.kt code to initialize your CardDataProvider, S3 for storage, and Cognito for auth.
override fun onCreate() {
super.onCreate()
try {
Amplify.addPlugin(AWSS3StoragePlugin())
Amplify.addPlugin(AWSCognitoAuthPlugin())
val outputs = AmplifyOutputs.fromResource(R.raw.amplify_outputs)
Amplify.configure(outputs, applicationContext)
applicationScope.launch {
try {
CardDataProvider.initialize(applicationContext)
} catch (e: Exception) {
e.printStackTrace()
}
}
...
Now that we've set up Amplify, modified our application, and uploaded our cards.json file to S3, we can build our app and run it again, testing in the emulator.
The card images and video playback function as expected. You've successfully integrated storage via S3 with Amplify.
If you're following along with the code repo, we're at the commit titled Retrieves card data via remote file with Amplify and S3.
To use storage with Amplify and S3, you’ve already created and deployed your authentication service. Now, it's time to create an authentication flow to handle user sign-in and store session information.
Documentation for using Amplify to set up authentication in an Android project can be found here.
To prepare for testing, create some users in your Cognito user pool. In amplify_outputs.json, you can see the user_pool_id. For example:
"auth": {
"user_pool_id": "us-east-1_8Riey238F",
"aws_region": "us-east-1",
…
In the AWS console, navigate to Cognito and find the user pool with this id. Within that user pool, navigate to User management -> Users. Then create a few new users. For this guide, we've created two users:
Email address | Password |
joe@example.com | My password is 1 number. |
jen@example.com | My password has 0 numbers. |
After creating these users, you'll notice that their confirmation status is "Force change password." Since you are simply using test users, you should confirm these user accounts with these passwords. This can be done with the AWS CLI. For example:
$ aws cognito-idp admin-set-user-password \
--profile amplify-app-developer \
--user-pool-id us-east-1_8Riey238F \
--username jen@example.com \
--password "My password has 0 numbers." \
--permanent
Now, your two test users are confirmed.
For users, add a simple sign-in status to your main page. Create a checkAuthSession() function which calls Amplify.Auth.fetchAuthSession to determine whether the user is signed in. If the user is not signed in, "Sign In" is displayed. If the user is signed in, the email address of the signed-in user is displayed, along with "Sign Out."
private fun checkAuthSession() {
Amplify.Auth.fetchAuthSession(
{ session ->
val cognitoSession = session as AWSCognitoAuthSession
if (cognitoSession.isSignedIn) {
handleSignedInState()
} else {
Handler(Looper.getMainLooper()).post {
updateAuthUI(false)
}
}
},
{ error ->
Handler(Looper.getMainLooper()).post {
updateAuthUI(false)
}
}
)
}
In the emulator, the page with different statuses looks like this:
Next, create SignInActivity.kt, which defines the activity screen for signing in. Define your layout in app/src/main/res/layout/activity_sign_in.xml, with fields for email address and password. This screen calls Amplify.Auth.SignIn upon form submission. You can check out the built-in Android connected component for this here.
Make sure to add this activity screen to your AndroidManifest.xml:
<activity
android:name=".SignInActivity"
android:exported="false"
android:theme="@style/Theme.AppCompat.NoActionBar" />
Build and run the application, testing in the emulator. Authentication is up and running, and you are able to sign in and out using credentials for the two test users you have in your Cognito user pool.
We want to show the use of Amplify to store and retrieve data for signed in users. To do this, we'll let signed-in users choose specific videos to mark or unmark as "favorites." When a user signs in, our app will show which videos the user has chosen.
Data regarding our user preferences will be stored in a GraphQL database, which our app will interface with via Amplify Data (which uses AppSync under the hood).
Create amplify/data/resource.ts to initialize your use of Amplify Data and define your data schema:
import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
const schema = a.schema({
Favorite: a
.model({
userId: a.string().required(),
videoId: a.string().required()
})
.authorization(allow => [
allow.authenticated()
]),
});
export type Schema = ClientSchema<typeof schema>;
export const data = defineData({
schema,
authorizationModes: {
defaultAuthorizationMode: 'userPool'
}
});
Then, add this to your Amplify backend definition in amplify/backend.ts:
import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { storage } from './storage/resource';
import { data } from './data/resource';
defineBackend({
auth,
storage,
data,
});
Finally, make sure to add the AWSApiPlugin to your application in AmplifyApp.kt.
...
import com.amplifyframework.api.aws.AWSApiPlugin
...
class AmplifyApp : Application() {
private val TAG = "AmplifyApp"
private val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
override fun onCreate() {
super.onCreate()
try {
Amplify.addPlugin(AWSS3StoragePlugin())
Amplify.addPlugin(AWSCognitoAuthPlugin())
Amplify.addPlugin(AWSApiPlugin())
...
As you make these updates, the running Amplify sandbox process will update your backend resources to support the use of Amplify Data. A quick check of the AWS AppSync service in your AWS Console shows the API set up for your application, along with the schema.
Because you've updated your Amplify app configurations, your configuration file (amplify_outputs.json) will be automatically updated. You can see the updated file now has details for your use of Amplify Data.
…
"data": {
"url": "https://kvvm75giyvdk5kjdttewbdfvry.appsync-api.us-east-1.amazonaws.com/graphql",
"aws_region": "us-east-1",
"default_authorization_type": "AMAZON_COGNITO_USER_POOLS",
"authorization_types": [
"AWS_IAM"
],
"model_introspection": {
"version": 1,
"models": {
"Favorite": {
"name": "Favorite",
"fields": {
"id": {
"name": "id",
"isArray": false,
"type": "ID",
"isRequired": true,
"attributes": []
},
"userId": {
"name": "userId",
"isArray": false,
"type": "String",
"isRequired": true,
"attributes": []
},
"videoId": {
"name": "videoId",
"isArray": false,
"type": "String",
"isRequired": true,
"attributes": []
},
…
Then, you need to generate the GraphQL client code which your app can use to conveniently author the requests you'll be sending to your data backend via Amplify.
~project/$ npx ampx \
--profile amplify-app-developer generate graphql-client-code \
--format modelgen \
--model-target java \
--out app/src/main/java/
The above command generates three Java files which your application will build and use.
~/project/app/src/main/java/com$ tree amplifyframework
amplifyframework/
└── datastore
└── generated
└── model
├── AmplifyModelProvider.java
├── Favorite.java
└── FavoritePath.java
Modify your screens to use a DetailsSupportFragment. Now, when you select a video card in the row, it opens up the details view, which you define in VideoDetailsFragment.kt. Instead of playing the video, icons for two possible actions are displayed: play the video (triangle) or favorite/unfavorite the video (heart).
Next, update the view of the row of cards in MainActivity.kt to show the favorite status.
You can also add a check to make sure that favorite status for each card is only shown when the user is signed in.
Use Amplify.API.query to see if a video is a favorite for the signed-in user. The list items call is straightforward, and you can take advantage of the GraphQL client code for the Favorite model which was generated for you. In your VideoCardPresenter.kt code, you have:
private fun checkFavoriteStatus(
cardView: ImageCardView,
cardData: CardData) {
val userId = AuthStateManager.getInstance().getCurrentUserId()
val query = ModelQuery.list(Favorite::class.java,
Favorite
.VIDEO_ID.eq(cardData.videoId)
.and(Favorite.USER_ID.eq(userId))
)
Amplify.API.query(
query,
{ response ->
if (response.hasData()) {
val isFavorite = response.data.items.count() > 0
cardView.post {
updateFavoriteIcon(cardView, isFavorite)
}
}
},
{ error ->
Log.e(TAG, "Error checking favorite status: ${error.message}", error)
}
)
}
val favorite = Favorite.builder()
.userId(userId)
.videoId(videoData.videoId)
.build()
val createFavorite = ModelMutation.create(favorite)
Amplify.API.mutate(createFavorite,
{ response ->
checkFavoriteStatus()
},
{ error ->
Log.e(TAG, "Error creating favorite: ${error.message}", error)
}
)
To unset the video as a favorite, retrieve the id of the record and then run a delete mutation.
val query = ModelQuery.list(Favorite::class.java,
Favorite
.VIDEO_ID.eq(videoData.videoId)
.and(Favorite.USER_ID.eq(userId))
)
Amplify.API.query(
query,
{ response ->
if (response.hasData() && response.data.items.any()) {
val favorite = response.data.items.first()
val deleteMutation = ModelMutation.delete(favorite)
Amplify.API.mutate(
deleteMutation,
{
isFavorited = false
updateFavoriteIcon()
},
{ error ->
Log.e(TAG, "Error deleting favorite: ${error.message}", error)
}
)
}
},
{ error ->
Log.e(TAG,
"Error querying favorite for deletion: ${error.message}",
Error
)
}
)
With all the code in place, build your application and test it in your emulator. You are able to mark and unmark individual videos as favorites.
After signing out and signing back in, the user's favorites are displayed, showing that backend data persists.
The application is complete!
In under an hour, we built a Fire TV app that used Amplify to handle:
By doing the heavy lifting for us, Amplify let us focus on what matters most: building an app that feels great to use on a Fire TV.
If you’re new to Fire TV development or just looking to prototype faster, Amplify gives you the right set of tools to move quickly without skipping the fundamentals. From here, you can expand this app with features like personalized recommendations, analytics, or push notifications—all backed by Amplify.