<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Giovanni Laquidara</title>
    <description>The latest articles on DEV Community by Giovanni Laquidara (@giolaq).</description>
    <link>https://dev.to/giolaq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178708%2F1ca9a411-df26-422c-8c30-3a0ba254bf63.png</url>
      <title>DEV Community: Giovanni Laquidara</title>
      <link>https://dev.to/giolaq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/giolaq"/>
    <language>en</language>
    <item>
      <title>What if the TV App of the Future Isn't an App but It's a Conversation?</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Mon, 16 Mar 2026 19:36:21 +0000</pubDate>
      <link>https://dev.to/giolaq/what-if-the-tv-app-of-the-future-isnt-an-app-but-its-a-conversation-2gkk</link>
      <guid>https://dev.to/giolaq/what-if-the-tv-app-of-the-future-isnt-an-app-but-its-a-conversation-2gkk</guid>
      <description>&lt;p&gt;Think about how you pick something to watch tonight. You open Netflix. You scroll. You read a synopsis. You scroll more. You check Hulu. More scrolling. You open a "what to watch" thread on Reddit. Twenty minutes later, you're still scrolling.&lt;/p&gt;

&lt;p&gt;Now imagine this: you tell an AI agent "I'm in the mood for something like Severance but funnier," and a full streaming interface appears inline: poster cards, hero banners, horizontal rows, all inside the chat. You click a card, a detail overlay slides in with ratings and a description. You say "actually, something shorter, maybe a movie." The interface reshuffles instantly. You say "Great! Let's watch it!" A video player starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Streaming UIs
&lt;/h2&gt;

&lt;p&gt;Every major streaming platform ships essentially the same product. A horizontal-scroll grid organized by algorithmic rows. "Because You Watched X." "Trending Now." "Continue Watching." The UI paradigm hasn't changed in a decade.&lt;/p&gt;

&lt;p&gt;The problem isn't the catalog or the recommendations. It's the input mechanism. A grid forces you to browse. You scan thumbnails, read titles, maybe click one to read a synopsis, back out, keep scanning. The cognitive load is on the user. You have to translate a vague feeling ("something light but not stupid") into a sequence of clicks and filters that the app was never designed to understand.&lt;/p&gt;

&lt;p&gt;Natural language flips this. "Something light but not stupid, maybe a comedy-drama, nothing longer than two hours" is a single sentence that an AI model can parse into filters and return results that match the actual intent, not just keywords. The UI still matters, you want to see posters, read descriptions, watch trailers but the main interaction becomes conversational.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpa5e7iqhfiatf2zpl3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpa5e7iqhfiatf2zpl3k.png" alt=" " width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MCP Apps are a way to this possible today. Here's how.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP Apps Are
&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol (MCP) already lets AI models call external tools, fetch data, run queries, trigger actions. &lt;a href="https://manufact.com/docs/typescript/server/mcp-apps" rel="noopener noreferrer"&gt;MCP Apps&lt;/a&gt; extend that with a UI layer. When a tool returns results, instead of dumping raw text, it can render a widget directly in the chat interface.&lt;/p&gt;

&lt;p&gt;A framework that makes this practical is &lt;a href="https://manufact.com/docs/home" rel="noopener noreferrer"&gt;&lt;strong&gt;mcp-use&lt;/strong&gt;&lt;/a&gt; from &lt;a href="https://manufact.com/" rel="noopener noreferrer"&gt;Manufact&lt;/a&gt;, a full-stack TypeScript SDK for building MCP servers with interactive widgets. It provides the server runtime, the React hooks for widgets, the build toolchain, and crucially, &lt;strong&gt;dual-protocol support&lt;/strong&gt;: widgets built with mcp-use work across both MCP Apps clients (Claude, Goose) and ChatGPT through automatic metadata transformation. Write once, deploy everywhere.&lt;/p&gt;

&lt;p&gt;The mental model: &lt;strong&gt;the AI decides &lt;em&gt;what&lt;/em&gt; to show, the widget decides &lt;em&gt;how&lt;/em&gt; to show it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72zp4fzx8sjc3h61ib8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72zp4fzx8sjc3h61ib8l.png" alt=" " width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A tool call returns both structured data for the model to reason about &lt;em&gt;and&lt;/em&gt; a widget with props that renders an interactive interface. mcp-use enforces a clean data separation here, the model sees only the text summary (via &lt;code&gt;output&lt;/code&gt;), while the widget receives structured props (via &lt;code&gt;structuredContent&lt;/code&gt;) that never inflate the model's context window. The model stays in the loop for decisions that need intelligence ("find me something similar to this movie"), while the widget handles interactions that don't need AI ("click this card to see details").&lt;/p&gt;

&lt;p&gt;For streaming, this means the AI handles the understanding of "what you're in the mood for" and the widget handles the familiar part showing you a interactive catalog you can browse, click, and play from.&lt;/p&gt;

&lt;h2&gt;
  
  
  TV MCP APP
&lt;/h2&gt;

&lt;p&gt;To demonstrate this experience end-to-end, I've built a working MCP App you can run locally or connect to any MCP-compatible client today. The full source is open source at &lt;a href="https://github.com/giolaq/tv-mcp-app/" rel="noopener noreferrer"&gt;github.com/giolaq/tv-mcp-app&lt;/a&gt; clone it, wire it to Claude Desktop or your MCP app compatibile LLM, and you have a conversational streaming interface running in minutes. The rest of this article walks through how it's built.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Server + Widget
&lt;/h2&gt;

&lt;p&gt;The MCP App built with mcp-use has two parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server (&lt;code&gt;index.ts&lt;/code&gt;)&lt;/strong&gt; — Uses &lt;code&gt;MCPServer&lt;/code&gt; from &lt;code&gt;mcp-use/server&lt;/code&gt; to define tools the AI model can call. Each tool does backend work (fetch data, filter, score) and returns responses via mcp-use's &lt;code&gt;text()&lt;/code&gt; and &lt;code&gt;widget()&lt;/code&gt; helpers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Widget (&lt;code&gt;resources/tv-streaming/widget.tsx&lt;/code&gt;)&lt;/strong&gt; — A React component wired to the server via mcp-use's React hooks (&lt;code&gt;useWidget&lt;/code&gt;, &lt;code&gt;useCallTool&lt;/code&gt;, &lt;code&gt;McpUseProvider&lt;/code&gt; from &lt;code&gt;mcp-use/react&lt;/code&gt;). It receives props from tool calls and renders the UI. It can also call tools directly for instant interactions, or send messages back to the AI via &lt;code&gt;sendFollowUpMessage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the project layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tv-mcp-app/
├── index.ts                          # Server: 7 tools, catalog logic
├── resources/tv-streaming/
│   └── widget.tsx                    # Widget entry point (mcp-use convention)
├── src/
│   ├── types.ts                      # Shared TypeScript interfaces
│   ├── hooks/                        # useCatalog, useKeyboardNav, useIntersectionPause
│   └── components/                   # HeroBanner, ContentRow, MovieCard, etc.
├── package.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mcp-use uses a convention-based widget system. Widgets live under &lt;code&gt;resources/&lt;/code&gt; — either as single files (&lt;code&gt;resources/weather-display.tsx&lt;/code&gt;) or as folders for complex UIs. This project uses the folder pattern: &lt;code&gt;resources/tv-streaming/widget.tsx&lt;/code&gt; is the required entry point, with supporting components and hooks in &lt;code&gt;src/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This separation mirrors how the experience feels to the user. The server is the brain it understands the catalog, filters it, scores recommendations. The widget is the screen, it renders the interface the user actually interacts with. The AI model is the remote control except instead of up/down/select, it understands "something like that but scarier."&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Server with mcp-use
&lt;/h2&gt;

&lt;p&gt;The server initializes with &lt;code&gt;MCPServer&lt;/code&gt; from &lt;code&gt;mcp-use/server&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;MCPServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mcp-use/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MCPServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tv-streaming&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TV Streaming&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A TV streaming assistant that helps users discover, filter, recommend, and play content.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MCP_URL&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s2"&gt;`http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// At the bottom of the file:&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MCPServer&lt;/code&gt; handles MCP protocol negotiation, widget asset serving, session management, and the double-iframe sandbox architecture that mcp-use uses for security isolation. The &lt;code&gt;baseUrl&lt;/code&gt; tells the server where widgets will be served from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Tools: Two Categories
&lt;/h2&gt;

&lt;p&gt;This project defines 7 tools split into two categories that serve fundamentally different purposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model-Visible Tools (5)
&lt;/h3&gt;

&lt;p&gt;These are tools the AI model calls in response to user messages. Each one uses mcp-use's &lt;code&gt;server.tool()&lt;/code&gt; to define a name, Zod schema, widget binding, and handler function.&lt;/p&gt;

&lt;p&gt;For instance &lt;code&gt;discover_content&lt;/code&gt; is the main browsing tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;discover_content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Browse and filter the TV streaming catalog. Opens the TV widget with filtered results.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Free-text search across titles and descriptions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;genres&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Filter by genre(s)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Filter by category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;min_rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Minimum star rating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;trending_only&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only show trending titles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;sort_by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tv-streaming&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;invoking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Searching catalog...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;invoked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Results ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;genres&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;min_rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;trending_only&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;sort_by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catalog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getCatalog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;// Apply filters...&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;genres&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;genresLower&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;genres&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;genres&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;genresLower&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... more filtering and sorting ...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;viewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;browse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredCatalog&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;activeFilters&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things to note about the mcp-use patterns at work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The schema uses Zod&lt;/strong&gt; (which mcp-use uses throughout for validation). The AI model reads these parameter descriptions to decide which fields to fill. When a user says "show me comedies," the model maps that to &lt;code&gt;{ genres: ["Comedy"] }&lt;/code&gt;. When they say "top-rated sci-fi from the last 3 years," it maps to &lt;code&gt;{ genres: ["Sci-Fi"], min_rating: 4, year_from: 2023, sort_by: "rating" }&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;code&gt;widget&lt;/code&gt; config binds the tool to a named widget&lt;/strong&gt; (&lt;code&gt;"tv-streaming"&lt;/code&gt;, matching the folder under &lt;code&gt;resources/&lt;/code&gt;). The &lt;code&gt;invoking&lt;/code&gt; and &lt;code&gt;invoked&lt;/code&gt; strings are status messages displayed to the user during tool execution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;mcp-use's &lt;code&gt;widget()&lt;/code&gt; helper enforces data separation.&lt;/strong&gt; The &lt;code&gt;props&lt;/code&gt; object becomes &lt;code&gt;structuredContent&lt;/code&gt; invisible to the model but available to the widget via &lt;code&gt;useWidget().props&lt;/code&gt;. The &lt;code&gt;output&lt;/code&gt; text (wrapped in mcp-use's &lt;code&gt;text()&lt;/code&gt; helper) becomes &lt;code&gt;content&lt;/code&gt; visible to the model for reasoning. The model sees "Found 8 comedies, here are the top 5..." as context for the conversation, while the widget receives the full filtered catalog for rendering.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All the model-visible tools follow the same pattern:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discover_content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Browse/filter/search the catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_title_details&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show detail overlay for a specific title&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;play_title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start video playback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_recommendations&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find similar titles by scoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_catalog_overview&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Return catalog stats as text (no widget)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Together, these five tools cover the full user journey from "what to watch?" to watching. The AI orchestrates the flow and the user just talks.&lt;/p&gt;

&lt;h3&gt;
  
  
  App-Only Tools (2)
&lt;/h3&gt;

&lt;p&gt;Some interactions don't need AI at all. When you click a movie poster, you want the detail overlay &lt;em&gt;now&lt;/em&gt; not after a 2-second round-trip to a language model.&lt;/p&gt;

&lt;p&gt;mcp-use supports this with &lt;code&gt;useCallTool&lt;/code&gt;, a React hook that lets the widget invoke server tools directly, bypassing the model entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;widget_show_details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App-only: Widget calls this when a user clicks a card to show the detail overlay.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The title ID to show details for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tv-streaming&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;invoking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Loading details...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;invoked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Details ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;catalog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getCatalog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;viewMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;detailItemId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({...&lt;/span&gt;&lt;span class="nx"&gt;catalog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;]}),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Showing details for: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the widget side, &lt;code&gt;useCallTool&lt;/code&gt; from &lt;code&gt;mcp-use/react&lt;/code&gt; creates a typed handle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;showDetailsToolCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallTool&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;widget_show_details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// When a card is clicked:&lt;/span&gt;
&lt;span class="nx"&gt;showDetailsToolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Instant. No AI round-trip.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hook provides &lt;code&gt;isPending&lt;/code&gt;, &lt;code&gt;isSuccess&lt;/code&gt;, &lt;code&gt;isError&lt;/code&gt;, and &lt;code&gt;data&lt;/code&gt; states, mcp-use also auto-generates TypeScript types from your tool schemas during &lt;code&gt;mcp-use dev&lt;/code&gt;, so you get full IntelliSense on tool names and parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Widget: React in the Chat
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wj5l36dtbcad0smgkov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wj5l36dtbcad0smgkov.png" alt=" " width="800" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The widget is a React component, wrapped with mcp-use's &lt;code&gt;McpUseProvider&lt;/code&gt; and wired to the server via hooks. It looks and feels like a native streaming app with dark theme, hero banners, horizontal scroll rows, poster cards with hover effects, a video player with custom controls. The difference is where it lives: inside an AI conversation.&lt;/p&gt;

&lt;p&gt;The widget's design is directly inspired by my work at Amazon's &lt;a href="https://github.com/AmazonAppDev/react-native-multi-tv-app-sample" rel="noopener noreferrer"&gt;react-native-multi-tv-app-sample&lt;/a&gt; a production-ready template for building cross-platform TV apps with React Native across Android TV, Apple TV, Fire TV, Vega OS and web. I've borrowed the same visual language: a dynamic hero header that updates based on focused content, horizontal content rows with poster cards, a detail overlay with metadata and action buttons, and a custom video player with spatial-navigation-friendly controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Interaction Patterns
&lt;/h3&gt;

