使用 ASP.NET MVC 开发混合移动应用

阅读数:5527 2013 年 6 月 7 日

移动设备无处不在

十年前,微软专业开发者大会(PDC)上,主办方播放的一段视频,勾画了未来的移动领域蓝图。视频演示了一个颇具未来感的 Windows 手机设备,如何完成诸如定位最近诊所的任务。在那个Palm VII算是最接近智能手机的年代,这段视频所演示的未来确实令人向往。

时间飞驰到 2013 年:我们毫无偏差地来到了这个未来时代,智能手机和其它移动设备无处不在。各种价位任君选择,而且价格也越来越亲民。事实上,对于大多数发展中国家的人来说,他们唯一的电脑就是所拥有的智能手机。

移动应用开发:Gartner 所预测的增长

Gartner 预测i,到 2016 年,至少 50% 以上的企业 email 用户将会主要依赖于浏览器、平板电脑、或移动客户端,而不是桌面客户端。据移动设备的使用增长状况可预计,在今后的几年中,针对这些设备的软件应用开发也会飞速增长。Garnter 继续预测,到 2015 年,针对智能手机及平板电脑的移动应用开发项目与原生 PC 项目之比将达到 4:1。Garnter 还预测,在今后的 4 年中,智能飞机与平板电脑在新设备中所占比重将会超过 90%。

Apple 的应用商店现已有超过 50 万的应用,Android 也接近这个数字,而新贵 Windows Phone 近期也超过了 5 万,并且还在快速发展中。

移动应用行业:市场分化带来的挑战

在这个令人振奋的背景下,我们能够确信,不久的将来移动平台上将出现大量行业应用。与机遇相随的是,移动应用开发也将面临着它自身的一系列挑战。

主要的挑战之一是市场分化的问题。2012 第三季度的调查显示,移动操作系统市场的分化问题非常严重。在这个季度所售出的设备中,Android 的各种型号占了大约 72%,iOS 占了大约 14%,黑莓(RIM/Blackberry)占了 5%,而 Windows Phone 平台占了 2%。(基于Gartner统计)

要开发一个能运行于所有设备上的商业应用,需要应用到以下这些的不同技术:

Platform

Primary development platform

Primary development language

Primary IDE

Development platforms

Android

Java based

Java

Eclipse

Windows, Mac OSX, Linux

iOS

Cocoa Touch framework

Objective C

Xcode

Mac OSX

RIM

Java ME

Java

Eclipse

Windows, Mac OSX

Windows Phone 8

.NET/native

C#/C++

Visual Studio

Windows

这些平台、语言及开发工具之间有着本质上的区别,一个能够运行在所有平台上的解决方案,其开发所需的投入也是很高的。

值得一提的是,即使在同一平台之下,分化的程度也很严重,当前处于领先局面的 Android 平台尤为明显。由于 Android 是开放的,并且厂家可以任意改动,导致如今市面上基于 Android 的设备已有几百种。其中的大部分只能使用特定版本的 Android API。而即使应用在支持的 API 版本之内,仍然有一部分设备在使用这些应用时会遇到问题。因而结论是,处理移动市场上的市场分化问题没有捷径可言。这使得实现一个运行于多个平台的原生解决方案异常困难。

移动 web 应用:市场分化的解决方案?

Web 应用是原生应用的一种替代方案。所有主流的移动平台都提供了可用的浏览器。而且,除 Windows Phone 浏览器之外,其它多数平台浏览器都是基于开源的 WebKit 浏览器平台,正是它实现了桌面版本的 Apple Safari 与 Google Chrome。这些浏览器平台对 JavaScript 都有很好的支持,jQuery 也在多数主流移动设备上得到完善的支持。另外,各浏览器也在提高对 HTML 5 与相关的 web 标准的遵循,这使得浏览器成为一个更吸引人的开发平台。使用当前的技术创建功能丰富的网站,并同样在移动设备上良好运行是完全可能的。

移动 web 应用:其它观点

