SharePoint Online, Apache Cordova et WinJS : Créer des Apps Mobiles d’entreprise multi-devices

 

1. Introduction

 

Si vous êtes intéressé par le développement d’Apps pour mobiles, vous devez sans-doute connaître Apache Cordova. Apache Cordova permet de créer simplement des applications pouvant être déployées, avec un même code, sur des appareils mobiles différents : iOS (iPhone et iPad sous iOS 6, 7 ou 8), Androïd (2.3.3 ou +), Windows Phone 8 ou pour Apps universelles Windows 8.1 (Windows Phone ou Windows 8.1). On appelle couramment ce type d’Apps des « Apps hybrides ». Cordova est aujourd’hui très populaire et est utilisée par de très nombreuses applications grand public.

Cordova offre quelques avantages notables pour la création d’Apps Mobiles, comme :

  • L’utilisation d’un seul et même code pour tous les types de périphériques
  • L’utilisation de technologies web (HTML 5, CSS, JavaScript), rapide à développer et bien connues
  • Ne nécessite pas une connaissance pointue des spécificités de développement de chaque plateforme

Aujourd’hui on peut tirer parti pleinement des capacités de Cordova dans le monde entreprise, et en particulier avec les plateformes Microsoft dans le cloud et Office 365.

Il est par exemple très simple de développer des applications capables de se connecter de façon sécurisée à Office 365 (et donc également à SharePoint Online). On peut proposer aux utilisateurs une vraie immersion du monde professionnel au sein de leur téléphone professionnel ou personnel.

Dans cet article, nous allons regarder comment réaliser une application mobile capable de se connecter à SharePoint Online pour remonter le contenu d’une liste d’actualité ou les derniers éléments d’une bibliothèque de documents.

NOTE : Vous pouvez télécharger le code source d’exemple de cette application en bas de cet article.

 

2. Les technologies et outils à connaître et installer

 

Dans ce chapitre, nous allons utiliser quelques briques importantes à connaître pour réaliser rapidement et efficacement une App Mobile.

2.1 Le moteur d’exécution et l’éditeur de code

 

Pour développer une App de ce type, il nous faut un certain nombre d’éléments installés.

Voici une liste des éléments qu’il vous faudra installer :

  1. Visual Studio 2013 avec les fonctionnalités "Tools for Maintaining Store apps for Windows 8" and "Windows Phone 8.0 SDK". Je vous conseille d’utiliser plutôt les versions Pro, Premium ou Ultimate de Visual Studio, mais vous pouvez également utiliser la version Express gratuite « Visual Studio Express 2013 with Update 4 for Windows »  disponible en téléchargement ici : https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx
  2. L’update 4 de Visual Studio 2013, que vous pouvez télécharger ici : https://www.microsoft.com/fr-fr/download/details.aspx?id=44921 
  3. Visual Studio Tools for Apache Cordova CTP3.1, que vous pouvez télécharger ici : https://www.microsoft.com/en-us/download/details.aspx?id=42675

Il existe un excellent guide sur MSDN pour vous aider dans l’installation des VS Tools pour Cordova : https://msdn.microsoft.com/en-us/library/dn771545.aspx

A noter que vous n’avez pas besoin d’installer Apache Cordova indépendamment, car les Tools pour Cordova vont réaliser un certain nombre de téléchargements et d’installation pour vous, pour vous permettre de débuguer et tester vos Apps sur Androïd par exemple.

Parmi eux, on peut noter :

  • Joyent Node.js
  • Git CLI
  • Google Chrome
  • Apache Ant
  • Oracle Java JDK 7
  • Android SDK
  • SQLLite for Windows Runtime
  • Apple iTunes

 

Dernier conseil (important) : si vous possédez un téléphone Windows Phone et que vous souhaitez déployer et tester votre App sur votre téléphone, il vous faut le « débloquer » en l’enregistrant en tant que téléphone de développement. La procédure est simple une fois que vous avez installé Visual Studio (qui contient le Windows Phone SDK), il vous suffit de suivre la procédure documentée ici :

