lunes, 21 de diciembre de 2015

Xamarin 4 Party Ciudad de México

WP_20151217_10_10_49_Pro
El pasado jueves 17 de Diciembre se llevo a cabo una Xamarin 4 Party en la ciudad de México.
En las oficinas de Microsoft México tuve la oportunidad de dar una serie de charlas sobre las novedades que tiene la versión 4 de Xamarin la cual fue lanzada en noviembre de este año.
Los temas fueron:
  • La plataforma Xamarin y Xamarin University
  • Xamarin.Forms 2.0
  • Xamarin Insigths
  • Xamarin UI Test
A continuación les dejo la galería de fotos del evento.
 
Y también les comparto las presentaciones que sirvieron de apoyo para mis exposiciones.

sábado, 28 de noviembre de 2015

Usando SQLite .NET multiplataforma en Xamarin Android, Xamarin IOS, Windows Phone y Windows Store (Parte 3 Android)

En este tercera publicación el turno es para Xamarin Android al igual que la parte anterior no voy a entrar a fondo a los pasos que ya se hicieron anteriormente (Parte 1 y Parte 2).
El primer paso igual que en ocasiones anteriores es crear un proyecto para Xamarin Android
3CreandoDroid
El paso siguiente es enlazar Core mediante el project linker, como lo explique en la primer publicación.
Utilizando SQLite .NET en el proyecto de Android
Con Xamarin Android no hay que agregar referencias extra para hacer funcionar SQLite, por lo cual podemos pasar a desarrollar la interfaz y funcionalidad con solo enlazar Core que contiene los archivos de SQLite .Net.
La interfaz va a contener los mismos campos que las aplicaciones de WP y WS.
image
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView
        android:text="Nombre"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView4" />
    <EditText
        android:inputType="textPersonName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/edtName" />
    <TextView
        android:text="Edad"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView3" />
    <EditText
        android:inputType="number"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/edtAge" />
    <TextView
        android:text="Correo Electrónico"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView2" />
    <EditText
        android:inputType="textEmailAddress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/edtMail" />
    <TextView
        android:text="Teléfono"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView1" />
    <EditText
        android:inputType="phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/edtPhone" />
    <Button
        android:id="@+id/btnSave"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Guardar" />
    <Button
        android:text="Búsqueda"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btnSearch" />
</LinearLayout>
El código de la funcionalidad es muy parecido, lo único que es diferente es lo referente a la interacción con la interfaz de usuario.
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using SQL.Core.Core;
using System.IO;

namespace SQL.Droid
{
    [Activity(Label = "SQL.Droid", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            Button btnSave = FindViewById<Button>(Resource.Id.btnSave);
            btnSave.Click += btnSave_Click;
            
            Button btnSearch = FindViewById<Button>(Resource.Id.btnSearch);
            btnSearch.Click += btnSearch_Click;

            InitializateDB();
        }

        void btnSearch_Click(object sender, EventArgs e)
        {
            Intent intent = new Intent(this,typeof(SearchActivity));
            StartActivity(intent);
        }
       
        void btnSave_Click(object sender, EventArgs e)
        {
            var edtName = FindViewById<EditText>(Resource.Id.edtName);
            var edtAge = FindViewById<EditText>(Resource.Id.edtAge);
            var edtPhone = FindViewById<EditText>(Resource.Id.edtPhone);
            var edtMail = FindViewById<EditText>(Resource.Id.edtMail);

            Contact contact = new Contact(edtName.Text,int.Parse(edtAge.Text), edtPhone.Text, edtMail.Text);
            crud.SaveValue<Contact>(contact);

        }

        CRUDManager crud;
        void InitializateDB()
        {
            var sqliteFilename = "ContactsDb";
            var path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), sqliteFilename); ;

            crud = new CRUDManager(path);

           

        }

    }
}

Para la segunda pantalla la cual muestra los resultados, voy a agregar el código de dos componentes uno es la plantilla xml con la que se mostraran los diferentes campos en la lista de resultados.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
           android:orientation="horizontal"
           android:minWidth="25px"
           android:minHeight="25px"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:id="@+id/Container"
           android:layout_marginTop="15dp"
           
           android:paddingLeft="20dp">
  <LinearLayout
      android:orientation="vertical"
      android:minWidth="25px"
      android:minHeight="25px"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/linearLayout28">
    <TextView
        android:text="Text"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:id="@+id/txvName"
        android:textSize="20sp"
        android:textColor="#005DAA" />
    <TextView
        android:text="Text"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:id="@+id/txvAge" />
    <TextView
      android:text="Text"
      android:layout_height="match_parent"
      android:layout_width="wrap_content"
      android:id="@+id/txvMail" />
    <TextView
        android:text="Text"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:id="@+id/txvPhone" />
  </LinearLayout>