移动 web 网站无法与原生应用的用户体验媲美。特定硬件平台上的用户已经习惯于原生应用所提供的良好体验,这些应用已经原生地安装于设备中,只需通过启动界面就能立即使用。而且原生应用遵守该设备上的用户界面约定,比如在 Android 设备上,按侧边栏分类菜单键通常会显示一个上下文菜单,这是用户所期望的表现。Web 应用可以在多数设备的启动界面上安装一个快捷方式,但它们在所安装的设备上无法遵守特定的用户体验期望。Web 应用的另一个劣势是,除了 HTML 与相关的 web 标准所提供的输出显示之外,它们对硬件没有任何原生访问的能力。比方如对于设备上的联系人、图片或摄像头不能直接的访问。对于许多应用来说,直接访问设备硬件上的关键元素是很重要的。

混合应用:web 与原生应用的最佳结合

混合应用是指在完全的原生应用中嵌入一个特定平台的 web 浏览器控件。所有主流的移动平台,包括 Android、iOS、Windows Phone 8 与 Blackberry/RIM 都支持将这些平台上的 web 浏览器控件嵌入应用中。由于包装器是完全原生的,用户甚至不太会查觉到他们正在与一个 web 应用在交互,原生的应用就完全可能提供一个无缝的浏览体验。

浏览器中显示的 web 页面也可以通过某种 JavaScript 桥接方式与原生的硬件进行交互,在每种主流的平台上都有该方式的某种实现。通过这种对原生平台的回调,使得访问联系人,抓获与选择图片,以及播放媒体文件成为可能。实际上,任何通过原生代码可以完成的操作都可以通过这种桥接方式实现。当然,对每一种目标平台,桥接代码都必须重新编写,不过这部分代码通常只占用你的整个应用代码的一小部分。

另外,现今已经出现了几种 JavaScript 桥接框架了,最流行的一种是开源的PhoneGap平台,它提供了这种桥接的一个重要部分。不过我们在这篇文章不打算使用任何框架,而是通过一个简单的 Android 包装器来演示这个概念。

ASP.NET MVC:一个优雅的后端框架

混合应用可以使用任何 web 后端技术,不过我们相信由 ASP.NET MVC 实现混合应用是个理想的选择ii。下文阐述了 ASP.NET MVC 作为这些良好选择的原因。

清晰的职责分离

MVC 环境提供了清晰的职责分离,这使得对于 HTML 输入的精确控制成为可能,也使得生成适合于移动平台的 HTML 变得非常简单。而那些内建的、独立的驱动能对所生成的标记控制。

与桌面或平板 web 客户端共享大部分代码

如果你有一个现成的针对桌面浏览器的 ASP.NET MVC 应用,那么许多代码都可以在你的移动应用中重用。Controller 和 Model 的代码基本可以完全重用,只需要修改视觉的部分。在当前版本的 ASP.NET MVC 中为移动客户端指定一个定制的视觉就不是什么难事了,而下一个版本的 ASP.NET MVC 会使得这一切更简单。关于即将到来的 ASP.NET MVC 版本中,移动开发新特性的其它细节,请参考ASP.NET MVC文档。

通过以下 web 开发模型将市场分化问题降至最低

ASP.NET MVC 对于无状态的 web 应用并没有创建很多抽象层,而是提供了一个非常简单的模型,它能够与底层的平台相集成,使得在客户端发起 AJAX 调用或使用 jQuery 变得非常简单。不必担心处理像 ASP.NET Web Forms 中的 ViewState 那样复杂的抽象了。

除此之外,值得一提的是,现有的.NET 应用中的业务层和数据库层可以重用在 ASP.NET MVC 应用中。ASP.NET MVC 完全不受业务层和数据库层的影响,它能够高效地应用在任何现有系统中。

混合应用示例

我们现在来看一个非常简单的示例,以演示使用 ASP.NET MVC 平台开发一个端到端的混合应用开发过程。该示例将显示某个虚拟的大学 - Contoso 大学的学生信息,它包含一些常用信息的链接,以及能够根据姓名查找学生信息的目录。为了使这个示例更清晰,它没有包含安全或错误处理的部分。代码本身并不复杂,因为示例本身并不是为了展现 ASP.NET MVC 平台的强大功能,而是想表现它作为一个后端平台,非常适于开发混合的原生移动应用。

