miércoles, noviembre 18, 2015

Cómo ser un Experto en Android | How to be an Android Expert

Chiu-ki tiene toda la razón.. Compartiendo el conocimiento es como te hace experto en algo.

martes, noviembre 17, 2015

Nueva campana de phishing apuntando a los desarrolladores de Google Play


Un mensaje de nuestros amigos de Google

New phishing campaign targeted to Google Play Developers If you've received an email from 'Google Play Developer Support' with the subject line 'Update of your Account Informations,' don't click on links within the message or submit any personal information. If you clicked any links, please immediately change your Google Account password and run anti-virus software on your computer. Report the fake email as 'phishing' via the link below. 
https://support.google.com/mail/answer/184963?rd=1

En plano español y bien resumido, si reciben un correo que dice Actualiza la información de tu cuenta, reportarlo como spam


Saludos

domingo, noviembre 01, 2015

Tutorial solicitar permisos en tiempo de ejecución "Run Time" en Android 6.0 Marshmallow

[ 02 de Enero de 2017]

Te recomiendo que te leas este post completo para entender cómo funciona la solicitud de permisos en Android +6.0.  Luego lee Solicitar permisos en Android en tiempo de ejecución más fácilmente en donde explico una forma re-utilizable para la solicitud de permisos. 


Uno de los grandes cambios que viene en Android 6.0 es la manera que las aplicaciones acceden a las características del teléfono, tales como, servicios de telefonía, escribir y leer contactos, datos en la memoria externa entre otros.

Según la documentación, Android separa en dos grupos los permisos: permisos normales y permisos peligrosos.

Los permisos normales, no ponen en riesgo directamente la privacidad del usuario, si tu app posee en su manifiesto permisos normales, el sistema les da acceso automáticamente. Lista de permisos normales

Los permisos peligrosos, pueden dar permiso al app acceso a datos confidenciales del usuario. Si tu app posee en su manifiesto permisos peligrosos, el usuario tiene que aprobar el permiso explícitamente. Grupos de permisos peligrosos

En fin, desde mi punto de vista es útil este cambio pero a la vez tedioso para el usuario y mas aún para el programador puesto que, el hecho de que un usuario le de permiso a tu aplicación una vez, no quiere decir que lo tendrá para siempre, el usuario puede en cualquier momento volver a revocar el permiso de tu app desde la actividad de configuración de la misma. En otras palabras, cada vez que nuestra aplicación necesite un permisos peligroso, nuestro código tiene que verificar si ésta tiene o no el permiso necesario. Acá un ejemplo de los permisos de WhatsApp, yo podría negar el permiso de contactos y la aplicación queda totalmente sin sentido. Hasta el momento WhatsApp no ha implementado completamente este nuevo sistema en Android 6.0, no vi los diálogos de permisos luego de revocar el de contactos.

De acuerdo con google hay maneras de evitar, la solicitud de permisos; un ejemplo sería  el uso de la cámara, en vez de crear tu propia lógica para tomar una foto, podemos llamar al intent de la cámara directamente y traernos la foto a nuestra app, +Nick Butcher explica esto en más detalle.


Ok, ahora a lo que vinimos, el código. Voy a demostrar el uso de los permisos en tiempo de ejecución de guardado de datos en el almacenamiento del dispositivo. pasaré por alto la parte de la interfaz gráfica a excepción de un detalle para la implementación del SnackBar.

Podemos solicitar permisos desde el Splash Screen si queremos, si es de vital importancia para que la aplicación funcione correctamente y simplemente no dejar al usuario hacer nada mas, pero este no es será caso, entonces.

Paso 1.

Usamos el método checkSelfPermission("nombre del permiso") para saber si la aplicación tiene o no el permiso, PackageManager tiene las constantes para la validación. Está bastante claro lo que hace, si la verificación es verdadera solicitamos el permiso, sino guardamos el comentario.

private void verifyPermission()
{
 //WRITE_EXTERNAL_STORAGE tiene implícito READ_EXTERNAL_STORAGE
 //porque pertenecen al mismo grupo de permisos 
 int writePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
 if (writePermission != PackageManager.PERMISSION_GRANTED){ 
  requestPermission();
 }
 else { 
  saveComments();
 }
}


Paso 2.

