Existem dispositivos Android de todos os tamanhos, formas e densidades de tela. É por isso que sou um grande fã da usar recursos vetorizados que não dependem de resolução. Mas o que exatamente eles são? Quais são os benefícios? Quais são os custos? Quando devem ser usados? Como devem ser criados e usados? Nesta série de postagens, gostaria de explorar esses questionamentos e explicar por que eu acho que a grande maioria dos recursos dos aplicativos deve ser composta por vetores e como aproveitá-los ao máximo.
A maioria dos formatos de imagem (png, jpeg, bmp, gif, webp, etc.) são rasterizados. Isso significa que eles descrevem a imagem como uma grade fixa de pixels. Sendo assim, são definidos em uma resolução específica e não conseguem entender informações sobre seu conteúdo, apenas a cor de cada pixel. Gráficos vetoriais, no entanto, descrevem a imagem como uma série de formas definidas em um tamanho de tela abstrato.
Os recursos vetorizados têm três benefícios principais. Eles são:
As imagens vetoriais podem ser redimensionadas com facilidade porque a descrição é feita em uma tela de tamanho abstrato. Assim, você pode aumentar ou diminuir a tela e redesenhar a imagem no tamanho desejado. Os recursos rasterizados, porém, podem se deteriorar ao serem redimensionados. A diminuição do tamanho dos recursos rasterizados costuma funcionar (já que você está descartando informações), mas aumentar o tamanho deles pode criar artefatos como distorções ou faixas porque os pixels que estiverem faltando precisarão ser interpolados.
É por isso que no Android precisamos oferecer diversas versões de cada recurso rasterizado para telas de diferentes densidades:
O Android seleciona a maior densidade aproximada e diminui o tamanho (se necessário). Devido à tendência de dispositivos com densidade de tela cada vez mais alta, os criadores de aplicativos precisam continuar gerando, incluindo e lançando versões cada vez maiores dos mesmos recursos. É importante lembrar que os dispositivos modernos não usam intervalos de densidade exatos. O Pixel 3 XL, por exemplo, é em 552 dpi, algo entre xxh dpi e xxxh dpi. Dessa forma, os recursos serão redimensionados com frequência.
Graças à excelente capacidade de redimensionamento dos recursos vetorizados, você pode adicionar um único recurso com a segurança de que ele funcionará em todas as densidades de tela.
Os recursos vetorizados são geralmente* mais compactos do que os rasterizados, pelo fato de você só precisar incluir uma única versão e pela compressão eficiente.
Por exemplo, aqui temos uma alteração feita no aplicativo Google I/O em que trocamos uma série de ícones PNG rasterizados por vetores, economizando 482 KB. Embora possa não parecer muito, esse resultado foi apenas com relação a pequenos ícones. Quando se trata de imagens maiores, como ilustrações, a economia é ainda mais relevante.
Esta ilustração, por exemplo, do fluxo de integração de um aplicativo I/O do ano passado:
Na época, não conseguimos substituir essa imagem por um VectorDrawable porque os gradientes ainda não eram amplamente compatíveis (spoiler: agora são!), então tivemos que lançar uma versão rasterizada. Usando um vetor, teríamos uma redução de 30% no tamanho e um resultado melhor :
Enquanto as divisões da configuração de densidade do Android App Bundle trazem benefícios semelhantes ao fornecer somente os recursos de densidade necessários ao dispositivo, um VectorDrawable geralmente será menor e além eliminará a necessidade de continuar criando recursos rasterizados cada vez maiores.
Por descrever seu conteúdo, ao invés de “achatar” as informações em pixels, as imagens vetoriais trazem novas e interessantes possibilidades como animação, interatividade ou temas dinâmicos. Falaremos mais sobre isso nas próximas postagens.
Os vetores têm algumas desvantagens que precisam ser consideradas:
Como mencionado anteriormente, os recursos vetorizados descrevem o conteúdo e, portanto, precisam ser inflados e desenhados antes do uso.
Há duas etapas para isso:
Essas duas etapas são proporcionais à complexidade do vetor e ao tipo de operação realizada. Se você usar formas muito intricadas, a análise para transformá-las em um caminho será mais demorada. De forma semelhante, mais operações de desenho levarão mais tempo para serem realizadas (e algumas são mais caras, como as operações de recorte). Abordaremos novamente esse assunto em uma postagem futura sobre a determinação dos custos.
Para vetores estáticos, o desenho precisa ser realizado somente uma vez e pode então ser armazenado em cache em um Bitmap. Os vetores animados não podem fazer essa otimização porque as propriedades são necessariamente alteradas, exigindo redesenho.
Compare isso com recursos rasterizados como o PNG, que só precisa decodificar o conteúdo do arquivo, algo que foi amplamente otimizado com o passar do tempo.
Esse é o principal ponto a ser considerado ao comparar os prós e os contras da rasterização e da vetorização. Os vetores proporcionam os benefícios mencionados acima, mas ao custo de uma renderização mais cara. No início do Android, os dispositivos eram menos poderosos e as densidades de tela variavam pouco. Atualmente, os dispositivos Android são mais poderosos e têm uma enorme variedade de densidades de tela. É por isso que eu acredito ser a hora de todos os aplicativos mudarem para recursos vetorizados.
Devido à natureza do formato, os vetores são ótimos para descrever alguns recursos, como ícones simples. Eles são péssimos para codificar imagens fotográficas, em que é mais difícil descrever o conteúdo com uma série de formas. Nesse caso, seria muito mais eficiente usar um formato rasterizado (como o webp). É claro que há muitas variações, então tudo depende da complexidade do recurso.
Nenhuma ferramenta de design (que eu conheça) pode criar VectorDrawables diretamente. Isso significa que há uma etapa de conversão a partir de outros formatos. Isso pode complicar o fluxo de trabalho entre designers e desenvolvedores. Trataremos desse tópico em detalhes em uma postagem futura.
Se você já trabalhou com formatos de imagem vetorial, já deve ter visto o formato SVG (gráficos vetoriais escalonáveis, na sigla em inglês), o padrão do setor na Web. Esse formato é eficiente, estabelecido e tem ferramentas consagradas, mas é também um padrão amplo . Ele inclui muitos recursos complexos como a execução de javascript arbitrário, efeitos de desfoque e filtro ou a incorporação de outras imagens, até mesmo gifs animados. O Android é executado em dispositivos móveis restritos, portanto, oferecer suporte a toda a especificação do SVG não era uma meta realista.
No entanto, o SVG inclui uma especificação de caminho que define como descrever e desenhar formas. Com essa API, você pode expressar a maioria das formas vetoriais. De modo geral, o Android é compatível com a especificação de caminho do SVG (e alguns adicionais).
Além disso, ao definir seu próprio formato, o VectorDrawable pode ser integrado a recursos da plataforma Android. Ele trabalha, por exemplo, com os recursos de sistema do Android para referenciar @colors, @dimens ou @strings, funcionando com atributos de tema ou AnimatedVectorDrawable usando animadores padrão.
Como mencionado, o VectorDrawable é compatível com a especificação de caminho do SVG, o que permite especificar uma ou várias formas a serem desenhadas. Ele é escrito como um documento XML semelhante a este:
Observe que você precisa especificar o tamanho intrínseco do recurso, que seria o tamanho que ele teria ao ser definido em um ImageView wrap_content. Os tamanhos da segunda janela de visualização definem a tela virtual ou coordenam o espaço no qual todos os comandos de desenho subsequentes são definidos. As dimensões intrínsecas e da janela de visualização podem variar (mas devem estar na mesma proporção): é possível definir os vetores em uma tela 1x1 se você desejar.
O elemento <vector> contém um ou muitos elementos <path>. Eles podem ser nomeados para referência posterior (como no caso de animações), mas é essencial que especifiquem um elemento pathData que descreva a forma. Essa string de aparência complexa pode ser compreendida como uma série de comandos controlando uma caneta em uma tela virtual:
Os comandos acima movem a caneta virtual, desenham uma linha até outro ponto, elevam e movem a caneta, para então desenhar uma nova linha. Com apenas os quatro comandos mais comuns, podemos descrever praticamente qualquer forma (há outros comandos, veja a especificação):
(Comandos em letra maiúscula usam coordenadas absolutas e aqueles em letra minúscula usam coordenadas relativas)
Você pode se perguntar se esse nível de detalhes é necessário. Não é possível conseguir isso com arquivos SVG? Embora você não precise ler um caminho e entender o que ele desenhará, ter um entendimento básico do que um VectorDrawable está fazendo é extremamente útil e necessário para compreender alguns dos recursos avançados que abordaremos depois.
Os caminhos por si só não desenham nada. Eles precisam ser traçados e/ou preenchidos.
A segunda parte desta série entrará em mais detalhes sobre as diferentes maneiras de preencher/traçar caminhos.
Você também pode definir grupos de caminhos. Isso permite que você defina transformações que serão aplicadas a todos os caminhos dentro do grupo.
Observe que você não pode girar, dimensionar ou traduzir caminhos individuais. Se desejar fazer isso, será necessário colocá-los em um grupo. Essas transformações fazem pouco sentido para imagens estáticas que poderiam “incorporá-las” em seus caminhos diretamente, mas são extremamente úteis no caso de animações.
Você também pode definir clip-paths, ou seja, mascarar a área na qual outros caminhos do mesmo grupo podem desenhar. Eles são definidos da mesma maneira que os caminhos.
Uma limitação importante é que os clip-paths não podem ser suavizados.
Esse exemplo (que eu tive que aumentar muito de tamanho para poder mostrar o efeito) demonstra duas abordagens de desenho do ícone de um obturador de câmera. A primeira desenha os caminhos, enquanto a segunda desenha um quadrado sólido, mascarado com a forma do obturador. O ato de mascarar pode criar efeitos interessantes (especialmente no caso de animações), mas é relativamente caro. Assim, procure evitá-lo, desenhando a forma de um modo diferente.
Os caminhos podem ser ajustados: é só desenhar um subconjunto do caminho inteiro. É possível ajustar caminhos preenchidos, mas os resultados podem ser surpreendentes! É mais comum ajustar caminhos traçados.
Você pode ajustar do início ou do fim de um caminho. Também é possível aplicar um deslocamento a qualquer ajuste. Eles são definidos como uma fração do caminho [0,1]. Veja como a definição de diferentes valores de ajuste altera a parte da linha que é desenhada. Perceba também que os deslocamentos podem fazer com que os valores de ajuste “se agrupem”. Mais uma vez, essa propriedade não faz muito sentido para imagens estáticas, mas é útil para animações.
O elemento vetor raiz é compatível com uma propriedade alfa [0, 1]. Os grupos não têm propriedade alfa, mas caminhos individuais são compatíveis com fillAlpha/strokeAlpha.
Espero que esta postagem ajude a compreender o que são os recursos vetorizados e os prós e contras deles. O formato vetorial do Android é eficiente e tem amplo suporte. Levando em consideração a variedade de dispositivos no mercado, o uso de recursos vetorizados deveria ser a escolha padrão, deixando a rasterização apenas para casos especiais. Junte-se a nós nas próximas postagens para saber mais:
Em breve: Desenho de um caminhoEm breve: Criação de recursos vetorizados para AndroidEm breve: Uso de recursos vetorizados em aplicativos AndroidEm breve: Criação de perfil do Android VectorDrawables
Postado por Tim Sneath, gerente de produto do grupo no Flutter
Hoje na Flutter Live, anunciaremos o Flutter 1.0, a primeira versão estável do kit de ferramentas de IU do Google para criar lindas experiências nativas para iOS e Android a partir de uma única base de código.
Atualmente, o desenvolvimento para várias plataformas de dispositivos móveis está repleto de concessões. Os desenvolvedores são forçados a escolher entre desenvolver o mesmo app diversas vezes para vários sistemas operacionais ou aceitar a solução do menor denominador comum que troca a velocidade e a precisão nativas pela portabilidade. Com o Flutter, temos a solução que une o útil ao agradável: IU e gráficos acelerados pelo hardware, alimentados pelo código ARM nativo e segmentados para os dois sistemas operacionais de dispositivos móveis mais usados.
O Flutter não substitui os modelos de app tradicionais da Apple e do Android para o desenvolvimento de apps. Em vez disso, ele é um mecanismo de app que pode ser incorporado a um app existente ou usado em um totalmente novo.
Pensamos as características do Flutter em quatro dimensões:
Junte tudo isso e combine às melhores ferramentas da classe, como Visual Studio Code, Android Studio, IntelliJ ou o editor de programação de sua escolha e você terá o Flutter: um ambiente de desenvolvimento para a criação de lindas experiências nativas para iOS e Android a partir de uma única base de código.
Anunciamos a primeira versão Beta do Flutter no Mobile World Congress há 10 meses e estamos felizes em ver a rapidez com que a grande comunidade o adotou. Prova disso são os milhares de apps do Flutter que já foram publicados nas lojas da Apple e do Google Play antes mesmo do lançamento da versão 1.0. Isso mostra que os desenvolvedores estão prontos para uma nova abordagem ao desenvolvimento de IU.
Já internamente, o Flutter está sendo usado no Google para uma variedade de produtos, como o Google Ads, que já foi transferido para uso com os apps para iOS e Android. Antes mesmo da versão 1.0, vários clientes internacionais, incluindo Abbey Road Studios, Alibaba, Capital One, Groupon, Hamilton, JD.com, Philips Hue, Reflectly e Tencent já estavam desenvolvendo ou enviando apps com o Flutter.
Michael Jones, diretor sênior de engenharia da equipe da Capital One, fala sobre a experiência da empresa com o Flutter:
“Estamos animados com a abordagem única do Flutter ao desenvolvimento de alto desempenho para várias plataformas. Nossos engenheiros gostaram da promessa de rápido desenvolvimento e dos recursos do Hot Reload. No último ano, vimos um progresso enorme na biblioteca, especialmente em relação à integração nativa. “O Flutter permite que a Capital One pense em recursos diretamente para a experiência móvel, em vez de se concentrar no iOS ou no Android. Estamos ansiosos para conferir o Flutter 1.0 e nos impressionar com o ritmo dos avanços e das novidades na comunidade de engenharia.”
“Estamos animados com a abordagem única do Flutter ao desenvolvimento de alto desempenho para várias plataformas. Nossos engenheiros gostaram da promessa de rápido desenvolvimento e dos recursos do Hot Reload. No último ano, vimos um progresso enorme na biblioteca, especialmente em relação à integração nativa.
“O Flutter permite que a Capital One pense em recursos diretamente para a experiência móvel, em vez de se concentrar no iOS ou no Android. Estamos ansiosos para conferir o Flutter 1.0 e nos impressionar com o ritmo dos avanços e das novidades na comunidade de engenharia.”
No evento Flutter Live de hoje, o serviço popular de pagamento Square, anunciou dois novos SDKs do Flutter que facilitam aceitar pagamentos de produtos e serviços com o Flutter, seja pessoalmente usando um leitor de pagamento do Square ou pelo app para dispositivos móveis. O Square apresentou um exemplo de como usar seu SDK de pagamentos com um app da Collins Family Orchards, um grupo de agricultura familiar que cultiva e vende frutas em mercados de agricultores no Noroeste Pacífico.
O desenvolvedor do app da Collins Family Orchards, Dean Papastrat, compartilhou sua experiência:
“Fiquei impressionado com a velocidade de todas as animações e transições nas versões de produção. Como desenvolvedor da Web, foi muito fácil fazer a transição para o Flutter. É incrível como consegui criar um app completamente funcional que aceita pagamentos em apenas uma semana.”
Na Flutter Live, a 2Dimensions anunciou a disponibilidade imediata do Flare, uma nova ferramenta incrível para designers que querem criar animações vetoriais que possam ser incorporadas diretamente ao app do Flutter e manipuladas com código. O Flare elimina a necessidade de desenvolver em um app, anima em outro e converter todo o trabalho para ativos e códigos específicos do dispositivo.
As animações criadas com o Flare podem ser incorporadas a um app existente do Flutter como um widget, permitindo que elas participem de todo o compositor e sejam sobrepostas com outras camadas de texto e gráficos ou até mesmo widgets de IU. Esse tipo de integração liberta as animações das limitações da “caixa preta” de outras arquiteturas e permite a colaboração contínua entre designers e desenvolvedores até a conclusão do app. Essa integração consistente entre o Flutter e o Flare oferece uma oferta exclusiva e irresistível para designers e animadores digitais que queiram criar experiências móveis altamente sofisticadas.
Outro parceiro que apostou no Flutter foi o Nevercode, um provedor em rápida expansão de ferramentas de integração e entrega contínua (CI/CD) relacionadas a apps para dispositivos móveis. Na Flutter Live, eles anunciaram o Codemagic, uma nova ferramenta projetada especialmente para o Flutter a fim de facilitar a automação de processos de desenvolvimento e criação de pacotes de apps do Flutter para Android e iOS a partir de uma única automação. Atualmente disponível na versão Beta, o Codemagic permite selecionar um repositório do GitHub com um projeto do Flutter e, com apenas alguns cliques, criar fluxos de versão contínuos que executam testes e geram pacotes de aplicativos binários que podem ser enviados para as lojas da Apple e do Google Play.
Criamos um pequeno vídeo para destacar o alcance e a variedade dos desenvolvedores de apps que usam o Flutter desde a versão Beta:
Desde a primeira versão Beta, trabalhamos para adicionar recursos e aperfeiçoar o Flutter. Em especial, concluímos nosso suporte a Apps para iOS com pixel perfeito com novos widgets, suporte para quase 20 serviços diferentes do Firebase. Além disso, trabalhamos para aprimorar o desempenho e reduzir o tamanho dos apps do Flutter. Também solucionamos milhares de problemas relatados pela comunidade.
O Flutter também inclui a versão mais recente da plataforma Dart, a 2.1, uma atualização ao Dart 2 que oferece tamanhos menores de código, verificações de tipo mais rápidas e melhor usabilidade para erros de tipo. Além disso, o Dart 2.1 oferece novos recursos de linguagem para melhorar a produtividade ao desenvolver experiências do usuário. Os desenvolvedores que já adotaram o Dart 2.1 relataram melhorias significativas na velocidade apenas ao trocar para o mecanismo mais recente:
Embora o foco principal da versão 1.0 seja a correção de bugs e a estabilização, também incluímos visualizações de dois grandes novos recursos para os desenvolvedores experimentarem no modo visualização. Esperamos lançar esses recursos na próxima versão trimestral em fevereiro de 2019: Adicionar ao app e visualizações da plataforma.
Ao desenvolver o Flutter, nós nos concentramos na produtividade para desenvolvedores que precisavam criar novos aplicativos do zero. Mas é claro, nem todos têm o luxo de começar com uma tábua rasa. Ao conversar com alguns dos nossos principais clientes, ficou claro que eles queriam usar o Flutter para novas jornadas do usuário ou recursos dentro de um aplicativo existente ou converter gradativamente esse aplicativo para o Flutter.
A arquitetura do Flutter oferece um bom suporte para esse modelo. Afinal de contas, cada app do Flutter inclui um contêiner do host do Android e do iOS. No entanto, estamos trabalhando para facilitar ainda mais a adoção gradual do Flutter, atualizando modelos, ferramentas e orientações de apps existentes. Já facilitamos o compartilhamento de recursos entre o Flutter e o código host. Também reformulamos as ferramentas para facilitar a inclusão em um processo existente do Flutter sem lançar o depurador com o aplicativo.
Continuaremos a trabalhar para tornar essa experiência ainda melhor. Embora vários clientes já saibam usar nossas orientações no Adicionar ao app, continuamos a adicionar amostras e ampliar o suporte para cenários complexos. Enquanto isso, nossas instruções para adicionar o Flutter a apps existentes estão na nossa Wiki, e você pode conferir o restante do trabalho no painel do projeto no GitHub.
Embora o Adicionar ao app seja útil para introduzir gradualmente o Flutter a um aplicativo existente, às vezes é vantajoso pegar o caminho contrário e incorporar um controle de plataforma para Android ou iPhone a um app do Flutter.
Assim, introduzimos os widgets de visualização da plataforma (AndroidView e UiKitView) que permitem incorporar esse tipo de conteúdo a cada plataforma. Visualizamos o suporte para Android por alguns meses, mas agora expandiremos o suporte para iOS e começaremos a adicionar plug-ins como o Google Maps e o WebView que aproveitam isso.
AndroidView
UiKitView
Assim como outros componentes, nossos widgets de visualização da plataforma participam do modelo de composição, o que significa que é possível integrá-lo a outros conteúdos do Flutter. Por exemplo, na captura de tela acima, o botão de ação flutuante no canto inferior direito é um widget do Flutter que tem uma cor de fundo com 50% Alfa. Isso demonstra bem as vantagens arquitetônicas exclusivas do Flutter.
Embora esse trabalho esteja pronto para ser testado por desenvolvedores, continuamos a trabalhar na melhoria do desempenho e da compatibilidade do dispositivo. Assim, recomendamos ter cuidado ao implantar apps que dependem de Visualizações da plataforma. Continuamos a otimizar ativamente as visualizações da plataforma e esperamos que elas fiquem prontas para produção na próxima atualização trimestral.
O Flutter tem sido direcionado principalmente a iOS e Android até agora. Mas nossa ambição é ultrapassar a barreira dos dispositivos móveis e levar o Flutter para um conjunto mais abrangente de plataformas. Na verdade, desde o início o Flutter foi projetado como um kit de ferramentas de IU portátil que fosse flexível o suficiente para ir onde os pixels estivessem.
Parte desse trabalho já está em andamento. O Flutter Desktop Embedding é um projeto ainda na fase inicial que leva o Flutter para os sistemas operacionais para computador, incluindo Windows, MacOS e Linux. Além disso, recentemente publicamos detalhes informais sobre como usar o Flutter no Raspberry Pi, como uma maneira de demonstrar o suporte à incorporação do Flutter em dispositivos de menor escala que talvez não incluam um ambiente completo para computador.
Nesta semana no Flutter Live, demos uma prévia de um projeto experimental que está sendo desenvolvido nos laboratórios e que aumenta significativamente o alcance do Flutter.
Hummingbird é uma implementação baseada na Web do tempo de execução do Flutter que aproveita o recurso da plataforma Dart para compilar não só para o código ARM nativo, mas também para JavaScript. Isso permite que o código do Flutter seja executado dentro dos padrões da Web sem alterações.
Temos um artigo separado no Medium que descreve os detalhes técnicos da implementação do Hummingbird. Teremos muito mais para compartilhar sobre o Hummingbird no Google I/O em 2019. Esperamos ver você lá!
É claro que os dispositivos móveis continuam sendo nossa prioridade. Nos próximos meses, você verá o grande investimento que fizemos nesses principais cenários de dispositivos móveis.
Com o lançamento do Flutter 1.0, estabelecemos um novo canal “estável”, além da versão Beta e em desenvolvimento existentes, bem como dos canais mestre. O canal estável atualiza com menos frequência do que outros canais, mas confiamos mais na sua qualidade por que as versões já foram aprovadas por outros canais. Esperamos atualizar nosso canal estável a cada trimestre com nossas versões mais preparadas.
Faça o download do Flutter 1.0 no nosso site em https://flutter.io, onde também há a documentação para desenvolvedores em transição de outras bibliotecas, laboratórios de códigos e um manual das amostras comuns, além de vídeos técnicos.
Agradecemos especialmente aos usuários iniciais que se juntaram a nós nessa jornada enviando feedback, identificando problemas, criando conteúdo e ajudando a moldar o produto. A comunidade do Flutter é um dos nossos grandes feitos em termos de projeto: um grupo acolhedor, diverso e prestativo de pessoas que se voluntariaram e investiram seu tempo porque esse projeto de código aberto também era importante para elas. Obrigado!
O Flutter está aguardando você. O que você vai criar?
lazy var vision = Vision.vision() let options = VisionFaceDetectorOptions() options.contourMode = .all let faceDetector = vision.faceDetector(options: options)
fast
faceDetector.process(visionImage) { faces, error in guard error == nil, let faces = faces, !faces.isEmpty else { return } for face in faces { if let faceContour = face.contour(ofType: .face) { for point in faceContour.points { print(point.x) // the x coordinate print(point.y) // the y coordinate } } }
landmarkMode
lazy var vision = Vision.vision() let options = VisionFaceDetectorOptions() options.landmarkMode = .all let faceDetector = vision.faceDetector(options: options)
faceDetector.process(visionImage) { faces, error in guard error == nil, let faces = faces, !faces.isEmpty else { return } for face in faces { // check for the presence of a left eye if let leftEye = face.landmark(ofType: .leftEye) { // TODO: put a monocle over the eye [monocle emoji] print(leftEye.position.x) // the x coordinate print(leftEye.position.y) // the y coordinate } } }
Intl.RelativeTimeFormat()
const rtf = new Intl.RelativeTimeFormat('en'); rtf.format(3.14, 'second'); // → 'in 3.14 seconds' rtf.format(-15, 'minute'); // → '15 minutes ago'
formatToParts()
Element.requestFullscreen()
navigationUI
"auto"
"show"
"hide"
"persistent-storage"
navigator.storage.persisted()
navigator.permissions.query({name:"persistent-storage"})
linear-gradient(45deg, black 25%, black 50%, white 50%, white 75%)
linear-gradient(45deg, black 25% 50%, white 50% 75%)
'left'
'right'
'text-underline-position'
"omit"
"same-origin"
response.body.text()
ReadableStream
Response.Body
Response.Body.pipeThrough(new TextDecoderStream())
MediaElementAudioSourceNode
MediaStreamAudioSourceNode
MediaStreamAudioDestinationNode
AudioContext
OfflineAudioContext
:host()
:host-context()
::slotted()
speechSynthesis.speak()
importScripts()
`installed`
URL.createObjectURL()
MediaStream
srcObject
document.origin
self.origin
Dan Lavelle, Chefe de Operações de Aprendizagem do Google Play
Ter uma ótima ideia para um aplicativo ou jogo é apenas o começo. No Google Play, nosso objetivo é oferecer as ferramentas e habilidades para você criar negócios bem-sucedidos de aplicativos para dispositivos móveis e jogos. Treinamento ainda é um dos recursos mais solicitados pelos desenvolvedores Android, e nós ouvimos seus comentários.
É por isso que estamos lançando uma nova plataforma de e-learning gratuita para que você possa atingir todo o potencial de seus negócios no Google Play.
Se sua intenção é expandir seu público-alvo, entender as métricas de desempenho ou aumentar sua receita, a Play Academy está aqui para ajudar você a entender as práticas recomendadas e os recursos do Play Console e ser bem-sucedido no Google Play. Criamos a Play Academy pensando em como incluí-la em sua agenda ocupada. Assista aos cursos no seu computador em casa ou no escritório ou ainda diretamente do seu dispositivo móvel.
Escolha entre 10 acervos de cursos breves, organizados com recursos e práticas recomendadas e que incluem temas como: Teste seu aplicativo antes do lançamento, Avalie o desempenho técnico do seu aplicativo e Monetize seu aplicativo.
Aprenda com uma experiência de e-learning multimídia e interativa.
Teste seus novos conhecimentos sobre recursos chave do Play Console e práticas recomendadas de aplicativos para dispositivos móveis.
Seja reconhecido por suas novas habilidades. Use com orgulho os indicadores de conquistas no seu perfil da Play Academy.
É fácil dar os primeiros passos com o conteúdo gratuito de e-learning do Google Play. Acesse g.co/play/academy para se inscrever e começar a sua jornada de desenvolvedor. Além disso, fique de olho nas novidades da Play Academy. Atualizaremos nossos cursos com frequência para ficar em dia com os recursos e programas mais recentes e ajudá-lo a estar sempre atualizado sobre os últimos insights de que precisa para expandir seus negócios de aplicativos ou jogos.
Esta postagem foi útil para você? Avalie!
★ ★ ★ ★ ★
LDFLAGS += -plugin-opt=-inline-threshold=0 \ -plugin-opt=-unroll-threshold=0
CONFIG_LTO_CLANG=y CONFIG_CFI_CLANG=y
CFI failure (target: [<fffffff3e83d4d80>] my_target_function+0x0/0xd80): ------------[ cut here ]------------ kernel BUG at kernel/cfi.c:32! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP … Call trace: … [<ffffff8752d00084>] handle_cfi_failure+0x20/0x28 [<ffffff8752d00268>] my_buggy_function+0x0/0x10 …
static int __nocfi address_space_conflict() { void (*fn)(void); … /* branching to a physical address trips CFI w/o __nocfi */ fn = (void *)__pa_symbol(function_name); cpu_install_idmap(); fn(); cpu_uninstall_idmap(); … }