示例的完整代码可以在bit.ly/mvc-native-mobile-apps找到。

运行示例代码的条件:

  • ASP.NET MVC 3 及 Visual Studio 2010(包括 Expression 在内的任何版本)
  • Android SDK 的功能安装,及 Eclipse 的 Android 开发工具插件。
  • 详细的指示及需求可以在这里找到。
  • jQuery 及 jQuery Mobile,这里不需要创建本地的拷贝,因为示例代码会引用 jQuery CDN。

ASP.NET MVC 后端部分

在示例代码中,_Layout.cshtml 包含了对 jQuery 与 jQuery Mobile 库的脚本引用。它们对创建 ASP.NET MVC 移动应用并不是必需的,但它们解决了很大一部分工作。我们在示例中使用 jQuery Mobile 以简化对移动设备上内容的格式化操作。

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile
;-1.0.min.css" />
<link rel="stylesheet" type="text/css" href="@Url.Content(" site.css?)? Content ~ />

<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js">
</script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0/jquery.mobile
-1.0.min.js"></script>

多数的移动 web 客户端都假设 web 页面会缩放至 900 像素左右的大小,并且能够自适应大小以便在设备上显示整个页面。为了将移动网站的显示优化在某个更小的设备上,我们可以提示设备不要自动伸缩,而是使用该设备的宽度。这可以通过使用 viewpoint 这个 meta 标签来实现,如下所示:

<meta name="viewport" content="width=device-width, initial-scale=1.0 ">

在 Home controller 中默认的 Index 行为方法将映射到以下的 view 标签。

<nav>
     <ul id="menu" data-role="listview">
         <li>@Html.ActionLink("About Us", "AboutUs", "Home")</li>
         <li>@Html.ActionLink("Contact Us", "ContactUs", "Home")</li>
         <li>@Html.ActionLink("Student Directory", "StudentDirectory", "Home")</li>
     </ul>
</nav>

我们有一个简单的无序列表,包含三个行为链接。通过在 jQuery Mobile 运行时中使用“data-role=listview”这个属性设置,我们指定该列表将自动格式化为一个列表视图。这样就能够在移动设备上显示以下的初始 UI。

图 1,初始界面

jQuery Mobile 运行时会负责将它格式化为一个列表视图。如之前所说,jQuery Mobile 并非必需,你可以选择最适合你的格式化及脚本的应用方式。

该示例也包含了选择“关于我们”及“联系我们”等选项时所显示的视图,这几个界面非常直白,无需进一步的说明。

打开学生目录链接将显示一个按首字母分组的学生名称页面,并显示每个字母下的学生数目。

图 2,学生目录初始界面

点击任一选项将显示学生列表,如下所示。

图 3,学生目录

学生目录的 view 也非常简单,仅仅是将列表中的数据迭代显示。显示学生详细信息的 view 如下所示。

@{
    ViewBag.Title = "Student Directory";
     Layout = "~/Views/Shared/_Layout.cshtml";
     var random = new Random();
}

<ul data-role="listview">
@foreach (string student in ViewBag.Students)
{ 
     <li>

         @{var number = random.Next(1000, 9999); }

         <img src="@Url.Content("~/Content/images/UserImages/80-80/" + student + 
".jpg")" alt="@student"/>
         <h3>@student</h3>
         <h4>919-555-@number</h4>
     </li>
}
</ul>

在使用 Android 包装器进行查看之前,可以先在桌面游览器中运行 ASP.NET MVC 后端并进行完整的测试,这也不失为一个好主意。稍后我们再进行 Android 包装器的开发。

如果你的测试设备能够访问待测试的网站,那么你也可以直接在它的移动游览器上进行测试。如果你的开发 PC 与设备测试处于同一个网络中,也可以通过修改 ASP.NET 开发浏览器或 IIS Express 的配置,以允许你的测试设备访问该 web 应用。而在默认情况下这种访问是被禁止的。

