Este artigo foi traduzido por máquina.

Cutting Edge

Desenvolvimento de site para celular, Parte 4: Gerenciando perfis de dispositivos

Dino Esposito

Baixar o código de exemplo

Dino EspositoNeste artigo falarei sobre uma maneira de classificar os dispositivos móveis e criar um site que serve de marcação diferente para diferentes dispositivos baseados nos recursos do dispositivo.

Se você não precisa se adaptar a marcação processada para os recursos de um navegador solicitante, a construção de um site móvel pode ser uma experiência perfeita.Mais frequentemente do que não, porém, você precisará ajustar o conteúdo para você serve e adaptá-lo para os eficazes recursos do navegador.Será que o som como a reiteração de uma velha história?Anos atrás, os desenvolvedores enfrentaram um problema semelhante para navegadores desktop.Era comum escrever páginas da Web que verifiquei o tipo (e às vezes a versão) do navegador antes de decidir sobre a marcação de retorno.Recentemente, como o foco da programação Web mudou-se mais para o lado do cliente, bibliotecas como o jQuery e o Modernizr deram um contributo significativo em manter os desenvolvedores distância de muitas das diferenças dos navegadores.

Ele ainda pode ser difícil e caro construir um site de área de trabalho que se parece e funciona da mesma forma independentemente do navegador.No entanto, o número de navegadores desktop é relativamente pequeno, e a diferença entre as versões mais recentes de todos os navegadores não é enorme.Quando se trata de navegadores móveis, porém, quase qualquer modelo de aparelho tem seu próprio navegador ligeiramente diferente e personalizado.Além disso, os usuários podem ter instalado um navegador entre dispositivos como Fennec ou Opera Mini.O grande número de navegadores móveis possíveis faz direcionamento de cada um deles separadamente — como os desenvolvedores fizeram com navegadores desktop — uma abordagem altamente impraticável.Uma abordagem mais inteligente é a partição de navegadores móveis em algumas classes e servir cada classe uma versão ad hoc de qualquer página.Esta abordagem é muitas vezes referida como multiserving.

O site de exemplo para este artigo é criado usando o ASP.NET MVC 3.Note-se, porém, que o ASP.NET MVC 4 traz algumas novas instalações que poderiam fazer com que a implementação de multiserving mais simples.Falarei sobre ASP.NET MVC 4 em relação aos mobile sites em uma coluna futura.

Da fragmentação à perfis de dispositivo

Fragmentação de móvel é significativa, com milhares de dispositivos exclusivos e centenas de recursos para descrever-lhes.Idealmente, você precisa páginas que inteligentemente podem ajustar as características dos navegadores solicitante.Para conseguir isso, você tem basicamente duas rotas possíveis.Um é de criação diferentes versões da mesma página — uma para cada classe de dispositivo é destinado a apoiar.O outro consiste em ter um modelo de página comum e enchendo-o com o conteúdo específico do dispositivo a cada pedido.

No final, no entanto, ambas as abordagens começam a partir de um terreno comum: Divida seu público esperado em algumas categorias.Em seguida, cada página do site irá fornecer a marcação ad hoc para cada uma das categorias.

Para domar a fragmentação de dispositivo, você deve decidir no início quantas versões do site móvel que você pretende ter.Esta é uma decisão-chave porque ele afeta a percepção do site e, em última análise, o seu sucesso.Não é, portanto, uma decisão para tomar de ânimo leve e considerações de negócios aplicam-se — não é simplesmente um detalhe ou tecnologia decisão de implementação.Dependendo do caso de negócio, você pode optar por oferecer o site apenas para smartphones e talvez otimizar o site para, digamos, dispositivos de Windows Phone, no muito a mesma maneira alguns sites de área de trabalho foram apresentando o rótulo de "melhor visualizado com XXX" uma década ou mais atrás.Mais provavelmente, porém, você vai querer ter pelo menos duas versões do site — para dispositivos inteligentes e legados — e talvez considerar ainda uma outra versão que especificamente destinos dispositivos de tablet ou até mesmo smart TVs.

