领先技术

移动站点开发,第 4 部分:管理设备配置文件

Dino Esposito

下载代码示例

Dino Esposito在这篇文章中,我将讨论的方式进行分类的移动设备,并生成一个 Web 站点,提供不同的标记,到不同的设备基于设备的功能。

如果您不需要适应的呈现的标记向发出请求的浏览器的功能,建设一个手机网站可以无缝的体验。往往不虽然,您需要调整您服务,并使它适应有效功能的浏览器的内容。这听起来不喜欢一个古老的故事的反复吗?几年前,开发商面临桌面浏览器的一个类似问题。这是共同写决定有关标记返回之前,检查该类型 (和有时版本) 的浏览器的 Web 页。最近,随着 Web 编程中的转向更向客户端,jQuery 和 Modernizr 等图书馆提供了保持开发人员从浏览器的差异的许多重大的贡献。

它仍然可以是困难和昂贵打造桌面的 Web 站点的外观和使用方式相同,浏览器无关。然而,桌面浏览器的数量是相对较小,和所有的浏览器的最新版本之间的差距并不大。向移动浏览器的时候,不过,几乎任何模式的设备有自己略有不同的和自定义的浏览器。此外,用户可能已经安装了 Fennec 或 Opera Mini 等跨设备浏览器。大量的可能的移动浏览器使分别针对每个 — — 与桌面浏览器开发者那样 — — 一个极不可行的方法。一种聪明的做法是页面的移动浏览器分成几类和服务的每个类特设的任何给定版本。这种方法通常被称为 multiserving。

这篇文章的示例 Web 站点是使用 ASP.NET MVC 3 生成的。不过,应该指出的是,ASP.NET MVC 4 带来一些新的设施,从而使简单的 multiserving 的执行情况。关于移动网站在以后的专栏中,我将涵盖 ASP.NET MVC 4。

从到的设备配置文件碎片

移动碎片是重要的是,数以千计的唯一设备和数以百计的充分描述他们的能力。理想情况下,您需要可以智能地调整特点的请求的浏览器的页。要做到这一点,你得基本上有两种可能的途径。其中一个创作在同一页面的不同版本 — — 一个用于每个类的它已经打算支持的设备。其他包括有一个共同的页面模板和填补与每个请求的特定于设备的内容。

最后,不过,这两种方法从启动一个共同点:您预期的观众分成几个类别。然后,该网站的每一页将为每个类别提供特设的标记。

驯服设备破碎,您应该决定要有多少早期版本的手机网站。这是一项关键决定,因为它会影响站点,并最终取得成功的看法。它不是,因此,决定采取掉以轻心及业务注意事项适用 — — 它不是简单地实现详细信息或技术决策。根据业务的情况下,您可能决定提供仅对智能手机网站,或许说,Windows Phone 设备的网站优化,很多相同方式有些桌面网站被展示"最佳浏览 XXX"十年的标签或前。更可能的是,不过,你就会想要至少两个版本的网站 — — 智能和旧式设备 — — 也许考虑具体目标平板设备,或甚至智能电视的另一个版本。

智能手机、 旧设备和片属于所有的设备配置文件,您将拆分您预期的观众。您不必编写您的移动网站到数千个地址的设备的名称 ; 相反,您确定几个设备配置文件,并定义哪些功能需参加每个配置文件。不言而喻,那里可能会不固定,定义当设备的通用规则是"智能手机",当它不。有没有批准的标准,为此,和您负责定义的设备要被划分为您的站点的上下文中的智能手机所需的功能。此外考虑一款智能手机的定义是由设计的变量。Windows CE 设备肯定被认为是一个非常聪明的设备仅有五、 六年前。今天,很难将其列入智能手机类别。

项目作用影响 — — 模式的努力 & 在微软的做法集团旨在建立一个移动参考网站 — — 将移动观众拆分为三个类,无拘无束称为 WWW、 短的哇、 工程和糟。