https://msdn.microsoft.com/en-us/library/windows/apps/ff769508(v=vs.105).aspx

 

2.2 La couche de communication avec Office 365 et SharePoint Online

 

Microsoft a publié des aides au développement spécialement pour Office 365, appelées « Office 365 API ». Ce kit de développement permet de facilement créer des applications capables de s’interconnecter avec la plateforme Office 365. Avec ce SDK on peut réaliser un grand nombre d’actions sans pour autant être expert des différents composants d’Office 365.

On va pouvoir réaliser des opérations du type :

  • Authentification et connexion de façon sécurisée ;
  • Gestion des utilisateurs et des groupes d’Azure Active Directory ;
  • Manipulation des données de messageries (mails, calendrier au sein d’Exchange Online) ;
  • Manipulation des fichiers au sein de son OneDrive ou de sites SharePoint Online.

Dès sa sortie, ce kit de développement a été rendu disponible à la fois pour .Net, mais aussi pour Cordova, Xamarin ou les SDK natives d’Androïd et iOS.

Pour utiliser le SDK Office 365, vous devez télécharger et installer les « Office Developer Tools for Visual Studio 2013 », disponible depuis ce lien :

https://aka.ms/officedevtoolsforvs2013

 

2.3 La couche de rendu graphique

 

Maintenant que vous avez installé les outils de développement et l’extension Visual Studio pour Office 365, il ne nous reste plus qu’à choisir un framework graphique et JavaScript qui va nous aider à développer une interface graphique adaptée aux mobiles.

Il existe un certain nombre de frameworks HTML 5 populaires qui permettent de réaliser simplement des interfaces de ce type, parmi eux on peut citer :

  • OnsenUI : Très beau framework qui se couple très bien avec AngularJS. OnsenUI présente un grand intérêt lorsque l’on souhaite réaliser une interface qui répond au basique des composants visuels pour iPhone ou Android. Seul bémol, il ne vaut mieux pas l’utiliser avec du JQuery, mais on peut facilement s’en passer. Plus d’information sur OnsenUI ici : https://onsen.io/
  • JQuery Mobile : Un kit HTML 5 pour faire des contrôles et interfaces orientés mobilité.  Pour une App mobile on ne retrouve pas forcément les éléments d’interface propre au monde de la téléphonie.
  • WinJS : Il s’agit d’un framework made-in-Microsoft pour réaliser simplement des interfaces en JavaScript avec le look-and-feel des interfaces Windows Modern UI et Windows Phone. WinJS peut être utilisé avec Angular ou non. Pour plus d’information sur WinJS, ça se passe ici : https://dev.windows.com/en-us/develop/winjs ou https://try.buildwinjs.com/

Dans cet exemple, nous allons utiliser WinJS pour notre couche graphique.

 

 3. Création d’un nouveau projet

 

3.1 Création du projet Cordova avec Visual Studio

 

Ouvrez Visual Studio 2013, cliquez sur « New » puis « Project ».

Dans la liste des templates à gauche, sélectionnez la partie JavaScript, puis la section « Apache Cordova Apps ». Sélectionner « Blank App », indiquer le nom de l’App ainsi qu’un chemin sur votre disque dur, puis cliquez sur « OK ».

 

Une fois créée, votre solution contient les fichiers HTML, JS et CSS de base vous permettant de commencer le développement orienté Web : 

 

Le fichier config.XML vous permet de modifier la plupart des paramètres de l’Application (comme son nom, l’éditeur, etc.) communs à toutes les plateformes, les plugins Cordova que vous souhaitez utiliser, ainsi que les paramétrages propres à chaque plateforme :

 