Smartphones, dispositivos herdados e comprimidos são exemplos de perfis de dispositivo no qual você dividir seu público esperado.Você não tem que escrever seu site móvel para o endereço de milhares de dispositivos pelo nome; em vez disso, identificar alguns perfis de dispositivo e definir quais recursos são necessários para se juntar a cada perfil.Escusado será dizer que lá não pode ser corrigido e regras universais que definem quando um dispositivo é um "smartphone" e quando não é.Não há nenhuma norma ratificada por isso, e você é responsável por definir os recursos necessários para um dispositivo ser classificado como um smartphone no contexto do seu site.Também consideram que a definição de um smartphone é variável por design.Um dispositivo Windows CE certamente foi percebido como um dispositivo muito inteligente há apenas cinco ou seis anos.Hoje, seria difícil incluí-lo na categoria smartphone.

Projeto Liike — um esforço dos padrões & Grupo de práticas Microsoft destinadas a construção de um site de referência móvel — divide o público móvel em três classes, familiarmente chamado WWW, abreviação de Wow, obras e gritos.

A classe de Wow se refere aos dispositivos de rico e inteligente de hoje.A classe de obras refere-se aos dispositivos não-assim-ricos e capazes.Finalmente, a classe de gritos refere-se a qualquer outro dispositivo legado que mal tem a capacidade de se conectar à Internet e processar alguns conteúdos básicos de HTML.Para obter mais informações sobre o projeto Liike, visite liike.github.com.

Neste artigo eu vou usar os perfis de dispositivo a seguir: Smartphone, tablet e móveis antigos.Figura 1 mostra o conjunto (mínimo) de regras costumava aceitar dispositivos em diversos perfis.Note que as regras devem ser expandidas para incluir recursos mais específicos que dependem de suas páginas o que precisam realmente de fazer.Por exemplo, se você planeja usar JavaScript assíncrono e manipulação de XML e HTML Document Object Model, convém garantir que os dispositivos tenham esses recursos.Se você está servindo vídeos, convém garantir que os dispositivos suportam alguns codecs determinado.Para dispositivos que não podem ser capazes de corresponder as suas expectativas, você deve fornecer uma página de retorno, e este é precisamente o papel do legado (ou seja, pega-tudo) perfil.

Figura 1 exemplo perfis de dispositivo

Perfil de dispositivo Recursos
Smartphone Dispositivo móvel, dispositivo de toque, tela largura maior que 240 pixels, com base em um sistema de operacional conhecido (2.1 Android, iOS, BlackBerry 6.0 ou Windows Phone).
Tablet PC Dispositivo móvel e o dispositivo do tablet.
Celular Não cair em outros perfis de dispositivo móvel.

Implementar um gerador de perfil de dispositivo simples

No site de exemplo, eu formalizar o conteúdo de Figura 1 em uma interface denominada IDeviceProfiler:

public interface IDeviceProfiler
{
  Boolean IsDesktop(String userAgent);
  String MobileSuffix { get; }
  Boolean IsMobile(String userAgent);
  String SmartphoneSuffix { get; }
  Boolean IsSmartphone(String userAgent);
  String TabletSuffix { get; }
  Boolean IsTablet(String userAgent);
}

O sufixo refere-se a um nome único usado para diferenciar os modos de exibição. Por exemplo, o index.cshtml da página será expandido para index.smartphone.cshtml, index.tablet.cshtml e index.mobile.cshtml para diversos perfis. Figura 2 mostra uma implementação básica para um objeto de dispositivo do profiler.

Figura 2 implementação do criador de perfil de dispositivo de mínima

