Partager via


Cet article a fait l'objet d'une traduction automatique.

ASP.NET MVC 3

Développement d'applications Web pour mobiles et hybrides natives

Shane Church

Téléchargez l'exemple de Code

Vous souhaitez créer une application mobile, mais vous êtes déconcertés par l'ensemble des dispositifs disponibles et API à apprendre.Quelle plateforme mobile choisir ?Les iOS de Apple (iPhone et iPad) utilise Objective C, Android de Google utilise Java et Windows Phone utilise Silverlight, mais chacune de ces options possède une API distincte et un marché distinct.Le choix de se concentrer sur une seule pile de technologie particulière puisse laisser 50 % du marché — ou plus — incapable d'utiliser votre application.Si vous choisissez d'essayer de soutenir toutes ces plateformes, vous avez au moins trois différents codes base pour maintenir, augmenter significativement vos coûts de développement et d'entretien.

Il y a une autre option : Vous pouvaient construire une application Web mobile, car il peut être vu sur aucun de ces appareils.Mais cette approche a également certains obstacles.Le plus grand obstacle pour le développement d'une application d'entreprise à l'aide de HTML et JavaScript est le manque d'accès à de nombreuses fonctionnalités de matériel périphérique natif comme l'appareil photo, GPS ou accéléromètre.

Clairement le marché mobile va seulement à se développer, Comment supportez-vous toutes ces options de périphérique tout en offrant la meilleure expérience utilisateur possible ?Dans cet article, je vais vous montrer comment créer une application mobile qui profite du meilleur des deux mondes en enroulant une application Web mobile avec une coquille d'une application native.

Le Concept d'Application hybride

Le concept de base d'une application hybride est d'encapsuler une application Web mobile optimisé dans une coquille d'application native spécifique au périphérique.La coquille de l'application native héberge un contrôle de navigateur Web est configuré pour lancer l'URL d'une application mobile spécifique lors de l'application shell lance.Autres éléments d'interface utilisateur peuvent être fournis dans la coquille de l'application native au besoin, mais seulement le contrôle de navigateur Web est requis.Le contrôle de navigateur Web natif écoute ensuite l'URL demandés, l'utilisateur accède au site.Lorsque l'utilisateur demande une adresse URL spécifique qui nécessite une fonctionnalité native, le contrôle de navigateur Web interrompt l'événement de navigation et appelle plutôt la fonctionnalité native.Comme l'utilisateur termine le processus natif, l'application navigue le contrôle de navigateur Web dans le flux du site Web dans l'emplacement approprié.

Pour illustrer comment c'est fait, je vais marcher à travers mon expérience de création d'une application avec mes collègues d'EffectiveUI pour un client.Construit pour un travailleur de terrain mobile qui traite un certain nombre d'ordres de travail entretien des biens municipaux tels que les signes, les bancs et les bouches d'incendie, l'application tire parti des fonctionnalités de prise en charge de navigateur pour obtenir l'emplacement actuel de l'utilisateur et l'accès matériel natif pour prendre des photos de biens et de les télécharger vers le serveur.La figure 1 affiche le menu principal de la demande dûment remplie.

The Completed Application Main MenuFigure 1 Menu principal demande dûment rempli

Création de l'Application Web

Lors de la création de cette application mobile, j'ai suivi un certain nombre de suggestions de l'article de Steve Sanderson, « Construire un meilleur Mobile Browsing Experience » (msdn.microsoft.com/magazine/hh288079) dans le numéro de juillet 2011 de MSDN Magazine.En plus de recommandations de cet article, j'ai appris quelques choses le long de la route :

  • Optimiser les éléments d'interface utilisateur pour toucher plus d'utilisateurs mobiles sont à l'aide d'interaction tactile-basé.L'interaction tactile est intrinsèquement moins précise que l'interaction axée sur la souris sur le Bureau.Tous les éléments interactifs tels que les boutons et les menus doivent être proportionnellement plus grande qu'ils sont dans l'expérience du bureau dans l'interface mobile.
  • Optimiser votre Mobile vues de bande passante plus les appareils mobiles sont des ressources limitées, surtout lorsque l'examen de la bande passante.Ne pas forcer votre utilisateur de télécharger un certain nombre de grandes images afin de pouvoir pour utiliser votre site.Sur les périphériques mobiles, les utilisateurs attendent interfaces sensibles et ils abandonneront rapidement de votre site ou votre application si elle n'est pas effectuer à leurs attentes.
  • Utiliser HTML5 et CSS3 parce que les navigateurs Web mobiles n'ont pas le long héritage des navigateurs de bureau, ils sont beaucoup plus rapides à adopter les nouvelles normes HTML5 et CSS3 que leurs homologues de bureau.Dans de nombreux cas, les navigateurs mobiles sont loin devant des navigateurs de bureau dans l'application de ces caractéristiques.Profitez de cela dans vos vues mobiles afin d'alléger la charge utile que le navigateur mobile à télécharger et à laisser le navigateur faire plus du rendu stylistique.