Pour exécuter et tester votre App, vous pouvez utiliser directement le lanceur de Visual Studio. Vous pouvez cibler différentes plateformes, avec l’émulateur correspondant ou directement sur un téléphone/périphérique connecté par USB à votre PC :

 

Pour iOS, il vous faudra toutefois un Mac serveur, pour porter le rôle de build. Pour Windows Phone, l’émulateur est directement installé avec le SDK et votre installation Visual Studio et pour Androïd également, le tout a été installé avec les tools Cordova pour VS.

Quelque chose de fort intéressant lorsque vous exécutez votre code est l’utilisation de Ripple (au lieu d’un device ou d’un emulator) :

 

Ripple est un émulateur Androïd fait par Apache dont la particularité est qu’il est exécuté directement dans Chrome. En fait on pourrait le résumer à une exécution spécifique en mode web dans Chrome, avec l’émulation des caractéristiques d’un téléphone ou d’une tablette. Très pratique car extrêmement rapide pour débuguer ses Apps (plus rapide qu’un émulateur à démarrer, monter en mémoire, etc.). Une documentation sur MSDN est disponible ici : https://msdn.microsoft.com/en-us/library/dn757052.aspx

Si vous essayez d’exécuter l’App avec Ripple, vous pourrez tester votre App dans Chrome, avec un rendu de ce type :

 

3.2 Ajout de la librairie WinJS

 

Maintenant que vous avez pris en main l’interface du projet, nous allons ajouter WinJS à notre solution. Pour cela, ouvrez la fenêtre dite « Package Manager Console » et dans la ligne de commande, saisir la commande d’installation de WinJS Install-Package winjs :

Une fois le package installé, un sous-répertoire contenant les scripts, styles etc. de WinJS est visible dans l’arborescence de la solution :

 

Pour exploiter WinJS dans notre App, on peut inclure dans le fichier index.html les appels au thème CSS à utiliser, ainsi qu’aux 2 fichiers JS du framework :  

 <link href="WinJS/css/ui-dark.css" rel="stylesheet" />
<script src="WinJS/js/base.js"></script>
<script src="WinJS/js/ui.js"></script>

 

 

3.3 Initialisation de WinJS

 

Dans le fichier index.js, nous allons initialiser l’application WinJS, avec le code générique suivant :

 //var activation = Windows.ApplicationModel.Activation;
var app = WinJS.Application;
var nav = WinJS.Navigation;
var sched = WinJS.Utilities.Scheduler;
var ui = WinJS.UI;

app.addEventListener("activated", function (args) {
    if (args.detail.kind === "Windows.Launch") {
        if (args.detail.previousExecutionState !== 3) {
            //3: terminated
            // TODO: This application has been newly launched. Initialize
            // your application here.
        } else {
            // TODO: This application has been reactivated from suspension.
            // Restore application state here.
        }

        nav.history = app.sessionState.history || {};
        nav.history.current.initialPlaceholder = true;

        // Optimize the load of the application and while the splash screen is shown, execute high priority scheduled work.
        ui.disableAnimations();
        var p = ui.processAll().then(function () {
            return nav.navigate(nav.location || Application.navigator.home, nav.state);
        }).then(function () {
            return sched.requestDrain(sched.Priority.aboveNormal + 1);
        }).then(function () {
            ui.enableAnimations();
        });

        args.setPromise(p);
    }
});

app.oncheckpoint = function (args) {
    // TODO: This application is about to be suspended. Save any state
    // that needs to persist across suspensions here. If you need to 
    // complete an asynchronous operation before your application is 
    // suspended, call args.setPromise().
    app.sessionState.history = nav.history;
};

app.start();

 

 

 

3.4 Utilisation du pattern navigator de WinJS

 

WinJS offre un pattern très appréciable appelé le « navigator ». Ce pattern permet de gérer une navigation fluide (sans rafraîchissement) entre les pages, ainsi qu’un découpage applicatif très élégant. Le code source du pattern navigator peut être encapsulé au sein d’un script générique, que nous allons également inclure dans notre page :

 <script src="scripts/navigator.js"></script>