public class DefaultDeviceProfiler : IDeviceProfiler
{
  public virtual String MobileSuffix {     get { return "mobile"; }   }
  public virtual Boolean IsMobile(String userAgent)
  {
    return HasAnyMobileKeywords(userAgent);
  }
  public virtual String SmartphoneSuffix {
    get { return "smartphone"; }
  }
  public virtual Boolean IsSmartphone(String userAgent)
  {
    return IsMobile(userAgent);
  }
  public virtual String TabletSuffix {
    get { return "tablet"; }
  }
  public virtual Boolean IsTablet(String userAgent)
  {
    return IsMobile(userAgent) &&
      userAgent.ContainsAny("tablet", "ipad");
  }
  public virtual Boolean IsDesktop(String userAgent)
  {
    return HasAnyDesktopKeywords(userAgent);
  }
  // Private Members
  private Boolean HasAnyMobileKeywords(String userAgent)
  {
    var ua = userAgent.ToLower();
    return (ua.Contains("midp") ||
      ua.Contains("mobile") ||
      ua.Contains("android") ||
      ua.Contains("samsung") ||      ...
}
  private Boolean HasAnyDesktopKeywords(String userAgent)
  {
    var ua = userAgent.ToLower();
    return (ua.Contains("wow64") ||
      ua.Contains(".
net clr") ||
      ua.Contains("macintosh") ||
      ...
}
}

Como você pode adivinhar Figura 2, cada dispositivo é identificado através de sua cadeia de caracteres de agente do usuário. A seqüência de caracteres de agente do usuário é processada para ver se ele contém algumas palavras-chave conhecida para representar um navegador móvel ou desktop. Por exemplo, uma seqüência de caracteres do agente de usuário que contém o "android" de Subcadeia de caracteres pode ser combinada com segurança para um navegador móvel. Da mesma forma, a subseqüência "wow64" geralmente se refere a um navegador de desktop Windows. Deixe-me dizer, na frente, que embora contando com seqüências de agente do usuário é, provavelmente, a melhor abordagem para detectar capacidades do dispositivo no lado do servidor, não é garantia de sucesso. Pessoalmente, eu recentemente comprei um tablet Android 4.0 e descobriu que o navegador incorporado apenas envia textualmente o agente de usuário de um iPad rodando iOS 3.2. Fragmentação de dispositivo é difícil devido a esses problemas.

Seleção de modo de exibição, Layout e modelo

Vamos dizer que o criador de perfil de dispositivo confiável pode nos dizer qual perfil o navegador solicitante pertence. Em um site ASP.NET MVC, como você selecionaria a vista direita e layout de dentro de cada método de controlador? Em qualquer método de controlador que retorna a marcação HTML, você pode indicar explicitamente o nome do modo de exibição e layout relacionado. Os dois nomes podem ser determinados o método de controlador, usando o seguinte código:

// Assume this code is from some Index method
var suffix = AnalyzeUserAgent(Request.UserAgent);
var view = String.Format("index.{0}", suffix);
var layout = String.Format("_layout.{0}", suffix);
return View(view, layout);

Em um cenário de multiserving, as diferenças entre modos de exibição para a mesma página não podem ser limitadas para o modelo de exibição. Em outras palavras, pegando um par específico de modelos de exibição e layout pode não ser suficiente — você pode precisar passar um objeto de modelo de exibição diferentes.

Se você está passando dados de modelo de exibição através de coleções internas ou ViewBag, ViewData, você pode considere mover qualquer código que lida com a análise da seqüência do agente do usuário sem o controlador. No download de código exemplo site móvel que acompanha este artigo, o método de índice da home page tem esta aparência:

public ActionResult Index()
{
  ViewBag.Title = "...";  ...
return View();
}

Como você pode ver, o modo de exibição é gerado sem uma indicação explícita do nome e layout. Quando isso acontece, o mecanismo de exibição é finalmente responsável para finalizar o modo de usar e seu layout. O mecanismo de exibição, portanto, é um lugar possível para incorporar qualquer lógica para gerenciar perfis de dispositivo. Criando e registrando um mecanismo de exibição personalizada, você isolar qualquer lógica para a análise de perfis de dispositivos em um único lugar, e o restante de seu site móvel pode ser desenvolvido como uma simples coleção de páginas relacionadas. O código a seguir mostra como registrar um mecanismo de exibição personalizada em global. asax:

 

// Get rid of any other view engines
ViewEngines.Engines.Clear();// Install an ad hoc mobile view engine
ViewEngines.Engines.Add(new MobileRazorViewEngine());

Figura 3 mostra o código fonte do mecanismo do modo de exibição personalizado (Razor-baseado).

Figura 3 mecanismo de exibição móvel-ciente

public class MobileRazorViewEngine : RazorViewEngine
{
  protected override IView CreatePartialView(
    ControllerContext context, String path)
  {
    var view = path;
    if (!String.IsNullOrEmpty(path))
      view = GetMobileViewName(context.HttpContext.Request, path);
    return base.CreatePartialView(controllerContext, view);
  }
  protected override IView CreateView(
    ControllerContext context, String path, String master)
  {
    var view = path;
    var layout = master;
    var request = context.HttpContext.Request;
    if (!String.IsNullOrEmpty(path))
      view = GetMobileViewName(request, path);
    if (!String.IsNullOrEmpty(master))
      master = GetMobileViewName(request, master);
    return base.CreateView(context, view, master);
  }
  public static String GetMobileViewName(
    HttpRequestBase request, String path)
  {
    var profiler =  DependencyResolver.Current.GetService(
      typeof(IDeviceProfiler)) as IDeviceProfiler
      ??
new DefaultDeviceProfiler();
    var ua = request.UserAgent ??
String.Empty;
    var suffix = GetSuffix(ua, profiler);
    var extension = String.Format("{0}{1}",
      suffix, Path.GetExtension(path));
    return Path.ChangeExtension(path, extension);
  }
  private static String GetSuffix(String ua, IDeviceProfiler profiler)
  {
    if (profiler.IsDesktop(ua))
      return String.Empty;
    if (profiler.IsSmartphone(ua))
      return profiler.SmartphoneSuffix;
    if (profiler.IsTablet(ua))
      return profiler.TabletSuffix;
    return profiler.IsMobile(ua)
      ?
profiler.MobileSuffix
      : String.Empty;
  }
}

Antes de renderizar uma vista, o mecanismo de exibição usa o criador de perfil de dispositivo instalado para consulta sobre o perfil do agente do usuário solicitante. Com base nisso, o mecanismo de exibição muda-se para a vista mais apropriada. Se o nome do layout é fornecido explicitamente chamada Vista de dentro do controlador, o mecanismo de exibição pode resolvê-lo sem problemas. Se o nome de layout é definido em _viewStart.cshtml (como na maioria dos códigos de ASP.NET MVC), o mecanismo de exibição não será capaz de resolvê-lo, porque o parâmetro mestre em CreateView está sempre vazio. Aqui é uma correção para aplicar em _viewStart.cshtml:

@using MultiServing.ProfileManager.Mvc
@{
  const String defaultLayout = "~/Views/Shared/_Layout.cshtml";
  Layout = MobileRazorViewEngine.GetMobileViewName(
    Context.Request, defaultLayout);
}

Se você usar modos de exibição com rigidez de tipos e os vários modos de exibição móveis para a mesma página (smartphone, tablet e assim por diante) cada requer seu próprio modelo de exibição? Nesse caso, você pode querer construir um componente de trabalho que analisa o agente do usuário e retorna o nome do layout da visualização e usa este componente de dentro de cada método de controlador. Como eu vejo as coisas, se você precisa analisar o direito de agente do usuário no nível do controlador para decidir sobre o modelo de exibição, baseando-se em um mecanismo de exibição personalizada é redundante, porque você já sabe que Ver os chamar.

Além deste ponto, é tudo sobre usando um gerador de perfil de dispositivo apropriado e construção de vários modelos de página HTML.

Configurando o WURFL no ASP.NET MVC

Como mencionado em parcelas anteriores desta série, o arquivo de recurso Universal Wireless (WURFL) é um popular repositório de descrição de dispositivo (DDR) usado nos back-ends do Google e Facebook mobile sites. WURFL oferece uma API multiplataforma e pode ser facilmente conectado a qualquer projeto de ASP.NET MVC usando NuGet (ver Figura 4).

Adding WURFL to ASP.NET MVC via NuGet
Figura 4 Adicionando WURFL para ASP.NET MVC via NuGet

WURFL adiciona um banco de dados XML para seu projeto que contém informações do dispositivo. O banco de dados deve ser carregado na memória na inicialização do aplicativo e fornece acesso quase instantâneo a perfis de dispositivo. No global. asax, você adiciona o código mostrado na Figura 5.

Figura 5 usando o WURFL

public class MyApp : HttpApplication
{
  public static IWURFLManager WurflContainer;
  protected void Application_Start()
  {    ...
RegisterWurfl();    
    DependencyResolver.SetResolver(new SimpleDependencyResolver());  }
  public static void RegisterWurfl()
  {
    var configurer = new ApplicationConfigurer();
    WurflContainer = WURFLManagerBuilder.Build(configurer);
  }
}

Em Figura 6, você vê um componente IDeviceProfiler que usa o WURFL para detectar a smartphones e tablets. Você resolver o criador de perfil através de um resolvedor de dependência personalizada. (Veja o código-fonte que acompanha para obter detalhes sobre a resolução.)

Figura 6 WURFL-Based Device Profiler

public class WurflDeviceProfiler : DefaultDeviceProfiler
{
  public override Boolean IsMobile(String ua)
  {
    var device = MyApp.WurflContainer.GetDeviceForRequest(ua);
    return device.IsWireless();
  }
  public override Boolean IsSmartphone(String ua)
  {
    var device = MyApp.WurflContainer.GetDeviceForRequest(ua);
    return device.IsWireless() && !device.IsTablet() &&
      device.IsTouch() &&
      device.Width() > 240 &&
      (device.HasOs("android", new Version(2, 1)) ||
      device.HasOs("iphone os", new Version(3, 2)) ||
      device.HasOs("windows phone os", new Version(7, 1)) ||
      device.HasOs("rim os", new Version(6, 0)));
  }
  public override Boolean IsTablet(String ua)
  {
    var device = MyApp.WurflContainer.GetDeviceForRequest(ua);
    return device.IsTablet();
  }
}

O método GetDeviceForRequest consulta o banco de dados do WURFL e retorna um objeto do IDevice que pode ser consultado usando uma sintaxe relativamente fluente. Note-se que métodos como IsTouch, IsTablet e HasOs são na verdade os métodos de extensão construídos sobre a API nativa do WURFL que você encontra no projeto de exemplo. Por exemplo, aqui está o código para IsTablet:

public static Boolean IsTablet(this IDevice device)
{
  return device.GetCapability("is_tablet").ToBool();
}

Eu tenho discutido nesta coluna um exemplo concreto de um site móvel do ASP.NET MVC construído para proporcionar uma experiência diferente em uma variedade de dispositivos: dispositivos móveis, smartphones, tablets e legado, como mostrado no Figura 7. Sugiro que você baixe o código fonte e executá-lo no Internet Explorer (ou outros navegadores), alternando para agentes de usuário diferente. Você também pode testar o site ao vivo no www.expoware.org/amse/ddr. Note-se que acessando o site de um navegador de desktop resulta na mensagem: "Este site não está disponível em navegadores desktop. Tente usar um celular ou tablet navegador."

Tablets, Smartphones and Plain Mobile Devices Accessing the Sample Site
Figura 7 comprimidos, Smartphones e dispositivos móveis simples, acessando o Site de exemplo

Dino Esposito é o autor de "Arquitetura móvel soluções para a empresa" (Microsoft Press, 2012) e "programação ASP.NET MVC 3" (Microsoft Press, 2011) e co-autor do livro "Microsoft .net: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Residente na Itália, Esposito é um palestrante sempre presente em eventos do setor no mundo inteiro. Siga-o no Twitter em twitter.com/despos.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Erik Porter e Camila Rodrigues