Solicitamos el permiso llamando al método requestPermission("lista de permisos", request code), en este punto podemos llamar siempre requestPermission, lo que mostrará el dialogo de solicitud varias veces pero la segunda vez que se muestra el dialogo éste trae un checkbox que dice "No volver a preguntar", si el usuario lo selecciona y niega el permiso, el dialogo no se mostrará nunca más.

Por este motivo google creó shouldShowRequestPermissionRationale() este método devuelve verdadero si ya se mostró el diálogo de permisos, si es así podemos instruir al usuario de por qué necesitamos el permiso o mostrar un mensaje en el SnackBar y asignar una acción.

El SnackBar requiere una vista donde mostrarse, para ello definimos la variable mLayout la cual se asigna en el onCreate y corresponde en este caso al linear layout principal de la actividad.




private void requestPermission() {
if(ActivityCompat.shouldShowRequestPermissionRationale(this,
   Manifest.permission.WRITE_EXTERNAL_STORAGE)) { 
       showSnackBar(); 
   }else {
     requestPermissions(
     new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_WRITE_EXTERNAL_STORAGE); 
   } 
}

private void showSnackBar() { 
    Snackbar.make(mLayout,R.string.permission_write_storage,Snackbar.LENGTH_LONG)
            .setAction(R.string.settings, new View.OnClickListener() {
                 @Override public void onClick(View view){ 
                openSettings(); 
    }}).show(); 
}

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mLayout = findViewById(R.id.linearLayoutMain);
}

Paso 3.

Procesar la respuesta del usuario, para esto, sobre escribimos el método onRequestPermissionsResult, este recibe el requestCode que asignamos cuando solicitamos el permiso, los permisos solicitados y las respuestas del usuario a las solicitudes de los permisos.

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, 
                                       int[] grantResults) 
{
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == MY_WRITE_EXTERNAL_STORAGE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
           saveComments();
        }else {
          showSnackBar();
        }
    }
}

Al principio es un poco complicado comprender lo que se debe hacer pero luego no es tanto.

En la sección Código Fuente encontrar el código completo del ejemplo, espero sus comentario.


viernes, octubre 23, 2015

Cómo mejorar el rendimiento de compilación en Android Studio (De verdad verdad)


Google | Android, está orgulloso de tener un IDE de desarrollo para Android llamado Android Studio (AS) el cual está basado en IntelliJ, yo nunca había escuchado sobre gradle hasta que empecé a trabajar con Android Studio fui usuario de Eclipse por muchos años y ya
estaba acostumbrado a este. Todo iba muy bien, hasta que llegue a la empresa donde trabajo actualmente. Acá los proyectos son gigantes, con varias librerías tanto de terceros como propias, fui yo quien empezó a insistir en migrar de IDE ya que Google en cualquier momento iba a dejar de dar soporte a Eclipse. Acá el articulo sobre el fin de soporte de ADT

De hecho fue así, comenzamos a migrarnos a AS,  aprendimos un poco sobre Gradle, las famosas dependencias y de lo maravilloso y sencillo que resulta actualizar una librería cuando vas al build.gradle. Yo soy un obsesionado con la actualizaciones, no puedo ver una notificación de actualización porque sin pensarlo quiero  tener la última versión. Lo mismo me pasaba con gradle, siempre tenía mis librerías en su última versión, que maravilla es Android Studio!