L'une des exigences techniques de mes clients lors de la création de cette application était de démontrer la logique de contrôleur partage entre le Bureau et mobiles vues du site.Cette exigence est commune à de nombreux clients et devrait être favorisée par les développeurs, ainsi, car il simplifie grandement le processus de création d'une application qui prend en charge les utilisateurs mobiles et de bureau.ASP.NET MVC 3 offre la possibilité de passer des vues basées sur les éléments de la demande, tels que le navigateur demandeur, tout en partageant toujours des contrôleurs et des modèles entre plusieurs vues.Il permet également au développeur de contrôler finement l'expérience sur le site pour chacune des plates-formes différentes, ce qui signifie le développeur doit seulement créer la logique métier une fois et puis adaptez la présentation pour chaque plate-forme.La figure 2 montre une fonction utilitaire pour décider qui en vue de présenter.

La figure 2 utilitaire pour décider qui voir à présent

private ActionResult SelectView(string viewName, object model,
  string outputType = "html")
{
  if (outputType.ToLower() == "json")
  {
    return Json(model, JsonRequestBehavior.AllowGet);
  }
  else
  {
    #if MOBILE
      return View(viewName + "Mobile", model);
    #else
      if (Request.Browser.IsMobileDevice)
      {
        return View(viewName + "Mobile", model);
      }
      else
      {
        return View(viewName, model);
      }
    #endif
  }
}

La fonction d'utilité m'a permis de satisfaire à l'exigence de partager le même code pour la prise de décision sur les avis de présenter à l'utilisateur en fonction de la demande entrante. Si la demande entrante est un script qui demande JSON au lieu de HTML, le contrôleur peut aussi répondre correctement en utilisant les mêmes catégories de logique et de modèle d'affaires en définissant simplement le paramètre outputType correctement. J'utilise également une déclaration précompilateur, cherchez le symbole de compilation conditionnelle MOBILE pour activer le débogage des vues mobiles à l'aide de mes navigateurs de bureau. Cela a été activé à l'aide d'une construction supplémentaire cible, « Mobile », dans l'ASP.NET MVC 3 projet et il m'a permis d'ignorer la vérification de Request.Browser.IsMobileDevice dans la configuration de débogage Bureau, grandement améliorer mon efficacité dans la construction et la version mobile de l'application de débogage.

Lors de la création de l'application, j'ai utilisé des pages maîtres distinctes pour les versions mobiles et de bureau du site. Les versions desktop et mobiles de la page maître sont significativement différentes pour traiter les disparités de présentation entre les plates-formes. La page maître mobile inclut des fichiers CSS mon mobile-spécifiques et une structure de mise en page simplifiée afin de faciliter le développement de vues individuelles à l'aide du balisage de jQuery cadre Mobile et la syntaxe.

Toutes les plateformes mobiles modernes permettent des accès à GPS radio d'un dispositif pour déterminer l'emplacement actuel de l'utilisateur grâce à la géolocalisation HTML5 World Wide Web Consortium (W3C) API. L'utilisation de l'API de géolocalisation a été examinée en détail dans l'article de Brandon Satrom, « Intégrer la géolocalisation en Applications Web » (msdn.microsoft.com/magazine/hh580735) dans le numéro de décembre 2011. Bien que cet article traite à l'aide d'un polyfill HTML5 JavaScript à l'appui de localisation sur les navigateurs qui ne supportent pas nativement la géolocalisation HTML5 API, plus récents navigateurs mobiles soutiennent la géolocalisation HTML5 API nativement, ce n'est la technique de polyfill probablement pas nécessaire. Vous devez considérer les dispositifs et les navigateurs qui vous êtes cible alors que vous êtes évaluer la nécessité de l'utilisation de la technique de polyfill. Une chose à noter spécifiquement pour Android est que vous devrez vous assurer que le paramètre enableHighAccuracy dans l'appel de la géolocalisation est définie sur « true » dans l'ordre avec succès l'accès et la fonctionnalité GPS dans l'émulateur Android, comme le montre Figure 3.