Une fois ce fichier JS appelé, nous allons pouvoir gérer nos pages de façon élégante et évolutive. Dans notre page index.html, nous allons pouvoir inclure le contrôle de navigation de la façon suivante :  

 <div id="contenthost" data-win-control="Application.PageControlNavigator" data-win-options="{home: 'pages/login/login.html'}"></div>

 

Ceci va indiquer à notre App que le contenu de la page va être retrouvé dans une page login.html dans le sous répertoire pages/login. La page de login va contenir son code de présentation html, et également appeler son propre fichier JavaScript et son propre fichier de style. Ceci va rendre notre application plus maintenable, chaque page de notre App ayant son propre contexte métier et graphique, bien isolé du reste du code :

 

La page login.html va contenir son propre code html, et appeler ses propres ressources :

 <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Login</title>

    <link href="login.css" rel="stylesheet" />
    <script src="login.js"></script>
</head>
<body>
    <div class="page fragment">
        <header class="page-header" aria-label="Header content" role="banner">
            <h1 class="titlearea win-type-ellipsis">
                <span class="pagetitle">Login</span>
            </h1>
        </header>
        <section class="page-section" aria-label="Main content" role="main">

                <!-- contenu de la page -->

        </section>
    </div>
</body>
</html>

 

Le fichier login.js pourra contenir le code métier propre à sa page html, avec des fonctions appelées automatiquement lors de certains évènements, comme « ready », « unload », etc. : 

 // For an introduction to the Page Control template, see the following documentation:
// https://go.microsoft.com/fwlink/?LinkId=232511
(function () {
    "use strict";

    WinJS.UI.Pages.define("/pages/login/login.html", {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.
        ready: function (element, options) {
            // TODO: Initialize the page here.
        },

        unload: function () {
            // TODO: Respond to navigations away from this page.
        },

        updateLayout: function (element) {
            /// <param name="element" domElement="true" />

            // TODO: Respond to changes in layout.
        }
    });
})();

 

Avec cette structuration de pages, nous allons pouvoir maintenant réaliser le contenu de notre application, faire des requêtes à des sites SharePoint, affiché le contenu dans des contrôles HTML 5 efficaces et beaux, et tout ça dans une App qui va pouvoir s’exécuter aussi bien sur Windows, Windows Phone, Androïd, iPhone et iPad ! 

 

4. Authentification à Office 365 et SharePoint Online

 

Avant d’envisager de faire des requêtes aux API de SharePoint Online ou Office 365, il est indispensable de gérer correctement l’authentification. Comme vous le savez sans doute, la brique de gestion et de connexion des utilisateurs d’Office 365 est basée sur Azure Active Directory (dit AAD).

Azure Active Directory, comme tous les services d’Office 365 expose un bon nombre de web services et API pour permettre de gérer par programmation l’authentification à ses services. AAD évolue vite et propose régulièrement des nouveaux services et méthodes d’authentification (par exemple récemment a été ajouté le support de l’authentification Multi-Facteurs, dite MFA).

C’est là notamment qu’intervient les Office 365 API. Pas besoin d’être un expert de l’authentification et des services AAD pour être capable de développer un système d’authentification. Pas besoin de stocker le login/mot de passe de l’utilisateur, ni de se préoccuper des évolutions futures de la plateforme : Office 365 API vous offre des moyens simples pour prendre en charge ses méthodes d’authentification !

Voici comment procéder : Faites un clic droit sur le nom de votre projet dans la fenête « Solution Explorer », puis aller dans le menu « Add », puis cliquer sur « Connected Service… » :

 

Cliquer dans le menu gauche sur « Office 365 APIs » dans la partie Office 365 : 

 

Saisir votre compte Office 365 :

 

