La velocidad ha sido uno de los principios fundamentales de Chrome desde su comienzo: trabajamos constantemente para ofrecer a los usuarios una experiencia instantánea a medida que navegan por la Web. Ahora bien, todos nos hemos sentido defraudados por alguna página web que pensamos que se cargaría rápido, pero que en realidad estuvo lejos de hacerlo. Creemos que es posible mejorar la Web y queremos no solo que los usuarios entiendan por qué un sitio podría cargarse más lento, sino también recompensar a aquellas páginas que ofrecen experiencias veloces.


En el futuro, puede que Chrome utilice insignias claras para identificar a los sitios que suelen cargarse de manera rápida o lenta. Probablemente eso se lleve a cabo de diversas formas, y tenemos pensado experimentar con diferentes opciones a fin de determinar cuál proporciona el mayor valor a nuestros usuarios. 


El objetivo de las insignias es identificar los casos en los que los sitios son creados de una manera que los hace más lentos en general, teniendo en cuenta las latencias de carga históricas. Más adelante, podríamos ampliar esto para poder identificar los casos en los que es probable que una página sea lenta en función de las condiciones del dispositivo y la red del usuario. 


Nuestras primeras exploraciones se centrarán en una serie de elementos de Chrome, incluida la pantalla de carga (pantalla de presentación), la barra de progreso de carga y el menú contextual de los vínculos. Esto último permitiría obtener estadísticas de las velocidades típicas de un sitio para que puedas estar al tanto de eso antes de comenzar a navegar. 




Nuestro plan para identificar los sitios que son rápidos o lentos se llevará a cabo en pasos graduales, basados en criterios cada vez más estrictos. Nuestro objetivo a largo plazo es definir las insignias para experiencias de alta calidad, que pueden incluir indicadores más allá de la velocidad. 


Estamos construyendo la insignia de velocidad en estrecha colaboración con otros equipos que trabajan etiquetando la calidad de las experiencias de Google. Creemos que esto garantizará que si optimizas tu sitio para que sea rápido, no se lo marcará con una insignia que no sea coherente de un elemento a otro.


Somos muy conscientes de nuestro enfoque respecto de lo que se considera una buena experiencia del usuario y esperamos llegar a algo que puedan lograr todos los desarrolladores. Si bien publicaremos actualizaciones acerca de este plan a medida que nos acerquemos a versiones futuras, optimiza tu sitio cuanto antes. Hay una serie de recursos disponibles que te mostrarán qué oportunidades puedes aprovechar para mejorar la velocidad de tu sitio.
Para evaluar el rendimiento, consulta lo siguiente:

Para obtener información sobre las prácticas recomendadas de rendimiento, consulta web.dev/fast, nuestra plataforma de aprendizaje que incluye guías y codelabs sobre cómo hacer que tus páginas se carguen al instante.


Nos encanta recompensar tu trabajo y dar a nuestros usuarios más transparencia respecto del rendimiento normal de los sitios. Esperamos que este esfuerzo anime a más sitios de la Web abierta a brindar mejores experiencias para todos los usuarios.


Publicado por Addy Osmani, Ben Greenstein y Bryan McQuade del equipo de Chrome






En I/O 2019, anunciamos que Android priorizará Kotlin. Sin embargo, algunos desarrolladores mencionaron que todavía no saben cómo proceder. Puede sonar aterrador tener que empezar a escribir código Kotlin, especialmente si nadie de tu equipo está familiarizado con él.





En I/O 2019, anunciamos que Android priorizará Kotlin. Sin embargo, algunos desarrolladores mencionaron que todavía no saben cómo proceder. Puede sonar aterrador tener que empezar a escribir código Kotlin, especialmente si nadie de tu equipo está familiarizado con él.
Los que usamos generadores de perfiles de Android Studio tomamos un enfoque gradual. El primer paso fue exigir que todas nuestras pruebas unitarias se escribieran en Kotlin. Debido a que estas clases estaban aisladas del código de producción, podíamos abordar cualquier error inicial que hacíamos.
Desde ese entonces, he recopilado la siguiente guía de problemas comunes que nuestro equipo experimentó durante varias revisiones de código. Incluiré los detalles a continuación con la esperanza de que ayude a otros miembros de la amplia comunidad de Android.
Nota: Esta publicación está dirigida a las personas que recién comienzan a usar Kotlin. Si tú y tu equipo ya escriben código Kotlin de manera efectiva, es posible que esta entrada no incluya información nueva. Sin embargo, si piensas que debería haber incluido algo que omití, ¡deja un comentario!

Acción de IDE: Convertir un archivo Java en uno de Kotlin

Si utilizas Android Studio, la forma más sencilla de empezar a aprender Kotlin es escribir la clase de prueba en Java y, luego, convertirla en Kotlin seleccionando Code → Convert Java File to Kotlin en la barra de menú.
Es posible que esa acción muestre el mensaje "Some code in the rest of your project may require corrections after performing this conversion. Do you want to find such code and correct it too?". Te recomiendo que elijas "No" para que puedas enfocarte en un solo archivo a la vez.
Si bien esta acción genera código Kotlin, siempre se puede mejorar ese resultado. Las siguientes secciones incluyen sugerencias comunes que hemos recopilado de docenas de revisiones respecto de ese código generado automáticamente. Es obvio que Kotlin es mucho más que lo que se describe a continuación, pero para no desviarnos, esta guía solo se centrará en los temas recurrentes que observamos.

Comparación de lenguajes de alto nivel

Desde un punto de vista de alto nivel, Java y Kotlin son bastante similares. A continuación, se incluye una clase de prueba de estructura escrita en Java y, luego, en Kotlin.
/// Java
public class ExampleTest {
  @Test
  public void testMethod1() throws Exception {}
  @Test
  public void testMethod2() throws Exception {}
}
/// Kotlin
class ExampleTest {
  @Test
  fun testMethod1() {}
  @Test
  fun testMethod2() {}
}
Vale la pena destacar las optimizaciones de Kotlin:
  • Los métodos y las clases son públicos de forma predeterminada.
  • No es necesario declarar explícitamente el tipo de resultado anulado.
  • No hay excepciones verificadas.

Los punto y coma son opcionales

Este es uno de esos cambios que probablemente incomoden al principio. En la práctica, no debes preocuparte demasiado por ello. En este caso, simplemente escribes tu código, y si pones punto y coma por costumbre, el código seguirá compilándose, y el IDE te lo indicará. Solo hay que quitarlos todos antes de enviarlos.
Independientemente de si odias esta opción o no, Java ya quita los punto y coma en algunos lugares, lo que se nota si se compara con C++ (que requiere puntos y coma en más partes).
/// C++
std::thread([this] { this->DoThreadWork(); });
/// Java
new Thread(() -> doThreadWork());
/// Kotlin
Thread { doThreadWork() }

Los tipos se declaran al final

/// Java
int value = 10;
Entry add(String name, String description)
/// Kotlin
var value: Int = 10
fun add(name: String, description: String): Entry
Al igual que los punto y coma opcionales, este cambio es uno que probablemente te resultará muy difícil de aceptar si no estás acostumbrado a él. Es exactamente el orden opuesto a lo que muchos han naturalizado a lo largo de su carrera como programadores.
Sin embargo, la ventaja de esta sintaxis es que facilita la omisión de tipos cuando se pueden inferir. Esto se trata con más detalle en la sección "Omisión de tipos de variables" que aparece más abajo.
Esta sintaxis también pone más énfasis en la variable en sí y no en su tipo. Creo que este orden suena más natural cuando se habla del código en voz alta:
/// Java
int result;     // An integer that is a variable called "result".
/// Kotlin
var result: Int // A variable called "result" that is an integer.
Lo último que voy a decir sobre esta sintaxis es que, por muy incómoda que sea al principio, te acostumbrarás a ella con el paso del tiempo.

Constructores sin el término "new"

Kotlin no requiere la palabra clave new antes de una llamada a un constructor.
/// Java
... = new SomeClass();
/// Kotlin
... = SomeClass()
Al principio, esto puede parecer como si estuvieras perdiendo información crucial, pero no es así, ya que muchas funciones de Java asignan memoria en segundo plano, y probablemente nunca lo hayas notado. Muchas bibliotecas incluso tienen métodos de creación estáticos, como los siguientes ejemplos:
/// Java
Lists.newArrayList();
Así que, en realidad, Kotlin solo hace que esto sea más coherente. Cualquier función puede o no asignar memoria como efecto secundario.
Esto también elimina el patrón en el que se asigna una clase temporal solo para llamar a una función sin asignarla a nada.
/// Java
new Thread(...).start(); // Awkward but valid
/// Kotlin
Thread(...).start()