La figure 3 géolocalisation utilisant HTML5

if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
$("#map_canvas").GoogleMap("addMarker", {
id: "device_location",
latitude: position.coords.latitude,
longitude: position.coords.longitude,
description: "Current Location",
iconImageUrl: '@Url.Content("~/Content/images/my-location-dot.png")',
callback: function () {
$("#map_canvas").GoogleMap("panToLocation", {
latitude: position.coords.latitude,
longitude: position.coords.longitude
});
}
});
}, function (error) {
}, {
enableHighAccuracy: true
});
}

À l'aide de jQuery Mobile

Le jQuery cadre Mobile est « un système d'interface utilisateur HTML5 unifiée pour toutes les plates-formes de périphérique mobile populaire, » selon le site Web du projet (jquerymobile.com). Il contient un certain nombre de widgets tactile optimisé et facilite grandement la tâche de construire des applications Web mobiles cette apparence comme des applications mobiles natives. jQuery Mobile peut être ajouté à votre ASP.NET MVC 3 projet via NuGet à l'aide de l'interface du gestionnaire de Package NuGet ou de la Console du gestionnaire de Package en exécutant la commande « jquery.mobile Install-Package. » Les fichiers de Mobile JavaScript et CSS jQuery ajoute à votre projet. Vous aurez toujours besoin ajouter des références aux fichiers jQuery Mobile JavaScript et CSS à votre page maître mobile, comme le montre Figure 4.

Figure 4 la Page Mobile Master

<!DOCTYPE html>
<html>
<head>
  <title>@ViewBag.Title</title>
  <meta name="viewport" content="width=device-width,
    initial-scale=1.0, user-scalable=no, height=device-height" />
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <link href="@Url.Content("~/Content/eui_assets/css/reset.css")"
    rel="stylesheet" type="text/css" />
  <link href="@Url.Content("~/Content/jquery.mobile-1.0.min.css")"
    rel="stylesheet" type="text/css" />
  <link href="@Url.Content("~/Content/mobile.css")"
    rel="stylesheet" type="text/css" />
  <script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")"
    type="text/javascript"></script>
  @RenderSection("PreJQueryMobileInit", false)
  <script src="@Url.Content("~/Scripts/jquery.mobile-1.0.min.js")" 
    type="text/javascript"></script>
  <script type="text/javascript">
    $('a[data-ajax="false"]').live('click', function (event) {
      if (!$(this).hasClass("camera-link")) {
        $.mobile.showPageLoadingMsg();
      }
    });
  </script>
  @RenderSection("Head", false)
</head>
<body class="eui_body" id="@ViewBag.BodyID">
  @RenderBody()
</body>
</html>

jQuery Mobile rend certaines modifications importantes pour les patrons qui tout jQuery développeur est familière. Pour citer le jQuery documentation Mobile :

La première chose que vous apprenez dans jQuery est d'appeler du code à l'intérieur de la fonction $(document).ready() pour tout ce qui s'exécutera dès que le DOM est chargé. Cependant, dans jQuery Mobile, [AJAX] est utilisée pour charger le contenu de chaque page dans le DOM, vous naviguez, et le gestionnaire d'événements DOM prêt s'exécute uniquement pour la première page. Pour exécuter le code chaque fois qu'une nouvelle page est chargée et créée, vous pouvez lier l'événement pageinit.

J'ai utilisé l'événement pageinit, à l'intérieur de toutes les pages dans l'application qui contenait le contrôle de Google Maps afin d'initialiser la carte lorsque la page est passée dans l'affichage via AJAX.

Une caractéristique supplémentaire de la page maître mobile est la ligne de @ RenderSection("PreJQueryMobileInit", false), en Figure 4, qui vous permet d'exécuter des scripts avant jQuery Mobile est initialisée sur la page. Dans l'exemple d'application, j'ai utilisé cette fonctionnalité pour lier à l'événement mobileinit, donc je pourrais mettre en place un rappel personnalisé lorsque le comportement de filtre listview Mobile de jQuery est terminée. J'ai également ajouté deux lignes de code de la bibliothèque Mobile jQuery pour ajouter une méthode de filterCompleteCallback pour le prototype de listview afin d'obtenir une notification lorsque le filtrage de la liste intégrée a été complète. Cela m'a permis d'actualiser les éléments correspondants sur la carte pour correspondre à la liste filtrée. La fonction de rappel nécessaire pour être ajoutés à listview jQuery Mobile avant jQuery Mobile a été appliquée à tout le balisage ; que le code est exécuté dans le gestionnaire d'événements mobileinit dans Figure 5.