&lt;p&gt;The widget uses three distinct patterns for different types of user actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 1: App-only tool call via &lt;code&gt;useCallTool&lt;/code&gt; (instant, no AI)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user clicks a movie card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSelectItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CatalogItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setSelectedItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;showDetailsToolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// No AI round-trip&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;showDetailsToolCall&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI updates immediately. This is indistinguishable from clicking a card on Netflix. The &lt;code&gt;callTool&lt;/code&gt; fires a request to the server, which returns fresh data as widget props, but the model is never involved. mcp-use routes the call directly through its JSON-RPC postMessage bridge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 2: Follow-up message via &lt;code&gt;sendFollowUpMessage&lt;/code&gt; (needs AI intelligence)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user clicks "More Like This" in the detail overlay:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleMoreLikeThis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CatalogItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sendFollowUpMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Show me titles similar to "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" (ID: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sendFollowUpMessage&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends a message as if the user typed it. The AI model receives it, decides to call &lt;code&gt;get_recommendations&lt;/code&gt;, the server scores candidates, and the widget re-renders with new results. The AI stays in the loop because "similar" is a judgment call (genre overlap, tone, rating proximity) and the model can weigh these factors in context. Maybe the user previously said "nothing too dark" and the model remembers that when filtering recommendations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pattern 3: Pure client-side (no server at all)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Search filtering, keyboard navigation, view transitions — these happen entirely in the widget with React state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;filterRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;allRows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;allRows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchQuery&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No tool call needed. The data is already in the widget; just filter it locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server-Side Patterns Worth Stealing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Catalog Caching with TTL
&lt;/h3&gt;

&lt;p&gt;The server fetches from a remote JSON feed and caches for 5 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cachedCatalog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Catalog&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cacheTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CACHE_TTL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCatalog&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Catalog&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedCatalog&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cacheTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;CACHE_TTL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedCatalog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CATALOG_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cachedCatalog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Catalog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;cacheTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedCatalog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every tool call goes through &lt;code&gt;getCatalog()&lt;/code&gt;. The first call fetches; subsequent calls within 5 minutes use cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running It
&lt;/h2&gt;

&lt;p&gt;The project uses mcp-use's CLI for development and builds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_OPTIONS='--max-old-space-size=8192' mcp-use build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp-use dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp-use start"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mcp-use"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.19.2-canary.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^19.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"react-dom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^19.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"zod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.3.5"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mcp-use dev&lt;/code&gt; starts the server with hot reload, auto-generates TypeScript types from your tool schemas, and serves an inspector at &lt;code&gt;/inspector&lt;/code&gt; for testing tools and widget rendering across protocols.&lt;/p&gt;

&lt;p&gt;For public access through a tunnel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--tunnel&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mcp-use creates a persistent subdomain like &lt;code&gt;https://&amp;lt;subdomain&amp;gt;.local.mcp-use.run/mcp&lt;/code&gt;. For production, you can deploy to Manufact Cloud with &lt;code&gt;npx mcp-use deploy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To connect it to Claude Desktop or ChatGPT, add the MCP server URL to the host's config.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means for Streaming
&lt;/h2&gt;

&lt;p&gt;An AI agent flips the usual UX of TV Streaming apps model. The input is natural language. The output is still a rich visual interface, you don't lose the posters, the trailers, the browse-and-discover experience that makes streaming fun.&lt;/p&gt;

&lt;p&gt;The TV app of the future probably won't be an app you open. It'll be a widget that appears when you say what you're in the mood for.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tv</category>
      <category>react</category>
      <category>mcp</category>
    </item>
    <item>
      <title>MWC 2026: What Every Developer Building AI Features Should Know</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Tue, 10 Mar 2026 16:39:15 +0000</pubDate>
      <link>https://dev.to/giolaq/mwc-2026-what-every-developer-building-ai-features-should-know-1a45</link>
      <guid>https://dev.to/giolaq/mwc-2026-what-every-developer-building-ai-features-should-know-1a45</guid>
      <description>&lt;p&gt;I spent three days walking the halls of Fira Gran Via in Barcelona last week. I came back with sore feet and one clear takeaway: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI assistants are the default now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I work on Alexa+ and I spend my days thinking and prototyping about how AI ( and voice) fit into people's actual lives. How to merge context, multi-turn conversations, smart home with stuff that matters at 7am when you're making coffee. I'm building every day trying to find the optimal architecture for my agents. And what I saw in Barcelona was in a way confirming what I think: There is a convergence. Xiaomi, Samsung, LG, Lenovo, Honor, TECNO, Deutsche Telekom, Origen... they all arrived at the same vision.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Browser Analogy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf6syju1ctxyosrigdtg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf6syju1ctxyosrigdtg.png" alt=" " width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember when every company shipped a browser? You stopped building for Netscape, a specific browser, or even just one OS. You started building to web standards. Same thing is happening with AI assistants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Many Booths Had an AI Assistant
&lt;/h2&gt;

&lt;p&gt;And I'm not talking about chatbots or summarisation demos. These are full AI assistants with a name, a personality, and an ecosystem strategy behind them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6sqdk8vk7nmxi0mykt5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6sqdk8vk7nmxi0mykt5x.png" alt="Xiaomi Miloco at MWC 2026" width="800" height="1023"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.hardwarezone.com.sg/lifestyle/home/xiaomi-miloco-smart-home-ai-appliances-mwc-2026" rel="noopener noreferrer"&gt;Xiaomi's Miloco&lt;/a&gt; was showing a complete solution with "Xiaomi Local Copilot". An AI for your home. It sees clutter and sends the robot vacuum. Reads your sleep state and adjusts the climate. Runs on HyperOS 3 across phones, tablets, wearables, smart home and EVs, all sharing one &lt;strong&gt;context&lt;/strong&gt; model. They call the whole thing &lt;a href="https://www.vrsus.io/xiaomi-shows-off-its-human-x-car-x-home-ai-ecosystem-at-mwc-2026/" rel="noopener noreferrer"&gt;"Human x Car x Home"&lt;/a&gt; defining a proper distributed architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feon4uxox3iws75lmbydk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feon4uxox3iws75lmbydk.png" alt="LG Uplus ixi-O at MWC 2026" width="800" height="974"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then there was &lt;a href="https://en.sedaily.com/technology/2026/03/03/lg-uplus-ceo-unveils-ai-voice-agent-ixi-o-at-mwc-2026" rel="noopener noreferrer"&gt;LG Uplus&lt;/a&gt; with &lt;strong&gt;ixi-O&lt;/strong&gt;. Started as a call assistant, now it &lt;a href="https://www.businesskorea.co.kr/news/articleView.html?idxno=264374" rel="noopener noreferrer"&gt;does a lot more&lt;/a&gt;. Detects spam, catches voice phishing mid-call, lets you pull up AI while you're talking to someone. Their CEO was pretty direct on stage: "AI will evolve into an agent that understands &lt;strong&gt;context&lt;/strong&gt; and finds tasks on its own." I've heard variations of this sentence from almost every assistant team I've spoken to. They all got there independently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://news.samsung.com/global/samsung-advances-galaxy-ai-and-its-connected-ecosystem-at-mwc-2026" rel="noopener noreferrer"&gt;Samsung&lt;/a&gt; did something I didn't expect with Galaxy AI. Bixby is becoming a proper conversational device agent, sure, but the real move is that users can now &lt;em&gt;choose&lt;/em&gt; between Bixby, Gemini, and Perplexity. Samsung's saying the &lt;strong&gt;orchestration layer&lt;/strong&gt; matters more than which model sits behind it. 🤔&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furqid5u82mir0n3zitqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furqid5u82mir0n3zitqp.png" alt="Honor Robot Phone at MWC 2026" width="800" height="1125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.honor.com/global/news/honor-mwc2026-launch/" rel="noopener noreferrer"&gt;Honor&lt;/a&gt; went somewhere completely different with the &lt;strong&gt;Robot Phone&lt;/strong&gt;. 200MP camera on a robotic arm that moves, tracks, nods, dances. A sort of physical AI assistant with spatial awareness and &lt;strong&gt;emotional expression&lt;/strong&gt; (nods when agreeing, shakes its head when disagreeing and others)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.telekom.com/en/media/media-information/archive/mwc-2026-world-premiere-of-ai-powered-call-assistant-1102906" rel="noopener noreferrer"&gt;Deutsche Telekom&lt;/a&gt; built the &lt;strong&gt;Magenta AI Call Assistant&lt;/strong&gt; with ElevenLabs and what got me is that it lives in the &lt;em&gt;network&lt;/em&gt;, not on your phone. Live translation, call summaries, mid-call Q&amp;amp;A, with appointment booking coming next. A telecom carrier building an &lt;strong&gt;AI life assistant into the network layer&lt;/strong&gt;... didn't see that one coming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digitalapplied.com/blog/lenovo-qira-ai-assistant-mwc-2026-cross-device" rel="noopener noreferrer"&gt;Lenovo&lt;/a&gt; showed &lt;strong&gt;Qira&lt;/strong&gt;, a &lt;strong&gt;cross-device assistant&lt;/strong&gt; that actually remembers. You start research on a ThinkPad, pick it up on a Tab, finish on your phone, and you never repeat yourself. &lt;strong&gt;Unified memory&lt;/strong&gt; across all three.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.prnewswire.com/news-releases/tecno-unveils-ai-investment-strategies-and-upgraded-ella-ai-assistant-at-mwc-2026-302701574.html" rel="noopener noreferrer"&gt;TECNO&lt;/a&gt; upgraded &lt;strong&gt;Ella&lt;/strong&gt; so it reads and replies to WhatsApp messages, summarises YouTube videos, organises your tasks. They processed over 500M AI requests in 2025, more than half in non-English languages. They're building for &lt;strong&gt;emerging markets&lt;/strong&gt; where an AI assistant might be how someone interacts with the digital world for the first time. &lt;/p&gt;

&lt;p&gt;And &lt;a href="https://aiunplugged.io/blog/origen-unveils-domia-at-mwc-2026-bringing-agentic-intelligence-into-the-home/" rel="noopener noreferrer"&gt;Origen&lt;/a&gt; showed &lt;strong&gt;DOMIA&lt;/strong&gt;, which kills if-this-then-that home automation and replaces it with LLM-powered &lt;strong&gt;multi-agent architecture&lt;/strong&gt;. You say "It's a bit dark" and it does something different at 2pm than it does at 10pm because it actually gets the context. A few years ago this kind of ambient intelligence needed billions in R&amp;amp;D. Again...&lt;strong&gt;context&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Silicon Is Ready Too
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.qualcomm.com/news/releases/2026/03/qualcomm-powers-the-rise-of-personal-ai-with-new-snapdragon-wear" rel="noopener noreferrer"&gt;Qualcomm&lt;/a&gt; dropped the &lt;strong&gt;Snapdragon Wear Elite&lt;/strong&gt;, the first wearable chip with a dedicated NPU. It runs &lt;a href="https://www.qualcomm.com/snapdragon/news/unveiled-at-mwc-2026--truly-personal-ai-powered-by-snapdragon-we" rel="noopener noreferrer"&gt;2B-parameter models on-device&lt;/a&gt; at 10 tokens/sec. Computer vision, text-to-speech, &lt;strong&gt;agentic AI on your wrist&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.mediatek.com/press-room/mediatek-exemplifies-ai-and-connectivity-leadership-at-mwc-2026" rel="noopener noreferrer"&gt;MediaTek&lt;/a&gt; talked about a "personal device cloud" where &lt;strong&gt;AI agents work together&lt;/strong&gt; across your family's devices over Wi-Fi or 6G.&lt;/p&gt;

&lt;h2&gt;
  
  
  People Aren't Waiting, They're Building Their Own
&lt;/h2&gt;

&lt;p&gt;The demand was there &lt;em&gt;before&lt;/em&gt; Barcelona. We all know some examples:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/OpenClaw" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt; hit &lt;a href="https://finance.yahoo.com/news/openclawd-releases-major-platform-openclaw-150000544.html" rel="noopener noreferrer"&gt;250,000 GitHub stars&lt;/a&gt; in 60 days. The AI agent that runs locally, connects to Claude or DeepSeek or GPT, and works through WhatsApp, Telegram, Signal. It went from a side project to &lt;a href="https://www.cnbc.com/2026/02/02/openclaw-open-source-ai-agent-rise-controversy-clawdbot-moltbot-moltbook.html" rel="noopener noreferrer"&gt;a global thing&lt;/a&gt; so fast that Shenzhen's government started drafting policy around it.&lt;/p&gt;

&lt;p&gt;Others like Rabbit R1 sold out at $199. The Humane AI Pin didn't make it, but people still paid for it. What all of these tell you is the same thing every MWC booth was responding to: people want an AI that &lt;em&gt;does things&lt;/em&gt; in their life. Not another chat window.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What Do You Do About It?
&lt;/h2&gt;

&lt;p&gt;If you're building in this space, here's what I keep coming back to.&lt;/p&gt;

&lt;p&gt;The assistant itself isn't the moat anymore. The real question becomes how deep your integration goes into someone's actual day.&lt;/p&gt;

&lt;p&gt;Context is where the power sits in and if your integration only works with one assistant, you've got a problem. You need to think &lt;strong&gt;multi-assistant&lt;/strong&gt;, and open standards are how you get there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Standards You Should Learn
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcale85vyyri9joa9k0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcale85vyyri9joa9k0n.png" alt=" " width="710" height="1088"&gt;&lt;/a&gt;&lt;br&gt;
Four things worth your time right now:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol (MCP)&lt;/a&gt;&lt;/strong&gt; — Write a tool once, any compatible assistant can use it. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://modelcontextprotocol.io/extensions/apps/overview" rel="noopener noreferrer"&gt;MCP Apps&lt;/a&gt;&lt;/strong&gt; - let you build UIs that any host can render. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://agentskills.io/home" rel="noopener noreferrer"&gt;Agent Skills&lt;/a&gt;&lt;/strong&gt; - let you package capabilities that any agent can call. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/andrewyng/context-hub" rel="noopener noreferrer"&gt;Context Hub&lt;/a&gt;&lt;/strong&gt; - A way to make your AI Agent fetch curated documentation about API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://google.github.io/A2A/" rel="noopener noreferrer"&gt;Agent-to-Agent (A2A)&lt;/a&gt;&lt;/strong&gt; — How agents discover and talk to each other. If you're building an agent that needs to coordinate with other agents, this is the protocol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-device model APIs&lt;/strong&gt; - &lt;a href="https://developer.apple.com/documentation/FoundationModels" rel="noopener noreferrer"&gt;Apple Foundation Model&lt;/a&gt; &lt;a href="https://www.qualcomm.com/developer/software/list?displayType=SDK&amp;amp;taxonomyFinder=/Features+and+Technologies/Artificial+Intelligence" rel="noopener noreferrer"&gt;Qualcomm's API&lt;/a&gt;. &lt;a href="https://neuropilot.mediatek.com/" rel="noopener noreferrer"&gt;MediaTek&lt;/a&gt; Optimized for latency, privacy. &lt;/p&gt;