Mutabilidad e inmutabilidad

Las variables de Java son mutables de forma predeterminada y requieren la palabra clave "final" para que sean inmutables. Por el contrario, Kotlin no la necesita. En cambio, es necesario etiquetar las propiedades con "val" para indicar un valor (inmutable) o "var" para indicar una variable (mutable).
/// Java
private final Project project; // Cannot reassign after init
private Module activeModule;   // Can reassign after init
/// Kotlin
private val project: Project     // Cannot reassign after init
private var activeModule: Module // Can reassign after init
A menudo, en Java encontrarás muchos campos que podrían haber sido definitivos, pero la palabra clave fue omitida (probablemente por accidente, ya que es fácil de olvidar). En Kotlin, debes ser explícito respecto de esta decisión en cada campo que declares. Si no sabes cuál debería ser, márcalo como valor predeterminado y cámbialo a "var" más tarde si se modifican los requisitos.
Por otro lado, en Java, los parámetros de función son siempre mutables y, al igual que los campos, pueden hacerse inmutables mediante el uso de "final". En Kotlin, los parámetros de función son siempre inmutables, es decir, se etiquetan implícitamente como "val".
/// Java
public void log(final String message) { … }
/// Kotlin
fun log(message: String) { … } // "message" is immutable

Nulidad

Kotlin no admite el uso de anotaciones "@NotNull" o "@Nullable". Si un valor puede ser nulo, simplemente debes declarar su tipo con un signo de interrogación.
/// Java
@Nullable Project project;
@NotNull String title;
/// Kotlin
val project: Project?
val title: String
En ciertos casos, si sabes que un valor nullable siempre será not-null, puedes usar el operador "!!" para reivindicarlo.
/// Kotlin
// 'parse' could return null, but this test case always works
val result = parse("123")!!// The following line is not necessary. !! already asserts.
❌ assertThat(result).isNotNull()
Si aplicas "!!" de forma incorrecta, el código podría arrojar un error "NullPointerException". En una prueba de unidad, esto solo causa una falla en la prueba, pero debes tener cuidado si usas esto en el código de producción. De hecho, muchos consideran que incluir "!!" en el código es un indicio de un posible problema (aunque hay suficiente evidencia de que esto amerita su propia entrada de blog).
En una prueba de unidad, es más aceptable afirmar que un caso específico es válido usando el operador "!!", porque si esta suposición deja de ser cierta, fallará la prueba y podrás arreglarla.
Si crees que tiene sentido utilizar el operador "!!", úsalo lo antes posible. Por ejemplo, haz lo siguiente:
/// Kotlin
val result = parse("...")!!
result.doSomething()
result.doSomethingElse()
Pero no hagas esto:
/// Kotlin (auto-generated)
val result = parse("...")
❌ result!!.doSomething()
❌ result!!.doSomethingElse()

Omisión de tipos de variables

En Java, verás un montón de código como este:
/// Java
SomeClass instance1 = new SomeClass();
SomeGeneric<List<String>> instance2 = new SomeGeneric<>();
En Kotlin, esas declaraciones de tipo se consideran redundantes y no es necesario escribirlas dos veces:
/// Kotlin
val instance1 = SomeClass()
val instance2 = SomeGeneric<List<String>>()
"¡Pero espera!" gritas. "¡A veces, sí tenía la intención de declarar esos tipos!". Por ejemplo:
/// Java
BaseClass instance = new ChildClass(); // e.g. List = new ArrayList
Esto se puede hacer en Kotlin usando la siguiente sintaxis:
/// Kotlin
val instance: BaseClass = ChildClass()

Sin excepciones verificadas

A diferencia de Java, Kotlin no requiere que sus métodos declaren qué excepciones lanzan. Ya no hay diferencia entre excepciones verificadas y excepciones del entorno de ejecución.
/// Java
public void readFile() throws IOException { … }
/// Kotlin
fun readFile() { … }
Sin embargo, para permitir que Java pueda llamar al código Kotlin, Kotlin admite la declaración indirecta de excepciones usando la anotación @Throws. La acción Java → Kotlin es segura y siempre incluye esta información.
/// Kotlin (auto-converted from Java)
@Throws(Exception::class)
fun testSomethingImportant() { … }
Pero nunca tendrás que preocuparte de que se llame a tus pruebas de unidad desde una clase Java. Por lo tanto, puedes ahorrarte algunas líneas y quitar de forma segura estas molestas declaraciones de excepción:
/// Kotlin
fun testSomethingImportant() { … }

Omisión de paréntesis con llamadas lambda

En Kotlin, si deseas asignar un cierre a una variable, se debe declarar su tipo explícitamente:
val sumFunc: (Int, Int) -> Int = { x, y -> x + y }
Sin embargo, si todo se puede ser inferir, esto se puede acortar a solo
{ x, y -> x + y }
Por ejemplo:
val intList = listOf(1, 2, 3, 4, 5, 6)
val sum = intList.fold(0, { x, y -> x + y })
Ten en cuenta que, en Kotlin, si el último parámetro de una función es una llamada lambda, puedes escribir el cierre fuera de los paréntesis. Lo anterior es idéntico a
val sum = intList.fold(0) { x, y -> x + y }
Sin embargo, solo porque puedas, no significa que debas hacerlo. Algunas personas dirán que la llamada de arriba se ve rara. En otras ocasiones, esta sintaxis puede generar menos molestia visual, especialmente si el único parámetro del método era un cierre. Supongamos que queremos contar números pares. Compara lo siguiente:
intList.filter({ x -> x % 2 == 0 }).count()
con
intList.filter { x -> x % 2 == 0 }.count()
O bien:
Thread({ doThreadWork() })
con
Thread { doThreadWork() }
Independientemente de cuál creas que es el mejor enfoque, verás esta sintaxis en el código Kotlin, y puede generarse automáticamente mediante la acción Java → Kotlin, así que deberías asegurarte de entender lo que está pasando cuando lo veas.

Igualdades, "==" y "==="

Kotlin se desvía de Java respecto de las pruebas de igualdad.
En Java, por ejemplo, se utiliza la comparación de iguales dobles (==), que es distinta del método de igualdad. Aunque esto puede sonar bien desde un punto de vista teórico, en la práctica, es fácil para un desarrollador utilizar accidentalmente "==" cuando se trata de usar igualdades. Esto podría generar errores sutiles y tomar horas para detectar o depurar.
En Kotlin, "==" es básicamente lo mismo que iguales: la única diferencia es que también procesa correctamente el caso de "null". Por ejemplo, "null == x" es correcto, mientras que "null.equals(x)" lanza un NPE.
Si necesitas comparar instancias en Kotlin, puedes utilizar, en cambio, tres iguales (===). Esta sintaxis es más difícil de usar indebidamente y es más fácil de detectar.
/// Java
Color first = new Color(255, 0, 255);
Color second = new Color(255, 0, 255);
assertThat(first.equals(second)).isTrue();
assertThat(first == second).isFalse();
/// Kotlin
val first = Color(255, 0, 255)
val second = Color(255, 0, 255)
assertThat(first.equals(second)).isTrue()
assertThat(first == second).isTrue()
assertThat(first === second).isFalse()
La mayoría de las veces que escribas código Kotlin, usarás "==", ya que la necesidad de utilizar "===" es bastante rara. Como precaución, el convertidor de Java a Kotlin siempre convertirá "==" a "===". Para mayor legibilidad e intención, considera cambiar a "==" cuando sea posible. Por ejemplo, esto es común en las comparaciones de enumeraciones.
/// Java
if (day == DayOfWeek.MONDAY) { … }
/// Kotlin (auto-converted from Java)
❌ if (day === DayOfWeek.MONDAY) { … }
/// Kotlin
if (day == DayOfWeek.MONDAY) { … }

Eliminación de prefijos de campo

En Java, es común tener un campo privado sincronizado con un captador y receptor público, y muchas bases de código adjuntan un prefijo en el campo, lo que es un vestigio de notación húngara.
/// Java
private String myName;
// or private String mName;
// or private String _name;
public String getName() { … }
public void setName(String name) { … }
Este prefijo pretende ser un marcador útil, solo visible para la implementación de la clase, que facilita la distinción entre los campos locales de la clase y, por ejemplo, los parámetros que se pasan a una función.
En Kotlin, los campos y los captadores y receptores se fusionan en un solo concepto.
/// Kotlin
class User {
  val id: String   // represents field and getter
  var name: String // represents field, getter, and setter
}
Sin embargo, cuando se convierte automáticamente el código, el prefijo Java a veces es arrastrado, y lo que antes era un detalle oculto dentro de la clase puede filtrarse a su interfaz pública.
/// Kotlin (auto-converted from Java)
class User {
❌ val myId: String
❌ var myName: String
}
Para evitar que se filtren los prefijos, acostúmbrate a quitarlos por motivos de coherencia.
Los campos sin prefijos pueden hacer que la revisión ocasional de código mediante herramientas web sea un poco más difícil de leer (por ejemplo, en una función demasiado larga incluida en una clase demasiado grande). Sin embargo, cuando se lee el código dentro de un IDE, queda claro qué valores son campos y cuáles son parámetros debido a su resaltado sintáctico. Quitar prefijos también puede fomentar mejores hábitos de codificación respecto de la escritura de métodos y clases más enfocados.