Une fois connecté, la liste de vos services accessible sur votre tenant Office 365 va apparaître. Cliquer sur « Sites », puis sur « Permissions » à droite :

 

Sélectionner la permission « Read items in all site collections », puis cliquer sur « Apply » :

 

Une fois la fenêtre précédente validée, des nouveaux fichiers de sources sont ajoutées dans votre solution, dans un sous-répertoire « services/office365 » :

 

Si vous ouvrez le fichier « settings.js », vous allez voir le paramétrage spécifique à votre application, avec les informations d’identification (client ID) et les adresses permettant à votre application de dialoguer avec le fournisseur d’authentification de votre tenant :

 var O365Auth;
(function (O365Auth) {
    (function (Settings) {
        Settings.clientId = 'you-client-id-guid';
        Settings.authUri = 'https://login.windows.net/common/';
        Settings.redirectUri = 'https://localhost:4400/services/office365/redirectTarget.html';
    })(O365Auth.Settings || (O365Auth.Settings = {}));
    var Settings = O365Auth.Settings;
})(O365Auth || (O365Auth = {}));

 

 Pour appeler et inclure les services d’Office 365 dans notre projet, les choses sont plutôt simples, il nous suffit d’inclure l’appel au fichier « o365loader.js » qui va se charger d’inclure les autres JS nécessaires :

 <!-- Office365 Service Libraries -->
<script src="services/office365/scripts/o365loader.js"></script>

 

Lorsque l’utilisateur va cliquer sur le bouton de Login, l’API Office 365 nous permet d’initialiser le contexte d’authentification, puis de demander le jeton pour accéder aux ressources SharePoint :

 authContext = new O365Auth.Context();
discoveryContext = new O365Discovery.Context();
discoveryContext.services(authContext.getAccessTokenFn('Microsoft.SharePoint')).then((function (value) {
    capabilities = value;
    getCurrentUser();
}).bind(this), function (error) {
    var errorAsString = JSON.stringify(error);
});

 

On peut alors extraire les informations du profil utilisateur et naviguer vers la page home.html :  

 // Get currently logged in user
function getCurrentUser() {
    authContext.getIdToken("https://outlook.office365.com/").then((function (token) {
        authToken = token;

        var options = { token: authToken, context: authContext, capabilities: capabilities };
//Bind the user name
var userName = { name: authToken.givenName + ' ' + authToken.familyName };
var personDiv = document.querySelector('#userName');
WinJS.Binding.processAll(personDiv, userName);

        WinJS.Navigation.navigate("/pages/home/home.html", options);

    }).bind(this), function (reason) {
        console.og(reason.message);
    });
}

 

Dans notre App, l’utilisateur peut maintenant s’authentifier dans l’App en trois étapes : 1 : Il clique sur le bouton Login, 2 : Il est invité à saisir ses crédentials sur son système d’authentification de son tenant Office 365, 3 : il est redirigé vers l’App :

 

5. Utilisation des web services de SharePoint Online

 

Maintenant que l’utilisateur est capable de se connecter, on peut réaliser des requêtes sur des ressources contenu au sein de site SharePoint.

Pour cet exemple, nous allons utiliser deux listes au sein d’un site d’équipe pour respectivement afficher des annonces et les derniers documents d’une bibliothèque SharePoint.

Exemple de listes Annonce :

 

Exemple de bibliothèque SharePoint Online :

 

Pour lire les données d’une liste ou d’une bibliothèque SharePoint, on peut utiliser les web services de l’API REST. On peut par exemple lister les données de la bibliothèque « Annonces » via un appel du type :

https://YOURTENANT.sharepoint.com/sites/WinJSSampleSite/_api/lists/getbytitle('Annonces')/items?$select=Title,Body,Modified

Le code suivant montre comment exécuter la requête HTML avec WinJS.xhr et lister les résultats :

 //Request the latest announcements