La figure 5, liaison à la mobileinit événement

if(navigator.geolocation) {   
  navigator.geolocation.getCurrentPosition(function (position) {
    $("#map_canvas").GoogleMap("addMarker", {
      id: "device_location",
      latitude: position.coords.latitude,
      longitude: position.coords.longitude,
      description: "Current Location",
      iconImageUrl: '@Url.Content("~/Content/images/my-location-dot.png")',
      callback: function () {
        $("#map_canvas").GoogleMap("panToLocation", {
          latitude: position.coords.latitude,
          longitude: position.coords.longitude
        });
      }
    });
  }, function (error) {
  }, {
    enableHighAccuracy: true
  });
}
@section PreJQueryMobileInit {
  <script type="text/javascript">
    $(document).bind("mobileinit", function () {
      $.mobile.listview.prototype.options.filterCompleteCallback = function () {
        // Note that filtercompletecallback is a custom
        // addition to jQuery Mobile and would need to be updated
        // in future revisions.
// See comments in jquery.mobile-1.0.js with SSC 09/12/2011
        var ids = [];
        var $visibleItems = $("#js-work-orders-list").find(
          "li:not(.ui-screen-hidden");
        for (var i = 0; i < $visibleItems.length; i++) {
          var item = $($visibleItems[i]).find("p");
          ids.push(item.text().substr(item.text().indexOf('#') + 1));
        }
        ids.push("device_location");
        $("#map_canvas").GoogleMap("hideAllMarkersExceptList", ids);
      }
    });
  </script>
}

jQuery Mobile prend l'avantage important de nouvelles fonctionnalités dans HTML5 comme les balises d'en-tête et de pied de page et les données-* attributs. Les attributs de données-rôle déterminent le comportement qui doit être attaché à un élément donné. Par exemple, de l'avis de MapMobile.cshtml en Figure 6, j'ai deux divs définis avec le rôle de données = l'attribut "page".

Balisage de la figure 6 MapMobile.cshtml

<div data-role="page" id="map_page" data-fullscreen="true"
  data-url="map_page" data-theme="a">
  <header data-role="header" data-position="fixed">
    <a href="@Url.Action("Index", "Home")" data-icon="home"
      data-direction="reverse">Home</a>
    <h1>Map Demo</h1>
    <a href="#" data-icon="back" id="js-exit-street-view"
      class="ui-btn-hidden">Exit Street View</a>
  </header>
  <div data-role="content" class="main-content">
    <div id="map_canvas" style="width:100%;height:100%"></div>
  </div>
  <footer data-role="footer" data-position="fixed"
    data-id="fixed-nav" data-theme="a">
    <nav data-role="navbar">
      <ul>
        <li><a href="#map_page" class="ui-btn-active
          ui-state-persist">Map</a></li>
        <li><a href="#items_page">Work Orders</a></li>
      </ul>
    </nav>
  </footer>
</div>
<div data-role="page" id="items_page" data-url="items_page" data-theme="a">
  <header data-role="header" data-position="fixed">
    <a href="@Url.Action("Index", "Home")" data-icon="home"
      data-direction="reverse">Home</a>
    <h1>Map Demo</h1>
  </header>
  <div data-role="content" class="main-content">
    <div class="list-container">
      <ul data-role="listview" id="js-work-orders-list" data-filter="true">
      @foreach (MapItem item in Model.Items)
  {
      <li class="work-order-id-@item.ID">
        <a href="@Url.Action("Details", "Home", new { id = item.ID })"
          data-ajax="false">
          <h3>@item.Issue</h3>
          <p>Work Order #@item.ID</p>
        </a>
      </li>
    }
      </ul>
    </div>
  </div>
  <footer data-role="footer" data-position="fixed"
    data-id="fixed-nav" data-theme="a">
    <nav data-role="navbar">
      <ul>
        <li><a href="#map_page" data-direction="reverse">Map</a></li>
        <li><a href="#items_page" class="ui-btn-active
          ui-state-persist">Work Orders</a></li>
      </ul>
    </nav>
  </footer>