</LinearLayout>

El otro es la clase “Adapter” que va a funcionar como fuente de datos de la lista que mostrara los resultados.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using SQL.Core.Core;

namespace SQL.Droid
{
    class ContactAdapter : BaseAdapter
    {

        private Activity activity;
        private List<Contact> data;
        private static LayoutInflater inflater = null;


        public ContactAdapter(Activity activity, List<Contact> data)
        {
            this.activity = activity;
            this.data = data;
            inflater = (LayoutInflater)activity.GetSystemService(Context.LayoutInflaterService);

        }

        public Contact GetContact(int position)
        {
            return data[position];
        }


        public override int Count
        {
            get { return data.Count; }
        }

        public override Java.Lang.Object GetItem(int position)
        {
            return position;
        }

        public override long GetItemId(int position)
        {
            return position;
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View vi = convertView;
            if (convertView == null)
                vi = inflater.Inflate(Resource.Layout.ContactRow, null);

            TextView name = (TextView)vi.FindViewById(Resource.Id.txvName);
            TextView age = (TextView)vi.FindViewById(Resource.Id.txvAge);
            TextView mail = (TextView)vi.FindViewById(Resource.Id.txvMail);
            TextView phone = (TextView)vi.FindViewById(Resource.Id.txvPhone);
            

            name.Text = data[position].Name;
            age.Text = data[position].Age.ToString();
            mail.Text = data[position].Mail;
            phone.Text = data[position].PhoneNumber;
          

            return vi;
        }
    }
}

Finalmente la pantalla creada es la siguiente:
image
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <EditText
        android:inputType="textPersonName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/edtName" />
    <Button
        android:text="Buscar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btnSearch" />
    <Button
        android:text="Mostrar Todos"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btnAllItems" />
    <ListView
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="350dp"
        android:id="@+id/lvResults" />
    <Button
        android:text="Eliminar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btnDelete" />
</LinearLayout>
Y su respectiva clase C# para la funcionalidad, al igual que con la primer pantalla la mayoría de los cambios son relativos a la interfaz de usuario
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using SQL.Core.Core;
using System.IO;

namespace SQL.Droid
{
    [Activity(Label = "SearchActivity")]
    public class SearchActivity : Activity
    {
        ListView lvResults;
        Contact selected;
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            SetContentView(Resource.Layout.Search);
            Button btnSearch = FindViewById<Button>(Resource.Id.btnSearch);
            btnSearch.Click += btnSearch_Click;

            Button btnAllItems = FindViewById<Button>(Resource.Id.btnAllItems);
            btnAllItems.Click += btnAllItems_Click;

            Button btnDelete = FindViewById<Button>(Resource.Id.btnDelete);
            btnDelete.Click += btnDelete_Click;

            lvResults = FindViewById<ListView>(Resource.Id.lvResults);
            lvResults.ItemClick += lvResults_ItemClick;

            InitializateDB();
        }

        void lvResults_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
        {
            selected = ((ContactAdapter)lvResults.Adapter).GetContact(e.Position);
        }

        

        void btnDelete_Click(object sender, EventArgs e)
        {
            if (selected != null)
            {
                crud.DeleteValue<Contact>(selected);
                lvResults.Adapter = new ContactAdapter(this, crud.GetAllItems<Contact>());

            }
        }

        


        void btnAllItems_Click(object sender, EventArgs e)
        {

            lvResults.Adapter = new ContactAdapter(this,crud.GetAllItems<Contact>());
        }

        CRUDManager crud;
        void InitializateDB()
        {
            var sqliteFilename = "ContactsDb";
            var path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), sqliteFilename); ;

            crud = new CRUDManager(path);



        }

        void btnSearch_Click(object sender, EventArgs e)
        {
            var lvResults = FindViewById<ListView>(Resource.Id.lvResults);

            lvResults.Adapter = new ContactAdapter(this,
                new List<Contact>() { crud.GetItem<Contact>(FindViewById<EditText>(Resource.Id.edtName).Text) });
        }
    }
}
Con esto queda concluido el proyecto, al igual que en los casos anteriores dejo el proyecto de Visual Studio http://1drv.ms/1aS1dTL