Empecé a reemplazar todas las librerías que venían es sus .jar por su equivalente en dependencia ( con dependencia me refiero a la de compile 'com.blahblah.xyz'  y me sentía muy feliz por esto. Todo hasta que empezamos a darnos cuenta en el equipo de Android que el AS se tardaba un montón de tiempo en compilar, que mi mac por ejemplo se moría cada vez que hacía un Run, y si iba a hacer  debug peor, no soportaba el ruido del ventilador de mi pobre máquina, estaba empezando a odiar AS. Este había sido el caso más extremo,


hasta que me pasó que ni quería compilar y tenía que matar AS.

Era muy frustrante tener que esperar tanto tiempo para compilar, leí muchos posts sobre cómo mejorar el rendimiento, pero nada de lo que decían funcionaba.  Por suerte había concluido un proyecto y pensaba en que no tendría que tocar ese código más, comencé con el otro proyecto, el código estaba Eclipse y lo migré a AS. A este proyecto no le había cambiado los .jar por dependencias.

La misma mañana que había hecho la migración tuve una discusión por skype con uno de mis compañeros sobre ser conservador (si funciona no lo toques) o progresista (en el sentido de cambios y mejoras al código)., más tarde durante el almuerzo analicé estas dos cosas, y até cabos, me pregunté, ¿Por qué el código recién importado a AS compila más rápido que el proyecto anterior?   -he aquí por qué el comentario de conservador y progresista- me dije.. los .jar, WTF... empecé a reemplazar todos los compile 'com.blahblah.xyz' por su .jar (obviamente en sus últimas versiones) y que pasó..


la compilación tardó NADA, ni volví a escuchar el ventilador de mi pobre Mac siquiera.

Luego de darme cuenta que esto mejoraba el rendimiento volví a amar Android Studio, así que para resumir acá les dejo lo que deben hacer si sus AS se tardan "para siempre" en compilar.

  1. Cambien el gradle a 2.8 el que trae AS por defecto es 2.2. Esto lo pueden hacer desde Module settings.




2. Reemplacen las librerías de terceros, por ejemplo, yo tengo jodatime, guava, openscv, entre otras a sus versiones .jar.

compile files('libs/joda-time-2.4.jar')
// compile 'joda-time:joda-time:2.4'


Nota,  las de android.support  y google play services si quedaron en su forma gradle (compile 'com.google.android.gms:play-services-gcm:8.1.0') y no da problema.

Luego de estos cambios verán el progreso y seguirán amando Android Studio.

Saludos.

Happy coding.


miércoles, mayo 13, 2015

Ley de gravitación universal Android

¿Se han preguntado por qué android tiene gravity y layout_gravity? Si no han sentido curiosidad, a continuación está la razón. 

Gravity


El atributo gravity afecta únicamente la gravedad interna del View. Supongamos que tenemos un botón con gravity "center", el resultado es el siguiente, cabe destacar que "center" es la gravedad default del botón.




Si cambiamos a "end" el resultado será el siguiente.





Si agregamos "|center_vertical" vamos a poder afectar la gravedad del View de dos maneras, vamos a alinear el texto del botón al final y a centro vertical del mismo.

El xml, es el siguiente.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center"
   android:orientation="horizontal" >
   <Button
       android:id="@+id/button1"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:gravity="end|center_vertical"
       android:text="@string/hello_world" />
</LinearLayout>

Al evaluar el XML, tenemos un layout vertical con gravedad center, lo cual centrará vertical y horizontalmente todo lo que esté dentro de el. Los siguiente no generará errores pero no tiene ningún sentido. 


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center|center_vertical"
   android:orientation="horizontal" >

Aquí estamos diciendo, LinearLayout, por favor alinea todos tus hijos en mi centro y alinéalos también en mi centro vertical. En este caso debemos eliminar la opción center y dejar solo center_vertical

Layout Gravity

El atributo layout_gravity afecta la gravedad del View pero con respecto a su padre. Continuando con el ejemplo anterior, si aplicamos layout_gravity="end" al botón, éste se irá al fondo del LinearLayout.




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:gravity="center"
   android:orientation="vertical" >

   <TextView
       android:id="@+id/textView1"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/hello_world" />
 
   <Button
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="end"
       android:gravity="center"
       android:text="@string/hello_world" />

</LinearLayout>


Al evaluar este xml, podemos ver que el LinearLayout le estamos diciendo, hey todos tus hijos van en mi centro, sin embargo el hijo rebelde llamado botón quiere ir a la derecha, y por lo tanto le podemos decir, ok, alinéate a la derecha de tu papá usando tu propiedad layout_gravity.

jueves, mayo 07, 2015

Verificar si tenemos conexión en Android.

En unas líneas de código podemos verificar si tenemos conexión a internet. a través de la red o a través de WiFi. Recuerden agregar en el manifiesto los permisos


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

luego, por favor no hagan un if - else para asignar un boolean cuando recibimos booleans.

public boolean checkConnectivity() {
 ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
 NetworkInfo mWifi = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
 NetworkInfo mMobile = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
 return mWifi.isConnectedOrConnecting() || mMobile.isConnectedOrConnecting();
}