</div>

Cet attribut indique à jQuery Mobile que chacune de ces balises div devrait être traitée comme une page distincte sur le périphérique mobile et à la transition entre eux en utilisant AJAX sans une navigation de page dans le navigateur. Cela produit l'effet démontré dans les captures d'écran dans Figure 7. Le site Web Mobile de jQuery fournit des recommandations et plus de détails sur la façon d'utiliser chacune des données-* attributs dans le contexte Mobile jQuery.

Transitioning Between Pages Via AJAX
La figure 7 transition entre Pages Via AJAX

Bâtiment les coquilles d'Application Mobile Native

Le patron de base à l'élaboration de chacune des coquilles application native est la conception d'une application qui contienne simplement un contrôle de navigateur Web plein écran. Dans ce contrôle, je capture l'événement qui est déclenché lorsque l'utilisateur demande une nouvelle page et comparer l'URL demandée contre une liste d'URL connue qui doit appeler des fonctionnalités natives. C'est où se trouve la « magie » d'une application Web dans une coquille d'une application native. Aux fins de la présente demande, l'URL que je correspondait au sein du site est « Accueil/Image » pour appeler la fonctionnalité native de caméra. Lorsque l'utilisateur est sur la page de détails de commande, il allez voir une icône de la caméra dans le coin supérieur droit de l'écran, comme illustré dans la Figure 8. En cliquant sur cette icône invoque la caméra native.

Invoking Native Camera Functionality
La figure 8, invoquant les fonctionnalités natives de caméra

Windows Phone

Windows Phone utilise Silverlight pour toutes les fonctionnalités natives. À certains égards, cela fait Windows Phone la plate-forme plus facile pour les développeurs de Web mobile qui est familier avec l'ASP.NET. La disposition de base XAML pour la couche d'application native est simple, comme illustré ici :

<Canvas x:Name="LayoutRoot" Background="Black" Margin="0">
  <phone:WebBrowser HorizontalAlignment="Left" Name="webBrowser1" 
    Navigating="webBrowser1_Navigating" IsScriptEnabled="True"
    IsGeolocationEnabled="True"
    Background="Black" Height="720" Width="480" />
</Canvas>

Les éléments clés à noter ici est que IsScriptEnabled est défini sur true, parce que, par défaut, le contrôle de navigateur Web en Windows Phone n'est pas activer le script — et que je suis traiter l'événement Navigating.

Dans la MainPage.xaml.cs, 9 Figure, manipuler l'événement webBrowser1_Navigating. Si l'URL de navigation correspond à l'URL que je cherche, je réponds à l'ID de l'ordre de travail que je travaille avec et invoquer la CameraCaptureTask autochtone tout en annulant la navigation du navigateur Web. Après que l'utilisateur prend la photo avec la caméra, le photoCaptureOr­méthode SelectionCompleted est appelée. Ici, télécharger l'image sur le serveur Web en utilisant le même formulaire HTTP action POST que le site allait utiliser si j'ai soumis un formulaire qui contenait un bouton d'entrée de fichier de téléchargement. Lorsque le téléchargement de photos se termine, upload_FormUploadCompleted est appelé, retourner le flux de demande Web de l'utilisateur.

La figure 9 Windows Phone MainPage.xaml.cs

public partial class MainPage : PhoneApplicationPage
{
  CameraCaptureTask cameraCaptureTask;
  BitmapImage bmp;
  string id = "";
  string baseURL = "http://...";
  // Constructor
  public MainPage()
  {
    InitializeComponent();
    cameraCaptureTask = new CameraCaptureTask();
    cameraCaptureTask.Completed +=
      new EventHandler<PhotoResult>(photoCaptureOrSelectionCompleted);
  }
  private void webBrowser1_Navigating(object sender, NavigatingEventArgs e)
  {
    // Catch Navigation and launch local camera
    if (e.Uri.AbsoluteUri.ToLower().Contains("home/image"))
    {
      id = e.Uri.AbsoluteUri.Substring(e.Uri.AbsoluteUri.LastIndexOf("/") + 1);
      cameraCaptureTask.Show();
      e.Cancel = true;
    }
  }
  void photoCaptureOrSelectionCompleted(object sender, PhotoResult e)
  {
    if (e.TaskResult == TaskResult.OK)
    {
      byte[] data = new byte[e.ChosenPhoto.Length];
      e.ChosenPhoto.Read(data, 0, data.Length);
      e.ChosenPhoto.Close();
      Guid fileId = Guid.NewGuid();
      Dictionary<string, object> postParameters = new Dictionary<string, object>();
      postParameters.Add("photo", new FormUpload.FileParameter(
        data, fileId.ToString() +
        ".jpg", "image/jpeg"));
      FormUpload upload =
        new FormUpload(baseURL + "Home/UploadPicture/" + id, postParameters);
      upload.FormUploadCompleted +=
        new FormUpload.FormUploadCompletedHandler(upload_FormUploadCompleted);
      upload.BeginMultipartFormDataPost();
    }
  }
  void upload_FormUploadCompleted(object source)
  {
    webBrowser1.Navigate(webBrowser1.Source);
  }
  private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
  {
    webBrowser1.Navigate(new Uri(baseURL));
  }
}