martes, 17 de noviembre de 2015

Serie de vídeos en español sobre Xamarin en Microsoft Channel 9

El día de hoy se publico el primer vídeo de una serie de vídeos sobre desarrollo con Xamarin, estos vídeos van a abarcar los temas básicos para comenzar a desarrollar apps IOS y Android y lo mejor de todo es que estarán en español.

En este primer vídeo hablo sobre los productos que ofrece Xamarin, cuales son las ventajas de utilizar la plataforma en el desarrollo de apps para IOS y Android; y también muestro como crear una cuenta con licencia de tipo Starter para comenzar a crear proyectos desde Visual Studio. 

Sin mas que decir este es el vídeo:


viernes, 30 de octubre de 2015

Usando SQLite .NET multiplataforma en Xamarin Android, Xamarin IOS, Windows Phone y Windows Store (Parte 2 WS)

Al igual que en el caso de Windows Phone lo primero es crear un proyecto nuevo, enlazarlo con Project Linker y agregar la referencia a una extensión como se hizo en la primera parte de este tutorial, por este motivo no me detendré en algunos pasos que se repiten en esta segunda parte y me enfocare a lo especifico de Windows Store.
Primero generamos el proyecto nuevo
5CreandoWS

El siguiente paso sería enlazar el proyecto Core a este que acabamos de crear del mismo modo en que se hizo con Windows Phone
Después de realizado lo anterior hay que instalar la extensión “SQLite for Windows Runtime(Windows 8.1)” desde el administrador de extensiones de Visual Studio (Menú Herramientas/Actualizaciones y extensiones)
image
Finalmente agregamos la referencia a esta extensión en nuestro proyecto.
image
Un detalle importante es que se debe crear un paquete de nuestra aplicación por arquitectura (x86,x64 o ARM) por lo cual hay que quitar esta referencia y volverla a agregar cada que cambiemos la arquitectura de lo contrario obtendremos la excepción “An exception of type 'System.BadImageFormatException' occurred in SQL.WS.exe but was not handled in user code”.  Esta excepción se debe a que la extensión agrega los paquetes específicos de la arquitectura que este definida en el momento en que se agrega la referencia.
image

Utilizando SQLite en el proyecto de Windows Store

Como ya tenemos desarrollada nuestra clase para administrar nuestra base de datos local (CRUDManager) y en pasos anteriores ya enlazamos Core a este proyecto solo nos resta generar la funcionalidad especifica de la plataforma, la cual básicamente es la interfaz de usuario y las llamadas a las funciones de CRUDManager.
En este caso el código es muy similar al de Windows Phone al ambos usar XAML como lenguaje para generar la interfaz de usuario. Aprovechando el tamaño de la pantalla y no dedicándole mucho tiempo al diseño voy a poner toda la funcionalidad en una misma pantalla a diferencia de Windows Phone que estaba acomodada por dos pantallas.
image
<Page
    x:Class="SQL.WS.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SQL.WS"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel Orientation="Horizontal">
            <StackPanel Width="320">
                <TextBlock FontSize="40">Guadar contactos</TextBlock>
                <TextBlock FontSize="20" >Nombre</TextBlock>
                <TextBox x:Name="txtName"></TextBox>
                <TextBlock FontSize="20">Edad</TextBlock>
                <TextBox x:Name="txtAge"></TextBox>
                <TextBlock FontSize="20">Correo Electrónico</TextBlock>
                <TextBox x:Name="txtMail"></TextBox>
                <TextBlock FontSize="20">Teléfono</TextBlock>
                <TextBox x:Name="txtPhoneNumber"></TextBox>
                <Button x:Name="btnSave" Margin="0,0,-3,0" Width="323" Click="btnSave_Click">Guardar</Button>

            </StackPanel>
            <StackPanel Width="300" Margin="100 0 0 0">
                <TextBlock FontSize="40">Buscar contactos</TextBlock>
                <TextBlock FontSize="20">Nombre</TextBlock>
                <TextBox x:Name="txtSName"></TextBox>
                <Button x:Name="btnSearch" Click="btnSearch_Click" Margin="0,0,-3,0" Width="303">Buscar</Button>
                <Button x:Name="btnAllItems" Click="btnAllItems_Click" Width="303" Margin="0,0,-3,0">Mostrar Todos</Button>
                <ListBox x:Name="lbResults" Height="250">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock FontWeight="Bold">Nombre</TextBlock>
                                <TextBlock Text="{Binding Name}"></TextBlock>
                                <TextBlock FontWeight="Bold">Edad</TextBlock>
                                <TextBlock Text="{Binding Age}"></TextBlock>
                                <TextBlock FontWeight="Bold">Correo Electrónico</TextBlock>
                                <TextBlock Text="{Binding Mail}"></TextBlock>
                                <TextBlock FontWeight="Bold">Teléfono</TextBlock>
                                <TextBlock Text="{Binding PhoneNumber}"></TextBlock>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
                <Button x:Name="btnDelete" Width="293" Click="btnDelete_Click">Eliminar seleccionado</Button>
            </StackPanel>
        </StackPanel>
    </Grid>
