{"id":730,"date":"2026-10-29T10:00:00","date_gmt":"2026-10-29T10:00:00","guid":{"rendered":"https:\/\/zydeno.com\/?p=730"},"modified":"2026-10-29T10:00:00","modified_gmt":"2026-10-29T10:00:00","slug":"portar-uma-aplicacao-para-telemovel-para-uma-extensao-de-navegador","status":"publish","type":"post","link":"https:\/\/zydeno.com\/pt\/portar-uma-aplicacao-para-telemovel-para-uma-extensao-de-navegador\/","title":{"rendered":"Portar uma aplica\u00e7\u00e3o para telem\u00f3vel para uma extens\u00e3o de navegador"},"content":{"rendered":"<p>O KeyRush come\u00e7ou no iPhone e no Android. Quando decidimos migr\u00e1-lo para o Chrome, tivemos de escolher: envolver a aplica\u00e7\u00e3o existente numa camada multiplataforma ou reescrev\u00ea-la para o navegador. Reescrevemo-lo, fazendo a portabilidade a partir da vers\u00e3o Android. JavaScript puro, Manifest V3, sem framework e sem etapa de compila\u00e7\u00e3o. Eis o que aprendemos ao faz\u00ea-lo.<\/p>\n<h2>O teclado j\u00e1 \u00e9 uma realidade<\/h2>\n<p>Num telem\u00f3vel, um programa de treino de digita\u00e7\u00e3o \u00e9 uma aproxima\u00e7\u00e3o. O teclado no ecr\u00e3 \u00e9, ao mesmo tempo, o dispositivo de introdu\u00e7\u00e3o de dados e o pr\u00f3prio objeto de estudo, o que constitui uma situa\u00e7\u00e3o um pouco estranha. No navegador, o utilizador tem um teclado real debaixo dos dedos \u2014 exatamente aquilo que a aplica\u00e7\u00e3o est\u00e1 a tentar ensinar.<\/p>\n<p>Isso mudou mais do que esper\u00e1vamos. Os layouts variam de pa\u00eds para pa\u00eds e de m\u00e1quina para m\u00e1quina. Existem teclas modificadoras. As pessoas mant\u00eam as teclas premidas, premem duas ao mesmo tempo ou mudam de layout a meio da sess\u00e3o. Num teclado f\u00edsico, cada pequena imprecis\u00e3o no simulador \u00e9 sentida imediatamente, pelo que tivemos de ser muito mais cuidadosos quanto ao que se considera uma tecla premida corretamente.<\/p>\n<p>Mantivemos o teclado no ecr\u00e3, mas a sua fun\u00e7\u00e3o mudou. Num telem\u00f3vel, \u00e9 aquilo em que se carrega. Na extens\u00e3o, funciona como um guia: destaca a tecla que se deve carregar a seguir, para que se possa manter o olhar no ecr\u00e3 em vez de nas m\u00e3os. \u00c9 esse o objetivo da digita\u00e7\u00e3o t\u00e1til, e o navegador permitiu-nos lev\u00e1-lo a s\u00e9rio.<\/p>\n<h2>As dimens\u00f5es das janelas n\u00e3o s\u00e3o fixas<\/h2>\n<p>Os ecr\u00e3s dos telem\u00f3veis apresentam-se em algumas formas diferentes. As janelas do navegador podem ter qualquer formato. Uma janela pop-up de uma extens\u00e3o \u00e9 estreita e curta; um separador completo pode ser enorme. A mesma aplica\u00e7\u00e3o tinha de fazer sentido em ambos os casos.<\/p>\n<p>Por isso, oferecemos as duas op\u00e7\u00f5es. O KeyRush abre como uma janela pop-up para um teste r\u00e1pido e numa aba completa quando se quer mais espa\u00e7o para li\u00e7\u00f5es e competi\u00e7\u00f5es. A combina\u00e7\u00e3o Alt+Shift+K abre-o sem precisar de recorrer ao rato \u2014 o que, para uma aplica\u00e7\u00e3o de digita\u00e7\u00e3o, pareceu-nos ser a predefini\u00e7\u00e3o certa.<\/p>\n<h2>As janelas pop-up esquecem tudo<\/h2>\n<p>Uma janela pop-up fecha assim que se clica fora dela, e tudo o que estava a ocupar na mem\u00f3ria desaparece com ela. No Android, uma aplica\u00e7\u00e3o pode ser colocada em segundo plano e voltar exatamente ao ponto em que ficou. Numa janela pop-up, \u00e9 preciso partir do princ\u00edpio de que o utilizador pode sair a qualquer momento.<\/p>\n<p>Assim, tudo o que \u00e9 importante fica armazenado no navegador, em vez de na janela, e tanto a janela pop-up como o separador completo leem o mesmo estado armazenado. Basta concluir um teste na janela pop-up, abrir o separador completo e o resultado j\u00e1 l\u00e1 est\u00e1. \u00c9 uma pequena decis\u00e3o arquitet\u00f3nica que tornou toda a extens\u00e3o mais s\u00f3lida.<\/p>\n<h2>As permiss\u00f5es s\u00e3o uma decis\u00e3o de conce\u00e7\u00e3o<\/h2>\n<p>As aplica\u00e7\u00f5es Android tamb\u00e9m solicitam autoriza\u00e7\u00f5es, mas os utilizadores raramente as l\u00eaem. Os utilizadores de extens\u00f5es, por outro lado, costumam faz\u00ea-lo, e o navegador apresenta os avisos diretamente na janela de instala\u00e7\u00e3o. O KeyRush solicita exatamente uma: armazenamento. N\u00e3o precisa de ver as p\u00e1ginas que visita, por isso n\u00e3o o solicita. Escrevemos um artigo separado sobre a import\u00e2ncia que isso tem para n\u00f3s.<\/p>\n<h2>O que guard\u00e1mos<\/h2>\n<p>Quase todo o produto em si se manteve inalterado: testes de velocidade cronometrados de 15, 30, 60 e 120 segundos, aulas de dactilografia organizadas por dedo, competi\u00e7\u00f5es contra advers\u00e1rios virtuais, estat\u00edsticas, um mapa de calor das teclas em que se falha, o desafio di\u00e1rio e todas as 44 conquistas. Quem estiver a mudar do telem\u00f3vel para a vers\u00e3o de secret\u00e1ria dever\u00e1 sentir-se \u00e0 vontade em menos de um minuto.<\/p>\n<p>Tamb\u00e9m mantivemos os princ\u00edpios. Funciona totalmente offline. O progresso fica guardado apenas no teu navegador. N\u00e3o h\u00e1 conta nem \u00e9 preciso iniciar sess\u00e3o.<\/p>\n<h2>Por que n\u00e3o partilh\u00e1mos o c\u00f3digo<\/h2>\n<p>Reescrever o c\u00f3digo parece dispendioso e, de certa forma, foi mesmo. Mas um programa de treino de digita\u00e7\u00e3o n\u00e3o \u00e9 uma aplica\u00e7\u00e3o de grande dimens\u00e3o, e a l\u00f3gica que importa \u2014 pontua\u00e7\u00e3o, li\u00e7\u00f5es, n\u00edveis, conquistas \u2014 \u00e9 suficientemente pequena para ser transferida cuidadosamente \u00e0 m\u00e3o a partir do original do Android. Em troca, obtivemos uma extens\u00e3o que carrega instantaneamente, n\u00e3o tem depend\u00eancias de terceiros que precisem de ser mantidas atualizadas e funciona como se tivesse sido feita para o navegador, porque foi mesmo.<\/p>","protected":false},"excerpt":{"rendered":"<p>O que mudou quando o KeyRush passou de Android para Chrome \u2014 e o que nos recus\u00e1mos a alterar.<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-730","post","type-post","status-publish","format-standard","hentry","category-journal"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v22.2 (Yoast SEO v22.2) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Porting a phone app to a browser extension - Zydeno Studio<\/title>\n<meta name=\"description\" content=\"Lessons from porting the KeyRush typing trainer from Android to a Manifest V3 Chrome extension: real keyboards, popups, window sizes and permissions.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zydeno.com\/pt\/portar-uma-aplicacao-para-telemovel-para-uma-extensao-de-navegador\/\" \/>\n<meta property=\"og:locale\" content=\"pt_PT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Porting a phone app to a browser extension\" \/>\n<meta property=\"og:description\" content=\"Lessons from porting the KeyRush typing trainer from Android to a Manifest V3 Chrome extension: real keyboards, popups, window sizes and permissions.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zydeno.com\/pt\/portar-uma-aplicacao-para-telemovel-para-uma-extensao-de-navegador\/\" \/>\n<meta property=\"og:site_name\" content=\"Zydeno Studio\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-29T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/zydeno.com\/wp-content\/uploads\/2026\/10\/zydeno-social.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Andrii Matiushev\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andrii Matiushev\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo estimado de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/\"},\"author\":{\"name\":\"Andrii Matiushev\",\"@id\":\"https:\/\/zydeno.com\/#\/schema\/person\/1af4d0e254f05b407f306ede28252259\"},\"headline\":\"Porting a phone app to a browser extension\",\"datePublished\":\"2026-10-29T10:00:00+00:00\",\"dateModified\":\"2026-10-29T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/\"},\"wordCount\":666,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/zydeno.com\/#organization\"},\"articleSection\":[\"Journal\"],\"inLanguage\":\"pt-PT\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/\",\"url\":\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/\",\"name\":\"Porting a phone app to a browser extension - Zydeno Studio\",\"isPartOf\":{\"@id\":\"https:\/\/zydeno.com\/#website\"},\"datePublished\":\"2026-10-29T10:00:00+00:00\",\"dateModified\":\"2026-10-29T10:00:00+00:00\",\"description\":\"Lessons from porting the KeyRush typing trainer from Android to a Manifest V3 Chrome extension: real keyboards, popups, window sizes and permissions.\",\"breadcrumb\":{\"@id\":\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#breadcrumb\"},\"inLanguage\":\"pt-PT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/zydeno.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Porting a phone app to a browser extension\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/zydeno.com\/#website\",\"url\":\"https:\/\/zydeno.com\/\",\"name\":\"Zydeno Studio\",\"description\":\"Zydeno is an indie studio designing apps across many categories \u2014 united by a shared obsession with craft and detail. Fast, opinionated, independent apps for iPhone, Android, Windows and Mac, plus extensions for Chrome, Edge and Firefox. Built slowly, shipped carefully.\",\"publisher\":{\"@id\":\"https:\/\/zydeno.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/zydeno.com\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-PT\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/zydeno.com\/#organization\",\"name\":\"Zydeno Studio\",\"url\":\"https:\/\/zydeno.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-PT\",\"@id\":\"https:\/\/zydeno.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/zydeno.com\/wp-content\/uploads\/2026\/04\/cropped-icon-512-1.png\",\"contentUrl\":\"https:\/\/zydeno.com\/wp-content\/uploads\/2026\/04\/cropped-icon-512-1.png\",\"width\":512,\"height\":512,\"caption\":\"Zydeno Studio\"},\"image\":{\"@id\":\"https:\/\/zydeno.com\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/zydeno.com\/#\/schema\/person\/1af4d0e254f05b407f306ede28252259\",\"name\":\"Andrii Matiushev\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-PT\",\"@id\":\"https:\/\/zydeno.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/4df57b6b4737601c798e728e7d4d209a9a9513422db2b613ff707286cb1ea58a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/4df57b6b4737601c798e728e7d4d209a9a9513422db2b613ff707286cb1ea58a?s=96&d=mm&r=g\",\"caption\":\"Andrii Matiushev\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Portar uma aplica\u00e7\u00e3o m\u00f3vel para uma extens\u00e3o de navegador - Zydeno Studio","description":"Li\u00e7\u00f5es aprendidas com a adapta\u00e7\u00e3o do programa de treino de digita\u00e7\u00e3o KeyRush do Android para uma extens\u00e3o Chrome do Manifest V3: teclados reais, janelas pop-up, tamanhos de janela e permiss\u00f5es.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zydeno.com\/pt\/portar-uma-aplicacao-para-telemovel-para-uma-extensao-de-navegador\/","og_locale":"pt_PT","og_type":"article","og_title":"Porting a phone app to a browser extension","og_description":"Lessons from porting the KeyRush typing trainer from Android to a Manifest V3 Chrome extension: real keyboards, popups, window sizes and permissions.","og_url":"https:\/\/zydeno.com\/pt\/portar-uma-aplicacao-para-telemovel-para-uma-extensao-de-navegador\/","og_site_name":"Zydeno Studio","article_published_time":"2026-10-29T10:00:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/zydeno.com\/wp-content\/uploads\/2026\/10\/zydeno-social.png","type":"image\/png"}],"author":"Andrii Matiushev","twitter_card":"summary_large_image","twitter_misc":{"Escrito por":"Andrii Matiushev","Tempo estimado de leitura":"3 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#article","isPartOf":{"@id":"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/"},"author":{"name":"Andrii Matiushev","@id":"https:\/\/zydeno.com\/#\/schema\/person\/1af4d0e254f05b407f306ede28252259"},"headline":"Porting a phone app to a browser extension","datePublished":"2026-10-29T10:00:00+00:00","dateModified":"2026-10-29T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/"},"wordCount":666,"commentCount":0,"publisher":{"@id":"https:\/\/zydeno.com\/#organization"},"articleSection":["Journal"],"inLanguage":"pt-PT","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/","url":"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/","name":"Portar uma aplica\u00e7\u00e3o m\u00f3vel para uma extens\u00e3o de navegador - Zydeno Studio","isPartOf":{"@id":"https:\/\/zydeno.com\/#website"},"datePublished":"2026-10-29T10:00:00+00:00","dateModified":"2026-10-29T10:00:00+00:00","description":"Li\u00e7\u00f5es aprendidas com a adapta\u00e7\u00e3o do programa de treino de digita\u00e7\u00e3o KeyRush do Android para uma extens\u00e3o Chrome do Manifest V3: teclados reais, janelas pop-up, tamanhos de janela e permiss\u00f5es.","breadcrumb":{"@id":"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#breadcrumb"},"inLanguage":"pt-PT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/zydeno.com\/porting-a-phone-app-to-a-browser-extension\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zydeno.com\/"},{"@type":"ListItem","position":2,"name":"Porting a phone app to a browser extension"}]},{"@type":"WebSite","@id":"https:\/\/zydeno.com\/#website","url":"https:\/\/zydeno.com\/","name":"Zydeno Studio","description":"A Zydeno \u00e9 um est\u00fadio independente que desenvolve aplica\u00e7\u00f5es em diversas categorias \u2014 todas unidas por uma obsess\u00e3o comum pelo trabalho artesanal e pelo detalhe. Aplica\u00e7\u00f5es r\u00e1pidas, com personalidade pr\u00f3pria e independentes para iPhone, Android, Windows e Mac, al\u00e9m de extens\u00f5es para o Chrome, o Edge e o Firefox. Desenvolvidas com calma, lan\u00e7adas com cuidado.","publisher":{"@id":"https:\/\/zydeno.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zydeno.com\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"pt-PT"},{"@type":"Organization","@id":"https:\/\/zydeno.com\/#organization","name":"Zydeno Studio","url":"https:\/\/zydeno.com\/","logo":{"@type":"ImageObject","inLanguage":"pt-PT","@id":"https:\/\/zydeno.com\/#\/schema\/logo\/image\/","url":"https:\/\/zydeno.com\/wp-content\/uploads\/2026\/04\/cropped-icon-512-1.png","contentUrl":"https:\/\/zydeno.com\/wp-content\/uploads\/2026\/04\/cropped-icon-512-1.png","width":512,"height":512,"caption":"Zydeno Studio"},"image":{"@id":"https:\/\/zydeno.com\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/zydeno.com\/#\/schema\/person\/1af4d0e254f05b407f306ede28252259","name":"Andrii Matiushev","image":{"@type":"ImageObject","inLanguage":"pt-PT","@id":"https:\/\/zydeno.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/4df57b6b4737601c798e728e7d4d209a9a9513422db2b613ff707286cb1ea58a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4df57b6b4737601c798e728e7d4d209a9a9513422db2b613ff707286cb1ea58a?s=96&d=mm&r=g","caption":"Andrii Matiushev"}}]}},"_links":{"self":[{"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/posts\/730","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/comments?post=730"}],"version-history":[{"count":1,"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/posts\/730\/revisions"}],"predecessor-version":[{"id":917,"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/posts\/730\/revisions\/917"}],"wp:attachment":[{"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/media?parent=730"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/categories?post=730"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zydeno.com\/pt\/wp-json\/wp\/v2\/tags?post=730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}