Windows Phone a certains comportements différents lorsqu'il interagit avec la version Web de Google Maps ou Bing Maps contrôles par rapport à Android ou iOS. Raison de la façon dont l'Internet Explorer 9 navigateur mobile capte touch, magnétiques et pincée de gestes sans passer par le moteur JavaScript, les cartes sur le Web ne peut pas zoom pan avec gestes et doit utiliser le zoom ou pan des contrôles prévus par la carte. Compte tenu de cette limitation, une amélioration future de ce projet serait d'invoquer le contrôle natif de Bing Maps sur Windows Phone où la fonctionnalité de la carte interactive est requise et revenir ensuite à l'application Web sur les écrans qui n'a pas besoin de la fonctionnalité de la carte interactive.

Android

Le code Java pour Android a été écrit par mon collègue, Sean Christmann et est similaire au code pour Windows Phone. La disposition suivante XML définit un schéma plein écran pour le contrôle en mode Web Android :

<?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"
    >
    <WebView android:id="@+id/webView"
      android:layout_width="match_parent" 
      android:layout_height="match_parent"></WebView>
</LinearLayout>

Au sein de l'EffectiveUIActivity.java, montre Figure 10, le remplacement pour onCreate met en place le WebViewClient pour remplacer l'onLoadResource et shouldOverrideUrlLoading méthodes du contrôle mode d'affichage Web à la recherche de la même chaîne correspondante dans Windows Phone et, si trouvé, crée l'activité de la caméra et annule la navigation. Le code substitue également onGeolocationPermissionsShowPrompt pour supprimer l'invite pour l'utilisateur qui se produirait à chaque exécution de l'application afin de permettre l'autorisation pour le contrôle de mode Web pour accéder à l'emplacement du GPS. Après l'exécution de l'activité de la caméra, la fonction onActivityResult affiche l'image sur le serveur Web en utilisant la même méthode que l'exemple précédent de la Windows Phone et ensuite renvoie l'utilisateur à l'écoulement d'application Web.

La figure 10 Android EffectiveUIActivity.java

    public class EffectiveUIActivity extends Activity {
      /** Called when the activity is first created.
    */
      WebView webView;
      String cameraId;
      static String baseURL = "http://...";
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        webView = (WebView)findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setGeolocationEnabled(true);
        webView.setVerticalScrollbarOverlay(true);
        webView.loadUrl(baseURL);
        final EffectiveUIActivity activity = this;
        webView.setWebViewClient(new WebViewClient(){
          @Override
          public void onLoadResource(WebView view, String url) {
            super.onLoadResource(view, url);
            if(url.contains("Home/Image")){
              activity.createCamera();
            }
          }
          @Override
          public boolean shouldOverrideUrlLoading(WebView view, String url){
            String match = "Home/Image/";
            int i = url.indexOf(match);
            if(i>0){
              cameraId = url.substring(i+match.length());
              activity.createCamera();
              return true;
            }
            return false;
          }
        });
        webView.setWebChromeClient(new WebChromeClient(){
          @Override
          public void onGeolocationPermissionsShowPrompt(
            String origin, GeolocationPermissions.Callback callback) {
            super.onGeolocationPermissionsShowPrompt(origin, callback);
            callback.invoke(origin, true, false);
          }
        });       
      }
      public void createCamera(){
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        startActivityForResult(intent, 2000);
      }
      @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
          if (resultCode == Activity.RESULT_OK && requestCode == 2000) {
            Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            thumbnail.compress(CompressFormat.JPEG, 75, bos);
            byte[] imagebytes = bos.toByteArray();
            ByteArrayBody bab = new ByteArrayBody(imagebytes, "image/jpeg",
              UUID.
    nameUUIDFromBytes(imagebytes).toString()+".jpg");
            HttpClient client = new DefaultHttpClient();
            HttpPost post = new HttpPost(baseURL+"Home/UploadPicture");
            MultipartEntity reqEntity =
              new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
            reqEntity.addPart("photo", bab);
            try {
              reqEntity.addPart("ID", new StringBody(cameraId, "text/plain",
                Charset.forName( "UTF-8" )));
            } catch (UnsupportedEncodingException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
              }
              post.setEntity(reqEntity);
              try {
                HttpResponse response = client.execute(post);
                BufferedReader reader = new BufferedReader(
                  new InputStreamReader(
                  response.getEntity().getContent(), "UTF-8"));
                String sResponse;
                StringBuilder s = new StringBuilder();
                while ((sResponse = reader.readLine()) != null) {
                  s = s.append(sResponse);
                }
              } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
              } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                }
                webView.loadUrl(webView.getUrl());
              }
            }
    }