&lt;h2&gt;
  
  
   What to Build Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add an MCP server to allow AI agents to use your tools or product. Consider an MCP App if you need UI. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Publish an Agent Skill so any AI agent will have the knowledge about how to use your services, tools and workflows. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Design for context, not just commands. Expose state and history, not just actions. Think about giving the agents all the information to be able to get the right decision for the users.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Honest Reflection
&lt;/h2&gt;

&lt;p&gt;Walking MWC was a good reminder that the whole industry got to the same conclusion on their own: people need AI that actually helps them run their lives.&lt;/p&gt;

&lt;p&gt;If you're a developer, now's the time to start building for the assistant layer. Not for one assistant. For the layer underneath all of them.&lt;/p&gt;

&lt;p&gt;I came back from MWC wanting to build faster. 🔥&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mwc</category>
      <category>agents</category>
    </item>
    <item>
      <title>Building Your Career in AI: Real Talk from the Trenches</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Mon, 29 Dec 2025 21:06:23 +0000</pubDate>
      <link>https://dev.to/giolaq/building-your-career-in-ai-real-talk-from-the-trenches-40p</link>
      <guid>https://dev.to/giolaq/building-your-career-in-ai-real-talk-from-the-trenches-40p</guid>
      <description>&lt;p&gt;&lt;em&gt;Inspired by insights from &lt;a href="https://www.youtube.com/watch?v=AuZoDsNmG_s" rel="noopener noreferrer"&gt;Andrew Ng and Lawrence Moroney's career advice talk&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Look, the AI space is absolutely wild right now. As someone who's been deep in developer advocacy, cross-platform development and best practices in software engineering, I'm watching this transformation happen in real-time, and honestly? It's pretty exciting, but also chaotic as hell.&lt;/p&gt;




&lt;h2&gt;
  
  
  We're Living in the Future (Kind of)
&lt;/h2&gt;

&lt;p&gt;💡 &lt;em&gt;Inspired by Andrew Ng's "&lt;a href="https://youtu.be/AuZoDsNmG_s?t=48" rel="noopener noreferrer"&gt;This is the golden age to be building&lt;/a&gt;"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's what's changed just in the last year or two:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tools got ridiculously powerful.&lt;/strong&gt; I'm talking about LLMs that can actually understand context, workflows that don't suck, voice AI that sounds more human, and coding assistants that legitimately boost your productivity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's point: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=181" rel="noopener noreferrer"&gt;We now have AI building blocks that were very difficult or did not exist a year or two ago: large language models, RAG-augmented workflows, voice AI, and deep learning frameworks&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've been experimenting with everything from various AI coding assistants to custom MCP servers, and the difference from even six months ago is night and day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building stuff got stupid fast.&lt;/strong&gt; I recently prototyped a &lt;a href="https://github.com/giolaq/ad-genius-system" rel="noopener noreferrer"&gt;video watcher persona system that generates custom advertisement videos on the fly&lt;/a&gt;, &lt;a href="https://github.com/giolaq/devtoagent" rel="noopener noreferrer"&gt;Multi-agent AI content generators&lt;/a&gt; or a "simple" vibe-coded &lt;a href="https://giolaq.github.io/vibepope/" rel="noopener noreferrer"&gt;Conclave RPG Game&lt;/a&gt;. The bottleneck isn't typing code anymore, it's knowing what to build and how to architect it properly. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's observation: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=224" rel="noopener noreferrer"&gt;With AI coding, the speed with which you can get software written is much faster than ever before&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Real Shift: It's About Vision, Not Just Code
&lt;/h2&gt;

&lt;p&gt;💡 &lt;em&gt;Directly inspired by Andrew Ng's "&lt;a href="https://youtu.be/AuZoDsNmG_s?t=335" rel="noopener noreferrer"&gt;Product Management Bottleneck&lt;/a&gt;" concept&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's something I've noticed working on React Native TV projects and AI automation pipelines: the hardest part isn't implementing features anymore. It's deciding &lt;em&gt;what&lt;/em&gt; to build, writing clear specs, and understanding what users actually need.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's key insight: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=342" rel="noopener noreferrer"&gt;When it is increasingly easy to go from a clearly written software spec to a piece of code, then the bottleneck increasingly is deciding what to build or writing that clear spec for what you actually want to build&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This changes everything. The traditional engineer-to-PM ratio is getting compressed. Teams that used to be 8 engineers to 1 PM are trending toward something closer to 1:1. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew noted: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=438" rel="noopener noreferrer"&gt;"I'm seeing the engineer to PM ratio trending downward maybe even two to one or one to one... some teams I work with the proposed head counts was like 1 PM to one engineer"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Translation for us developers:&lt;/strong&gt; If you can think like a product person &lt;em&gt;and&lt;/em&gt; ship code, you're gold. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew emphasized: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=478" rel="noopener noreferrer"&gt;"engineers that can also shape product can move really fast... the subset of engineers that learn to talk to users, get feedback, develop deep empathy for users so that they can make decisions about what to build, those engineers are the fastest moving people"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How to Actually Succeed (From Someone in the Arena)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Stay Current or Get Left Behind
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Andrew's advice on staying at the frontier of tools&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'm not trying to be dramatic, but tooling changes every 3-6 months in this space. I've seen it everywhere, AI coding assistants, and automation workflows. Being one generation behind means you're working twice as hard for half the output.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's experience: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=265" rel="noopener noreferrer"&gt;"If you ask me every three months what my personal favorite coding tool is, it actually probably changes definitely every six months, but quite possibly every three months. Being half a generation behind in these tools means being frankly quite a bit less productive"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Practical advice: Set aside time weekly to experiment with new tools. I literally block calendar time for this.&lt;/p&gt;




&lt;h3&gt;
  
  
  Build Real Shit
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Andrew and Lawrence's emphasis on building and showing work&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Don't just play around—build things that solve actual problems. I've been working on automated video pipelines, MCP servers for app KPIs, and content automation systems. These aren't toy projects; they're solving real workflow problems.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's encouragement: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=316" rel="noopener noreferrer"&gt;"Just go and build stuff right... your opportunity to build things and I think showing them to others is greater than ever before"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lawrence's advice: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=2019" rel="noopener noreferrer"&gt;"Don't let your output be for the job you have, let your output be for the job you want"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🔥 Real-world example:&lt;/strong&gt; &lt;a href="https://x.com/karpathy/status/1873067301511630926" rel="noopener noreferrer"&gt;Andrej Karpathy recently shared&lt;/a&gt; how he used Claude Code to reverse-engineer his entire Lutron home automation system in a single session. It found controllers on his network, discovered open ports, pulled PDF documentation, connected to devices, and even tested by turning his kitchen lights on and off. He's now "vibe coding" a master command center to replace the janky official app. This is what building real things looks like—taking AI tools and solving actual problems you have.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F905gnqf6iux91rqcgou4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F905gnqf6iux91rqcgou4.png" alt=" " width="800" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your portfolio should show you can ship, not just prototype. Conference presentations are great (I do a ton of them), but shipping production code or tools people actually use? That's what gets attention.&lt;/p&gt;




&lt;h3&gt;
  
  
  Your Team Matters More Than the Logo
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Andrew's story about the student assigned to Java backend payment processing&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I've worked with teams at various companies, and here's the truth: the brand on your business card matters less than the people you're learning from. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's warning: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=772" rel="noopener noreferrer"&gt;He told a story about a Stanford student who joined a company with a "hot AI brand" that refused to tell them which team they'd join. After signing, they were assigned to backend Java payment processing instead of AI work and left after a year of frustration&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Engineers who are genuinely curious and stay current&lt;/li&gt;
&lt;li&gt;Teams that ship regularly, not just talk about shipping&lt;/li&gt;
&lt;li&gt;Environments where you can experiment without getting shut down immediately&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's emphasis: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=564" rel="noopener noreferrer"&gt;"One of the most strong predictors for your speed of learning and for your level of success is the people you surround yourself with... instead of working for the company with the hottest brand, sometimes if you find a really good team with really hardworking, knowledgeable, smart people trying to do good with AI, but the company logo just isn't as hot, I think that often means you actually learn faster"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Access to emerging tech and working with smart people? Invaluable. That's what moves your career forward.&lt;/p&gt;




