desarrolloMobile.NET Noticias
jueves, noviembre 04, 2010
sábado, noviembre 14, 2009
Actualizando HTC Dream de Movistar a Cupcake (Android 1.5)
Pues ejerciendo el falso y sobrevalorado “derecho” de Canje de Puntos después de contribuir durante más dos años a aumentar las arcas de Telefónica para que, cada vez más vayan subsituyendo mano de obra en los departamentos de atención telefónica por maquinaria automática absurda, adquirí el viernes, y no voy a entrar a explicaros todos los pasos que he realizado para conseguirlo, pues empezaría a blasfemar, un HTC Dream tras pagar 239pavos e hipotecar mi futuro dos años con Movistar.
La decisión de compra se debió a que mi flamante HTC HD con Windows Mobile tuvo un pequeño percance. Mi relación con el soporte técnico de HTC no lo detallaré pues convertiría este post en un manifiesto anti-multinacionales tecnológicas.
La cuestión es que tras empezar a utilizar el HTC Dream de Movistar y familiarizarme un poco con Android (gracias al Centro de Soporte Telefónico del Maestro Alejandro Mezcua ;-) ) me cercioré de que la versión de Android que suministra este terminal, además de estar basado en Android 1.1, está algo capada. Por ejemplo, no puedo sincronizar contactos. Manda huevos. Buscando, encontré en http://and.roid.es un post de un tal Rick el cual explicaba paso por paso la actualización del HTC Dream de Movistar a Cupcake con lo que me puse manos a la obra.
Escribo este post para animar a los que no están muy seguros de si actualizar o no. En comparación, tras instalar Android 1.5, encuentro, además de la posibilidad de sincronización de Agenda, Contactos y Correo (menos mal), muchas otras aplicaciones que no vienen de serie, como por ejemplo uso de la Videocámara, además de algún Widget que otro. Además en el propio proceso de actualización se actualiza la radio (firmware), lo cual sí he notado, especialmente en cobertura.
Actualización
Seguid los pasos tal y como indica Rick en su post. Únicamente hay una error en la combinación de teclas que enumera para reiniciar el dispositivo en Fastboot, que es Home+Back en lugar de alt + back. Aseguraros de descargaros todos los componentes antes de todo. La guía hace referencia al SDK del Android 1.5 r1 y la última es la r3, pero es trivial.
Recomendable descargarse el FastBoot desde la Web de HTC e instalarla en un directorio de la raíz, al poder ser dentro de un subdirectorio del SDK pues se tiene que ejecutar desde la línea de comandos. Tras reiniciar el dispositivo en modo FastBoot no te resultará muy difícil seguir las instrucciones pues además de estar en castellano las opciones son claras. Si no quieres reiniciar el dispositivo en varias ocasiones y debido a que tienes que utilizar la SD para copiar los archivos update.zip (del cupcake y del firmware) no estaría de más tener un lector de tarjetas microSD he ir copiando y/o renombrando archivos.
No olvidéis actualizar el firmware. Yo me equivoqué y descargué y renombre un archivo zip de recursos el cual tenia la radio, con lo que tras ejecutarlo con Fastboot me dio un error; únicamente hay que comprimir en update.zip la carpeta radio.
Tras la actualización del cupcake y de la radio, no tuve que hacer nada más si utilizas la ROM de Ricky. El teclado funcionan perfectamente y la conexión APN de movistar viene configurada.
miércoles, noviembre 04, 2009
SQL Server –> Sync <- SQL Azure = Proyecto Huron muestra sus cartas!
Ayer se presentó en el SQL Pass Conference, en Seattle, las primeras imágenes del proyecto “Huron” el cual permitirá la sincronización de orígenes de datos SQL Server con SQL Azure.
En breve, Microsoft pondrá a disposición del público la primera CTP así como un add-in para SQL Server Management Studio. La idea es proporcionar un Wizard para la creación de un contexto de sincronización para que posteriormente SQL Agent sea el encargado de ejecutar las sincronización de ambos proveedores.
Probablemente el próximo PDC hayan más noticias.
Aquí van una imágenes.
viernes, octubre 30, 2009
GroupBy con LINQ to Objects
El agrupamiento de un conjunto de datos mediante LINQ, ya sea mediante la extensión de IEnumerable o IQueryable, tiene una serie de características las cuales me gustaría comentar aquí.
Para explicar un poco las posibilidades del agrupamiento mediante la extensión GroupBy voy a exponer un ejemplo con LINQ to Objects y para ello, primero, definiremos una clase sencilla que represente la entidad Cliente.
public class Cliente
{
public int IdProvincia { get; set; }
public int Tipo { get; set; }
public string Nombre { get; set; }
public decimal VolumenNegocio { get; set; }
public override string ToString()
{
return string.Format("\t\t-> Cliente: {0} - Provincia:{1} - Tipo: {2} - Vol.:{3}e\n",
Nombre, IdProvincia, Tipo,VolumenNegocio);
}
}
Como se puede observar no es más que una clase con 4 propiedades implícitas y el método ToString() sobrescrito para poder mostrar por la consola la información de un objeto iterado del tipo Cliente.
Vamos a generar una lista de clientes mediante una lista genérica de la siguiente forma://inicializamos lista de clientes
var list = new List<Cliente>
{
new Cliente {IdProvincia = 1, Nombre = "Cliente1", Tipo = 10, VolumenNegocio = 100.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente2", Tipo = 20, VolumenNegocio = 20.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente3", Tipo = 20, VolumenNegocio = 230.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente4", Tipo = 20, VolumenNegocio = 500.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente5", Tipo = 30, VolumenNegocio = 10.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente6", Tipo = 10, VolumenNegocio = 750.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente7", Tipo = 20, VolumenNegocio = 340.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente8", Tipo = 20, VolumenNegocio = 170.00m}
};
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, IEnumerable<TSource>, TResult> resultSelector);
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector);
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer);
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
IEqualityComparer<TKey> comparer);
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector);
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer);
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
IEqualityComparer<TKey> comparer);
En todas ellas existen un denominador común, el parámetro keySelector del tipo Func<TSource, TElement> que determina el valor de tipo TKey por el cual se agrupara la lista. Por otro lado GroupBy puede retornar un objeto del tipo IEnumerable<TSource> si se especifica el parámetro resultSelector (tipo Func<TSource, TKey>) o bien un objeto del tipo IEnumerable<IGroupingKey<TKey, TElement>> para todos los demás. Vamos centrarnos en éste último por ahora.
Manejando resultados IEnumerable<IGroupingKey<TKey, TElement>>
Si el agrupamiento se realiza sobre una lista de elementos iterativos o “IEnumerables” es obvio que el resultado, otra lista de subelementos agrupados por una clave del tipo TKey, sea otra lista de elementos iterativos de ahí que el tipo resultante sea IEnumerable<T>. La singularidad esta en el tipo genérico en la iteración del valor retornado el cual es del tipo IGroupingKey<TKey,TElement> y vamos a ver el porqué. Lo que LINQ hará ante un GroupBy es realizar un recorrido completo por la lista y seleccionará todos los elementos del tipo TElement de una misma clave (TKey). Por consiguiente el resultado será una lista del agrupamiento de elementos definidos por la interfaz IGroupingKey<TKey,TElement>, en la que almacenará la clave y el conjunto de elemento agrupados por el valor de dicha clave, respetivamente en cada tipo genérico. Veamos un ejemplo.
En nuestra lista de clientes vamos a agrupar los elementos por el identificador de provincia definido por Cliente.IdProvincia. Para ello definiremos una variable del tipo IEnumerable<IGroupingKey<int,Cliente> pues el tipo de datos de agrupamiento es del tipo int (propiedad IdProvincia) y el elemento a agrupar es del tipo Cliente, por tanto:
IEnumerable<IGrouping<int, Cliente>> groupByProv =
from cliente in list group cliente by cliente.IdProvincia;
O lo que es lo mismo:
var groupByProv = list.GroupBy(cliente => cliente.IdProvincia);
Ahora la variable groupByProv posee una lista de todas las clave/agrupaciones realizadas. De hecho podemos comprobarlo de la siguiente forma:
foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));
}
Cuyo resultado por pantalla seria:
La variable implícita cProv posee tanto la clave utilizada (IdProvinicia) como la iteración de los clientes agrupados por dicha propiedad, de forma que podría ser recorrida de igual forma.
foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));
foreach(var cliente in cProv)
Console.WriteLine(cliente.ToString());
}
Y es resultado:
Sin embargo podríamos rizar aún más el rizo y agrupar, de nuevo, cada una de las agrupaciones por el tipo de cliente. De esta forma tendríamos una primera agrupación según la IdProvincia del cliente y por cada uno, una agrupación por tipo de cliente de la siguiente forma:
1: foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
2: {
3: Console.WriteLine(string.Format("Provincia {0} ", cProv.Key));
4:
5: IEnumerable<IGrouping<int, Cliente>> groupByTipo = cProv.GroupBy(cliente => cliente.Tipo);
6:
7: foreach (var cTipo in groupByTipo)
8: {
9: Console.WriteLine(string.Format("\tTipo {0} \n", cTipo.Key));
10:
11: foreach (var cliente in cTipo)
12: Console.WriteLine(cliente.ToString());
13: }
14: }
Lo que hemos hecho en el ejemplo anterior es aprovechar la iteración del primer agrupamiento para volver a generar un extensión GroupBy pero en esta ocasión con la propiedad Cliente.Tipo (int) como TKey. El resultado:
Manejando resultados IEnumerable<TSource>
Como comenté anteriormente, GroupBy puede devolver una iteración de tipo IEnumerable<TSource> indicando en la sobrecarga el parámetro resultSelector. Para ver este ejemplo, en base a la lista de cliente generada anteriormente, vamos a mostrar, por ejemplo, para cada una de las provincias (agrupamiento) el número total de clientes, el valor máximo, mínimo y medio de la propiedad Cliente.VolumenNegocio (decimal) de modo que nos ofrecerá información, por cada provincia, de los valores máximo, mínimo y medio del volumen de negocio de los clientes.
Para ello utilizaremos la sobrecarga:
1: System.Linq.Enumerable.GroupBy<TSource, TKey, TResult>(
2: this System.Collections.Generic.IEnumerable<TSource>,
3: System.Func<TSource,TKey>,
4: System.Func<TKey,System.Collections.Generic.IEnumerable<TSource>,TResult>)
1: var groupByInfo = list.GroupBy(
2: cliente => cliente.IdProvincia, //seguimos con el agrupamiento por provinicia
3: (provincia, clientes) => new //retornamos un tipo anónimo
4: {
5: //con info sobre el agrupamiento
6: Key = provincia,
7: Count = clientes.Count(),
8: Min = clientes.Min(c => c.VolumenNegocio),
9: Max = clientes.Max(c => c.VolumenNegocio),
10: Avg = clientes.Average(c => c.VolumenNegocio)
11: });
El primer lugar, el tipo de la iteración de retorno es del tipo anónimo y es por ello que nos basamos en una variable implícitamente tipada (var). El primer parámetro (línea 2) es del tipo keySelector que vimos anteriormente y como dije es común en todas las sobrecargas pues es el valor clave de agrupamiento. Seguidamente el segundo parámetro (líneas 3-11), del tipo Func<int,IEnumerable<Cliente>,anonymous type> es donde se proyectará el resultado del agrupamiento.
Iteramos y mostramos los resultados.
1: foreach (var res in groupByInfo)
2: Console.WriteLine(
3: string.Format("Provinicia:{0}\n\tCount:{1}\n\tMin Volumen:{2}\n\tMax Volumen:{3}\n\tAvg:{4}"
4: , res.Key, res.Count, res.Min, res.Max, res.Avg));
En total 3 iteraciones con sus respectivas “estadísticas”:
El código completo:
namespace LINQGroupingBy
{
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
//Ejemplo para LINQ to Objects
//inicializamos lista de clientes
var list = new List<Cliente>
{
new Cliente {IdProvincia = 1, Nombre = "Cliente1", Tipo = 10, VolumenNegocio = 100.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente2", Tipo = 20, VolumenNegocio = 20.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente3", Tipo = 20, VolumenNegocio = 230.00m},
new Cliente {IdProvincia = 3, Nombre = "Cliente4", Tipo = 20, VolumenNegocio = 500.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente5", Tipo = 30, VolumenNegocio = 10.00m},
new Cliente {IdProvincia = 2, Nombre = "Cliente6", Tipo = 10, VolumenNegocio = 750.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente7", Tipo = 20, VolumenNegocio = 340.00m},
new Cliente {IdProvincia = 1, Nombre = "Cliente8", Tipo = 20, VolumenNegocio = 170.00m}
};
//obtenemos todos los clientes agrupados por provincias
var groupByProv = list.GroupBy(cliente => cliente.IdProvincia);
//tambien se puede expresar como:
//
//IEnumerable<IGrouping<int, Cliente>> groupByProv =
// from cliente in list group cliente by cliente.IdProvincia;
foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(
string.Format("Provincia {0}, {1} clientes", cProv.Key, cProv.Count()));
foreach(var cliente in cProv)
Console.WriteLine(cliente.ToString());
}
Console.ReadKey();
foreach (var cProv in groupByProv)//cProv es del tipo IEnumerable<IGrouping<int, Cliente>>
{
Console.WriteLine(string.Format("Provincia {0} ", cProv.Key));
IEnumerable<IGrouping<int, Cliente>> groupByTipo = cProv.GroupBy(cliente => cliente.Tipo);
foreach (var cTipo in groupByTipo)
{
Console.WriteLine(string.Format("\tTipo {0} \n", cTipo.Key));
foreach (var cliente in cTipo)
Console.WriteLine(cliente.ToString());
}
}
Console.ReadKey();
Console.Clear();
//volvemos a agrupar
var groupByInfo = list.GroupBy(
cliente => cliente.IdProvincia, //seguimos con el agrupamiento por provinicia
(provincia, clientes) => new //retornamos un tipo anónimo
{
//con info sobre el agrupamiento
Key = provincia,
Count = clientes.Count(),
Min = clientes.Min(c => c.VolumenNegocio),
Max = clientes.Max(c => c.VolumenNegocio),
Avg = clientes.Average(c => c.VolumenNegocio)
});
//mostramos los resultados
foreach (var res in groupByInfo)
Console.WriteLine(
string.Format("Provinicia:{0}\n\tCount:{1}\n\tMin Volumen:{2}\n\tMax Volumen:{3}\n\tAvg:{4}"
, res.Key, res.Count, res.Min, res.Max, res.Avg));
Console.ReadKey();
}
public class Cliente
{
public int IdProvincia { get; set; }
public int Tipo { get; set; }
public string Nombre { get; set; }
public decimal VolumenNegocio { get; set; }
public override string ToString()
{
return string.Format("\t\t-> Cliente: {0} - Provincia:{1} - Tipo: {2} - Vol.:{3}e\n",
Nombre, IdProvincia, Tipo, VolumenNegocio);
}
}
}
}
domingo, octubre 25, 2009
miércoles, octubre 14, 2009
Mas detalles sobre Marketplace Fase 2
En la segunda fase planificada para Noviembre/Diciembre de este mismo año, Marketplace lanzará un entorno para PC. De esta forma podremos se internacionalizará la compra de aplicaciones entre clientes/desarrolladores de diferentes países mediante una nueva caraterística denominada "geo selector". Además estaran disponibles centenares de aplicaciones de pago y gratuitas e incluirá soporte para dispositivos con Windows Mobile 6 / 6.1.
Fuente: modaco.com
sábado, octubre 10, 2009
Listado de recursos de desarrollo para Windows Mobile 6.5
A continuación detallo un conjunto de recursos para Windows Mobile 6.X/6.5:
Titulo | Tipo | Descripción |
Artículo | Presenta todos los recursos Online para Windows Mobile 6.5 | |
Developing Web Applications for Internet Explorer Mobile 6 on Windows Mobile 6.5 | Artículo
| Como sacar el máximo provecho a las nuevas características del navegador Internet Explorer Mobile de Windows Mobile 6.5. |
Artículo | Desarrollar Widgets para Windows Mobile 6.5. | |
Creating Location-Aware Applications for Windows Mobile Devices | Artículo | Desarrollo de aplicaciones basadas en los Servicios Basados en Localización para Windows Mobile 6.x. |
Creating a Compelling UI for Windows Mobile and the Microsoft .NET Compact Framework | Artículo | Aprende a utilizar las API’s de la plataforma Windows Mobile® para aumentar la experiencia de usuario.
|
Selecting a Windows Mobile API - .NET Compact Framework and Win32 | Artículo
| Este artículo habla acerca de Microsoft® Win32® API y las APIs de Microsoft .NET Compact Framework (NETCF) para Windows Mobile® 6 y posterior. |
Getting Started with Building Windows Mobile Solutions with Visual Studio and Windows Mobile 6 SDK | Artículo | Como empezar en el desarrollo de aplicaciones para Windows Mobile® utilizando las mismas herramientas que entornos Desktop con Microsoft® Visual Studio® 2008, y específicamente para Microsoft .NET Compact Framework 3.5. También describe como utilizar las herramientas contenidas en el Windows Mobile SDK. |
Optimizing Query and DML Performance with SQL Server Compact Edition 3.5 and SqlCeResultSet | Artículo
| Comparación en la inserción y manipulación de filas utilizando Microsoft® SQL Server® Compact Edition 3.5 SP1, con un especial enfoque para el usuario acerca de cómo utilizar los objetos SqlCeResultSet. |
Programming Microsoft Synchronization Services for ADO.NET (Devices) | Artículo | Una de las características más importantes de Microsoft® SQL Server® Compact Edition 3.5 SP1 es el soporte a Microsoft Synchronization Services for ADO.NET. Esta tecnología de sincronización permite la sincronización de diferentes orígenes de datos para entornos dos, N capas y arquitecturas orientadas a Servicios. |
Porting the Amplitude Application from the iPhone to a Windows Mobile Device – a Case Study | Artículo | Case de estudio documentado de portación de aplicación iPhone a dispositivo Windows Mobile 6.5.
|
Blog post | Detalles acerca de los pasos necesarios para la certificación de una aplicación al nuevo Marketplace. | |
Blog post | El Games API (GAPI) está obsoleto y este post habla de alternativas. | |
patterns & practices: Mobile Application Blocks - Community Release (was solution factory) | Codigo | Permite a los desarrolladores desarrollar aplicaciones mobile basadsa en VS2008, .NET CF 3.5 y WM6.1. Basado en el block de Mobile Client Software Factory v1, July 2006 e incluye mejoras realizadas por Microsoft Dynamics Mobile PU. |
Documentación | Documentación para la nueva API de Windows Mobile para el reconocimiento de trazas, Gesture API de Windows Mobile 6.5. | |
Windows Mobile 6 Professional and Standard Software Development Kits Refresh | Descarga
| Requisito para Windows Mobile 6.5 Developer Toolkit (DTK) |
Descarga | Windows Mobile 6.5 Developer Tool Kit (documentación, emuladores,…). | |
DVD | ||
FAQ | FAQ de Marketplace | |
Videos |
| |
Webcasts & Hands on labs | Programa RampUp para desarrollo con Windows Mobile 6.x | |
Webcasts | Dos webcast específicos para el nuevo API de Gesture. | |
Codigo | Libreria para .NET 2.0 para Windows Mobile 6.0/6.1 con controles Touch. | |
Descarga
| Windows Mobile Line of Business Solution Accelerator es un ejemplo de aplicación Windows Mobile que muestra el uso de diferentes tecnologias (WCF, Sync Services, multi idioma, etc.) en una misma aplicación. |
martes, septiembre 22, 2009
Code Camp Tarragona 2009 - Abierto los registros
Code Camp Tarragona 2009 es un evento gratuito para todos los asistentes.
Debido a que el evento cubre dos dias, sábado 17 de octubre y domingo 18 de octubre, se ha llegado a un acuerdo con el Hotel Palas Pineda con unas tarifas excepcionales y únicamente válidas para los asistentes al Code Camp Tarragona 2009.
Que incluye el Hotel
El precio del Hotel incluye la comida y cena del sábado dia 17 de octubre y el desayuno y Coffee Break del domingo dia 18 de octubre.
Habitación compartida o individual. FAQ.
- P: Quiero compartir habitación pero no tengo compañero,. ¿Que puedo hacer?- R: Selecciona " Registro CodeCamp Tarragona 2009 + Una noche Hotel Palas Pineda **** (Pensión Completa) con habitación compartida " y nosostros te asignaremos un compañero que se encuentre en las mismas condiciones que tú.
- P: Ire acompañado/a de mi pareja pese a que el/ella no asistirá al Code Camp. ¿Que debo hacer?- R: Debéis registraros ambos seleccionando la opción " Registro CodeCamp Tarragona 2009 + Una noche Hotel Palas Pineda **** (Pensión Completa) con habitación compartida ". Pese a que uno de los asistente no tenga intención de asistir al Code Camp se registrará como tal.
- P: Quiero compartir habitación y conozco a mi compañero quien tambien se registrará,. ¿Que puedo hacer?- R: Debéis registraros los dos, conjuntamente o por separado, y enviarnos un correo electrónico a mailto:hotel@codecamp.esindicando nombre y apellidos de los dos asistentes.
- P: ¿Si no quiero compartir habitación con nadie?- R: Entonces selecciona " Registro CodeCamp Tarragona 2009 + Una noche Hotel Palas Pineda **** (Pensión Completa) con habitación individual ".
- P: Asistiré al Code Camp pero no quiero hacer uso de los servicios del Hotel. ¿Hay algún problema?- R: No evidentemente que no lo hay. Sin embargo, no podras utilizar los servicios de comida, cena y desayuno así como las actividades del sábado por la noche que compartiremos con todos los asistentes registrados.
Para más Información o dudas
Para cualquier duda en relación al CodeCamp (registro, agenda, ...) , por favor utiliza los foros disponibles en http://www.codecamp.es/foros.aspx
martes, septiembre 01, 2009
Dispositivo Windows Mobile 6.5 a partir del 6 de octubre
Ya es oficial. Apartir del 6 de octubre empezaran a ver la luz la nueva "saga" de dispositivos Windows Mobile 6.5.
Se trata de la nueva versión anunciada en el pasado Mobie World Conference del pasado mes de febrero que tuvo lugar en Barcelona, junto a la nueva propuesta de Microsoft para el mercado de aplicaciones, Microsoft Marketplace, el cual ya se encuentra abierto a registros de nuevas aplicaciones.
Por lo que a España y Latino América respecta, las operadoras de telefonía móvil que ofrecerán estos nuevos dispositivos serán Orange y Vodafone en España y TIM Brasil así como fabricantes como HTC, LG Electronics, Samsung, Acer, Toshiba y Sony Ericsson los cuales lanzaran nuevas versiones de sus ya conocidos dispositivos como el Touch Diamond 2, Touch Pro 2, Omnia, etc.
miércoles, julio 01, 2009
Presentación de CodeCamp Tarragona 2009!!!!
Pues sí!! Ya es oficial. Los grupos de usuarios CatDotNet, BCNDEV, Spain.NET, Second NUG, LoNet Camp y Andorra.NET hemos unido nuestras fuerzas para organizar un CodeCamp de dos dias de duración para el 17 y 18 de octubre en Vila-Seca (Tarragona).
Entra en la Web Oficial o síguenos en twitter!!!!
jueves, junio 11, 2009
Must Have Tools para Windows Mobile
La lista del Windows Mobile Developer
jueves, junio 04, 2009
¡Emuladores Windows Mobile 6.5 ya estan aquí!
Para descargar los emuladores haz click aquí.
Para empezar con Widgets haz click aquí.
Visual Studio 2010 + Windows Mobile + .NET Compact Framework
Tras la tan esperada Beta 1 de Visual Studio 2010 muchos de vosotros habéis podido apreciar que NO existe soporte de proyectos para dispositivos Windows Mobile. Lo cierto es que tras la decepción inicial acompañada de la poca información y ausencia de una postura oficial por parte de Microsoft, ahora sí, Microsoft ha publicado de forma oficial en MSDN lo siguiente:
[Traducción del ingés]
"Microsoft está comprometido en hacer de Visual Studio una potente herramienta de desarrollo para el desarrollador de dispositivos móviles, y por tanto Visual Studio 2010 ofrecerá soporte para el desarrollo de dispositivos móviles, pero no se pueden ofrecer detalles al respecto, en estos momentos. Para los actuales desarrolladores de dispositivos móviles en Visual Studio 2008, Microsoft ofrecerá un emulador de Windows Mobile 6.5 que trabajará junto a los existentes SDK de Windows Mobile 6."
Mola ¿no? ;-)
martes, mayo 05, 2009
Proyecto “Huron”: Montacargas hacia la nube
Dentro de la plataforma Microsoft Azure, aparece cada vez con más fuerza un proyecto del que se ha venido hablando en los últimos meses y que promete ser, a priori, un revulsivo dentro de la apuesta de Microsoft en escenarios de sincronización. Huron (nombre en clave del proyecto) nace de la comunión de SQL Data Services y Microsoft Sync Framework. La idea es clara, Huron sera la plataforma de sincronización entre los datos "en la nube" y clientes desconectados. Huron, además, tratará de minimizar toda la complejida que conlleva la compartición de orígenes de datos, tales como la configuración y la seguridad, mediante el uso de herramientas de configuración (Huron Management Studio) y componentes de desarrollo.
Obviamente, los proveedores para los que, incialmente, estaran soportados seran SQL Server y SQL Server Compact, aunque se prevee soporte para Microsoft Access tal y como explica desde el blog del equipo de desarrollo de Microsoft Sync Framework. En dicho blog, se detalla algunas de las modificaciones respecto a las pretensiones iniciales, que ha sufrido Huron y de las cuales algunas ya se han hablado en Geeks.ms.
Por otro lado, y dado el contexto que se trata, Huron pretende ir más allá ofreciendo características tales como:
- Publicar bases de datos en la nube
- Suscribirse a una base de datos publicada en la nube y mantenerla sincronizada automaticamente.
- Propagar las modificaciones sobre SQL Data Services a las bases de datos suscritas.
- Habilitar la sincronización programada en background.
- Realizar Backups y Restores de bases de datos hacia y desde la nube, respectivamente.
En definitiva, un proyecto del que deberemos estar al tanto y cuyas perspectivas iniciales le auguran un importante hueco “entre las nubes”.
martes, abril 28, 2009
Error: No se puede mostrar un mensaje de error porque no se pudo encontrar un ensamblado de recursos opcional que lo contiene.
Aka: Could not find resource assembly
Esta mensaje de error aparece cuando se produce una excepción y no se encuentra el archivo de recursos de descripciones de errores para .NET Compact Framework.
Todas las cadenas de error asociadas a .NET Compact Framework 2.0 se almacenan en un archivo de recursos externo, llamado System.SR.dll. Este ensamblado no se distribuye para liberar memoria RAM del dispositvo.
La solución pasa por instalar el CAB System.SR.[Lang].cab dónde Lang denota el idioma en el que queremos mostrar el mensaje de la excepción. Dicho CAB se encuentra en:
%PROGRAM_FILES%\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\Diagnostics
NOTA: De forma análoga sucede lo mismo para mensajes de error relacionados con .NET Compact Framework 3.5. Alejandro Mezcúa publicó hace poco un post sobre ello.
domingo, abril 26, 2009
Bluetooth en .NET [Compact] Framework
Hará aproximadamente tres años empecé a desarrollar una libreria en .NET para la gestión de Bluetooth en Windows Mobile a raíz de un artículo que se publicó en dotNetMania num 35 (Marzo 2007).
Durante el tiempo que estuve desarrollando dicha libreria, pude apreciar realmente la dificultad que entraña un desarrollo sobre dicha tecnologia. De hecho, la libreria para Windows Mobile no pude finalizarla –se quedó con algunos Bugs- y la de Windows XP/Vista (unicamente 32 bits) logré que permitiera gestionar la radio Bluetooth, buscar dispositivos cercanos, emparejarse y comunicarse via COM mediante el servicio RFCOMM; quise expandir la libreria mediante el uso de la capa SDP (Service Discovery Protocol) de búsqueda y uso de servicios específicos a través del API de Bthioctl.dll de Windows Vista, pero ahí se quedó por falta de tiempo.
Desde que el material está expuesto en desarrolloMobile.NET, recibo muy a menudo preguntas o curiosidades en mi buzón de correo personal de las que, pese a que algunas desconozco, la mayoria hacen referencia a cómo empezar y de ahí el motivo de este post, para todos aquellos que quieran saber por dónde pueden empezar a implementar soluciones basadas en Bluetooth en sus proyectos.
Aspectos básicos
Incialmente, tanto Windows Mobile como Windows XP/Vista nos ofrece librerias nativas para poder inicializar y obtener la información de la radio bluetooth local y algunas de esas APIs las podemos ver en el siguiente código y cuyas referencias las encontraréis aqui.
1: public enum BthEstadosRadio : int
2: { Desactivado, Activado, Detectable };
3:
4: public class BTHRadio : IDisposable
5: {
6: [DllImport("bthutil.dll", SetLastError = true)]
7: private static extern int BthGetMode(out BthEstadosRadio mode);
8: [DllImport("bthutil.dll", SetLastError = true)]
9: private static extern int BthSetMode(BthEstadosRadio mode);
10: [DllImport("Btdrt.dll", SetLastError = true)]
11: private static extern int BthReadLocalVersion(
12: ref byte phci_version, ref ushort phci_revision,
13: ref byte plmp_version, ref ushort plmp_subversion,
14: ref ushort pmanufacturer, ref byte plmp_features);
15: [DllImport("Btdrt.dll", SetLastError = true)]
16: private static extern int BthReadCOD(ref CategoriaDispositivo pcod);
17: [DllImport("Ws2.dll", SetLastError = true)]
18: public static extern int WSACleanup();
19: [DllImport("Ws2.dll", SetLastError = true)]
20: public static extern int WSAStartup(ushort version, byte[] wsaData);
21: //los enumeradores Fabricantes y CategoriaDispositivo son
22: //identificadores únicos (http://www.bluetooth.org)
23: private Fabricantes _fabricante;
24: private short _versionRadio;
25: private CategoriaDispositivo _claseDisp;
26: //constructor
27: public BTHRadio()
28: { // inicializamos sockets
29: ushort wsv =
30: ((ushort)(((byte)(2)) ((ushort)((byte)(2))) << 8));
31: byte[] _data = new byte[512];
32: WSAStartup(wsv, _data);
33: //obt. versión y fabricante
34: byte version = 0, lversion = 0, caract = 0;
35: ushort revision = 0, lsubrevision = 0, fab = 0;
36: BthReadLocalVersion(ref version, ref revision,
37: ref lversion, ref lsubrevision, ref fab, ref caract);
38: this._fabricante = fab;
39: this._versionRadio = (short)lsubrevision;
40: //obtenemos categoría disp.
41: BthReadCOD(ref this._claseDisp);
42: }
43: //propiedad lectura/escritura del estado de radio
44: public BthEstadosRadio EstadoRadio
45: {
46: get
47: {
48: BthEstadosRadio currentMode;
49: BthGetMode(out currentMode);
50: return currentMode;
51: }
52: set
53: { BthSetMode(currentMode); }
54: }
55: //liberamos WS2.dll
56: public void Dispose()
57: { WSACleanup(); }
58: }
Con esta clase podemos empezar a gestionar nuestro Bluetooth (siempre y cuando se MS Bluetooth Stack) pero en realidad nos ofrecerá muy poca funcionalidad al no ser que la finalidad de la aplicación sea mostrado el estado e información de la radio. La información, en definitiva, que muestra este código es la que podemos ver en la siguiente captura de pantalla:
Aspectos avanzados
Sin embargo, el uso de esta tecnología en nuestros desarrollos requiere unos requisitos previos. En primer lugar es altamente recomendable que se entienda el funcionamiento de Bluetooth. A grandes rasgos, remarcaría dos conceptos muy distintos.
PRIMERO: Debemos conocer el perfil sobre el queremos trabajar. Bluetooth es un protocolo y com tal gestiona el intercambio de mensajes en base a un estándard desarrollado con el fin de comunicar dos dispositivos. No haremos “nada” sólo con Bluetooth, en todo caso sobre Bluetooth y lo haremos a través de los perfiles los cuales definen el comportamiento de los dispositivos y la comunicación. No es lo mismo que una aplicación haga uso de Bluetooth para la gestión de un manos libres que para el intercambio de archivos entre un dispositivo Windows Mobile y Windows Vista, por ejemplo. Los perfiles definen el cómo se lleva a cabo la comunicación. La comunicación con un manos libres utiliza un perfil (HFP), y el intercambio de objectos (archivos, contactos y demás) utiliza otro (OBEX).
SEGUNDO: En cuanto a la conexión entre dispositivos recordad que el proceso que normalmente realizamos para el emparejamiento manual se debe hacer programaticamente, con todo lo que ello conlleva. Para conectarnos a un dispositivos necesitamos saber la dirección del dispositivo y el Guid del servicio al que queremos conectarnos. El proceso de emparejamiento podría ser algo así:
1: public class BTHDispositivo
2: {
3: [DllImport("Btdrt.dll", SetLastError = true)]
4: private static extern int BthCreateACLConnection(byte[]
5: remoteBthAdd,
6: ref ushort phandle);
7:
8: [DllImport("Btdrt.dll", SetLastError = true)]
9: private static extern int BthCloseConnection(ushort phandle);
10:
11: [DllImport("Btdrt.dll", SetLastError = true)]
12: private static extern int BthAuthenticate(byte[] remoteBthAdd);
13:
14: [DllImport("btdrt.dll", SetLastError = true)]
15: private static extern int BthSetPIN(byte[] localBthAdd,
16: int pinLength, byte[] ppin);
17:
18: public string _nombre;
19: public byte[] _direccion;
20:
21: //pin.Length => 0 y pin.Length <= 16
22: public void EstablecerPIN(string pin)
23: {
24: byte[] pinbytes = System.Text.Encoding.ASCII.GetBytes(pin);
25: int len = pin.Length;
26: BthSetPIN(_direccion, len, pinbytes);
27: }
28: public bool QuitarPin()
29: {
30: BthRevokePIN(_direccion);
31: }
32:
33: public void Emparejar(string pin)
34: {
35: ushort handle = 0;
36: //conectamos
37: BthCreateACLConnection(_direccion, ref handle);
38: //autenticamos
39: BthAuthenticate(_direccion);
40: //desconectamos
41: BthCloseConnection(handle);
42: }
43: }
Una vez emparejado toca conectar mediante un servicio común entre ellos cuya conexión se puede realizar mediante Sockets a través de un EndPoint que exponga el servicio o perfil a utilizar (SOCKADDR_BTH) tal y como muestra el siguiente enlace. En modo de ejemplo a continuación se muestra el método de conexión de la libreria de desarrolloMobile.NET para WinXP.
1: public void Conectar(Servicios.BthServicio servicio)
2: {
3: clienteSck = new BthSocket();
4:
5: BthEndPoint endPoint = new BthEndPoint(this, servicio);
6:
7: try
8: {
9: clienteSck.Connect(endPoint);
10: }
11: catch (SocketException se)
12: {
13: throw;
14: }
15: catch (Exception ex)
16: {
17: throw;
18: }
19: }
¿Ahora bien, cómo averiguamos la dirección y el Guid del Servicio?
En cuanto a los servicios o perfiles, todos y cada uno tienen un Guid asociado que es universal (estandarizado). En sitio oficial de Bluetooth podeis encontrar una lista completa (NOTA: Debéis registraros).
En cuanto a la dirección del dispositivo a conectar hay que saber lo siguiente. Hablando desde el punto de vista programático las únicas formas de conocer la dirección destino es a través del descubrimiento de dispositivos cercanos o consultando los dispositivos ya emparejados (previo descubrimiento). Es aqui, en este punto, dónde la mayoria de desarrollos quedan atascados, puesto que el código de desubrimiento es complejo y se lleva a cabo a través de las clases WSALookUpServiceBegin, WSALookUpServiceNext y WSALookUpServiceEnd y cuya forma de proceder la podéis encontrar aquí. Siempre podemos conocer la dirección del dispositivo emparejandolo manualmente y por norma general, MS Bluetooth Stack almacena la dirección de todos los dispositivos previamente emparejados en el registro.
Microsoft tiene un ejemplo de uso para Bluetooth que podéis encontrar aquí. En este ejemplo, además, podéis ver el método de descubrimiento de servicios dado un dispositivo. Además muestra en la clave dónde se almacenan los dispositivos emparejados o de confianza.
Debug
Otros de los quebraderos de cabeza fue el Debug del proyecto. Si éste se realiza sobre una aplicación Windows Desktop no hay nada que decir pero si se realiza sobre Windows Mobile, entonces el emulador de poco me servía. Debía emparejar un dispositivo físico, realizar el despliegue sobre él a través de ActiveSync y depurar la aplicación sobre la misma.
Sin embargo, hace poco me topé con un artículo de codeproject que permitia emular la radio Bluetooth sobre un emulador Windows Mobile. El autor es
Dmitry Klionsky, y el enlace lo podéis encontrar aquí.
Recomendaciones
- Utiliza, en la medida de lo posible, componentes de gestión de pilas Bluetooth de terceros. No voy a decir ningún proveedor puesto que no he utilizado ninguno en especial. Pero el desarrollo de una libreria o componente propio debería ser la última alternativa.
- Conoce la pila de tu dispositivo Bluetooth(http://en.wikipedia.org/wiki/Bluetooth_stack). Las mas comunes son Microsoft Bluetooth Stack y Widcomm y la mayoria de componentes de terceros ofrecen servicios para como mínimo ambas pilas. Recuerda que una libreria para Bluetooth desarrollada para Microsoft Bluetooth stack NO es compatible con Widcomm y viceversa. De hecho las librerias que encontrarás en desarrolloMobile.NET no son válidas para dispositivos Widcomm y demás. Encontraras un enlace con el tipo de pilas utilizas por dispositivos (modelo/marca) aqui.
- Si te apatece profundizar sobre el tema, en desarrolloMobile.NET (sección Bluetooth) encontrarás más recursos. Otros de los sitios que no puedes dejar de visitar es el proyecto 32feet.net.