Consideraciones finales

Esperamos que esta guía te ayude a iniciar tu aprendizaje de Kotlin. Primero, empezarás escribiendo Java y convirtiéndolo a Kotlin, luego escribirás Kotlin como Java, y finalmente, en poco tiempo, ¡estarás escribiendo código Kotlin idiomático como un profesional!
Esta publicación solo muestra una pequeña parte de lo que se puede hacer con Kotlin. Es solo una breve introducción para aquellos que no tienen mucho tiempo y solo necesitan hacer su primera prueba de Kotlin rápidamente, a la vez que presenta una buena parte de los aspectos fundamentales del lenguaje.
Sin embargo, es probable que no abarque todo lo que necesites. En ese caso, consulta la documentación oficial:
Referencia del lenguaje: https://kotlinlang.org/docs/reference/
Instructivos interactivos:
https://try.kotlinlang.org/
La referencia del lenguaje es muy útil. Abarca todos los temas de Kotlin sin llegar a ser tan profunda como para resultar abrumadora.
Los instructivos te darán la oportunidad de practicar el uso del lenguaje, y también incluyen koanes (una serie de ejercicios cortos) para ayudar a confirmar tus conocimientos recién adquiridos.
Y, por último, consulta nuestro codelab oficial sobre cómo refactorizar código en Kotlin. Trata temas presentados en esta entrada de blog y mucho, mucho más.



Actulización (10/28/2019): Corregimos los puntos 2 y 3 de la sección "Cómo prepararse; complejidades conocidas".

En mayo, Chrome anunció la implementación de un modelo para cookies seguro de forma predeterminada, basado en un nuevo sistema de clasificación de cookies ...


Actulización (10/28/2019): Corregimos los puntos 2 y 3 de la sección "Cómo prepararse; complejidades conocidas".

En mayo, Chrome anunció la implementación de un modelo para cookies seguro de forma predeterminada, basado en un nuevo sistema de clasificación de cookies (especificaciones). La iniciativa es parte de nuestro trabajo permanente tendiente a mejorar la privacidad y la seguridad en la Web.

Chrome tiene planificado implementar el nuevo modelo en la versión Chrome 80, en febrero de 2020. Mozilla y Microsoft también indicaron que pretenden implementar el nuevo modelo en Firefox y Edge de acuerdo con sus respectivos cronogramas. Si bien faltan algunos meses para la implementación de estos cambios, es importante que los desarrolladores que administran cookies evalúen si están preparados. En esta entrada de blog se describen algunos conceptos generales.

Consulta Explicación de las cookies SameSite en web.dev, donde se incluye información para desarrolladores.

Descripción de los contextos de cookies entre sitios ("cross-site") y en el mismo sitio ("same-site")

Los sitios web suelen integrar servicios externos a los fines de la publicidad, las recomendaciones de contenido, los widgets de terceros, las funciones sociales incorporadas y otras prestaciones. Mientras navegas por la Web, es posible que esos servicios externos almacenen cookies en tu navegador y que, posteriormente, accedan a esas cookies para entregar experiencias personalizadas o medir la interacción con el público. Toda cookie está asociada a un dominio. Si el dominio asociado a una cookie coincide con un servicio externo y no con el sitio web de la barra de direcciones del usuario, se considera un contexto cross-site (o "de terceros").

Algunos casos de uso cross-site menos evidentes incluyen las situaciones en las que una entidad que posee varios sitios web utiliza una cookie en todas esas propiedades. Aunque la misma entidad es propietaria de la cookie y de los sitios web, el contexto se sigue considerando cross-site o "de terceros" si el dominio de la cookie no coincide con los sitios desde los que se accede a la cookie.
Cuando un recurso externo de una página web accede a una cookie que no coincide con el dominio del sitio, es un contexto cross-site o "de terceros".


En cambio, el acceso a cookies en un contexto same-site (o "de primera mano") se da cuando el dominio de una cookie coincide con el dominio del sitio web de la barra de direcciones del usuario. Las cookies same-site suelen usarse para conservar el inicio de sesión de las personas en sitios web específicos, recordar sus preferencias y contribuir al análisis del sitio web.

 
Cuando un recurso de un sitio web accede a una cookie que coincide el sitio web que visita el usuario, es un contexto same-site o "de primera mano".


Un nuevo modelo para la seguridad y la transparencia de las cookies


Actualmente, si un desarrollador desea que solo sea posible acceder a una cookie en un contexto de primera mano, tiene la opción de aplicar una de dos configuraciones (SameSite=Lax o SameSite=Strict) para evitar el acceso externo. Sin embargo, son muy pocos los desarrolladores que aplican esta práctica recomendada, por lo que muchas cookies same-site quedan innecesariamente expuestas a riesgos, como los ataques de falsificación de solicitudes entre sitios.

A fin de proteger más sitios web y a sus usuarios, el nuevo modelo seguro de forma predeterminada da por sentado que todas las cookies deben protegerse del acceso externo a menos que se especifique lo contrario. Los desarrolladores deben usar una nueva configuración, SameSite=None, para designar aquellas cookies que admiten el acceso cross-site. Si se incluye el atributo SameSite=None, es necesario usar un atributo Secure adicional para que solo sea posible acceder a las cookies cross-site mediante conexiones HTTPS. El modelo no mitiga todos los riesgos relacionados con el acceso cross-site, pero ofrece protección contra los ataques de red.

Más allá de las ventajas inmediatas en términos de seguridad, la declaración explícita del uso de cookies cross-site implica una mayor transparencia y una mejor decisión del usuario. Por ejemplo, los sitios web podrían ofrecer a los usuarios controles minuciosos para administrar las cookies a las que solo se accede desde un solo sitio independientemente de aquellas a las que se accede desde varios sitios.

Implementación en Chrome a partir de febrero de 2020

A partir del lanzamiento de Chrome 80 en febrero, Chrome tratará las cookies sin un valor SameSite declarado como cookies SameSite=Lax. Solo las cookies con la opción SameSite=None; Secure estarán disponibles para acceso externo, siempre y cuando se acceda a ellas desde conexiones seguras. Los dispositivos de seguimiento de estado de la plataforma Chrome de SameSite=None y Secure seguirán actualizándose con la información de lanzamiento más reciente.

Mozilla reafirmó su compromiso con el nuevo modelo de clasificación de cookies mediante la declaración de su intención de implementar los requisitos SameSite=None; Secure para las cookies cross-site en Firefox. Microsoft anunció recientemente sus planes de comenzar a implementar el modelo de forma experimental en Microsoft Edge 80.

Cómo prepararse; complejidades conocidas

Si administras cookies cross-site, debes aplicar la opción SameSite=None; Secure a esas cookies. Si bien la implementación no debería resultar problemática para la mayoría de los desarrolladores, recomendamos que comiencen a hacer pruebas para identificar complejidades y casos especiales como los siguientes:

  • Por el momento, no todos los lenguajes ni todas las bibliotecas admiten el valor "None", por lo que los desarrolladores tienen que configurar el encabezado de la cookie directamente. En este repositorio de GitHub se incluyen instrucciones para implementar SameSite=None; Secure en distintos lenguajes, bibliotecas y marcos.
  • Es posible que algunos navegadores (incluidas algunas versiones de Chrome, Safari y UC Browser) interpreten el valor None de maneras inesperadas, lo que exige que los desarrolladores programen excepciones para esos clientes. Esta situación afecta a Android WebViews con tecnología de versiones anteriores de Chrome. Esta es una lista de clientes incompatibles conocidos.
  • Se recomienda que los desarrolladores de apps declaren la opción de cookie SameSite adecuada para Android WebViews con tecnología de versiones de Chrome compatibles con el valor None, tanto para las cookies a las que se accede mediante encabezados HTTP(S) como a las que se accede mediante la API de CookieManager de Android WebView, aunque el nuevo modelo no se aplicará en Android WebView sino hasta dentro de cierto tiempo.
  • Es posible que los administradores de TI empresariales tengan que implementar políticas especiales para revertir el navegador Chrome al comportamiento anterior transitoriamente si algunos servicios, como el inicio de sesión único o las aplicaciones internas, no están listos para el lanzamiento de febrero.
  • Si tienes cookies a las que accedes en contextos de primera mano y de terceros, contempla la posibilidad de usar cookies separadas para obtener las ventajas en términos de seguridad del valor "SameSite=Lax" en un contexto de primera mano.
  • En