</Page>
Finalmente el código que da funcionalidad a esta interfaz es prácticamente el mismo que para WP
using SQL.Core.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace SQL.WS
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            InitializateDB();
        }

        CRUDManager crud;
        void InitializateDB()
        {
            var sqliteFilename = "ContactsDb";
            var path = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, sqliteFilename); ;

            crud = new CRUDManager(path);
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            Contact contact =
                new Contact(txtName.Text, int.Parse(txtAge.Text), txtPhoneNumber.Text, txtMail.Text);

            crud.SaveValue<Contact>(contact);
            lbResults.ItemsSource = crud.GetAllItems<Contact>();
        }

        private void btnSearch_Click(object sender, RoutedEventArgs e)
        {
            //Buscamos el contacto que coincida con lo introducido por el usuario
            lbResults.ItemsSource = new List<Contact> { crud.GetItem<Contact>(txtName.Text) };
        }

        private void btnAllItems_Click(object sender, RoutedEventArgs e)
        {
            //Mostramos todos los registros
            lbResults.ItemsSource = crud.GetAllItems<Contact>();
        }



        private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
            //Eliminamos el contacto seleccionado
            crud.Delete<Contact>(((Contact)lbResults.SelectedItem).Key);
            lbResults.ItemsSource = null;
        }
    }
}

jueves, 15 de octubre de 2015

Usando SQLite .NET multiplataforma en Xamarin Android, Xamarin IOS, Windows Phone y Windows Store (Parte 1 WP)

En esta serie de publicaciones voy a mostrar cómo crear una aplicación multiplataforma que permita crear bases de datos locales SQLite usando SQLite.Net para las plataformas:
  • Windows Phone 8.1 (Parte 1)
  • Windows Store (Parte 2)
  • IOS y Android (Parte 3)
Para empezar Vamos a generar una solución en Visual Studio la cual contenga los 4 proyectos que se van a usar a lo largo de este tutorial. Para este ejemplo se va a compartir el código mediante un proyecto Core que va a ser enlazado a los diferentes proyectos de la aplicación, en un futuro escribiré una publicación para mostrar el uso de SQLite usando una Librería de clases portable.
  • Librería de clases de C# (SQL.Core)
  • Proyecto de Windows Phone (SQL.WP)
  • Proyecto de Windows Store (SQL.WS)
  • Proyecto de Xamarin Android (SQL.Droid)
  • Proyecto de Xamarin IOS (SQL.IOS)

Creando el proyecto Core

1CreandoCore

domingo, 23 de agosto de 2015

Charla sobre Xamarin en TelmexHub (12 de Septiembre 4:00pm)





El próximo 12 de septiembre a las 4:00pm estaré en TelmexHub hablando sobre Xamarin y sus ventajas en el desarrollo multiplataforma.

El objetivo de la charla es conocer el porque Xamarin es una excelente herramienta para desarrollar Apps para IOS y Android además de poder utilizar ese mismo código en aplicaciones Windows Phone, Desktop, Web y otras plataformas que usan C# como lenguaje nativo.

Esta platica no será de desarrollar mucho código por lo cual no es necesario asistir con equipo a menos de que quieran realizar el ejemplo, aunque esta es mas una platica para dar a conocer como funciona Xamarin y hablar sobre como es el tema de las licencias y los beneficios que existen actualmente para los estudiantes.