哇类是指今天的富裕和智能设备。作品类指的并不是那么富有和有能力的设备。最后,糟类指几乎没有连接到互联网,并呈现一些基本的 HTML 内容的能力中的其他任何旧式设备。项目作用影响的详细信息,请访问 liike.github.com

在这篇文章中,我将使用以下设备配置文件:智能手机、 平板电脑和旧手机。图 1 显示 (最小) 的一组规则用于接受各种配置文件中的设备。请注意应扩大规则 》,以包括更多特定的功能,取决于您的网页确实需要做些什么。例如,如果您计划使用异步 JavaScript 和 XML 和 HTML 文档对象模型的操作,您可能想要确保设备具有这些功能。如果你正在服务的视频,您可能想要确保设备支持某些给定的编解码器。对于不能与你的期望的所有匹配的设备,您应该提供一个备用的页面,而这是遗留下来的角色正是 (即,捕获全部) 配置文件。

图 1 示例的设备配置文件

设备配置文件 功能
Smartphone 触摸设备,移动设备的屏幕宽度大于 240 像素,基于一个已知的操作系统 (Android 2.1、 iOS,黑莓 6.0 或 Windows Phone)。
平板电脑 移动设备和平板电脑设备。
移动 移动设备不能陷入其他配置文件。

执行简单的设备事件探查器

在示例网站上,我正式的内容图 1 到名为 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);
}

后缀是指一个唯一的名称,用于区分的意见。 例如,页 index.cshtml 将会扩大到 index.smartphone.cshtml、 index.tablet.cshtml 和 index.mobile.cshtml 的各种配置文件。 图 2 显示为设备事件探查器对象的基本实现。

图 2 小设备事件探查器实施

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") ||
      ...
}
}

您可以从猜到图 2,通过其用户代理字符串识别每个设备。 用户代理字符串进行处理以查看它是否包含已知代表移动或桌面浏览器的一些关键字。 例如,一个用户代理字符串,包含的子字符串"android"可以安全地匹配到移动浏览器。 同样地,"wow64"子字符串通常是指 Windows 桌面浏览器。 让我说最前面虽然依靠用户代理字符串可能是最好的办法来检测设备功能在服务器端,它不是成功的保证。 就个人而言,我最近买了 Android 4.0 平板电脑,发现嵌入式浏览器只是发送出逐字记录运行 iOS 3.2 iPad 的用户代理。 设备碎片硬盘,这是这些问题的。

选择视图、 布局和模型

让我们假设设备探查器可以可靠地告诉我们请求浏览器属于哪个配置文件。 在 ASP.NET MVC 的网站,如何将您选择的右视图和布局从内每个控制器的方法? 在任何控制器的方法,它返回的 HTML 标记,您可能明确表示视图和相关的布局的名称。 在控制器的方法使用下面的代码中,可以确定两个名称:

// 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);

在 multiserving 的情况下,在同一页的视图之间的差异可能不限于视图的模板。 换句话说,捡起一特定视图和布局模板可能还不够 — — 您甚至可能需要通过不同的视图的模型对象。

如果你正在传递视图模型通过 ViewBag 或交错的内置集合中的数据,您可以考虑移动处理的分析出该控制器的用户代理字符串的任何代码。 伴随这篇文章的示例移动网站代码下载,在主页上的索引方法看起来像这样:

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

正如您所看到的该视图生成无名称和布局的明确指示。 当发生这种情况时,查看发动机是最终负责最后确定要使用的视图和其布局。 查看发动机因此是不可能的地方要嵌入任何逻辑管理设备配置文件。 通过创建和注册自定义视图引擎,您隔离任何逻辑分析的设备配置文件在一个地点,和你的手机网站的其余部分可以发展为平原的相关页面的集合。 下面的代码演示如何在 global.asax 中注册的自定义视图引擎:

 

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

图 3 显示的自定义 (基于剃刀) 查看发动机的源代码。