Explicación de las cookies SameSite se ofrece información específica sobre las situaciones antes descritas y sobre los canales para plantear problemas y dudas.

Para probar el efecto del nuevo comportamiento de Chrome en tu sitio o las cookies que administras, puedes ir a chrome://flags en Chrome 76+ y activar los experimentos "SameSite by default cookies" y "Cookies without SameSite must be secure". Además, estos experimentos se activarán de forma automática para un subconjunto de usuarios de Chrome 79 Beta. Es posible que algunos usuarios beta con los experimentos activados experimenten problemas de compatibilidad con los servicios que todavía no admiten el nuevo modelo. Para abandonar los experimentos beta, los usuarios pueden desactivarlos en chrome://flgas.

Si administras cookies a las que solo se accede en un contexto same-site (cookies same-site), no debes hacer nada; Chrome evitará automáticamente que las entidades externas accedan a esas cookies, incluso si falta el atributo "SameSite" o si no se definió un valor. Dicho eso, recomendamos que apliques un valor SameSite adecuado (Lax o Strict) y que no dependas del comportamiento predeterminado del navegador, ya que no todos los navegadores protegen las cookies same-site de forma predeterminada.

Por último, si te preocupa la preparación de los proveedores y de las otras partes que prestan servicios a tu sitio web, puedes buscar advertencias de la consola de las herramientas del desarrollador de Chrome 77+ respecto de las páginas con cookies cross-site que no tienen la configuración necesaria:

A cookie associated with a cross-site resource at (cookie domain) was set without the `SameSite` attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.

Algunos proveedores (lo que incluye algunos servicios de Google) implementarán los cambios necesarios en los meses previos al lanzamiento de Chrome 80 en febrero. Es recomendable que te pongas en contacto con tus socios para confirmar si están preparados.


Publicado por Barb Palser, Chrome and Web Platform Partnerships





Publicado por Alyssa Perez, consultora de Crecimiento de Desarrolladores (Google Play)
Este texto es parte de una serie más grande de artículos y seminarios web de crecimiento comercial sobre cómo analizar el rendimiento de las apps en Google Play en función de métricas clave. Recomendamos leer




Publicado por Alyssa Perez, consultora de Crecimiento de Desarrolladores (Google Play)
Este texto es parte de una serie más grande de artículos y seminarios web de crecimiento comercial sobre cómo analizar el rendimiento de las apps en Google Play en función de métricas clave. Recomendamos leer Parte 1, "Introducción a las métricas" y Parte 2, "Cómo atraer y retener usuarios nuevos", o bien mirar nuestros seminarios web on demand.
Si estás buscando formas de optimizar tu estrategia de monetización para una app o un juego, es posible que necesites métricas diferentes a fin de medir el rendimiento de tus apps y quieras saber por dónde empezar. Si tu modelo comercial se basa en compras directas desde la aplicación (IAP, por su sigla en inglés) o quizás en un híbrido entre IAP y otro modelo, este artículo te proporcionará una base para el análisis del rendimiento respecto de cómo obtener más ingresos. Veremos algunas métricas de monetización primarias y secundarias (junto con cómo calcularlas), sugerencias para establecer prioridades y ejemplos ilustrativos sobre cómo utilizar nuestro árbol de métricas de Google Play a fin de descubrir qué puedes hacer para alcanzar tus objetivos.


Árbol de métricas de KPI para Google Play Apps y Juegos
Un árbol de métricas, creado a partir de Ingresos diarios. (Las líneas punteadas hacen referencia a métricas secundarias que se agregan para igualar la métrica superior. Todas los demás se multiplican).

Hoy vamos a ver detalladamente las prácticas recomendadas de IAP y a ofrecer sugerencias para que ajustes tu diseño, los precios y las pruebas a fin de atraer a más usuarios. La siguiente guía te ayudará a responder preguntas como estas:
  • "¿Qué relación tiene aumentar el compromiso con los ingresos?"
  • "¿Cómo sé qué métricas debo optimizar para impulsar mis ingresos?"
  • "¿El diseño de mi app o juego y sus activos integrados afectan mi monetización?"
Vamos a empezar.

La monetización está directamente relacionada con el compromiso

Antes de profundizar en el árbol de métricas, solo quiero mencionar brevemente la importancia de pensar en la participación de los usuarios en el contexto de la monetización.
Un buen modelo de monetización de IAP debe poder vincularse directamente con el compromiso de los usuarios. En otras palabras, la actividad clave de tu app debería ser relevante para explicar por qué un usuario podría querer hacer una compra directa desde la aplicación. Veamos algunos ejemplos.
Juegos para combinar 3 elementos:
  • La modalidad de juego estándar de este género implica que los jugadores intercambian objetos en un tablero para crear filas o columnas de tres objetos iguales (como gemas, caramelos o comida). La acción central es completar niveles y superar diferentes retos. Cada nivel es más difícil, y en ocasiones se requiere que el jugador logre una variedad de objetivos en una cantidad limitada de movimientos o segundos. Si el jugador pierde, es posible que deba esperar para poder jugar de nuevo, o bien pagar para recargar las vidas e intentarlo de nuevo al instante. Este es un ejemplo simple de compromiso (completar más niveles) que impulsa la demanda de compras directas desde la aplicación: cuanto más juega un usuario, más está dispuesto a gastar.
Apps de citas:
  • Una de las principales motivaciones de los usuarios es establecer una conexión con otra persona. La acción principal podría ser deslizar el dedo o "darle me gusta" a alguien, además de enviar mensajes. Algunas aplicaciones integran IAP para mejorar la experiencia del usuario ofreciéndole más oportunidades de usar "matches" o "me gusta" diarios. Esto significa que cuanto más interactúe el usuario con la aplicación y complete esa acción principal, más incentivado estará a pagar para desbloquear esas funciones, ya que ha visto el valor de la actividad y quiere seguir aprovechándola.
Piensa en cómo las motivaciones de los usuarios quedan satisfechas cuando interactúan con tu app y, a continuación, comprueba si existe la oportunidad de impulsar las compras mejorando esa experiencia. Si estás interesado en aprender más sobre este tema, obtén más información en mi publicación de Medium Bridging the Gap.

KPI de ingresos

En este gráfico, cada métrica "superior" es un producto de la métrica "secundaria" que se encuentra debajo, y todas las métricas secundarias se multiplican para calcular el número superior (con la única excepción de que están delineadas con una línea punteada, que se suman en lugar de multiplicarse). Veamos esto en práctica en la rama del árbol Ingreso promedio por usuario activo diario (ARPDAU, por su sigla en inglés).


KPI Metrics Tree_ARPDAU
La rama de ARPDAU del árbol de métricas.

Conceptos básicos de ARPDAU:
  • Conversión diaria, o el porcentaje de usuarios activos que ven suficiente valor para gastar dinero (cualquier cantidad) en un día específico, multiplicado por el Ingreso promedio por usuario que paga (ARPPU, por su sigla en inglés).
  • Por ejemplo, si el 3% de tus usuarios activos gastan dinero, y la cantidad promedio de un usuario que paga es USD 8, entonces tu ARPDAU (ingreso promedio por usuario activo diario) es de USD 0.24.
Veamos las ramificaciones de Conversión diaria:
  • Conversión de comprador nuevo es el porcentaje de usuarios que gastaron dinero (cualquier cantidad) por primera vez.
  • Conversión de comprador repetido es el porcentaje de usuarios que gastaron dinero (cualquier cantidad) y que ya lo habían hecho antes.
  • Los hemos delineado con líneas punteadas en el gráfico para recordarte que esos números sesuman para calcular la Conversión diaria.
Ahora veamos con más atención la parte de Ingreso promedio por usuario que paga (ARPPU):
  • Valor promedio de transacción es la cantidad en dólares promediada solamente de usuarios que paga (Si una mitad de tus usuarios paga USD 2 y la otra USD 4, el valor de transacción promedio es de USD 3 por usuario que paga).
  • Transacciones por comprador es la cantidad promedio de veces que realiza una transacción un usuario que paga. (Si la mitad de tus usuarios compra un artículo y la otra compra tres, el valor de transacción por comprador es dos).
  • Estos valores se multiplican para obtener la métrica superior: ARPPU.
  • Usando los ejemplos anteriores, si el valor promedio de transacción es de USD 3 y el valor de transacción por comprador es dos, entonces tu ARPPU es de USD 6.