&lt;h3&gt;
  
  
  Think Like a Builder, Not Just a Developer
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence's "Business Focus" pillar&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The best opportunities come when you understand the &lt;em&gt;why&lt;/em&gt; behind what you're building. Whether it's optimizing a TV interface for 10-foot viewing or designing an AI workflow for content creation, knowing the business context makes you infinitely more valuable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's framework: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=2251" rel="noopener noreferrer"&gt;"Business focus is non-negotiable... Everything is geared towards production. Everything is biased towards production... the bottom line is that the bottom line is the bottom line"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Industry is Splitting (And That's Okay)
&lt;/h2&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence Moroney's "Bifurcation of AI" prediction&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You've got two paths forming:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Big AI&lt;/strong&gt;: Cloud-based LLMs, massive compute, platform services (think Claude, GPT-4, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small AI&lt;/strong&gt;: Self-hosted models, edge computing, specialized use cases&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's insight: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=4474" rel="noopener noreferrer"&gt;"Over the next five years there's going to be a bifurcation... Big AI will be what we see today with the large language models getting bigger in the desire to drive towards AGI... The other side is self-hostable models are becoming they're exploding onto the landscape"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both are valid. I work across both using cloud LLMs for content generation while also thinking about edge processing for TV platforms. Pick what aligns with your interests and the problems you want to solve.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Talk on Technical Debt
&lt;/h2&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence's entire framework on "vibe coding" and technical debt&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI systems can accumulate technical debt &lt;em&gt;fast&lt;/em&gt;. I've learned this the hard way building automation pipelines. Here's the framework I use: think about technical debt like financial debt. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's analogy: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=2952" rel="noopener noreferrer"&gt;"Think about debt the way you normally would, right? Buying a house... you end up paying back the bank about a million dollars on half a million owned. That is probably a good debt to take on... A bad debt would be an impulse purchase on a high interest credit card"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every time you generate code with AI, ask yourself: &lt;strong&gt;Is this worth the technical debt I'm taking on?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lawrence's framework for avoiding bad technical debt:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/AuZoDsNmG_s?t=3134" rel="noopener noreferrer"&gt;&lt;strong&gt;Clear objectives met&lt;/strong&gt;&lt;/a&gt;: You knew what you needed to build, didn't just spin out code randomly&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/AuZoDsNmG_s?t=3180" rel="noopener noreferrer"&gt;&lt;strong&gt;Business value delivered&lt;/strong&gt;&lt;/a&gt;: How's this helping the business? "It's really cool" isn't enough&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/AuZoDsNmG_s?t=3236" rel="noopener noreferrer"&gt;&lt;strong&gt;Human understanding&lt;/strong&gt;&lt;/a&gt;: Can your team understand and maintain this code?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Balance quick prototyping (which AI enables) with sustainable architecture. Document your shit. Your future self (and your team) will thank you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's warning: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=3188" rel="noopener noreferrer"&gt;"Code is cheap now in the age of generated code. Finished code, engineered code is not cheap"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Navigate the Hype
&lt;/h2&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence's extensive discussion on the "Anatomy of Hype"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI space is drowning in hype, and you need to learn to filter signal from noise. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's key insight: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=3428" rel="noopener noreferrer"&gt;"The currency of social media is engagement. Accuracy is not the currency of social media... if you are the kind of person who can filter the signal from the noise and then who can encourage others around the signal and not the noise, that puts you in a huge advantage"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When someone comes to you saying "we need to implement agents" or "we need AI," your first question should be: &lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's story: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=3543" rel="noopener noreferrer"&gt;A European company CEO asked him to implement agents because "everybody's telling me that I'm going to save business costs." Lawrence kept asking "why?" until they got to the real need: making salespeople more efficient by reducing research time from 80% to 20% of their work&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Learn to make things "as mundane as possible" to truly understand them. Strip away the magic and hype to see what's actually happening under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  Concrete Actions You Can Take
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Diversify Your Skills
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence's advice on avoiding being a "one-trick pony"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'm not just an AI person, I do TV platforms, React Native, developer advocacy, content creation, friction logging of new sdks and tools. This breadth makes you resilient and more interesting to work with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's warning: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=4749" rel="noopener noreferrer"&gt;"Don't be that one-trick pony who only knows how to do one thing. I've worked with brilliant people who are fantastic at coding a particular API or particular framework and then the industry moved on and they got left behind"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Ship to Production
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence's emphasis that everything is about production now&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Move past proofs of concept. Learn deployment, monitoring, scaling. The bar has moved from "can you build cool demos" to "can you deliver business value?"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's observation: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=2165" rel="noopener noreferrer"&gt;"What's it actually like working in AI right now? As recently as like two or three years ago working in AI was if you can do a thing, you're great... Unfortunately, that's not the case anymore. It's really a lot of today, what you'll see is the P word production"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Build in Public
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Andrew and Lawrence on showing your work&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Share what you're learning. Write posts on dev.to, speak at conferences, create GitHub repos. The community feedback loop is invaluable, and it opens doors you didn't know existed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's example: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=2046" rel="noopener noreferrer"&gt;When he interviewed at Google, instead of answering random questions, he showed code he'd built, a Java application running in Google Cloud for predicting stock prices. "My entire interview loop was them asking me about my code... It gave me the power to communicate about things that I knew"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Understand Agentic Workflows
&lt;/h3&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence's breakdown of what makes something "agentic"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're going to work with AI agents, understand the &lt;a href="https://youtu.be/AuZoDsNmG_s?t=3727" rel="noopener noreferrer"&gt;four-step pattern&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Understand intent&lt;/strong&gt;: Use LLMs to grasp what needs to be done&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Planning&lt;/strong&gt;: Declare available tools and create a plan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt;: Use the tools to get results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflection&lt;/strong&gt;: Review results against intent, iterate if needed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't just buzzword compliance—it's engineering discipline applied to AI systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prepare for the Bubble (But Don't Panic)
&lt;/h2&gt;

&lt;p&gt;💡 &lt;em&gt;Lawrence's discussion on the AI bubble and industry maturation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Look, there's probably a bubble coming. Lawrence laid out the anatomy: hype at the top, massive VC investment drying up, unrealistic valuations, me-too products everywhere, and a small kernel of real value at the bottom.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's lesson from the dot-com bubble: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=4309" rel="noopener noreferrer"&gt;"Amazon, Google, you know, they did it right. They understood the fundamentals of what it was to build a .com. They understood the fundamentals of what it was to build a business on .com. And when the bubble of hype burst, they didn't go with it"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The survivors will be those who:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus on fundamentals&lt;/li&gt;
&lt;li&gt;Build real solutions&lt;/li&gt;
&lt;li&gt;Understand the business side&lt;/li&gt;
&lt;li&gt;Diversify their skills&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's advice: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=4718" rel="noopener noreferrer"&gt;"For you for your career to avoid the impact of any bubble bursting, focus on the fundamentals, build those real solutions, understand the business side, and most of all, diversify your skills"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;💡 &lt;em&gt;Synthesizing Andrew and Lawrence's core messages&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI space is moving fast, but the fundamentals still matter: solve real problems, ship regularly, stay curious, and work with good people. Don't get caught up in hype cycles—focus on building things that work and creating actual value.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Andrew's encouragement: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=938" rel="noopener noreferrer"&gt;"There are so many things that each of you can build and what I find is the number of ideas out in the world is much greater than the number of people with the skill to build them... There are a lot of projects in the world that if you don't build it I think no one else will build it either"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Business focus is non-negotiable now. Understand the business requirements, focus on production, and become that trusted advisor who can translate technical reality to leadership.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's positioning: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=3473" rel="noopener noreferrer"&gt;"Becoming that trusted advisor... if you are the kind of person who can filter the signal from the noise and then who can encourage others around the signal and not the noise, that puts you in a huge advantage that makes you very distinctive"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And remember: the best tool is the one you actually use and understand deeply, not the shiniest new thing on Hacker News. Code is cheap now in the age of AI—but well-engineered, production-ready code? That's still expensive and valuable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lawrence's final wisdom: &lt;a href="https://youtu.be/AuZoDsNmG_s?t=2127" rel="noopener noreferrer"&gt;"Ideas are cheap. Execution is everything"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🚀 Now go build something cool.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>programming</category>
      <category>technology</category>
    </item>
    <item>
      <title>How to animate Fire TV splash screens with React Native &amp; Lottie</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Mon, 11 Sep 2023 04:24:09 +0000</pubDate>
      <link>https://dev.to/amazonappdev/how-to-animate-fire-tv-splash-screens-with-react-native-lottie-32ca</link>
      <guid>https://dev.to/amazonappdev/how-to-animate-fire-tv-splash-screens-with-react-native-lottie-32ca</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Author's Note:&lt;/strong&gt; In my &lt;a href="https://dev.to/amazonappdev/develop-animated-splash-screens-on-fire-tv-with-lottie-5emp"&gt;previous Lottie article&lt;/a&gt;, we covered how to create animated custom splash screens on Fire TV using Kotlin for Android and &lt;a href="https://github.com/airbnb/lottie-android" rel="noopener noreferrer"&gt;Lottie&lt;/a&gt;. For this article, we'll focus on those of you building Android apps using React Native. Since Lottie supports React Native, we'll cover the essentials to get you up and running quickly. Let's dive in!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Quick recap for Lottie&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://airbnb.io/lottie/#/" rel="noopener noreferrer"&gt;Lottie&lt;/a&gt; is an open-source animation library created by Airbnb to render complex animations on mobile devices in real time. It's an excellent choice for creating interactive animations for both Android and iOS. Since Fire OS is based on the Android Open source Project &lt;a href="https://source.android.com/" rel="noopener noreferrer"&gt;AOSP&lt;/a&gt; we can use Lottie to render complex animated splash screens on Fire TV apps with React Native.&lt;/p&gt;

&lt;p&gt;Let's now walk through how to create an animated splash screen for a React Native app running on Fire TV!&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Prerequisite:&lt;/strong&gt; Create a React Native project
&lt;/h3&gt;

&lt;p&gt;You can use your own existing React Native project or create a new one using the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx react-native@latest init SplashScreenApp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; If you're new to React Native and want to learn how to setup your development environment and command line tools, head over to &lt;a href="https://reactnative.dev/docs/environment-setup" rel="noopener noreferrer"&gt;the React Native official docs&lt;/a&gt; to get up and running.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1:&lt;/strong&gt; Prepare the Lottie animation
&lt;/h3&gt;

&lt;p&gt;To integrate Lottie animations into our TV splash screen, we need to first build an animation to match our app's branding and theme. For this example, we'll use the &lt;a href="https://lottiefiles.com/animations/tv-watching-g5Lr55wxgp" rel="noopener noreferrer"&gt;TV Watching&lt;/a&gt; animation by &lt;a href="https://lottiefiles.com/wovencontent" rel="noopener noreferrer"&gt;Alan Murphy&lt;/a&gt; available as a sample from &lt;a href="https://lottiefiles.com/" rel="noopener noreferrer"&gt;LottieFiles&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvitz7foralsqe9gmbwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvitz7foralsqe9gmbwe.png" alt="Lottie animation from LottieFiles" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2:&lt;/strong&gt; Place the Lottie animation into the React Native app project
&lt;/h3&gt;

&lt;p&gt;Create a directory &lt;code&gt;assets&lt;/code&gt; in your React Native project and download the "&lt;a href="https://lottiefiles.com/animations/tv-watching-g5Lr55wxgp" rel="noopener noreferrer"&gt;TV Watching Animation&lt;/a&gt;" in Lottie JSON format from the step above. Place the JSON file in the new &lt;code&gt;assets&lt;/code&gt; folder and make sure to rename the JSON file &lt;code&gt;splashscreen.json&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3:&lt;/strong&gt; Include Lottie as a package dependency
&lt;/h3&gt;

&lt;p&gt;From the command line, inside the root directory of your React Native app execute the command to add Lottie as a dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add lottie-react-native
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4:&lt;/strong&gt; Define the main components for your splash screen
&lt;/h3&gt;

&lt;p&gt;For this sample app, we'll declare all required components inside &lt;code&gt;App.tsx&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The 3 components are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;App&lt;/code&gt;, which represents the main app component&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SplashScreen&lt;/code&gt; for initiating the splash screen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MainContent&lt;/code&gt; for the view that is shown after the splash screen disappears&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's open the file &lt;code&gt;App.tsx&lt;/code&gt; and remove all the content generated by the React Native command line.&lt;/p&gt;

&lt;p&gt;Then at the top of the file, add the required imports for the components we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StyleSheet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LottieView&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lottie-react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up you will declare the 3 components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SplashScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onAnimationFinish&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;

&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MainContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;

&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in addition set the styles we will apply for each of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StyleSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;splashContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;splash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;mainContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;marginTop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fontWeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to export the &lt;code&gt;App&lt;/code&gt; component at the end of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5:&lt;/strong&gt; Implement the SplashScreen component
&lt;/h3&gt;

&lt;p&gt;Implement the SplashScreen component by declaring its components. For this we will have a View containing a &lt;code&gt;LottieView&lt;/code&gt; with the previous json animation file assigned to the &lt;code&gt;source&lt;/code&gt; property of the &lt;code&gt;LottieView&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also define the &lt;code&gt;autoPlay&lt;/code&gt; property in the &lt;code&gt;LottieView&lt;/code&gt; in order to automatically start the animation and set the &lt;code&gt;loop&lt;/code&gt; property as false so that we only show the animation one time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SplashScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onAnimationFinish&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splashContainer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LottieView&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./assets/splashscreen.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="nx"&gt;autoPlay&lt;/span&gt;
      &lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onAnimationFinish&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onAnimationFinish&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 6:&lt;/strong&gt; Implement the MainContent component
&lt;/h3&gt;

&lt;p&gt;To start, this step will just show Text and then you choose when to display your app's home screen after the Splash Screen animation ends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MainContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mainContainer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nx"&gt;Awesome&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="nx"&gt;Screen&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 7:&lt;/strong&gt; Implement the App component
&lt;/h3&gt;

&lt;p&gt;The App component handles the logic to display and hide the Splash screen. &lt;/p&gt;

&lt;p&gt;Declare a &lt;code&gt;loaded&lt;/code&gt; state and set it to false. This allows the the animation to load prior to the Splash Screen being rendered on screen. Once the animation resource is ready, a callback will flip the &lt;code&gt;loaded&lt;/code&gt; state to true to then make the &lt;code&gt;MainContent&lt;/code&gt; component visible on the Fire TV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoaded&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleAnimationFinish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setLoaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MainContent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SplashScreen&lt;/span&gt; &lt;span class="nx"&gt;onAnimationFinish&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleAnimationFinish&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Wrap Up:&lt;/strong&gt; Load up and test our animated splash screen!
&lt;/h2&gt;

&lt;p&gt;Now we can test either by using &lt;a href="https://developer.amazon.com/docs/fire-tv/connecting-adb-to-device.html" rel="noopener noreferrer"&gt;Fire TV via adb&lt;/a&gt; or &lt;a href="https://developer.android.com/training/tv/start/start#run-on-a-virtual-device" rel="noopener noreferrer"&gt;starting an Android TV emulator&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Either approach will let us see the sample in action by running this command from the project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to press &lt;code&gt;a&lt;/code&gt; to run the Android version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyxq87fbnnwiylijvikd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyxq87fbnnwiylijvikd.gif" alt="Animated Splash screen" width="600" height="714"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://github.com/lottie-react-native/lottie-react-native" rel="noopener noreferrer"&gt;Lottie for React Native&lt;/a&gt; is an easy way to enrich your app with beautiful animations and make your user happy.&lt;/p&gt;

&lt;p&gt;Thanks for reading this guide and make sure to check out the sample project source code &lt;a href="https://github.com/giolaq/splash-screen-tv-app-react-native" rel="noopener noreferrer"&gt;on Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay updated&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;For the latest Amazon Appstore developer news, product releases, tutorials, and more:&lt;/p&gt;

&lt;p&gt;📣 Follow &lt;a href="https://twitter.com/AmazonAppDev" rel="noopener noreferrer"&gt;@AmazonAppDev&lt;/a&gt; and &lt;a href="https://twitter.com/i/lists/1580293569897984000/members" rel="noopener noreferrer"&gt;our team&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;📺 Subscribe to our &lt;a href="https://www.youtube.com/amazonappstoredevelopers" rel="noopener noreferrer"&gt;Youtube channel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📧 Sign up for the &lt;a href="https://m.amazonappservices.com/devto-newsletter-subscribe" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  About the author
&lt;/h3&gt;

&lt;p&gt;Giovanni ("Gio") Laquidara is a Senior Dev Advocate at Amazon, where he works on supporting developers around the world using the Amazon Appstore across many devices. &lt;/p&gt;

&lt;p&gt;Previously, Gio worked as a software engineer building mobile apps, real-time defence systems, and VR/AR experiences. For fun, Gio enjoys low level programming, IoT hacking, and command line apps ⌨️✨.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can connect with Gio on &lt;a href="https://twitter.com/giolaq" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/glaquidara/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, and &lt;a href="https://giolaq.dev" rel="noopener noreferrer"&gt;giolaq.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>howto</category>
      <category>tutorial</category>
      <category>reactnative</category>
      <category>lottie</category>
    </item>
    <item>
      <title>Develop Animated Splash Screens on Fire TV with Lottie</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Wed, 26 Jul 2023 22:11:26 +0000</pubDate>
      <link>https://dev.to/amazonappdev/develop-animated-splash-screens-on-fire-tv-with-lottie-5emp</link>
      <guid>https://dev.to/amazonappdev/develop-animated-splash-screens-on-fire-tv-with-lottie-5emp</guid>
      <description>&lt;p&gt;A smooth and visually appealing on-boarding experience can greatly impact how users perceive the quality of your app. In my &lt;a href="https://dev.to/amazonappdev/how-to-develop-custom-splash-screens-on-fire-tv-mcm"&gt;previous article&lt;/a&gt;, we explored how to create custom splash screens on Fire TV apps to optimize the startup time and improve user experience. Building on that knowledge we will take a step further and learn how to develop an animated splash screen using &lt;a href="https://github.com/airbnb/lottie-android" rel="noopener noreferrer"&gt;Lottie&lt;/a&gt; for Fire TV applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Lottie?&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://airbnb.io/lottie/#/" rel="noopener noreferrer"&gt;Lottie&lt;/a&gt; is an open-source animation library created by Airbnb to render complex animations on mobile devices in real time. It is an excellent choice for creating captivating and interactive animations for both Android and iOS. Since Fire OS is based on the Android Open source Project &lt;a href="https://source.android.com/" rel="noopener noreferrer"&gt;AOSP&lt;/a&gt; we can use Lottie to render eye-catching, captivating splash screens on Fire TV apps.&lt;/p&gt;

&lt;p&gt;Before we proceed, I highly recommend checking out the previous article, &lt;a href="https://dev.to/amazonappdev/how-to-develop-custom-splash-screens-on-fire-tv-mcm"&gt;"How to Develop Custom Splash Screens on Fire TV"&lt;/a&gt; and the &lt;a href="https://github.com/giolaq/splash-screen-fire-tv-demo" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;. We will be using the same project adapting the code to use Lottie.&lt;/p&gt;

&lt;p&gt;Let's create a splash screen for our app on Fire TV!&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1:&lt;/strong&gt; Prepare the Lottie animation
&lt;/h3&gt;

&lt;p&gt;To integrate the Lottie animation into our splash screen, we need to build an animation to match our app's branding and theme. For this article, we'll use the &lt;a href="https://lottiefiles.com/animations/cat-tv-loading-animation-sz7kZo9SCY" rel="noopener noreferrer"&gt;Cat TV Loading Animation&lt;/a&gt; by &lt;a href="https://lottiefiles.com/evaschicker" rel="noopener noreferrer"&gt;Eva Schicker&lt;/a&gt; available at &lt;a href="https://lottiefiles.com/" rel="noopener noreferrer"&gt;LottieFiles&lt;/a&gt;. This delightful animation features an adorable cat waiting for our app to load, bringing a touch of fun to the onboarding experience. Create your own custom Lottie animations using After Effects, Figma or other graphics tools you prefer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfbiuwcbi3qe5o5equ18.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfbiuwcbi3qe5o5equ18.png" alt="Lottie animation from LottieFiles" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2:&lt;/strong&gt; Place the Lottie animation into the Android app project
&lt;/h3&gt;

&lt;p&gt;Download the &lt;a href="https://lottiefiles.com/animations/cat-tv-loading-animation-sz7kZo9SCY" rel="noopener noreferrer"&gt;"Cat TV Loading Animation"&lt;/a&gt; in Lottie JSON format from LottieFiles  and place the JSON file in the &lt;code&gt;res/raw&lt;/code&gt; folder of our Fire TV Android project. Rename the JSON file &lt;code&gt;cattv.json&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3:&lt;/strong&gt; Lottie as a dependency
&lt;/h3&gt;

&lt;p&gt;Add Lottie as a dependency to our project app's &lt;code&gt;build.gradle&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"com.airbnb.android:lottie:6.1.0"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4:&lt;/strong&gt; Implement the Animated Splash Screen
&lt;/h3&gt;

&lt;p&gt;Add a &lt;code&gt;LottieAnimationView&lt;/code&gt; view in the splash screen xml layout file &lt;code&gt;splashscreen_activity.xml&lt;/code&gt;. This layout represents the UI of the splash screen. You will notice Lottie Animation, centered on a white background, auto playing when the app starts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;androidx.constraintlayout.widget.ConstraintLayout&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:background=&lt;/span&gt;&lt;span class="s"&gt;"@color/background_splashscreen"&lt;/span&gt;
    &lt;span class="na"&gt;tools:context=&lt;/span&gt;&lt;span class="s"&gt;".SplashScreenActivity"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;com.airbnb.lottie.LottieAnimationView&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/loading_animation"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
        &lt;span class="na"&gt;app:lottie_rawRes=&lt;/span&gt;&lt;span class="s"&gt;"@raw/cattv"&lt;/span&gt;
        &lt;span class="na"&gt;app:lottie_autoPlay=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
        &lt;span class="na"&gt;app:lottie_loop=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
        &lt;span class="na"&gt;android:layout_margin=&lt;/span&gt;&lt;span class="s"&gt;"16dp"&lt;/span&gt;
        &lt;span class="na"&gt;app:layout_constraintBottom_toBottomOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;
        &lt;span class="na"&gt;app:layout_constraintEnd_toEndOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;
        &lt;span class="na"&gt;app:layout_constraintStart_toStartOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt;
        &lt;span class="na"&gt;app:layout_constraintTop_toTopOf=&lt;/span&gt;&lt;span class="s"&gt;"parent"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5:&lt;/strong&gt; Implement the SplashScreenActivity
&lt;/h3&gt;

&lt;p&gt;We need to start the &lt;code&gt;MainActivity&lt;/code&gt; of the app once the animation completes. Let's modify the &lt;code&gt;SplashScreenActivity.java&lt;/code&gt; to remove the delay logic and delegate the Lottie animation to launch the &lt;code&gt;MainActivity&lt;/code&gt; intent when the animation finishes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SplashScreenActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SplashscreenActivityBinding&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SplashscreenActivityBinding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layoutInflater&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Start the MainActivity after Lottie animation completes&lt;/span&gt;
        &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loadingAnimation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAnimatorUpdateListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;animatedFraction&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;1f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Wrap Up:&lt;/strong&gt; Load and test our animated splash screen!
&lt;/h2&gt;

&lt;p&gt;Now we can build and &lt;a href="https://developer.amazon.com/docs/fire-tv/connecting-adb-to-device.html?cmp=2023_07_devg-sa&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;test&lt;/a&gt; our app on Fire TV to see the cat Splash screen in action!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwdaj26h6tu4mccg9iyf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwdaj26h6tu4mccg9iyf.gif" alt="Animated Splash screen" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source code&lt;/strong&gt;&lt;br&gt;
You can find the complete project source code on this &lt;a href="https://github.com/giolaq/splash-screen-fire-tv-demo/tree/lottie" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay updated&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;For the latest Amazon Appstore developer news, product releases, tutorials, and more:&lt;/p&gt;

&lt;p&gt;📣 Follow &lt;a href="https://twitter.com/AmazonAppDev" rel="noopener noreferrer"&gt;@AmazonAppDev&lt;/a&gt; and &lt;a href="https://twitter.com/i/lists/1580293569897984000/members" rel="noopener noreferrer"&gt;our team&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;📺 Subscribe to our &lt;a href="https://www.youtube.com/amazonappstoredevelopers" rel="noopener noreferrer"&gt;Youtube channel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📧 Sign up for the &lt;a href="https://m.amazonappservices.com/devto-newsletter-subscribe" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  About the author
&lt;/h3&gt;

&lt;p&gt;Giovanni ("Gio") Laquidara is a Senior Dev Advocate at Amazon, where he works on supporting developers around the world using the Amazon Appstore across many devices. &lt;/p&gt;

&lt;p&gt;Previously, Gio worked as a software engineer building mobile apps, real-time defence systems, and VR/AR experiences. For fun, Gio enjoys low level programming, IoT hacking, and command line apps ⌨️✨.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can connect with Gio on &lt;a href="https://twitter.com/giolaq" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/glaquidara/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, and &lt;a href="https://giolaq.dev" rel="noopener noreferrer"&gt;giolaq.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>howto</category>
      <category>tutorial</category>
      <category>lottie</category>
      <category>tv</category>
    </item>
    <item>
      <title>Introducing the Input SDK for Amazon Appstore</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Thu, 06 Jul 2023 14:07:14 +0000</pubDate>
      <link>https://dev.to/amazonappdev/introducing-the-input-sdk-for-amazon-appstore-3760</link>
      <guid>https://dev.to/amazonappdev/introducing-the-input-sdk-for-amazon-appstore-3760</guid>
      <description>&lt;p&gt;by Gio Laquidara&lt;/p&gt;

&lt;p&gt;Imagine a skilled game developer successfully launches a popular game for Android. The mobile game features intuitive touch controls and engaging gameplay. There are hundreds of positive reviews in the appstore, and user growth is the current priority.&lt;/p&gt;

&lt;p&gt;There's now a sizable opportunity to expand the game to PCs through &lt;a href="https://developer.amazon.com/docs/appstore-on-windows/overview.html?cmp=_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Amazon Appstore for Windows 11&lt;/a&gt; and the &lt;a href="https://learn.microsoft.com/en-us/windows/android/wsa/" rel="noopener noreferrer"&gt;Windows Subsystem for Android (WSA)&lt;/a&gt;. However in order to support Android apps on PCs, the existing touch screen controls need to now work with mouse and keyboard inputs which can pose refactoring challenges. How can you ensure the best user experience for PC gamers? To understand how to support keyboard and mouse inputs in existing touch-based game or app, read my recent suggestions in this &lt;a href="https://developer.amazon.com/apps-and-games/blogs/2023/03/mapping-app-input-with-wsa?cmp=_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;developer article on mapping inputs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.amazon.com/docs/appstore-on-windows/input-sdk.html?cmp=_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Amazon Input SDK&lt;/a&gt; enhances the user experience by providing display on-screen information for the available inputs for specific actions in games. This article will show how to use the Input SDK to help users understand how to navigate and interact using mouse and keyboard inputs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3w69lao4zq3ofeo18zm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3w69lao4zq3ofeo18zm.png" alt="Help Screen" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whether you prefer native Android development or building with Unity, we have you covered. The Amazon Input SDK comes in two versions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://developer.amazon.com/docs/appstore-on-windows/input-sdk.html?cmp=_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Amazon Input SDK (Java/Kotlin)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.amazon.com/docs/appstore-on-windows/input-sdk-unity.html?cmp=_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Amazon Input SDK for Unity&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The following sections cover how integrate both flavors of the Input SDK. &lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon Input SDK (Java/Kotlin)
&lt;/h3&gt;

&lt;p&gt;Let's start by exploring the usage of the &lt;a href="https://developer.amazon.com/docs/appstore-on-windows/input-sdk.html?cmp=_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Amazon Input SDK for Java/Kotlin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To begin using the SDK in your app, add the Amazon Input SDK to the dependencies section of your app-level build.gradle file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;...&lt;/span&gt;
      &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.amazon.device.inputmapping:inputsdklib:1.0.0'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main component of this SDK is the &lt;code&gt;InputMappingProvider&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When a user requests a help screen, the SDK will use this provider to present the control-action map. The first step in using this SDK is to implement the InputMappingProvider interface and return your input map in the onProvideInputMap method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomInputMapProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;InputMappingProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onProvideInputMap&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;InputMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// returns the input map&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have implemented this interface, you can register your input mapping provider through the Input static class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;inputMappingClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInputMappingClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;inputMappingClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputMappingProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomInputMapProvider&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The active input mapping provider is not affected by the activities lifecycle events and remains valid across different activities. However, you can change it whenever you prefer by using the InputMappingClient and setting a different input mapping provider.&lt;/p&gt;

&lt;p&gt;After defining the input mapping provider, you can simply call the following method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;TriggerHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;showHelp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"My App"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will display the help screen to guide users on how to play your game.&lt;/p&gt;

&lt;p&gt;Now let's dive into the details of the &lt;strong&gt;Input Map&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1llf0asi1ngqw3ux3tsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1llf0asi1ngqw3ux3tsm.png" alt=" " width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;InputMap&lt;/code&gt; is the collection of your app's input-action mappings &lt;code&gt;InputAction&lt;/code&gt; arranged in groups &lt;code&gt;InputGroup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An input action refers to an event that corresponds to an action performed within the app. This action can be associated with a single key or a combination of keys. For instance, in the given example, the action "Jump" is linked to the pressing of the space key, while the action "Move" is associated with the movement of the mouse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;jumpInputAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Jump"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;MyGameActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;JUMP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ordinal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// MyGameActions here is an enumeration in the game&lt;/span&gt;
            &lt;span class="nc"&gt;InputControls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;KeyEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KEYCODE_SPACE&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nf"&gt;emptyList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;move&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Move"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;MyGameActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MOVE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ordinal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;InputControls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;emptyList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InputControls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MOUSE_MOVEMENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each input action must be linked to a specific input group. Each input group consists of a label and a collection of input actions categorized within the group. In the previous section, we defined various input actions, and now we can illustrate this concept with an example. Let's create an input group called "Basic Movement," which includes the defined input actions from the previous section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;movementGroup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InputGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Basic Movement"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jumpInputAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After defining all the necessary groups, you can pass them to the InputMap.create method to return the input map for your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;InputMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;moveGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gameControls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;MouseSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;InputMap.create()&lt;/code&gt; method allows you to define the mouse settings applicable to the app.&lt;/p&gt;

&lt;p&gt;Specifically, you can enable the adjustment of the mouse sensitivity and invert the Y-axis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;MouseSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;adjustableSensitivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;invertedYAxis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unity SDK
&lt;/h3&gt;

&lt;p&gt;If you are using Unity for your game and want to use the Amazon Input SDK, here are the steps to integrate the SDK into your Unity projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download the Amazon Input SDK for Unity &lt;a href="https://developer.amazon.com/docs/appstore-on-windows/input-sdk-unity.html?cmp=_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The download includes the &lt;code&gt;.unitypackage&lt;/code&gt; file and a sample app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From the Assets menu, select Import Package &amp;gt; Custom Package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Browse for &lt;code&gt;amazon.device.inputmapping.unitypackage&lt;/code&gt; and select it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select all the files in the subsequent import dialog and click Import.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to Preferences &amp;gt; External Tools. In the Android section, uncheck Gradle installed with Unity and choose the required Gradle version for your project. We recommend Version 5.6.4.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to Project settings &amp;gt; Player, select the Android tab, and expand the Publishing settings section.&lt;br&gt;
In the Build section, click the checkbox for Custom Launcher Gradle Template as shown in the following image.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6dkw8aum74j6pwlxz4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6dkw8aum74j6pwlxz4a.png" alt="Custom launcher Gradle Option" width="663" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the following dependencies in the dependency section of the Gradle launcher template file
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.android.support.constraint:constraint-layout:2.0.4'&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.android.support:recyclerview-v7:28.0.0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After setting up the Input SDK for your Unity Project, you are ready to use the main component that provides the input map on request: the InputMappingProvider interface.&lt;/p&gt;

&lt;p&gt;Implement this interface and the Amazon Input SDK for Unity will be able to show the input mapping when a user requests a help screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// C# example for Unity&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomInputMappingProvider&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;InputMappingProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;InputMap&lt;/span&gt; &lt;span class="nf"&gt;OnProvideInputMap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// create an input map&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inputMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use your custom Input Mapping Provider, you need to register it by calling SetInputMappingProvider of the InputMappingClient, as shown in the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
 &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_inputMappingClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInputMappingClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_inputMappingClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetInputMappingProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CustomInputMappingProvider&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After registering it you will be able to show the help screen with the mapping to the user calling&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;TriggerHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ShowHelp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"My App"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Input Map
&lt;/h3&gt;

&lt;p&gt;The input map returned from the OnProvideInputMap of your CustomInputMappingProvider will contains all the mapping key events/mouse click to input actions.&lt;/p&gt;

&lt;p&gt;An input action is an event corresponding to an app action. The input action can be mapped to a key or a combination of keys. In the following example, the "Jump" action is mapped to the space key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jump&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"Jump"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JUMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//where Actions is an enumeration for the game actions&lt;/span&gt;
        &lt;span class="n"&gt;InputControls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; 
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;AndroidKeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYCODE_SPACE&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the "Move Left" action is mapped to the left key on the numeric keypad and "Move Right" is mapped to the right key on the numeric keypad.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;moveLeft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"Move Left"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MOVE_LEFT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;InputControls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;AndroidKeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYCODE_NUMPAD_LEFT&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;moveRight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"Move Right"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MOVE_RIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;InputControls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;AndroidKeyCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEYCODE_NUMPAD_RIGHT&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will have to group all the desired actions in a InputGroup&lt;/p&gt;

&lt;p&gt;An input group has a group label and a list of input actions that belong to the group. The following example shows a "Basic Movement" input group created with the input actions defined in the previous section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;InputGroup&lt;/span&gt; &lt;span class="n"&gt;movementInputGroup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InputGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Basic Movement"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;jump&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;moveLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;moveRight&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then collect all your groups of input and pass it to the InputMap creation. The input map also contains the mouse settings that are applicable for the app, such as allowing the adjustment of the sensitivity of the mouse or inverting the Y Axis (in the following code false and true respectively).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;inputMap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InputMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;movementInputGroup&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;MouseSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are ready not to return your input map from the OnProvideInputMap of your InputMappingProvider&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap up
&lt;/h3&gt;

&lt;p&gt;By integrating the Amazon Input SDK in touch games on Android, you can provide clear instructions to players on how to use keyboard and mouse inputs effectively on devices with keyboard and mice. This will help ensure a smooth transition from touch controls to PC inputs and enhance the overall user experience.&lt;/p&gt;

&lt;p&gt;To know more about Amazon Input SDK head over to &lt;a href="https://developer.amazon.com/docs/appstore-on-windows/input-sdk.html?cmp=2023_07_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;our docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay updated&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;For the latest Amazon Appstore developer news, product releases, tutorials, and more:&lt;/p&gt;

&lt;p&gt;📣 Follow &lt;a href="https://twitter.com/AmazonAppDev" rel="noopener noreferrer"&gt;@AmazonAppDev&lt;/a&gt; and &lt;a href="https://twitter.com/i/lists/1580293569897984000/members" rel="noopener noreferrer"&gt;our team&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;📺 Subscribe to our &lt;a href="https://www.youtube.com/amazonappstoredevelopers" rel="noopener noreferrer"&gt;Youtube channel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📧 Sign up for the &lt;a href="https://m.amazonappservices.com/devto-newsletter-subscribe" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  About the author
&lt;/h3&gt;

&lt;p&gt;Giovanni ("Gio") Laquidara is a Senior Dev Advocate at Amazon, where he works on supporting developers around the world using the Amazon Appstore across many devices. &lt;/p&gt;

&lt;p&gt;Previously, Gio worked as a software engineer building mobile apps, real-time defence systems, and VR/AR experiences. For fun, Gio enjoys low level programming, IoT hacking, and command line apps ⌨️✨.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can connect with Gio on &lt;a href="https://twitter.com/giolaq" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/glaquidara/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, and &lt;a href="https://giolaq.dev" rel="noopener noreferrer"&gt;giolaq.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adding IAP to Flutter apps for Amazon Appstore</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Fri, 02 Jun 2023 14:29:05 +0000</pubDate>
      <link>https://dev.to/amazonappdev/adding-iap-to-flutter-apps-for-amazon-appstore-45jc</link>
      <guid>https://dev.to/amazonappdev/adding-iap-to-flutter-apps-for-amazon-appstore-45jc</guid>
      <description>&lt;p&gt;After spending countless hours developing a high-quality app experience, it's time to build monetisation features into your product. An effective way to do this is by implementing an in-app purchasing (IAP) system and deploy your app across multiple platforms and app stores. &lt;/p&gt;

&lt;p&gt;By utlizing powerful cross-platform app development frameworks such as &lt;a href="https://flutter.dev/" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt;, you are able to build your app once and deploy it across both iOS and Android.  Integrating In-app purchasing across app stores can be challenging when having to manage multiple SDKs.&lt;/p&gt;

&lt;p&gt;Over the past few months, I've been interested in building a Flutter app that integrates in-app purchasing across Google Play, Apple Appstore and Amazon Appstore. I was interested in proving this out with Flutter specifically to test out their "&lt;a href="https://docs.flutter.dev/development/platform-integration/platform-channels" rel="noopener noreferrer"&gt;platform channels&lt;/a&gt;" feature for building with platform-specific code. This enables me to integrate each In-app purchasing SDK in one code base. While this is possible, I'm aware that this can easily become a lengthy process.&lt;/p&gt;

&lt;p&gt;Thankfully the open source community has built a related project: Introducing the &lt;a href="https://github.com/dooboolab/flutter_inapp_purchase" rel="noopener noreferrer"&gt;flutter_inapp_purchase&lt;/a&gt; library. This project is an interesting open-sourced plugin for easily integrating in-app purchasing for each of the app stores mentioned above.&lt;/p&gt;

&lt;p&gt;For this guide, walk-through how to integrate a sample music artist's app that integrates with the Amazon Appstore SDK for in-app purchasing and subscriptions. Let's dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case Study: GIOLAQ's Music App 💿👨‍🎤
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpxvr4bevx5qj86vkegc.gif%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmpxvr4bevx5qj86vkegc.gif%3Fraw%3Dtrue" alt="GIOLAQ's Music App" width="600" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's pretend that "&lt;strong&gt;GIOLAQ&lt;/strong&gt;" is a fictional singer with an international fan base. In order to grow revenue, his record label launched an artist app for his music and merchandise to be available to purchase around the world.&lt;/p&gt;

&lt;p&gt;Fan's of GIOLAQ can listen to the music albums if they pay to unlock the exclusive content. The in-app purchasing options for the app are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.amazon.com/docs/in-app-purchasing/iap-overview.html#types-of-purchasable-items?cmp=2023_06_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Entitlements&lt;/a&gt; - Unlocking one of GIOLAQ's albums for your account to listen&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.amazon.com/docs/in-app-purchasing/iap-overview.html#types-of-purchasable-items?cmp=2023_06_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Subscriptions&lt;/a&gt; - An annual pass to listen to all the music produced by GIOLAQ&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.amazon.com/docs/in-app-purchasing/iap-overview.html#types-of-purchasable-items?cmp=2023_06_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Consumables&lt;/a&gt; - Concert tickets to GIOLAQ's live music concerts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup for In-app purchasing
&lt;/h2&gt;

&lt;p&gt;Before going through the code, let's first take care of the in-app purchase setup on the back-end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; If your need to integrate in-app purchasing with Flutter and Google Play or Apple, check out some excellent &lt;a href="https://medium.com/codechai/flutter-in-app-purchase-7a3fb9345e2a" rel="noopener noreferrer"&gt;community tutorials&lt;/a&gt; on how to do it. You'll notice the integration steps are almost the same, which includes activating IAP services in each of the app store console and creating the IAP items in your developer settings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For integrating In-app purchasing for the Amazon Appstore, make sure to also reference the &lt;a href="https://developer.amazon.com/docs/in-app-purchasing/iap-create-and-submit-iap-items.html#create-new-in-app-items?cmp=_06_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;official guide&lt;/a&gt; in the Appstore docs.&lt;/p&gt;

&lt;p&gt;For building GIOLAQ Music I've created 3 IAP items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;em&gt;Entitlement&lt;/em&gt; IAP item to buy the whole album of GIOLAQ&lt;/li&gt;
&lt;li&gt;A yearly &lt;em&gt;subscription&lt;/em&gt; to grant all the music for one year.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;consumable item&lt;/em&gt; for the live music tickets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to test the GIOLAQ app, make sure to create the same IAP items that map to their unique identifiers which are referred to to as &lt;a href="https://developer.amazon.com/docs/in-app-purchasing/iap-overview.html#skus?cmp=_06_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;SKUs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to creating products with mapping SKUS remember to download the JSON file with the items. To this this, you'll navigate to the In-App Items tab of your app and click the &lt;em&gt;Export Multiple IAPs&lt;/em&gt; button with JSON as the selected format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08bbmt87yel6hywtlfju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08bbmt87yel6hywtlfju.png" alt="Download IAP Json file from Amazon Appstore Console" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you take these steps, the downloaded JSON file will used during testing. My sample JSON file for testing is &lt;a href="https://github.com/giolaq/flutter_amazon_iap_demo/blob/0e4a6a1e87fdd34cd5d8a4644966916ee74a7da3/iapitems/amazon.sdktester.json" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you would like to follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code base
&lt;/h2&gt;

&lt;p&gt;For the GIOLAQ Music project, I've inserted all the business logic for in-app purchasing in a file named &lt;code&gt;iap_handler.dart&lt;/code&gt;. The 3 additional files I've built are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;main.dart&lt;/code&gt; which handles the the main widget of the app and navigation between the two screens&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;music.dart&lt;/code&gt; handles the music UI screen for displaying the album cover and the locked/unlocked state of the purchasable items&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;purchase_page.dart&lt;/code&gt; is where you can spend your virtual money to buy the purchasable items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are UI examples of these files in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgiolaq%2Fflutter_amazon_iap_demo%2F30e14060fec11469091e3aab8ae1a9d7d30f8440%2Fimages%2Fhomelocked.png%3Ftoken%3DGHSAT0AAAAAACCYIWJWAKQDB6CYTI5DB7LYZDLKIYA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgiolaq%2Fflutter_amazon_iap_demo%2F30e14060fec11469091e3aab8ae1a9d7d30f8440%2Fimages%2Fhomelocked.png%3Ftoken%3DGHSAT0AAAAAACCYIWJWAKQDB6CYTI5DB7LYZDLKIYA" alt="GIOLAQ's Music App UI" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgiolaq%2Fflutter_amazon_iap_demo%2Fmain%2Fimages%2Fpurchase-completed.png%3Ftoken%3DGHSAT0AAAAAACCYIWJX2SAPVIBW47CZRETQZDLKPSA" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgiolaq%2Fflutter_amazon_iap_demo%2Fmain%2Fimages%2Fpurchase-completed.png%3Ftoken%3DGHSAT0AAAAAACCYIWJX2SAPVIBW47CZRETQZDLKPSA" alt="GIOLAQ's Music App UI" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrating the Flutter IAP plugin
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Add the Flutter IAP package as a dependency
&lt;/h3&gt;

&lt;p&gt;To start using the Flutter IAP Plugin from dooboolab remember to add the dependency on the &lt;code&gt;pubspec.yaml&lt;/code&gt; so that you can then ‌import all the packages objects and classes into your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter&lt;/span&gt;

  &lt;span class="na"&gt;flutter_inapp_purchase&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^5.3.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Initialize the plugin
&lt;/h3&gt;

&lt;p&gt;Initialize the plugin with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;    &lt;span class="n"&gt;FlutterInappPurchase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; This has to be done before purchasing, on &lt;strong&gt;iOS&lt;/strong&gt; it also checks if the client can make payments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my app, I've initialized the plugin and wrapped the instance in a class as a singleton. This is useful if you want to adopt different SDKs in the future or for easy testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Subscribe to the IAP connections
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;IAP_HANDLE&lt;/code&gt; widget, you'll write some code to subscribe to &lt;code&gt;StreamSubscription&lt;/code&gt;  in order to listen for IAP Connection status, Purchases status, and Errors. &lt;/p&gt;

&lt;p&gt;Here's an example of how to listen for these events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;_connectionSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;FlutterInappPurchase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connectionUpdated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="c1"&gt;// Do something with the connection status&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;_purchaseUpdatedSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;FlutterInappPurchase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;purchaseUpdated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;productItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Update the UI with updated status of the purchase&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;_purchaseErrorSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;FlutterInappPurchase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;purchaseError&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;purchaseError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="c1"&gt;// Handle IAP Error&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Load the purchasable objects
&lt;/h3&gt;

&lt;p&gt;Next, you will load the Purchasable objects according to their SKUs. In this line of code, I am populating a list of purchasable items in order to display them in the purchase screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;iapItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;FlutterInappPurchase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skuList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Make a test purchase!
&lt;/h3&gt;

&lt;p&gt;To purchase an item, go ahead and call the following method with the SKU of the item you want to purchase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;FlutterInappPurchase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requestPurchase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The purchase confirmation will arrive on the &lt;code&gt;_purchaseUpdatedSubscription&lt;/code&gt; where you can handle the updates of your UI based once the purchase is successful.&lt;/p&gt;

&lt;p&gt;In GIOLAQ Music app the &lt;code&gt;requestPurchase()&lt;/code&gt; call is wrapped into a &lt;code&gt;buy&lt;/code&gt; function. This function is called by the &lt;code&gt;onPressed&lt;/code&gt; of the widgets within the Purchase screen to associate the objects to buy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Handle the purchase update
&lt;/h3&gt;

&lt;p&gt;Remember to handle purchase result using the callbacks you registered in &lt;strong&gt;&lt;em&gt;Step 3 Subscribe to the IAP connections&lt;/em&gt;&lt;/strong&gt;. For this example, I've used the following snippet to propagate the purchase state in the Music screen to unlock the music or increment the quantity of purchased ticket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt; &lt;span class="n"&gt;FlutterInappPurchase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;purchaseUpdated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;productItem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;_purchasesUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productItem&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="n"&gt;_updateStreamOnDone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 7: Clean up when you leave!
&lt;/h3&gt;

&lt;p&gt;Remember to cancel the &lt;code&gt;StreamSubscription&lt;/code&gt; when you are no longer using. The following code within the &lt;code&gt;dispose&lt;/code&gt; method of the &lt;code&gt;IAP_Handler&lt;/code&gt; widget is an example of how to get this done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;    &lt;span class="n"&gt;_connectionSubscription&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_purchaseUpdatedSubscription&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_purchaseErrorSubscription&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing phase
&lt;/h2&gt;

&lt;p&gt;To test the app , make sure to pick up an &lt;a href="https://www.amazon.com/Amazon-Fire-Tablet-Family/b/?node=6669703011" rel="noopener noreferrer"&gt;Amazon Fire tablet&lt;/a&gt; for yourself and active the &lt;a href="https://developer.amazon.com/docs/fire-tablets/connecting-adb-to-device.html?cmp=_06_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;developer options&lt;/a&gt; in order to support sideloading test apps from Android Studio. Using &lt;a href="https://developer.android.com/tools/adb" rel="noopener noreferrer"&gt;Android debug bridge (adb)&lt;/a&gt;, upload the IAP JSON file to the device using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb push &amp;lt;_Your_JSON_File_Folder_&amp;gt;/amazon.sdktester.json /sdcard/amazon.sdktester.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, enable sandbox mode with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb shell setprop debug.amazon.sandboxmode debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this make sure you have installed the Amazon App Tester on the Tablet. Once thats done, you can build and run the app from your IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;I'm always delighted when I discover new ways the open-source community is fixing issues and covering needs. Special thanks to the open source maintainers at &lt;a href="https://dooboolab.com/docs/works/projects/dooboo/" rel="noopener noreferrer"&gt;dooboolab&lt;/a&gt; for building and maintaining this &lt;a href="https://github.com/dooboolab/flutter_inapp_purchase/" rel="noopener noreferrer"&gt;flutter community plugin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to check out the source code of my sample GIOLAQ Music app and review how I built in in-app purchasing for Amazon Appstore, head over head to GitHub to try the &lt;br&gt;
&lt;a href="https://github.com/giolaq/flutter_amazon_iap_demo" rel="noopener noreferrer"&gt;flutter_amazon_iap_demo&lt;/a&gt; project for yourself.&lt;/p&gt;

&lt;p&gt;To know more about Amazon In-App Purchasing SDK head over to the &lt;a href="https://developer.amazon.com/docs/in-app-purchasing/iap-overview.html?cmp=_06_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay updated&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;For the latest Amazon Appstore developer news, product releases, tutorials, and more:&lt;/p&gt;

&lt;p&gt;📣 Follow &lt;a href="https://twitter.com/AmazonAppDev" rel="noopener noreferrer"&gt;@AmazonAppDev&lt;/a&gt; and &lt;a href="https://twitter.com/i/lists/1580293569897984000/members" rel="noopener noreferrer"&gt;our team&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;📺 Subscribe to our &lt;a href="https://www.youtube.com/amazonappstoredevelopers" rel="noopener noreferrer"&gt;Youtube channel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📧 Sign up for the &lt;a href="https://m.amazonappservices.com/devto-newsletter-subscribe" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  About the author
&lt;/h3&gt;

&lt;p&gt;Giovanni ("Gio") Laquidara is a Senior Dev Advocate at Amazon, where he works on supporting developers around the world using the Amazon Appstore across many devices. &lt;/p&gt;

&lt;p&gt;Previously, Gio worked as a software engineer building mobile apps, real-time defence systems, and VR/AR experiences. For fun, Gio enjoys low level programming, IoT hacking, and command line apps ⌨️✨.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can connect with Gio on &lt;a href="https://twitter.com/giolaq" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/glaquidara/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, and &lt;a href="https://giolaq.dev" rel="noopener noreferrer"&gt;giolaq.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>amazonappstore</category>
      <category>flutter</category>
      <category>iap</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Resizing apps in Windows Subsystem for Android™ (WSA)</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Fri, 17 Feb 2023 10:18:07 +0000</pubDate>
      <link>https://dev.to/amazonappdev/resizing-apps-in-windows-subsystem-for-android-wsa-jj3</link>
      <guid>https://dev.to/amazonappdev/resizing-apps-in-windows-subsystem-for-android-wsa-jj3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Because Microsoft is ending support for the Windows Subsystem for Android (WSA), Amazon Appstore on Windows 11 will no longer be supported after March 5, 2025. Amazon and Microsoft are partnering to create a smooth end of support experience for developers and customers of Amazon Appstore on Windows 11. Developers will no longer be able to submit net new apps targeting Windows 11 after March 5, 2024, but developers with an existing app can continue to submit app updates until Amazon Appstore on Windows 11 is fully discontinued.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Starting on March 6, 2024, Windows 11 customers will not be able to search for Amazon Appstore or associated apps from the Microsoft Store. Customers may continue using Amazon Appstore apps that they previously installed and will still be able to receive app updates.&lt;/p&gt;

&lt;p&gt;As an Android developer, porting your app to the &lt;a href="https://developer.amazon.com/apps-and-games/appstore-on-windows-11?cmp=2023_02_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Amazon Appstore for Windows 11&lt;/a&gt; can help expand your customer base. However, it's important to keep in mind that Windows 11 allows users to freely resize app windows, and it's crucial to ensure that your app is responsive and stable when the viewport window is resized.&lt;/p&gt;

&lt;p&gt;In this guide, we will cover key considerations for handling window resizing in your Android app on Windows Subsystem for Android™ (WSA).&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimum screen requirements
&lt;/h2&gt;

&lt;p&gt;To ensure a seamless experience for users, Windows 11 enforces a minimum screen requirement of 720p resolution (1280x720) for screens larger than 9”. When the aspect ratio of a window size does not align with the device screen size, the result may be letterboxing or pillarboxing, which results in bars being placed on the sides of the window in order to center it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs0e9hwj156v5uuthggzy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs0e9hwj156v5uuthggzy.jpg" alt="Pillarboxing and Letterboxing" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial launch size
&lt;/h2&gt;

&lt;p&gt;There are several launch size options to consider when launching your app on Windows 11:&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;static launch bounds&lt;/strong&gt;. Use &lt;code&gt;&amp;lt;layout&amp;gt;&lt;/code&gt; inside the manifest entry of your activity to specify a "fixed" starting size. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;layout&lt;/span&gt; &lt;span class="na"&gt;android:defaultHeight=&lt;/span&gt;&lt;span class="s"&gt;"500dp"&lt;/span&gt;
         &lt;span class="na"&gt;android:defaultWidth=&lt;/span&gt;&lt;span class="s"&gt;"600dp"&lt;/span&gt;
         &lt;span class="na"&gt;android:gravity=&lt;/span&gt;&lt;span class="s"&gt;"top|end"&lt;/span&gt;
         &lt;span class="na"&gt;android:minHeight=&lt;/span&gt;&lt;span class="s"&gt;"450dp"&lt;/span&gt;
         &lt;span class="na"&gt;android:minWidth=&lt;/span&gt;&lt;span class="s"&gt;"300dp"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use dynamic launch bounds&lt;/strong&gt;. An activity can create and use &lt;code&gt;ActivityOptions.setLaunchBounds(Rect)&lt;/code&gt; when creating a new activity. By specifying an empty rectangle, your app can be maximized.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Make sure to specify these options only for the root activity and consider using a springboard activity to clear the activity stack in the task with a new start.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Better visual control through responsive layouts
&lt;/h2&gt;

&lt;p&gt;Supporting different screen sizes with &lt;strong&gt;responsive layouts&lt;/strong&gt; ensures that you have control of the presentation layout no matter which form factor the screen is presented.&lt;/p&gt;

&lt;p&gt;For a more information on dynamic Window sizes and establishing clear breakpoints for your app’s user interface in Kotlin and Java, read &lt;a href="https://developer.android.com/guide/topics/large-screens/support-different-screen-sizes#:~:text=Responsive%2Fadaptive%20layouts%20provide%20an,such%20as%20multi%2Dwindow%20mode." rel="noopener noreferrer"&gt;Android’s guide on supporting different screen sizes&lt;/a&gt;. Also, consider how &lt;a href="https://developer.android.com/guide/topics/large-screens/multi-window-support" rel="noopener noreferrer"&gt;multi-window mode&lt;/a&gt; can enable your app to function next to other apps, and consider the differences between activity context and application context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resizing windows
&lt;/h2&gt;

&lt;p&gt;You can provide a better user experience by ensuring that the app’s layout adapts to the new window size. This can be achieved by using the &lt;a href="https://developer.android.com/reference/android/view/View#onSizeChanged(int,%20int,%20int,%20int)" rel="noopener noreferrer"&gt;&lt;code&gt;onSizeChanged()&lt;/code&gt;&lt;/a&gt; method in your activity class. This method is called when the size of the app window changes, and you can use it to adjust the layout of the app accordingly.&lt;/p&gt;

&lt;p&gt;In Windows 11, users can resize an app's window by dragging the lower right corner. There are two options for handling window resizing when using the View class:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Respond to configuration changes dynamically&lt;/strong&gt; by calling onConfigurationChanged() and adding &lt;code&gt;android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"&lt;/code&gt; to the activity's manifest. Read the &lt;a href="https://developer.android.com/guide/topics/resources/runtime-changes" rel="noopener noreferrer"&gt;handling configuration changes docs&lt;/a&gt; for more code snippets and details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Let the system restart the activity&lt;/strong&gt;. In this case, you should implement &lt;code&gt;onSaveInstanceState()&lt;/code&gt; and use the ViewModel architecture component to restore the previous saved state.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Windows 11 allows users to change the screen orientation of their device, so it's important to make sure that your app can handle changes in screen orientation without crashing. You can do this by adding &lt;code&gt;android:configChanges="orientation|screenSize"&lt;/code&gt;to your activity in the AndroidManifest.xml file. This will allow your app to handle changes in &lt;strong&gt;screen orientation&lt;/strong&gt; without restarting the activity.&lt;/p&gt;

&lt;p&gt;If your app is using Jetpack Compose, the resizing behavior depends on the size of the app window and the layout that is used. You can use the Compose's layout composables such as Box, Row, and Column to layout the components of your app. See the &lt;a href="https://developer.android.com/jetpack/compose/layouts/basics" rel="noopener noreferrer"&gt;Compose layout basics docs&lt;/a&gt; for more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional resizing considerations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test your app&lt;/strong&gt; for both functionality and visual UI issues to make sure it handles changes in window size appropriately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't call &lt;a href="https://developer.android.com/reference/android/app/Activity#finish()" rel="noopener noreferrer"&gt;&lt;code&gt;finish()&lt;/code&gt;&lt;/a&gt; in your activity's &lt;a href="https://developer.android.com/guide/components/activities/activity-lifecycle#ondestroy" rel="noopener noreferrer"&gt;&lt;code&gt;onDestroy&lt;/code&gt;&lt;/a&gt; method&lt;/strong&gt;. This causes the app to close upon resize, rather than restart.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid using window types that are not compatible&lt;/strong&gt;, such as &lt;code&gt;TYPE_KEYGUARD&lt;/code&gt; and &lt;code&gt;TYPE_APPLICATION_MEDIA&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make sure that an activity restart is fast&lt;/strong&gt; by caching objects that have been previously allocated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If you do not want the user to resize your app&lt;/strong&gt;, specify &lt;code&gt;android:resizeableActivity=false&lt;/code&gt; within the &lt;code&gt;&amp;lt;application&amp;gt;&lt;/code&gt; subclass within your manifest file.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you have prepped and tested your app, remember to reach out via our &lt;a href="https://developer.amazon.com/support/contact-us?cmp=2023_02_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Contact Us&lt;/a&gt; page to request your app for WSA submission access. Once the request is approved, log in to the &lt;a href="https://developer.amazon.com/home.html?cmp=2023_02_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;Amazon Appstore Developer Console&lt;/a&gt; and then select the app from the &lt;a href="https://developer.amazon.com/apps-and-games/console/apps/list.html?cmp=2023_02_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;My Apps list&lt;/a&gt;. On the app detail page, open the &lt;strong&gt;Supported Devices&lt;/strong&gt; menu, navigate to the &lt;strong&gt;Windows Devices&lt;/strong&gt; tab, select Windows devices for targeting, and complete your submission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To discuss developer issues with the community and file bugs or feature requests, &lt;a href="https://github.com/microsoft/WSA" rel="noopener noreferrer"&gt;visit the Windows Subsystem for Android GitHub repository&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To receive updates regarding future Amazon Appstore on Windows 11 program updates, sign up for &lt;a href="https://developer.amazon.com/apps-and-games/appstore-on-windows-11?cmp=2023_02_devg&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org#stay-up-to-date" rel="noopener noreferrer"&gt;email notifications&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/windows/android/wsa/#window-management-and-resizing" rel="noopener noreferrer"&gt;Microsoft’s guide to Window resizing&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developer.android.com/topic/arc/window-management" rel="noopener noreferrer"&gt;Android docs on Windows management&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>authentication</category>
      <category>networking</category>
      <category>security</category>
    </item>
    <item>
      <title>How to develop custom splash screens on Fire TV</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Mon, 23 Jan 2023 20:53:06 +0000</pubDate>
      <link>https://dev.to/amazonappdev/how-to-develop-custom-splash-screens-on-fire-tv-mcm</link>
      <guid>https://dev.to/amazonappdev/how-to-develop-custom-splash-screens-on-fire-tv-mcm</guid>
      <description>&lt;p&gt;&lt;a href="https://androidweekly.net/issues/issue-555" rel="noopener noreferrer"&gt;Featured in AndroidWeekly 555&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Storytime: Blank screens and suboptimal UX
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Here's a common scenario:&lt;/strong&gt; A user turns on the Fire TV device and immediately launches your app. Unfortunately for everyone, your app has not fully-loaded into memory, which is known by developers as "&lt;a href="https://developer.android.com/topic/performance/vitals/launch-time#cold" rel="noopener noreferrer"&gt;cold start&lt;/a&gt;". Cold starts cause delays between the start of your app and when the launcher activity’s &lt;code&gt;onCreate()&lt;/code&gt; function is called. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w6r6bk1o96txrytctaq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8w6r6bk1o96txrytctaq.gif" alt="Black screen at cold start" width="600" height="338"&gt;&lt;/a&gt;&lt;br&gt;&lt;em&gt;👆 Loading wait times + blank screens = *low&lt;/em&gt; app satisfaction* 
  &lt;/p&gt;

&lt;p&gt;While your app is executing the &lt;code&gt;onCreate()&lt;/code&gt; function, memory-intensive operations may further delay the launch of the main activity. Delays will cause your users to see a blank/black screen while this activity inflates the screen’s UI. Often this suboptimal user experience leads to a common risk: users perceive your app as non-responsive and will exit the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution: Define splash screens
&lt;/h2&gt;

&lt;p&gt;An efficient way to overcome this ambiguous first launch user experience is by creating a custom theme that overrides the &lt;code&gt;android:windowBackground&lt;/code&gt; property. As part of the custom theme, applications can specify their branded splash screen image. Android will display the splash screen specified as part of &lt;code&gt;windowBackground&lt;/code&gt; while launching the application, thus improving the user experience. Assign this to an Activity responsible to display the splash screen and launch the main activity.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1:&lt;/strong&gt; Create your custom splash screen
&lt;/h3&gt;

&lt;p&gt;Create a file named &lt;code&gt;splashscreen.xml&lt;/code&gt; in the &lt;code&gt;drawable&lt;/code&gt; directory. This file will contain all the graphic elements and layers of your splash screen. This file should have the following markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;layer-list&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt; &lt;span class="na"&gt;android:opacity=&lt;/span&gt;&lt;span class="s"&gt;"opaque"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;shape&lt;/span&gt; &lt;span class="na"&gt;android:shape=&lt;/span&gt;&lt;span class="s"&gt;"rectangle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;solid&lt;/span&gt; &lt;span class="na"&gt;android:color=&lt;/span&gt;&lt;span class="s"&gt;"@android:color/white"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/shape&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;android:drawable=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/splashscreen_logo"&lt;/span&gt; &lt;span class="na"&gt;android:gravity=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/layer-list&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;  The SVG (Scalable Vector Graphics) image format load faster compared to other image formats when testing on FireTV devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2:&lt;/strong&gt; Create the splash screen theme
&lt;/h3&gt;

&lt;p&gt;Define a new style in the file &lt;code&gt;styles.xml&lt;/code&gt; of your project then add an &lt;code&gt;android:windowBackground&lt;/code&gt; item set as the &lt;code&gt;@drawable/splashscreen&lt;/code&gt; splash screen you created in the prior step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"SplashScreenTheme"&lt;/span&gt; &lt;span class="na"&gt;parent=&lt;/span&gt;&lt;span class="s"&gt;"Theme.SplashScreenTV.NoActionBar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"android:windowBackground"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@drawable/splashscreen&lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3:&lt;/strong&gt; Create the splash screen activity
&lt;/h3&gt;

&lt;p&gt;Create a new activity responsible for displaying the splash screen, launch the main activity, then terminate:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Kotlin&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SplashScreenActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Java&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SplashScreenActivity&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt; &lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onCreate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;startActivity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4:&lt;/strong&gt; Apply the splash screen theme to the splash screen activity
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;AndroidManifest.xml&lt;/code&gt;, set the theme attribute of the &lt;code&gt;SplashScreenActivity&lt;/code&gt; to the theme you setup in step 2. The &lt;code&gt;SplashScreenActivity&lt;/code&gt; will be the first activity called by the launcher, so remember to move the intent filter with the action &lt;code&gt;android.intent.action.MAIN&lt;/code&gt; and category &lt;code&gt;android.intent.category.LEANBACK_LAUNCHER&lt;/code&gt; from the Main Activity to the &lt;code&gt;SplashScreenActivity&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".SplashScreenActivity"&lt;/span&gt;
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
    &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"@string/title_activity_splash_screen"&lt;/span&gt;
    &lt;span class="na"&gt;android:theme=&lt;/span&gt;&lt;span class="s"&gt;"@style/SplashScreenTheme"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LEANBACK_LAUNCHER"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Success:&lt;/strong&gt; Your custom splash screen is now complete!
&lt;/h2&gt;

&lt;p&gt;You have now implemented a custom splash screen and optimized the starting time of your Fire TV app displaying your branding image. To test this for yourself, use the Android Debug Bridge and follow our &lt;a href="https://developer.amazon.com/docs/fire-tv/installing-and-running-your-app.html?cmp=2022_01_devg-sa&amp;amp;ch=soc&amp;amp;chlast=soc&amp;amp;pub=devto&amp;amp;publast=devto&amp;amp;type=org&amp;amp;typelast=org" rel="noopener noreferrer"&gt;docs on installing your app on Fire TV&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3t7btoj06nh3mxy8dxk1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3t7btoj06nh3mxy8dxk1.gif" alt="Splash screen at cold start" width="600" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source code&lt;/strong&gt;&lt;br&gt;
You can find the complete project source code on this &lt;a href="https://github.com/giolaq/splash-screen-fire-tv-demo" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://www.linkedin.com/in/kostakis-bouzoukas" rel="noopener noreferrer"&gt;Kostas&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/thomasjoe" rel="noopener noreferrer"&gt;Joe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay updated&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;For the latest Amazon Appstore developer news, product releases, tutorials, and more:&lt;/p&gt;

&lt;p&gt;📣 Follow &lt;a href="https://twitter.com/AmazonAppDev" rel="noopener noreferrer"&gt;@AmazonAppDev&lt;/a&gt; and &lt;a href="https://twitter.com/i/lists/1580293569897984000/members" rel="noopener noreferrer"&gt;our team&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;📺 Subscribe to our &lt;a href="https://www.youtube.com/amazonappstoredevelopers" rel="noopener noreferrer"&gt;Youtube channel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📧 Sign up for the &lt;a href="https://m.amazonappservices.com/devto-newsletter-subscribe" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  About the author
&lt;/h3&gt;

&lt;p&gt;Giovanni ("Gio") Laquidara is a Senior Dev Advocate at Amazon, where he works on supporting developers around the world using the Amazon Appstore across many devices. &lt;/p&gt;

&lt;p&gt;Previously, Gio worked as a software engineer building mobile apps, real-time defence systems, and VR/AR experiences. For fun, Gio enjoys low level programming, IoT hacking, and command line apps ⌨️✨.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can connect with Gio on &lt;a href="https://twitter.com/giolaq" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/glaquidara/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, and &lt;a href="https://giolaq.dev" rel="noopener noreferrer"&gt;giolaq.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>How to integrate push notifications for Amazon Appstore</title>
      <dc:creator>Giovanni Laquidara</dc:creator>
      <pubDate>Fri, 18 Nov 2022 18:25:51 +0000</pubDate>
      <link>https://dev.to/amazonappdev/how-to-integrate-push-notifications-for-amazon-appstore-39j5</link>
      <guid>https://dev.to/amazonappdev/how-to-integrate-push-notifications-for-amazon-appstore-39j5</guid>
      <description>&lt;p&gt;Recently I was at &lt;a href="https://london.droidcon.com" rel="noopener noreferrer"&gt;Droidcon London&lt;/a&gt; catching up ✨ &lt;em&gt;in-person&lt;/em&gt; ✨ with Android developers and longtime friends. The event was well-run, full of engaging technical talks and great conversations.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yb4spq5cqz4k20o96y7.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8yb4spq5cqz4k20o96y7.jpeg" alt=" " width="562" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One particular conversation I had was with an Android + iOS app developer who found a way to sustainably freelance by launching multiple revenue streams: Ads, In App Purchasing (IAP), and selling online programming courses &lt;em&gt;(...a dream of mine to do someday when I have the time...&lt;/em&gt; 😉⏳ &lt;em&gt;).&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;He was building everything from games to utility apps and was confronted with a recurring issue: The app user base would steadily grow until hitting a plateau after a variable amount of time (months). Once new interest peaked, less new users were discovering and installing his apps. &lt;/p&gt;

&lt;p&gt;While I don't pretend to have a magic solution, I shared a suggestion based on a talk my colleague and I delivered hours earlier: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Launch your app in multiple app stores.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...and in my role as a Developer Advocate, I have to recommend these apps should definitely be the Amazon Appstore! 🥳📲&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.amazon.com/apps" rel="noopener noreferrer"&gt;Amazon Appstore&lt;/a&gt; offers an active global user base and one of the coolest features: existing apps can be installed directly on Windows 11.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What if your app could now reach millions of new desktop/laptop Windows 11 users around the world?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This developer then asked the standard software engineering questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Yes but...&lt;br&gt;
Are all the features I already developed going to be supported on the new system? How much effort is involved to port the app?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The classic yet honest answer to this is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"it depends!"&lt;/em&gt; 🤷&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So let's dive in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Porting Android apps to Amazon Appstore
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8bkcwynhne6kcu708se.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8bkcwynhne6kcu708se.jpg" alt=" " width="800" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.amazon.com/gp/mas/get/amazonapp" rel="noopener noreferrer"&gt;Amazon Appstore&lt;/a&gt; runs on Fire OS devices (Fire Tablets, Fire TVs...) and can be installed on directly on Android devices. Fire OS is based on &lt;a href="https://source.android.com/" rel="noopener noreferrer"&gt;AOSP (Android Open Source Project)&lt;/a&gt; and without Google Play Services running on it. So for developers with app features dependent on Google Play Services, some migration work is needed.&lt;/p&gt;

&lt;p&gt;For example, if your app relies on Firebase Cloud Messaging (FCM) for push notifications, this should be updated. Specifically in Fire OS, push notifications function through &lt;a href="https://developer.amazon.com/docs/adm/overview.html" rel="noopener noreferrer"&gt;Amazon Device Messaging (ADM)&lt;/a&gt;. Integrating the ADM SDK will allow your app to run smoothly in Fire OS.&lt;/p&gt;

&lt;p&gt;To support both FCM and ADM, the Amazon Appstore team also created Amazon Appstore Abstraction Library &lt;a href="https://developer.amazon.com/docs/a3l-messaging/understanding-a3l-messaging.html" rel="noopener noreferrer"&gt;A3L&lt;/a&gt; - an SDK to reduce porting time and code maintenance needs for notifications and messaging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating your app with A3L
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 0:&lt;/strong&gt; Download the A3L SDK&lt;/p&gt;

&lt;p&gt;Download the A3L SDK from our &lt;a href="https://developer.amazon.com/docs/a3l-messaging/understanding-a3l-messaging.html#download" rel="noopener noreferrer"&gt;developer documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterwards, make sure to add the downloaded &lt;strong&gt;.aar&lt;/strong&gt; to the &lt;strong&gt;app/libs&lt;/strong&gt; directory of your Android project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Add the A3L dependency to your project&lt;/p&gt;

&lt;p&gt;After this, you will have to add the dependency on this file of the project. Open the &lt;code&gt;build.gradle&lt;/code&gt; file and insert the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="o"&gt;...&lt;/span&gt;
     &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;files&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"libs/A3L-Messaging-1.0.0.aar"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Obtain the credentials&lt;/p&gt;

&lt;p&gt;Similar to what you already have done with Firebase through the &lt;code&gt;google-services.json&lt;/code&gt; file, you have to obtain ADM credentials in order to uniquely identify your app the web service.&lt;/p&gt;

&lt;p&gt;Once you have credentials, follow the instructions in our &lt;a href="https://developer.amazon.com/docs/adm/obtain-credentials.html" rel="noopener noreferrer"&gt;ADM docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Define the messaging service&lt;/p&gt;

&lt;p&gt;Now you will should create the Service that listens for messages and tokens from ADM.&lt;/p&gt;

&lt;p&gt;To do this, you will have to extend the class &lt;code&gt;A3LMessagingService&lt;/code&gt; and override these 2 methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyA3LMessagingService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;A3LMessagingService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onMessageReceived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;remoteMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RemoteMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"From: ${remoteMessage.from}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onNewToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Refreshed token: $token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To Enable this service you will need to declare in the &lt;code&gt;AndroidManifest.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;application&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;receiver&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MyA3LMessagingService"&lt;/span&gt;
        &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
        &lt;span class="na"&gt;android:enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.amazon.A3L.messaging.intent.REGISTRATION"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.amazon.A3L.messaging.intent.MESSAGE"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/receiver&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;meta-data&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.a3l.clsName"&lt;/span&gt; 
    &lt;span class="na"&gt;android:value=&lt;/span&gt;&lt;span class="s"&gt;"com.example.mya3lapp.MyA3LMessagingService"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

 &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Initialize the Service&lt;/p&gt;

&lt;p&gt;Now you define the callback &lt;code&gt;MainActivity&lt;/code&gt; to handle the registration phase and initialize the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;TAG&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"MainActivity"&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;onInitCallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OnInitCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;OnInitCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onReady&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initCallbackResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;InitCallbackResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initCallbackResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isSuccessFul&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Device Id: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;initCallbackResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Registration failed with Error: "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt;
                                &lt;span class="n"&gt;initCallbackResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;A3LMessaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onInitCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;supportFragmentManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginTransaction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;EggTimerFragment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newInstance&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commitNow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and with that update, you are all set! Let's see how to test this implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;You have three ways to test this integration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Web Console&lt;/li&gt;
&lt;li&gt;Server-side scripts&lt;/li&gt;
&lt;li&gt;Solution-specific APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For our use-case, the easiest way is with the &lt;a href="https://developer.amazon.com/adm/console" rel="noopener noreferrer"&gt;Amazon Appstore ADM Web Console&lt;/a&gt;. I suggest running the app on a Fire Tablet in order get the Device registration ID.&lt;br&gt;
This will be available in the &lt;code&gt;onReady&lt;/code&gt; of the &lt;code&gt;onInitCallback&lt;/code&gt;.&lt;br&gt;
Copy the ID and head to the Appstore ADM Web Console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40botem83irw35tkz007.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F40botem83irw35tkz007.png" alt=" " width="800" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select your target app to test and enter the Client ID and secret for your app. (You should have these saved from when you obtained your ADM credentials)&lt;/p&gt;

&lt;p&gt;In the Device registration ID field, enter the value previously saved.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;Notification message&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Populate the fields &lt;strong&gt;Notification Title&lt;/strong&gt; and &lt;strong&gt;Body content&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Send test message&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should then receive an app notifications appearing on your Fire Device.&lt;/p&gt;

&lt;p&gt;For the other ways of testing, you can check the &lt;a href="https://www.developer.amazon.com/docs/a3l-messaging/test.html" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap up
&lt;/h3&gt;

&lt;p&gt;I hope the Droidcon developer I spoke with and you are able to quickly launch existing apps for Amazon Appstore.&lt;/p&gt;

&lt;p&gt;Using A3L will allow your app to support both FCM and ADM. If you want to try an A3L sample project with support for both Firebase Cloud Messaging and Amazon Device Messaging, check out my recent &lt;a href="https://github.com/giolaq/android-amazon-notifications-porting" rel="noopener noreferrer"&gt;repo on GitHub&lt;/a&gt; and our related &lt;a href="https://developer.amazon.com/docs/a3l-messaging/understanding-a3l-messaging.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Make sure to review the full &lt;a href="https://developer.amazon.com/apps-and-games/app-submission" rel="noopener noreferrer"&gt;pre-submission checklist&lt;/a&gt; when you’re ready to submit your app in the Amazon Appstore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay connected&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;For the latest Amazon Appstore developer news, product releases, tutorials, and more:&lt;/p&gt;

&lt;p&gt;📣 Follow &lt;a href="https://twitter.com/AmazonAppDev" rel="noopener noreferrer"&gt;@AmazonAppDev&lt;/a&gt; and &lt;a href="https://twitter.com/i/lists/1580293569897984000/members" rel="noopener noreferrer"&gt;our team&lt;/a&gt; on Twitter&lt;/p&gt;

&lt;p&gt;📺 Subscribe to our &lt;a href="https://www.youtube.com/amazonappstoredevelopers" rel="noopener noreferrer"&gt;Youtube channel&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📧 Sign up for the &lt;a href="https://m.amazonappservices.com/devto-newsletter-subscribe" rel="noopener noreferrer"&gt;Developer Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cli</category>
      <category>terminal</category>
    </item>
  </channel>
</rss>