Después de esta platica tengo planeado ofrecer un curso de C# como preparación a un futuro curso de Xamarin Android/IOS y apps para Windows Store.

Finalmente quien guste asistir debe registrarse en la pagina del evento: http://telmexhub.org/evento/3607

Del mismo modo les adjunto la página de Meetup donde se van a ir poniendo las fechas de los eventos futuros http://www.meetup.com/es/Devs-Xamarin-Android-IOS-y-Windows-Ciudad-de-Mexico/events/224780385/

jueves, 20 de agosto de 2015

Guardar datos de contacto en una etiqueta NFC con WP 8.1

Hace unos días encontré una etiqueta NFC que tengo desde hace unos años y por curiosidad decidí probar si aun funcionaba. Después de comprobar que aun funciona decidí actualizar mi App, la cual estaba hecha para Windows Phone 8, a Windows Phone 8.1 utilizando la función que sirve para generar una vCard para compartir datos de contacto mediante NFC.

Parte teórica

Elegí esta función sobre otras (escribir un “Hola Mundo” o un enlace a una página web) debido a que el crear una vCard involucra entender de mejor manera un estándar para almacenar datos NFC, voy a tratar de explicarlo de manera muy rápida, dejando algunas fuentes que me sirvieron por si quieren conocer mas a fondo del tema.

El estándar NDEF (Data Exchange Format) creado por el NFC Forum sirve para definir la estructura de datos de aplicación que se transmiten entre dos dispositivos NFC. Por otro lado el NFC Forum también definió el concepto de “NFC Forum Type Tag Operations” el cual sirve para identificar el tipo de operación que va a realizar una TAG NFC.

Para una referencia formal sobre este tema pueden visitar este documento; http://www.nxp.com/documents/other/R_10014.pdf y por supuesto la página del NFC Forum con las especificaciones http://members.nfc-forum.org/specs/spec_list/ 

Ya entrando al tema importante del post, lo primero es tener el formato en que se guardara la información de contacto en la etiqueta NFC, el cual es el siguiente para este ejemplo:

BEGIN:VCARD
VERSION:2.1
FN:
N:;
TEL;CELL:
EMAIL;INTERNET:
END:VCARD

Se pueden agregar mas datos siguiendo el estándar de una vCard, en este caso con la información de Wikipedia es suficiente https://en.wikipedia.org/wiki/VCard

Resumiendo todo lo mencionado anteriormente, lo que se va a hacer el lo que muestra este diagrama tomado del primer pdf sobre NDEF que deje mas arriba
image
  1. La entrada son los datos que se van a almacenar, en este caso los de la tarjeta de contacto
  2. El mensaje NDEF que encapsula lo anterior. Este mensaje tiene la siguiente estructura:
image
Parte importante aquí es que el mensaje define el tipo de dato que contiene, en el PDF se encuentra una lista muy completa de los tipos de dato. Algunos ejemplos (incluido el que usaremos)
image
  1. El NFC Type Tag Platform, para entender mejor esto si hay que leer la especificación del NFC Forum  debido a que habla de las especificaciones de las etiquetas como la memoria, velocidad, etc.
  2. Y finalmente la etiqueta donde se va a almacenar esta información.

Parte practica

Ahora si ya viene el código, para empezar definimos la interfaz XAML de nuestra aplicación, la cual simplemente contiene los campos con los datos (Nombre, apellido, teléfono y e-mail)
<Page
    x:Class="NfcVCard.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:NfcVCard"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">


    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contiene el nombre de la aplicación y el título de la página-->
        <StackPanel Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="NFC Writer" Style="{StaticResource SubheaderTextBlockStyle}"/>
            <TextBlock Text="vcard" Margin="9,-7,0,0" Style="{StaticResource HeaderTextBlockStyle}"/>
        </StackPanel>

        <!--ContentPanel. Colocar aquí el contenido adicional-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel>
                <TextBlock>Nombre</TextBlock>
                <TextBox InputScope="NameOrPhoneNumber" x:Name="txtNombre"></TextBox>
                <TextBlock>Apellido</TextBlock>
                <TextBox InputScope="NameOrPhoneNumber" x:Name="txtApellido"></TextBox>
                <TextBlock>Telefono</TextBlock>
                <TextBox InputScope="TelephoneNumber" x:Name="txtTelefono"></TextBox>
                <TextBlock>Mail</TextBlock>
                <TextBox InputScope="EmailSmtpAddress" x:Name="txtMail"></TextBox>
                <Button x:Name="btnEscribir" Click="btnEscribir_Click">Escribir Tag</Button>
            </StackPanel>
        </Grid>
    </Grid>