Enfócate en métricas primarias antes de optimizar las secundarias
Aquí, en el equipo de Expertos en Crecimiento Empresarial de Google Play, consideramos que la Conversión de compradores diarios es una métrica de monetización "primaria". Esto se debe a que ayuda a entender qué tan exitosas son tus medidas para monetizar toda tu base de usuarios. Te da una idea de lo bien que estás convirtiendo a los usuarios en compradores (y logrando que esos nuevos compradores se conviertan en compradores recurrentes). Por otra parte, el promedio de ingresos por usuario que paga (ARPPU) sería una métrica de monetización "secundaria". Esto se debe a que optimizar la métrica ARPPU solo implicar dirigirse a los usuarios que han gastado dinero en tu app o juego, que es solo un pequeño porcentaje de tu base de usuarios activos. Optimizar en función de esa métrica significa tratar de obtener más valor de un grupo más pequeño de usuarios, lo que no es tan sostenible a largo plazo.
Enfócate en la amplitud (a cuántos usuarios puedes llegar creando estrategias de monetización dirigidas a diferentes segmentos de tu base de usuarios activos) antes de intentar optimizar cuánto dinero obtienes de los compradores. Piensa en formas de minimizar las pérdidas: es mejor que 100 usuarios gasten USD 1 cada uno que un usuario gaste USD 100 (si pierdes un usuario en el primer caso, seguirás teniendo USD 99, pero si pierdes al único usuario del segundo caso, tendrás USD 0). Es mucho más fácil hacer que los usuarios empiecen a gastar más de manera incremental (hacer que noten un poco más de valor y gasten más dinero) que continuar sacando más provecho de un usuario que ya está pagando una gran cantidad. Definitivamente, encontrar el equilibrio correcto entre las métricas primarias y secundarias es una ciencia, pero vamos a ver qué puedes hacer para mejorarlas.
Consideraciones para impulsar las métricas de monetización primaria
Hay dos cosas que puedes hacer para impulsar una mayor conversión de compradores: aumentar la cantidad de compradores nuevos o aumentar el número de compradores que regresan. Consulta el árbol de métricas como guía.


KPI Metrics Tree_ARPDAU
La rama de monetización del árbol de métricas.

Para la Conversión de comprador nuevo, hay algunas opciones que debes tener en cuenta:
  • Utiliza tus datos existentes a fin de analizar el tiempo esperado de conversión correspondiente a compradores nuevos. ¿Cuál es el período más común (en días o tiempo en la aplicación) para que un usuario se convierta en comprador? ¿Qué lo generó? ¿Qué oferta o SKU se compró con más frecuencia?
  • Los precios introductorios o paquetes iniciales son formas comunes de incentivar a los usuarios para que se conviertan en compradores. No hay ninguna opción de paquete inicial que satisfaga todas las necesidades, y las pruebas continuas y la iteración son importantes. Piensa en qué ofertas son más valiosas y cómo puedes agrupar varias cosas para aumentar la percepción de valor de la oferta inicial. Y, lo que es más importante, piensa en qué descuento puedes aplicarle a esa oferta si un usuario decide no comprarla la primera vez. ¿Hay alguna oportunidad para que reflotes esa oferta algunas semanas después a un precio ligeramente más bajo para hacerla más tentadora?
  • Un usuario necesitará ver el valor de tu app o juego para decidir hacer una compra. Por lo tanto, asegúrate de darle al usuario tiempo suficiente para que interactúe con tu título antes de mostrar cualquier tipo de oferta introductoria o paquete inicial.
  • Ofertas o ventas de larga duración para no compradores. Es posible que haya algunos usuarios que sigan interactuando con tu título, pero que nunca se hayan convertido en compradores. Por lo tanto, están agregando valor social, pero no monetario. Considera la posibilidad de crear ofertas a precios bajos a fin de incentivar a esos usuarios para que se conviertan en compradores.
  • Prueba tus puntos de precio disponibles. Un aspecto que puede afectar directamente a los compradores nuevos es el precio por puntos disponible en tu app. Es importante probar tanto el paquete inicial como el precio estándar de SKU para asegurarte de no estar mostrando precios más elevados a usuarios nuevos en tu app. ¿Cuál es el precio de tu paquete inicial? ¿Qué hay del precio más bajo? ¿Debe variar mi mercado?
Asegúrate de que cada una de estas sugerencias se corresponda con la experiencia de usuario que intentas crear. Lo más importante antes de convertir a un usuario es asegurarte de que está lo suficientemente comprometido como para que siga volviendo y vea el valor de hacer una compra directa desde la aplicación.
Para la Conversión de comprador repetido, ten en cuenta las compras anteriores de un usuario:
  • Sé "predeciblemente impredecible" con tu cadencia de ventas y contenido. Las ventas y los lanzamientos de contenido son formas populares de atraer a más compradores, pero es importante no ser predecible con ninguna de estas ofertas. Si un usuario sabe que los sábados publicas ofertas, eso puede reducir la probabilidad de que compre fuera del día de venta esperado. Por lo tanto, asegúrate de proporcionar un incentivo para comprar en cualquier día con nuevos lanzamientos de contenido.
  • Ofertas relevantes basadas en compras anteriores. Ten en cuenta el precio y el artículo que un usuario compra para crear una oferta de paquete especial que esté disponible durante tiempo limitado.
  • Comprende cuándo hay necesidad de realizar una compra. Por ejemplo, si tu usuario tiene algún tipo de billetera de activos, haz una oferta cuando se encuentre por debajo de un determinado umbral (por ejemplo, por debajo del percentil 25 del tamaño de la billetera del usuario que paga), ya que es probable que tenga una mayor necesidad de conversión que aquellos con un tamaño de billetera elevado. También puedes utilizar la fecha de compra reciente como indicador para mostrar una oferta.
  • Ofertas especiales para compradores que aún están activas en tu app o juego. Si un usuario era comprador y no ha adquirido en un período de tiempo prolongado, piensa en cómo puedes utilizar todos estos ejemplos para que vuelva a tu cadencia de compra específica.
Puedes obtener más información sobre estas consideraciones en mi artículo de Medium sobre los enfoques de segmentación de usuarios en juegos.

Consideraciones para optimizar las métricas de monetización secundarias

Para impulsar el ingreso promedio por usuario que paga (ARPPU), hay dos opciones disponibles en nuestro árbol de métricas: el valor de la transacción o la cantidad de transacciones que realiza un usuario.
  • Hemos descubierto que el valor de transacción está correlacionado de manera lineal y positiva con el ingreso promedio por usuario que paga. Esto significa que si puedes lograr que los usuarios paguen un precio más alto, es probable que obtengas más ingresos de ellos. En los juegos con monedas integradas, descubrimos que el valor promedio de transacción es el principal impulsor de los ingresos promedio por usuario que paga.
  • Por otra parte, las transacciones por comprador no tienen un patrón claro y fiable cuando se comparan con los ingresos promedio por usuario que paga. Esto se debe probablemente a que este KPI está más relacionado con el compromiso y el diseño de tu app o juego, y con qué tan estrechamente relacionado está con los impulsores de la monetización.
  • Si tu app tiene algún tipo de moneda integrada, considera algunas de las siguientes preguntas que pueden tener un impacto natural en la cantidad de transacciones que haría un comprador:
  • ¿Cuántos activos vendes en tu app o juego? Varias ofertas disponibles por dinero real pueden generar un valor de transacción por comprador ligeramente más alto, en lugar de tener solo un activo disponible para la venta.
  • ¿Con qué rapidez se consumen los activos que compra un usuario? ¿Cuál es la velocidad de uso del dinero? Si tu app o juego incentiva el acaparamiento de activos (por ejemplo, los usuarios pueden comprar un solo paquete con un gran conjunto de activos que les durará un largo período de tiempo), eso puede reducir la cantidad de transacciones que obtienes de los compradores a medida que disminuye la demanda de compra.
Mi colega escribió una publicación sobre indicadores de monetización subóptima con compras directas desde la aplicación, en la que puedes leer más sobre este tema y ver algunas correlaciones y puntos de referencia interesantes de las métricas de monetización secundaria.
Las optimizaciones en función de métricas de monetización secundarias son probablemente muy específicas de una app o un juego, así como una oportunidad para ejercitar la creatividad. Recuerda que debes buscar el equilibrio óptimo entre la conversión de un comprador y el promedio de ingresos por usuario que paga (ARPPU) para tratar de conseguir que la mayor cantidad posible de usuarios se conviertan al precio óptimo de tu app.