图 3 移动注意查看发动机

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;
  }
}

之前渲染视图,查看发动机使用已安装的设备探查器查询有关的请求的用户代理配置文件。 基于这一点,查看发动机切换到最适当的视图。 如果布局的名称是显式地查看调用中从控制器中,查看发动机可以解决它无缝地提供。 如果在 _viewStart.cshtml (在大多数 ASP.NET MVC 代码) 中设置布局名称,则查看发动机不能解决这个问题,因为在 CreateView 中的主参数总是空。 这里是在 _viewStart.cshtml 中应用的修补程序:

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

如果您使用强类型的意见及各种移动视图相同的页 (智能手机和平板电脑等) 每个需要自己的视图模式吗? 在这种情况下,您可能想要建立一个工人组件分析用户代理,并返回该视图的布局的名称,并使用此组件从内每个控制器的方法。 当我看到的东西,如果你需要解析用户代理权控制器一级决定有关视图模型,然后依靠一个自定义视图引擎是冗余因为你已经知道哪个视图来调用。

除了这一点,它是所有有关使用适当的设备事件探查器和建设多个 HTML 页面模板。

在 ASP.NET MVC 中配置 WURFL

在这一系列的以前的专栏文章中提到,无线通用资源文件 (WURFL) 是流行设备描述存储库 (复员方案) 在谷歌和 Facebook 的移动网站的后端中使用。 WURFL 提供一个多平台的 API,可以方便地插入到任何使用 NuGet 的 ASP.NET MVC 项目 (请参阅图 4)。

Adding WURFL to ASP.NET MVC via NuGet
图 4 将 WURFL 添加到 ASP.NET MVC 通过 NuGet

WURFL 将 XML 数据库添加到您的项目,其中包含设备信息。 数据库应加载到内存时,应用程序的启动,并提供对设备配置文件几乎即时访问。 Global.asax,在您添加中所示的代码图 5

使用 WURFL 的图 5

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);
  }
}

图 6,你看到 IDeviceProfiler 组件,它使用 WURFL 来检测的智能手机和平板电脑。 您来解决,探查器通过一个自定义依赖项冲突解决程序。 (请参阅附带的源代码冲突解决程序有关的详细信息)。

图 6 基于 WURFL 的事件探查器设备

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();
  }
}

GetDeviceForRequest 方法查询 WURFL 数据库,并返回一个 IDevice 对象,可以使用一种较流利的语法进行查询。 请注意 IsTouch、 IsTablet、 HasOs 等方法实际上建在本机的 WURFL API,您找到示例项目中的扩展方法。 作为一个例子,这是 IsTablet 的代码:

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

我讨论过此列中的 ASP.NET MVC 的手机网站,建立在各种设备上提供不同的体验一个具体的例子:智能手机、 平板电脑和遗留下来的移动设备,如图所示,在图 7。 我建议您下载的源代码并在 Internet Explorer (或其他的浏览器),切换到不同的用户代理中运行它。 您还可以测试住在 www.expoware.org/amse/ddr 的网站。 请注意从桌面浏览器访问该网站,结果在消息中:"这个网站不是桌面浏览器上的可用的。 请尝试使用移动电话或平板电脑的浏览器。

Tablets, Smartphones and Plain Mobile Devices Accessing the Sample Site
图 7 平板电脑、 智能手机和平原移动设备访问示例站点

Dino 埃斯波西托是"构建移动解决方案的企业"(微软出版社,2012年) 的作者和"编程 ASP.NET MVC 3"(微软出版社,2011年),并散布"Microsoft.net:Architecting Applications for the Enterprise》(Microsoft Press,2008 年)的合著者。 Esposito 定居于意大利,经常在世界各地的业内活动中发表演讲。 有关他的情况,请访问 Twitter 上的 twitter.com/despos

衷心感谢以下技术专家对本文的审阅:埃里克 · 波特和 Pranav Rastogi