var rootSiteRessourceId;
options.capabilities.forEach(function (v, i, a) {
    if (v.capability === 'RootSite') {
        rootSiteRessourceId = v.resourceId;
    }
});

options.context.getAccessToken(rootSiteRessourceId).then((function (bearerToken) {
    var options = {
        url: "https://YOURTENANT.sharepoint.com/sites/WinJSSampleSite/_api/lists/getbytitle('Annonces')/items?$select=Title,Body,Modified",
        type: 'GET',
        headers:
            {
                "accept": "application/json;odata=verbose",
                "content-type": "application/json;odata=verbose",
                "Authorization": "Bearer " + bearerToken
            }
    };
    WinJS.xhr(options).done(
        function (result) {

            var feed = JSON.parse(result.responseText);
            for (var i = 0, len = feed.d.results.length; i < len; i++) {
                var item = feed.d.results[i];

                latestNews.push(
                    {
                        name: item["Title"],
                        icon: "images/calendar.png",
                        time: formatDate(item["Modified"]),
                        readStateColor: "rgba(255, 255, 255, 4)",
                        readStateFont: "Segoe UI Semibold",
                        messageText: removeHtml(item["Body"])
                    });

            }

 

 

6. Afficher des données et interface graphique avec WinJS

 

Une fois la requête exécutée nous pouvons afficher les résultats à l’aide d’un contrôle ListView de WinJS. Ce contrôle permet de « binder » une liste de résultats à partir d’une template HTML. On peut également utiliser le contrôle WinJS.UI.Pivot pour afficher les deux listes sous la forme d’onglets :

 <div class="messageTemplate" data-win-control="WinJS.Binding.Template">
    <div class="message">
        <div class="userIcon"><img src="#" data-win-bind="src: icon" width="48"/></div>
        <div class="messageContent">
            <div class="contactInformation">
                <div class="contactName" data-win-bind="textContent: name"></div>
                <div class="contactTime" data-win-bind="textContent: time; style.color: readStateColor; style.fontFamily: readStateFont"></div>
            </div>
            <div class="messagePreview" data-win-bind="textContent: messageText; style.color: readStateColor; style.fontFamily: readStateFont"></div>
        </div>
    </div>
</div>

<div id="messageList" data-win-control="WinJS.UI.Pivot" data-win-options="{ selectedIndex: 0 }">
                
    <div class="pivotItem" data-win-control="WinJS.UI.PivotItem" data-win-options="{ 'header': 'Latest News' }">
        <div data-win-control="WinJS.UI.Repeater" data-win-options="{ data: DataSet.LatestNews, template: select('.messageTemplate') }"></div>
    </div>

    <div class="pivotItem" data-win-control="WinJS.UI.PivotItem" data-win-options="{ 'header': 'Latest Docs' }">
        <div data-win-control="WinJS.UI.Repeater" data-win-options="{ data: DataSet.LatestDocs, template: select('.messageTemplate') }"></div>
    </div>

</div>

 

Dans le code JavaScript associé, on peut initialiser les listes : 

 var latestNews = new WinJS.Binding.List([]);
var latestDocs = new WinJS.Binding.List([]);

WinJS.Namespace.define("DataSet", {
    LatestNews: latestNews,
    LatestDocs: latestDocs
});

 

 

Voici le rendu des écrans sur un téléphone en mode vertical :

 

Ou en mode horizontal :

 

Conclusion

 

Il est simple de développer une App mobile capable de pleinement exploiter les API d’Office 365 pour interroger un site SharePoint Online. Grâce aux extensions Apache Cordova pour Visual Studio, on peut facilement rendre cette application compatible pour les types de devices mobiles comme Windows Phone, Androïd ou iOS.

Proposer des applications mobiles connectées avec ses sites Intranet SharePoint, sa messagerie Exchange Online, son espace OneDrive ou encore son Office Graph sont autant de choses facilement réalisables grâce à l'Office 365 API.

MyWinJSCordovaApp.zip