¿Qué sigue?

Ahora que hemos dejado atrás la versión de IAP de la rama de monetización del árbol de métricas, nuestro próximo artículo de la serie se centrará en los negocios basados en suscripciones y en el uso de KPI similares para impulsar comportamientos de suscripción sólidos.
Si te interesa ver cómo deberían ser las tendencias de datos para cada uno de estos indicadores clave de rendimiento y ejemplos prácticos adicionales, o si deseas hacer preguntas a nuestros expertos en crecimiento empresarial de Google Play relacionadas con este árbol, regístrate para asistir a uno de nuestros próximos seminarios web dedicados a este tema y síguenos aquí para ver los próximos artículos de esta serie. ¡Diviértete analizando!

¿Qué opinas?

¿Con qué métricas estás más o menos familiarizado cuando analizas el rendimiento de tus apps? Háznoslo saber en los comentarios de abajo o envía un tweet usando #AskPlayDev y te responderemos desde @GooglePlayDev, donde compartimos noticias y sugerencias sobre cómo tener éxito en Google Play.


Administrar los comentarios en proyectos grandes de código abierto como Flutter

En Google, siempre nos alegra ver el modo en que Flutter crece como un proyecto comunitario de código abierto. Ya sea en términos de ...

Administrar los comentarios en proyectos grandes de código abierto como Flutter

En Google, siempre nos alegra ver el modo en que Flutter crece como un proyecto comunitario de código abierto. Ya sea en términos de popularidad en GitHub, cantidad de proyectos creados o aumento de las habilidades, el 2019 fue un año muy importante para el proyecto y queremos expresarte nuestra eterna gratitud por la ayuda y los aportes que hicieron de Flutter el proyecto que hoy es. Creamos Flutter contigo y para ti, y esperamos que eso se manifieste en todo lo que hacemos.
A medida que crecemos, también aumenta la cantidad de problemas que debemos controlar. Los problemas en GitHub no solo sirven para notificar errores, sino también para hacer referencia a cualquier unidad de trabajo del proyecto. Todas las personas pueden notificar errores y estos se clasifican en las siguientes categorías:
  • Solicitudes de funciones, que hacen referencia a aspectos que Flutter podría incorporar o mejorar.
  • Problemas de asistencia, es decir, preguntas de los usuarios sobre el funcionamiento de Flutter o lo que pueden hacer en el proyecto. Aunque es mejor formular estas preguntas en Stack Overflow, muchas mencionan también aspectos de nuestra documentación que podríamos mejorar.
  • Defectos legítimos, en otras palabras, elementos que no funcionan como deberían. Esto abarca problemas graves (como fallas y regresiones de rendimiento) y también esos pequeños errores molestos que suelen ocurrir en sistemas de software importantes.
  • Elementos no evaluados que no se analizaron ni etiquetaron.
Con esto queda demostrado que nuestros problemas no son solo una recopilación de defectos, sino que constituyen trabajo acumulado. Todo aspecto en el que deseemos trabajar debe representarse como un problema y etiquetarse correctamente. De este modo, tendremos un punto de partida para planificar nuestras metas y objetivos.
Algunos proyectos usan la cantidad de errores sin resolver como un parámetro para medir la calidad de las versiones y clasifican los errores como defectos o problemas. Flutter no funciona así. Lo que hacemos es controlar los errores y problemas en el mismo lugar (GitHub) y no mantenemos nada en secreto. En consecuencia, siempre serán más las tareas de las que podríamos ocuparnos que aquellas de las que nos ocupamos. Esto sucede con muchos proyectos de código abierto que funcionan bien; basta con echar un vistazo a los que están hace tiempo, como Tensorflow, Chrome, Dart, Go o VSCode.
Sin embargo, queremos asegurarnos de que los problemas que recibimos estén bien etiquetados y llevar adelante las tareas necesarias para que la base de datos de problemas refleje correctamente el estado de nuestro producto. A tal fin, nos involucramos con la comunidad y convocamos a un grupo de voluntarios que nos ayudan durante la evaluación inicial. Además, nos complace anunciar que nos asociamos con Nevercode, que son los proveedores de Codemagic (un sistema de IC/EC líder para Flutter) para que también nos ayuden con las evaluaciones iniciales.

El ciclo de vida de un problema

Siempre estamos dispuestos a recibir notificaciones sobre errores. En las Pautas de evaluación, describimos el proceso que usamos para evaluar errores. Así es como funciona en la práctica:
Un problema empieza contigo (usuario de Flutter) o con un colaborador del proyecto de código abierto. Una vez que lo notificas (lo mejor es que los errores incluyan casos reproducibles o las solicitudes de funciones detallen claramente qué propones y por qué), se envía a la etapa de evaluación inicial.
Durante esta etapa, un participante de la comunidad, como un voluntario, alguien de Nevercode o un ingeniero de Flutter, analiza el problema y formula varias preguntas:
  • ¿Está claramente definido?
  • Si es un error, ¿incluye un caso reproducible e información suficiente para continuar?
  • Si es una mejora de una función, ¿entendemos bien qué pide el usuario para poder evaluar si constituye un aporte para la plataforma?
  • ¿Ya se notificó este problema en el pasado?
A medida que hacemos esto, aplicamos la mayor cantidad posible de etiquetas al problema durante la evaluación inicial. Usamos las etiquetas de muchas formas, por ejemplo, para establecer la prioridad relativa, determinar cómo dirigir un problema a un equipo específico y decidir si hace falta incluir el problema en un objetivo futuro. Usamos las consultas de GitHub y algunas herramientas personalizadas para analizar los problemas en busca de elementos que indiquen qué busca la comunidad y por qué.
Luego, tiene lugar la evaluación secundaria, durante la cual un equipo asignado analiza el problema y formula preguntas, por ejemplo, cómo se adapta el problema al trabajo que realiza el equipo actualmente y cuándo pueden programar la finalización del trabajo. Nuevamente, se agregan o cambian etiquetas, ya que nos permiten obtener la mejor perspectiva sobre el trabajo que queremos hacer y quién puede hacerlo.
Con el tiempo, un ingeniero se ofrece a trabajar en el problema. A diferencia de muchos proyectos de software, no solemos asignar los problemas a colaboradores. En cambio, son los colaboradores (de Google o externos) quienes se ofrecen a abordar los problemas en lugar de que se los asignen a partir del trabajo acumulado. Al permitir que sean los desarrolladores quienes se ofrezcan, dejamos el equilibrio de carga en manos de ellos. Cada colaborador se asigna a sí mismo solamente los problemas en los que esté trabajando activamente y define objetivos para que podamos saber cuándo llegarán a la rama principal. Los líderes pueden pedir a una persona específica que se ocupe de un problema si así lo desean, pero, en definitiva, es solo eso: un pedido de ayuda, no un ultimátum ni una asignación.
Después de que estamos satisfechos con la resolución del problema, lo cerramos. Solemos incluir un vínculo a la solicitud de incorporación de cambios en la que se aborda el problema, pero también se cierran problemas por otros motivos, como los siguientes:
  • ¿Se trata de una solicitud de asistencia? Si es así, dirigimos a la persona que envió la notificación a un canal de asistencia, como la lista de distribución de flutter-dev@googlegroups.com, el sitio de Reddit r/FlutterDev, nuestras comunidades de Discord (el chat de usuarios o el chat de la comunidad que usan principalmente los colaboradores) o Stack Overflow.
  • ¿Ya se notificó antes este problema? Antes de cerrarlo, incluimos un vínculo al problema original y lo actualizamos.
  • ¿Hay suficiente información para reproducir el problema y pudimos hacerlo? Si no es así, es muy probable que no podamos hacer nada y cerraremos el problema.

Nuestros avances hasta el momento

Como puedes imaginarlo, el aumento de nuestra popularidad trae aparejado más problemas abiertos y cerrados en github.com/flutter/flutter (donde se almacenan todos los problemas, salvo los del sitio web, que se registran en github.com/flutter/website):


Comparación entre errores cerrados y abiertos a finales de mes desde enero de 2018

También es notoria la cantidad de problemas que no tienen una etiqueta de uno de nuestros equipos de evaluación secundaria, como marco de trabajo, motor o complemento.


Problemas sin etiquetas de evaluación secundaria, de mayo de 2019 a la fecha