一种较简单的替代方案是使用代理,它能够将对外部端口的访问重定向到内部的服务器,我们就经常使用这种方式。我们所使用的代理可以从GitHubiii下载。

Android 包装器

Android 包装器将在一个原生的 Android 应用中托管这个 web 应用,其代码所下所示。

package com.syncfusion.contoso;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class ContosoActivity extends Activity {

    WebView mWebView;

    private class ContosoWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }
     

    /** Called when the activity is first created. */          
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView) this.findViewById(R.id.webview);

        // Disable scrollbars 
        mWebView.setVerticalScrollBarEnabled(false);
        mWebView.setHorizontalScrollBarEnabled(false);

        // Scrollbar Overlay Content
        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);

        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setAppCacheEnabled(false);
        mWebView.loadUrl("http://your-web-link");
        mWebView.setWebViewClient(new ContosoWebViewClient() );
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

这段代码也很容易理解。

  • WebView 在 Android 上等同于 WebBrowser 控件,它是默认基于 WebKit 的 Android 浏览器的包装类。
  • 我们获取了对某个 Android WebView 控件的实例(它定义在某个 XML layout 文件中,并由 Android 运行时进行创建)的访问。
  • 我们为这个 WebView 实例开启了 JavaScript 功能,因为在 WebView 控件中,JavaScript 默认是关闭的。接下来我们对拖动框的显示做了一些调整,其实就是把它关闭,以模拟原生应用的外观。
  • 再接下来,我们调用了 WebView 实例的 loadUrl API,以加载实际的 web 应用。你应该修改 web 链接,以指向你的 web 应用。
  • 最后一部分代码处理了对硬件的回退按钮的调用,以使得嵌入的 WebView 回退到之前的页面。

如你所见,这段代码对 web 应用并没有直接的依赖关系,也不需要在不同的应用之间进行大量的修改。当你需要访问设备上的特定硬件功能时,你只需要添加一些额外的代码。在这里我们对这个主题不会做深入研究,如果你有兴趣进行更深入的钻研,请查看 WebView 中的addJavascriptInterface方法的相关内容。

出于简便,我们只介绍了 Android 包装器的内容,类似的包装器与扩展机制也存在于所有其它主流移动平台上。

图 4,在原生应用 shell中使用 Android 4.0模拟器显示的“联系我们”页面

结论

对于任何移动行业应用来说,混合应用都是一种值得考虑的有前景的解决方案。对于需要对原生硬件进行大量访问(例如在游戏中)的场景来说它并不适合,但对于其它多数场景它都有良好的表现。由 web 后端实现的解决方案很有可能不会过时。这些年来 HTML 的标准在缓慢地演化中,它也不太可能像专利解决方案那样倾向于做出重大的改变。这就为应用的创建提供了一个稳定的基础,也确保这些应用在可预见的将来能够继续工作。Mobile 平台的供应商为 HTML 5 与相关标准的实现投入了巨大的精力,它们将使 web 应用更加强大,并能够完成很大一部分在原生应用中可以实现的工作。

你可以充分利用你现有的.NET web 开发技术,并在更多的设备上创建强大的解决方案。在 Syncfusion,我们为混合应用所提供的无限潜力感到激动不已。

关于作者

Daniel Jebaraj 作为副总裁,主导 Syncfusion 产品的开发。总体掌控产品开发并制订发布计划。通过积极地与客户沟通,Daniel 确保每个新产品都能基于客户反馈进行改进。早前,作为开发团队的副总裁,她专注于驱动 Syncfusion 的产品开发。在 2001 年加入 Syncfusion 之前,Daniel 管理 Rogue Wave Software 的开发团队。获得克莱蒙森大学(Clemson University)的工学硕士学位。

iGartner Reveals Top Predictions for IT Organizations and Users for 2012 and Beyond

ii Ignore ASP.NET MVC at Your Own Peril: Lessons Learned from the Trenches.

iii 更多细节请参考James 的代码

查看英文原文:Hybrid Mobile Apps with ASP.NET MVC


感谢李琼对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。

收藏

评论

微博

发表评论

注册/登录 InfoQ 发表评论