</Page>



Y el código de funcionalidad es el siguiente:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Networking.Proximity;
using Windows.Storage.Streams;
using Windows.UI.Popups;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=391641

namespace NfcVCard
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            this.NavigationCacheMode = NavigationCacheMode.Required;

        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.
        /// This parameter is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // TODO: Prepare page for display here.

            // TODO: If your application contains multiple pages, ensure that you are
            // handling the hardware Back button by registering for the
            // Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
            // If you are using the NavigationHelper provided by some templates,
            // this event is handled for you.

        }

        ProximityDevice _device;
        private void btnEscribir_Click(object sender, RoutedEventArgs e)
        {
            StatusBarProgressIndicator progressbar = StatusBar.GetForCurrentView().ProgressIndicator;
            progressbar.ShowAsync();
            progressbar.Text = "Acerca la etiqueta";
            btnEscribir.IsEnabled = false;

            string nombreCompleto = txtNombre.Text + " " + txtApellido.Text;
            string nombre = txtNombre.Text;
            string apellido = txtApellido.Text;
            string celular = txtTelefono.Text;
            string mail = txtMail.Text;
     //Obtenemos el dispositivo NFC del teléfono
            _device = ProximityDevice.GetDefault();
            //Creamos la tarjeta virtual con el formato que debe ser
            var vcard = string.Format("BEGIN:VCARD\nVERSION:2.1\nFN:{0}\nN:{1};{2}\nTEL;CELL:{3}\nEMAIL;INTERNET:{4}\nEND:VCARD", nombreCompleto, apellido, nombre, celular, mail);
            //El DataWriter que contiene los datos para escribir el mensaje binario a la etiqueta NFC
            var dataWriter = new DataWriter() { UnicodeEncoding = UnicodeEncoding.Utf8 }; dataWriter.WriteString(vcard);
            //Publicamos el mensaje binario en la etiqueta NFC, definimos el tipo de mensaje que es y támbien que método se va a ejecutar al finalizar el guardado
            _device.PublishBinaryMessage("WindowsMime:WriteTag.text/vcard", dataWriter.DetachBuffer(), MesssageTransmitted);
        }

        private async void MesssageTransmitted(ProximityDevice sender, long messageId)
        {
            //Le indicamos al dispositivo que deje de escribir el mensaje
            _device.StopPublishingMessage(messageId);



            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                StatusBarProgressIndicator progressbar = StatusBar.GetForCurrentView().ProgressIndicator;
                progressbar.HideAsync();
                btnEscribir.IsEnabled = true;
                new MessageDialog("Contenido guardado").ShowAsync();
            });
        }
    }
}

Para que lo anterior funcione de manera correcta hay que hacer dos cosas extra, hay que darle los permisos necesarios a la aplicación para que pueda usar el sensor NFC, de lo contrario obtendremos el error

An exception of type 'System.UnauthorizedAccessException' occurred in NfcVCard.ni.EXE but was not handled in user code

Additional information: Access is denied.

Esto se hace en el Manifiesto en la secciones de “Requirements” y “Capabilities”

image

image

En este enlace dejo el código fuente: Proyecto NFC

Aquí también un pequeño video de muestra de como se ve el proyecto en acción y como la etiqueta se puede leer perfectamente desde WP y desde un dispositivo con Android.


lunes, 17 de agosto de 2015

Xamarin gratis para desarrolladores Windows Phone

  Xamarin-Heart-Windows

Si publicaste una app para Windows Phone antes del día de hoy (17 de agosto de 2015) puedes pedir una licencia de Xamarin IOS y Android gratis la cual incluye el soporte para Visual Studio.

Esta oferta termina el 31 de Agosto para los desarrolladores independientes que quieran una suscripción para uso personal y no aplica para clientes actuales de Xamarin.

Para obtener la licencia hay que llenar el siguiente formulario: https://resources.xamarin.com/xamarin-for-windows-phone-app.html   Fuente: Xamarin Blog