Se ve claramente cuándo empezamos a involucrar a Nevercode en el proceso de evaluación (a inicios de septiembre) y cómo se lograron avances importantes para mediados de septiembre cuando Nevercode se puso al corriente.
El énfasis en la evaluación es fiel reflejo de nuestra meta: en lugar de eliminar los errores abiertos, buscamos eliminar los errores sin etiquetar para que nuestra comunidad nos brinde los indicadores que necesitamos para priorizar mejor el trabajo. A medida que Flutter aumenta su popularidad, esperamos que siga creciendo el número de problemas abiertos que requieren evaluación, muchos de los cuales constituirán solicitudes de funciones nuevas enviadas por la comunidad. Seguiremos usando etiquetas como ayuda para determinar qué errores requieren atención inmediata, cuáles pueden esperar hasta nuestra próxima versión beta o estable, y cuáles son solicitudes de funciones nuevas.

¿Cómo puedes ayudarnos?

Una forma de ayudarnos es mantener organizada la base de datos de problemas solo con problemas que se puedan abordar. Cuando notifiques un problema, ten presente lo siguiente:
  • No uses GitHub si necesitas asistencia. Como parte del proceso de evaluación de problemas, cerraremos las solicitudes de asistencia publicadas en GitHub y redirigiremos a los usuarios a canales más adecuados. Es más probable que allí encuentres a alguien que pueda responder tu pregunta y es más fácil para otros usuarios encontrar preguntas y respuestas en estos canales.
  • Recuerda incluir casos reproducibles, especialmente si el problema es tuyo. Si no es tuyo, igual aceptamos casos reproducibles que puedas notificar. Escribir casos reproducibles de errores es una excelente forma de empezar a aprender a usar Flutter con ejemplos reales.
  • Actualiza problemas que te resulten importantes o súmate a ellos.
  • Aporta casos de prueba al repositorio de Flutter. Esta es otra forma de introducirte al mundo de Flutter y formar parte de la comunidad. También ayuda a evitar las regresiones; aunque todo el código nuevo viene acompañado de casos de prueba, intentamos aumentar la cobertura de las pruebas como práctica recomendada. Si te interesa colaborar de este modo, puedes echar un vistazo a los problemas con la etiqueta a: tests.
  • Considera ayudarnos a evaluar problemas que notifican otras personas.
Te agradecemos enormemente la ayuda y la confianza que depositas en nosotros al dedicar tu tiempo a Flutter y aportar tus ideas sobre aplicaciones. Nos encanta que la comunidad participe, ya sea notificando un error o una función que te gustaría ver, o creando una solicitud de incorporación de cambios para que Flutter sea la plataforma en la que quieres trabajar. ¡Gracias!

En esta serie de entradas, te proponemos conocer el mundo de las animaciones en Flutter y te enseñamos a crear animaciones simples y complejas para tu aplicación.
Esta entrada también está disponible en
En esta serie de entradas, te proponemos conocer el mundo de las animaciones en Flutter y te enseñamos a crear animaciones simples y complejas para tu aplicación.
Esta entrada también está disponible en video si lo prefieres.

En esta primera entrada, nos concentraremos en explicar el método más directo para agregar animaciones a tu aplicación. No hace falta conocimiento experto sobre las animaciones o su terminología para agregarlas a una aplicación. A medida que avancemos, te presentaremos widgets y terminología que te ayudarán a introducirte de inmediato en el mundo de las animaciones y te brindarán contexto para el resto de las entradas de esta serie.

Widgets con animaciones implícitas

Flutter incluye un grupo de widgets que son versiones animadas de otros que probablemente ya usas en tu aplicación, como la versión AnimatedContainer del widget Container y la versión AnimatedPositioned del widget Positioned.
Estos widgets animan automáticamente los cambios en sus propiedades. Cuando vuelves a crear el widget con valores de propiedad nuevos (como setState de StatefulWidget), el widget se ocupa de activar la animación del valor anterior al nuevo.


Grabación de pantalla en la que el código de una aplicación se modifica y la aplicación cambia el tamaño de un widget de estrella.

Estos widgets se denominan widgets con animaciones implícitas. Suelen ser los más comunes a la hora de agregar animaciones a una aplicación y constituyen una forma sencilla de agregar animaciones sin aumentar la complejidad.

El widget AnimatedContainer

Veamos en más detalle cómo puedes usar uno de estos widgets con animaciones implícitas para animar tu aplicación.
En esta aplicación, hay un contenedor y un botón. Al presionar el botón, se llama a setState y el contenedor vuelve a crearse con un valor nuevo para width. Observa cómo el contenedor cambia el ancho de inmediato, sin animación alguna.


La estrella crece inmediatamente, sin usar animación entre un estado y otro.

@override
Widget build(BuildContext context) {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      Container(
        width: _bigger ? 100 : 500,
        child: Image.asset('assets/star.png'),
      ),
      RaisedButton(
        onPressed: () => setState(() {
          _bigger = !_bigger;
        }),
        child: Icon(Icons.star),
      ),
    ],
  );
}
Si queremos agregar animación a esta aplicación, podemos reemplazar el widget Container por un widget AnimatedContainer y especificar la duración de la animación.
AnimatedContainer(
  width: _bigger ? 100 : 500,
  child: Image.asset('assets/star.png'),
  duration: Duration(seconds: 1),
),
Ahora, al presionar el botón, el contenedor aplica una animación gradual desde el ancho anterior hasta el ancho nuevo.


La transición entre los estados de la estrella ahora es animada.

Denominamos interpolación a este proceso de aplicar animación entre un valor anterior y uno nuevo. AnimatedContainer se ocupa de interpolar sus propiedades entre el valor anterior y el nuevo cada vez que cambian.
Esto se aplica a todas las propiedades de AnimatedContainer, por ejemplo, la decoración. Podemos modificar el degradado dentro de una decoración y que AnimatedContainer se ocupe de la interpolación entre el degradado anterior y el nuevo:
AnimatedContainer(
  decoration: BoxDecoration(
    gradient: RadialGradient(
      colors: [Colors.purple, Colors.transparent],
      stops: [ _bigger ? 0.2 : 0.5, 1.0])
  ),
),


Ahora, el degradado de la estrella es animado

Controlar la animación con las propiedades de duración y curva

Los widgets con animaciones implícitas (como AnimatedContainer) tienen dos propiedades que puedes usar para controlar el comportamiento de la animación. Para controlar cuánto demora la interpolación hacia el nuevo valor, puedes configurar la propiedad de duración.
AnimatedContainer(
  width: _bigger ? 100 : 500,
  child: Image.asset('assets/star.png'),
  duration: Duration(seconds: 5),
),


Más rápido a la izquierda y más lento a la derecha

En este ejemplo, hicimos que la animación demore mucho más.
También puedes usar la propiedad de curva para controlar el mecanismo de interpolación entre el valor anterior y el nuevo. Las curvas controlan la velocidad a la que sucede el cambio y pueden agregar más realismo a las animaciones. En el siguiente ejemplo, reemplazamos la curva lineal predeterminada por una curva Quintic más pronunciada.
AnimatedContainer(
  width: _bigger ? 100 : 500,
  child: Image.asset('assets/star.png'),
  duration: Duration(seconds: 1),
  curve: Curves.easeInOutQuint,
),


Curva lineal a la izquierda y Quintic a la derecha

Existen muchas curvas incorporadas diferentes que sirven para dar a tus animaciones un poco de carácter, y también puedes definir curvas personalizadas si lo prefieres. Incluso existen las curvas discontinuas, como la curva SawTooth.
Este es un ejemplo de una curva personalizada llamada SineCurve que usa la función sinusoidal para crear una curva que rebota:
class SineCurve extends Curve {
  final double count;
 
  SineCurve({this.count = 1});
 
  @override
  double transformInternal(double t) {
    return sin(count * 2 * pi * t) * 0.5 + 0.5;
  }
}
Como puedes ver, SineCurve hace que la estrella rebote de arriba abajo:


¡Que estrella tan alegre!

En resumen

Flutter ofrece widgets con animaciones implícitas que no son otra cosa que versiones animadas de widgets comunes. Puedes usar las propiedades de duración y curva para controlar el mecanismo de las animaciones.
AnimatedContainer es un widget animado particularmente eficaz porque tiene muchas propiedades que afectan su aspecto y todas se interpolan automáticamente.
Todos los demás widgets con animaciones implícitas también son opciones eficaces y fáciles de usar que permiten agregar animaciones sin aumentar demasiado la complejidad.
Además, no es obligatorio que coloques estos widgets en un StatefulWidget y uses setState; puedes usar StreamBuilder y FutureBuilder para activar animaciones, como en este ejemplo.

Explora más a fondo el mundo de las animaciones