iOS

Le code Objective-C pour iOS a aussi été écrite par mon collègue, Sean Christmann, et est également similaire à celle utilisée pour Windows Phone et Android. Au sein de WebCameraViewController.m en Figure 11, le UIWebView contrôle exécute la méthode shouldStartLoadWithRequest pour faire le modèle correspondant à l'URL demandée. Si correspond à la chaîne d'URL, le code renvoie à « Non » pour annuler la navigation et appelle la UIImagePickerController native. Cela permet à l'utilisateur de choisir une image de la bibliothèque de photo ou de prendre une nouvelle image avec la caméra embarquée. Après la sélection de l'image, le code affiche ensuite l'image sur le serveur Web à l'aide de la bibliothèque ASIFormDataRequest (allseeing-i.com/ASIHTTPRequest) avant de retourner la UIWebView vers le flux de l'application normale.

La figure 11 iOS Code

- (void) choosefromCamera {
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil];
    if ([UIImagePickerController
      isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
      picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    }else{
      picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    }
    [self presentModalViewController:picker animated:YES];
}
- (void)imagePickerController:(UIImagePickerController *)picker   
    didFinishPickingMediaWithInfo:(NSDictionary *)info {
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    NSData *jpg = UIImageJPEGRepresentation(image, 0.3);
    [picker dismissModalViewControllerAnimated:YES];
    [picker release];
    NSString *url =
      [NSString stringWithFormat:@"%@:7511/WorkOrders/UploadPicture", baseURL];
    ASIFormDataRequest *request =
      [ASIFormDataRequest requestWithURL:[NSURL URLWithString:url]];
    [request addData:jpg withFileName:[
      NSString stringWithFormat:@"%@.jpg", [self GetUUID]]
      andContentType:@"image/jpeg" forKey:@"photo"];
    [request addPostValue:cameraId forKey:@"ID"];
    [request setDelegate:self];
    [request setDidFinishSelector:@selector(imageUploaded:)];
    [request setDidFailSelector:@selector(imageUploaded:)];
    [request startSynchronous];
    [webView reload];
}
-(void) imageUploaded:(ASIFormDataRequest *)request {
    NSString *response = [request responseString];
    NSLog(@"%@",response);
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(
  NSURLRequest *)request
    navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = [request URL];
    NSString *str = [url absoluteString];
    NSRange range = [str rangeOfString:@"WorkOrders/Image/"];
    if (range.location != NSNotFound) {
      cameraId = [str substringFromIndex:range.location+17];
      [cameraId retain];
      NSLog(@"%@", cameraId);
      [self choosefromCamera];       return NO;
    }else{
      return YES;
    }
}

Dégradation gracieuse de l'expérience Mobile

Que se passe-t-il si l'utilisateur du site Web mobile n'est pas à l'aide de la couche application native pour accéder à la caméra ? Dans ce scénario, il est important d'avoir une dégradation gracieuse de l'expérience utilisateur. Dégradation élégante est le concept de construction de votre application afin qu'elle continue de fonctionner correctement, même si elle est considérée avec les logiciels moins optimal. Cela ne signifie pas que chaque fonctionnalité fonctionne dans exactement de la même façon ou qu'il semble même similaire à l'expérience prévue, mais elle vise à s'assurer que tous les objectifs fondamentaux de l'utilisateur peuvent encore être accomplis même si l'utilisateur n'est pas la meilleure expérience.