Los widgets con animaciones implícitas son una opción para agregar animaciones, pero no son la única alternativa que el sistema de Flutter tiene para ofrecer. En el resto de esta serie, exploraremos los niveles más profundos del sistema de animación de Flutter y te enseñaremos a usarlo para crear directamente animaciones avanzadas.
Todo lo demás puedes encontrarlo en flutter.dev.



Publicado por Dan Galpin, representante de desarrolladores



Flujo de pantalla óptimo
Cualquier discrepancia en la sincronización puede crear incoherencias importantes en los tiempos de los marcos. Si la representación de un marco demora muy poco, puede reducir la presentación del marco anterior y generar una secuencia de 33 ms, 16 ms y 50 ms, por ejemplo.


Publicado por Dan Galpin, representante de desarrolladores



Con más de 2500 millones de dispositivos activos por mes, la plataforma de Android aumenta exponencialmente el alcance de los desarrolladores. Aprovechar esa oportunidad puede resultar desafiante, especialmente si el juego que desarrollas intenta realmente superar los límites de los dispositivos móviles. Después de años de trabajar en conjunto con los desarrolladores de juegos para detectar y solucionar los problemas más importantes, por fin podemos plasmar los resultados de nuestro esfuerzo en el lanzamiento del SDK de juegos para Android. Este SDK es un conjunto de bibliotecas que puedes usar para mejorar los juegos de Android.

La primera biblioteca que tenemos previsto lanzar en el SDK de juegos para Android ayuda a los desarrolladores con la regulación de marcos, es decir, la sincronización del bucle de representación de un juego con el subsistema de la pantalla del SO y su hardware subyacente. El subsistema de la pantalla de Android está diseñado para evitar la división que tiene lugar cuando el hardware de la pantalla cambia a un marco nuevo durante una actualización. Para lograrlo, guarda marcos anteriores en el búfer, detecta si un marco llega tarde y, en tal caso, vuelve a reproducirlo. Cuando la velocidad del bucle de representación de un juego es diferente de la del hardware nativo de la pantalla, el flujo óptimo de la pantalla se logra sincronizando el bucle de representación del juego con el compositor del sistema y el hardware de la pantalla. Este sería el caso de un juego que se ejecuta a 30 marcos por segundo e intenta reproducirse en un dispositivo compatible con 60 FPS de forma nativa.
Flujo de pantalla óptimo
Flujo de pantalla óptimo
Cualquier discrepancia en la sincronización puede crear incoherencias importantes en los tiempos de los marcos. Si la representación de un marco demora muy poco, puede reducir la presentación del marco anterior y generar una secuencia de 33 ms, 16 ms y 50 ms, por ejemplo.
Incoherencia en la sincronización: representación muy rápida
Incoherencia en la sincronización: representación muy rápida
Si la representación de un marco demora demasiado, ocurre algo similar. La presentación del marco abarca un marco adicional y se genera una secuencia de 50 ms, 16 ms y 33 ms, por ejemplo.
Incoherencia en la sincronización: marco lento

Incoherencia en la sincronización: marco lento

En cualquiera de estas situaciones, el jugador experimenta demoras incoherentes entre los datos que envía el juego y las actualizaciones de la pantalla. En términos visuales, el juego sufre interrupciones y se ve menos pulido. Pueden verse afectadas la experiencia de juego y el aspecto.

La biblioteca de regulación de marcos usa la API de Choreographer de Android para lograr la sincronización con el subsistema de la pantalla. A tal fin, utiliza extensiones de marca de tiempo para la presentación en API de OpenGL y Vulkan a fin de garantizar que los marcos se presenten en el momento adecuado, además de límites de sincronización que evitan que se llene el búfer. Si el dispositivo lo admite, se manejan varias frecuencias de actualización para otorgar al juego más flexibilidad a la hora de presentar un marco. En el caso de dispositivos que admiten frecuencias de actualización de 60 Hz y 90 Hz, un juego incapaz de producir 60 marcos por segundo puede reducir la frecuencia a 45 FPS (en lugar de 30) para evitar las interrupciones. La biblioteca detecta la velocidad de marcos prevista del juego y ajusta automáticamente los tiempos de presentación de marcos para adaptarse. La biblioteca de regulación de marcos permite que los juegos aprovechen las pantallas con mayor velocidad de actualización (de 90 y 120 Hz), al tiempo que facilita fijar dicha velocidad en un valor deseado, independientemente de la velocidad de actualización subyacente de la pantalla.

La biblioteca de regulación de marcos está integrada en las versiones de Unity a partir de la 2019.2. Basta con seleccionar la casilla de verificación para optimizar la regulación de marcos en la configuración de Android y lograrás que las velocidades de marcos de tus juegos funcionen sin interrupciones. Si tienes acceso al motor del juego, resulta muy sencillo integrar la biblioteca en el representador de OpenGL o Vulkan. Los archivos binarios pueden descargarse en developer.android.com/games/sdk/ o puedes descargar el código fuente desde el Proyecto de código abierto de Android.

Para obtener más información sobre la regulación de marcos, consulta la documentación en developer.android.com, junto con la sección sobre regulación de marcos de la charla acerca de cómo optimizar el rendimiento de los juegos para Android que tuvo lugar en Google I/O 2019. No olvides suscribirte a nuestro canal de Twitter ni te pierdas los anuncios de GDC 2020 para enterarte qué estamos haciendo a fin de mejorar el desarrollo de juegos para Android y permitirte generar la mejor experiencia de juego en miles de millones de dispositivos.

  • Google Accelerator celebra su semana de graduación de la segunda edición de su programa para América Latina

  • 19 startups de 10 países comparten experiencias junto a inversores estratégicos 
  • Google Accelerator celebra su semana de graduación de la segunda edición de su programa para América Latina

  • 19 startups de 10 países comparten experiencias junto a inversores estratégicos 

Miami, 10  de diciembre de 2019. El ecosistema startup de Miami se eleva con los esfuerzos de Google y TheVentureCity  para realizar la parte final del programa Launchpad Acclerator, que comenzó en México, pasó por Argentina y termina conectando con inversores clave en Miami.

Las nueve empresas que han realizado el programa de Google se encuentran durante la semana con diez de las compañías del programa de Growth Acceleration de TheVentureCity para compartir experiencias, recibir formación y demostrar el gran momento que viven las startups. TheVentureCity ha convocado a inversores top de Europa, Estados Unidos y América Latina a su campus de Miami como un beneficio agregado para las startups de ambos programas. 



“Realizar este programa para todos los países de la región; se siente como un sueño hecho realidad, pues nos brinda la oportunidad de atraer la atención al gran trabajo que los emprendedores y desarrolladores latinoamericanos están haciendo”, dijo Paco Solsona, gerente de Google Developers.

Para Laura González-Estéfani, CEO y fundadora de TheVentureCity, estas jornadas “consolidan a Miami como un epicentro de innovación y emprendimiento, que convoca a compañías que piensan sin fronteras. Pensamos que el talento está distribuido por todo el mundo, no así las oportunidades”. 



Google Launchpad Accelerator trae a Miami empresas de Argentina, México, Colombia, Chile y El Salvador. Éstas son 1,2,3Seguro, Al Turing, Apli, DevF, Hugo, Jetty, Jüsto, Odd Industries y TransparentBusiness. Las empresas del programa de TheVentureCity que participan en el ‘bootcamp’ junto a Google serán Qempo, Cajero, ComigoSaude, Digital Innovation One, TheFastMind, eMasters, Alba, 1Doc3, Stayfilm y Erudit. Estas compañías representan el talento, la diversidad y riqueza del ecosistema innovador de hispanoamérica, concentrado en TheVentureCity.


Una gran ventaja de reunir este talento en Miami es diversificar el ecosistema tech americano y mantener a los inversores y jugadores claves actualizados sobre los diferentes retos que están enfrentando los fundadores en este sector. Esta es la segunda vez en 2019 que Google y TheVentureCity potencian a las startups en Miami, tras el exitoso Launchpad Start del pasado mes de marzo, una versión de una semana que se llevó a cabo también en Miami.

Sobre TheVentureCity

TheVentureCity es nuevo modelo de inversión y aceleración que ayuda a que emprendedores de todo tipo tengan impacto global. Nuestra misión es dar acceso justo a oportunidades a fundadores globales. TheVentureCity apoya a los fundadores con ambición global a conseguir su siguiente gran logro.

Sobre Google Developers Launchpad

Google Developers Launchpad es un programa de aceleración que empodera los ecosistemas de startups globales con la misión de resolver los desafíos más grandes del mundo con lo mejor de Google: su gente, investigación y tecnologías avanzadas. Comenzado por ti. #AceleradoporGoogle.