Pour activer la dégradation gracieuse dans cette application, j'ai construit une page ASP.NET MVC 3 contrôleur et affichage de l'URL d'image capture, « Accueil/Image, » qui est capturée par les obus de l'application native pour fournir un simple fichier téléchargement formulaire comme le montre Figure 12. Ce formulaire permet aux utilisateurs qui ne sont pas à l'aide de la coquille mobile améliorée pour accomplir la même tâche d'ajouter une image à un ordre de travail, bien qu'ils ne reçoivent pas l'expérience intégrée. La forme des postes à la même action de contrôleur utilisée par les obus de l'application native, encourageant la réutilisation du code entre toutes les différentes plates-formes et les vues.

A Simple File Upload Form for Graceful Degradation
Figure 12 Simple fichier télécharger formulaire pour dégradation gracieuse

Avantages de coûts significatifs

L'approche d'application hybride peut fournir des avantages significatifs sur les applications natives uniques, tant à court et à long terme. Des outils tels que jQuery Mobile réduire les différences de facilité d'utilisation, qui peuvent conduire à des avantages commerciaux importants où l'accès natif de périphérique n'est pas obligatoire.

Avec les appareils mobiles multiplient comme les incendies de forêt, vous avez quelques choix lors de la recherche pour créer une application mobile :

  • Construire une Application Native pour chaque plate-forme vous souhaitez prendre en charge cela a l'avantage d'offrir la meilleure expérience utilisateur et performance pour chaque plate-forme, tout en permettant l'accès à toutes les fonctionnalités natives de l'appareil et la puissance marketing des magasins app. L'inconvénient, cependant, est qu'il pourrait être beaucoup plus cher à construire et entretenir parce qu'il faudra un distinct codebase pour chaque plate-forme que vous souhaitez soutenir. En outre, chaque nouvelle version de l'application nécessite que l'application réexaminées dans les magasins de l'app.
  • Construire un cette Application de Web Mobile a l'avantage de l'option plus simple et moins cher à développer, lancer et mettre à jour pour toutes les plates-formes, mais l'expérience utilisateur peut être compromise par le manque d'accès aux fonctions natives matérielles. Manque d'accès aux magasins app peut également compromettre l'adoption de votre application, tous de la commercialisation de votre demande pour vous pousser.
  • Construire un hybride originaire et Application Web Mobile le présent est l'approche que j'ai discuté, qui fournit un solid compromis entre les coûts élevés de développement d'une application native unique pour chaque plateforme et le manque d'accès matériel natif pour une application Web mobile. Cette option permet également d'accéder à l'app stores, augmentant la portée de votre application.

Il est important de noter qu'aucun de ces approches n'est intrinsèquement meilleure que les autres — ont tous leurs propres forces et faiblesses. Une analyse de rentabilité complète de chacune des options permettra de déterminer quel chemin est celui de droite pour vos utilisateurs et votre entreprise. Lors de la prise de cette décision, il est important de tenir compte de l'expérience utilisateur, les coûts initiaux de développement et les coûts d'entretien en cours ainsi que les plus subtils facteurs tels que l'adoption de marketing et d'utilisateur.

Pour de nombreux scénarios d'application commerciale, je préconise pour l'inclusion d'un Web mobile ou une application hybride, l'effort supplémentaire de construire des applications natives uniques pour chaque plate-forme mobile pouvait l'emporter sur les avantages de l'entreprise. Les scénarios d'entreprise doivent être soigneusement examinée dans le cadre d'un déploiement des applications Web ou hybride mobile.

Les applications mobiles sont ici pour rester et sont de plus en plus importantes dans le calcul des déplacements hors de l'expérience de bureau traditionnel à un éventail d'expériences mobiles. Que vous regardez pour construire des applications dans l'espace mobile, n'oubliez pas que compromis n'est toujours pas un mot et qu'elle peut se traduire dans le meilleur des deux mondes.

Shane Church est un responsable technique d'EffectiveUI à Denver, au Colorado Il a mis au point dans le Microsoft.NET Framework en mettant l'accent sur l'ASP.NET et Microsoft technologies mobiles depuis 2002. Son blog est situé à s-church.net. Vous pouvez en apprendre plus sur EffectiveUI à effectiveui.com.

Merci à l'expert technique suivant d'avoir relu cet article : **Dr.**James McCaffrey