Condividi tramite



Settembre 2015

Volume 30 Numero 9

Il presente articolo è stato tradotto automaticamente.

App per dispositivi mobili connesse al cloud - Sviluppare un'app Xamarin con l'autenticazione e il supporto offline

Da Kraig Brockschmidt

Come descritto nella prima parte di questa serie in due parti, "Creare un Web servizio con Azure Web App e processi Web" (msdn.microsoft.com/magazine/mt185572), nell'agosto emettere, molte applicazioni per dispositivi mobili attualmente connessi a uno o più servizi Web che forniscono dati utili e interessanti. Sebbene sia facile semplicemente le chiamate API REST dirette a tali servizi e le risposte di processo nel client, questo approccio può essere costoso in termini di alimentazione a batteria, la larghezza di banda e la limitazione delle limitazioni imposte da diversi servizi. Le prestazioni potrebbero diminuire anche su hardware di fascia bassa. Ha senso, quindi per ripartire il lavoro a un back-end personalizzato, come viene illustrato con il progetto "Altostratus" che verranno discussi in questo articolo.

Altostratus back-end, illustrati nella parte 1, periodicamente raccoglie e normalizza "conversazioni" da StackOverflow e Twitter (solo per utilizzare due diverse origini dati) e li archivia in un database di Microsoft Azure. Ciò significa che i dati esatti necessari dai client possono essere forniti dai direttamente, il back-end consente di ridimensionare il back-end in Azure per supportare un numero di client senza raggiungere i limiti della limitazione dei provider originale. Per normalizzare i dati sul back-end in modo che corrisponda il client deve, abbiamo inoltre ottimizzare lo scambio di dati tramite l'API Web, risparmio di risorse insufficienti mai dei dispositivi mobili.

In questo articolo, illustreremo i dettagli dell'applicazione client (vedere Figura 1). Si inizia con l'architettura dell'applicazione per impostare il contesto globale, quindi nel nostro uso dei Xamarin e Xamarin.Forms, l'autenticazione con il back-end, la creazione della cache offline e la compilazione con Xamarin in Team Foundation Server (TFS) e Visual Studio Online.

The Xamarin Mobile App in esecuzione su un Tablet Android (a sinistra), un Windows Phone (al centro) e un iPhone (a destra)
Figura 1 The Xamarin Mobile App in esecuzione su un Tablet Android (a sinistra), un Windows Phone (al centro) e un iPhone (a destra)

Architettura delle applicazioni client

L'applicazione client dispone di tre pagine principali o viste: Elemento, il cui condividono questi nomi, Home e configurazione (vedere Figura 2). Una pagina di accesso secondaria senza interfaccia utente e viene semplicemente l'host per il provider OAuth pagine Web. Utilizza una struttura di base Model-View-ViewModel (MVVM), ogni pagina principale, ad eccezione di account di accesso dispone di una classe di modello di visualizzazione associata per gestire le relazioni di associazione tra le viste e le classi di modello di dati che rappresentano gli elementi, categorie e le impostazioni di configurazione (incluso un elenco di provider di autenticazione).

L'architettura dell'applicazione Client Altostratus, che mostra i nomi delle classi principali coinvolti (file del progetto corrispondano questi nomi di classe, a meno che non indicato)
Figura 2 architettura dell'applicazione Client Altostratus, che mostra i nomi delle classi principali coinvolti (file del progetto corrispondano questi nomi di classe, a meno che non indicato)

(Nota: Gli sviluppatori spesso preferiscono separare le visualizzazioni XAML in una libreria di classi portabile [PCL] separata dalle altre classi e i modelli di visualizzazione consente ai progettisti di lavorare in modo indipendente con le viste in strumenti di Blend. Non rendere tale separazione per semplificare la struttura del progetto e anche perché al momento non funziona con i controlli Xamarin.Forms Blend.)

Il modello di dati sempre consente di popolare gli oggetti da un database SQLite locale, che viene inserito automaticamente alla prima esecuzione dell'applicazione. Sincronizzazione con il back end che avviene nel modello di dati, è un semplice processo di recupero dei nuovi dati (il meno possibile per ridurre al minimo il traffico di rete), l'aggiornamento del database con i dati, pulizia qualsiasi vecchi dati e indicare il modello di dati per aggiornare i relativi oggetti. Ciò attiva l'aggiornamento dell'interfaccia utente, grazie all'associazione dati con i modelli di visualizzazione.

Come viene discusso più avanti, un numero di eventi diversi attiva una sincronizzazione: pulsante nell'interfaccia utente, la modifica della configurazione, l'autenticazione con il back-end (che recupera una configurazione salvata in precedenza), la ripresa dell'app dopo 30 minuti, di un aggiornamento e così via. Naturalmente, la sincronizzazione è la comunicazione primaria con il back-end tramite l'API Web, ma il back-end fornisce inoltre un'API per la registrazione di un utente, il recupero delle impostazioni dell'utente autenticato e l'aggiornamento di tali impostazioni quando un utente autenticato viene modificata la configurazione.

Xamarin.Forms per un Client multipiattaforma

Come detto in MSDN Magazine, Xamarin consente di utilizzare linguaggi c# e Microsoft .NET Framework per creare applicazioni per Android, iOS e Windows, con una grande quantità di codice condiviso tra piattaforme. (Per una panoramica della nostra configurazione sviluppo, vedere la sezione successiva, "Creazione con Xamarin in TFS e Visual Studio online".) Il framework Xamarin.Forms aumenta ulteriormente questa quantità, fornendo una soluzione comune dell'interfaccia utente per XAML / c#. Con Xamarin.Forms, il progetto Altostratus condivide più del 95% del relativo codice in un singolo PCL. Il codice specifico della piattaforma solo nel progetto, sono in effetti, i bit di avvio che provengono da modelli di progetto, renderer per le pagine di accesso che si occupano di un controllo browser Web e alcune righe di codice per copiare il database SQLite prepopolato nella posizione appropriata in lettura-scrittura nell'archivio locale.

Si noti che un progetto Xamarin può anche essere configurato per utilizzare un progetto condiviso, anziché un PCL. Tuttavia, Xamarin consiglia l'utilizzo di un driver PCL ed è il vantaggio principale con Altostratus che utilizziamo PCL stesso in un'applicazione console Win32 per creare il database di pre-popolato. Ciò significa è non duplicare qualsiasi codice del database per questo scopo e il programma inizializzatore sarà sempre sincronizzato con il resto dell'applicazione.

Occorre tenere presente che il codice condiviso non molto riduce lo sforzo necessario per testare l'applicazione in ogni piattaforma di destinazione; tale parte del processo richiederà circa come se ogni applicazione scritta in modo nativo. Inoltre, poiché Xamarin.Forms è piuttosto nuovo, è possibile bug specifici della piattaforma o altri comportamenti che è necessario gestire nel codice. Per informazioni dettagliate su alcuni abbiamo trovato durante la scrittura di Altostratus, vedere il post a bit.ly/1g5EF4j.

Se si verificano strani problemi, il primo strumento deve essere il database dei bug Xamarin (bugzilla.xamarin.com). Se il problema discusso disponibili non sono visibili, Inserisci una domanda o problema nei forum Xamarin (forums.xamarin.com), dove sono disponibili il personale di Xamarin sia abbastanza reattiva.

Ciò detto, la gestione di singoli risolvere questi problemi è molto più semplice che imparare i dettagli del livello dell'interfaccia utente di ciascuna piattaforma singoli. E poiché Xamarin.Forms è relativamente nuova, individuazione dei problemi di questo tipo consente al framework diventano sempre più affidabili.

Modifiche specifiche della piattaforma

All'interno di Xamarin.Forms, talvolta è necessario apportare modifiche per una piattaforma o un'altra, come ottimizzare il layout. (Fare riferimento a ottimo libro Petzolds "Programming App Mobile con Xamarin.Forms" [bit.ly/1H8b2q6], per un numero di esempi.) È anche possibile gestire alcune incoerenze funzionali, ad esempio quando un elemento webview viene attivato il primo evento Navigating (anche in questo caso, per alcune si sono verificati, vedere il post a bit.ly/1g5EF4j).

A tale scopo, Xamarin.Forms è un'API di Device.OnPlatform < T > (iOS_value, Android_value, Windows_value) e un elemento XAML corrispondente. Come si può immaginare, OnPlatform restituisce un valore diverso a seconda del runtime corrente. Ad esempio, il codice XAML seguente nasconde i controlli di accesso della pagina di configurazione in Windows Phone in quanto il componente xamarin. auth ancora non supporta tale piattaforma, pertanto viene sempre eseguito non autenticati (configuration.xaml):

<StackLayout Orientation="Vertical">
  <StackLayout.IsVisible>
    <OnPlatform x:TypeArguments="x:Boolean" Android="true" iOS="true"
      WinPhone="false" />
  </StackLayout.IsVisible>
  <Label Text="{ Binding AuthenticationMessage }" FontSize="Medium" />
  <Picker x:Name="providerPicker" Title="{ Binding ProviderListLabel }"
    IsVisible="{ Binding ProviderListVisible }" />
  <Button Text="{ Binding LoginButtonLabel}" Clicked="LoginTapped" />
</StackLayout>

Parlando di componenti, Xamarin stesso si basa principalmente dei componenti che astraggono le funzionalità comuni delle piattaforme native, molti dei quali rimetterlo Xamarin.Forms per l'interfaccia utente. Alcuni di questi componenti sono incorporati in Xamarin, mentre altri, inclusi i contributi alla community, ottenuta da components.xamarin.com. Oltre a xamarin. auth, Altostratus utilizza il plug-in connettività (tinyurl.com/xconplugin) per visualizzare un indicatore e disattivare il pulsante di aggiornamento quando il dispositivo è offline.

Abbiamo scoperto esiste sempre un ritardo tra quando viene modificata la connettività del dispositivo (riflesse nella proprietà IsConnected del plug-in) e quando il plug-in viene generato l'evento. Ciò significa che possono essere presenti alcuni secondi tra il dispositivo di disconnessione e il pulsante Aggiorna modifica allo stato disabilitato. Per gestire questa situazione, utilizziamo l'evento di comando di aggiornamento per controllare lo stato di IsConnected del plug-in. Se è in linea, viene immediatamente disattivare il pulsante, ma impostare un flag che indica il gestore ConnectivityChanged per avviare automaticamente una sincronizzazione quando viene ripristinata la connettività.

Altostratus utilizza inoltre xamarin. auth (tinyurl.com/xamauth) per gestire i dettagli di autenticazione tramite OAuth, che verrà trattata tra breve. Il problema è che il componente supporta attualmente solo iOS e Android e non Windows Phone e non nell'ambito per il progetto risolvere tale problema specifico. Fortunatamente, l'applicazione client viene eseguito senza problemi non autenticato, il che significa semplicemente che le impostazioni dell'utente non vengono mantenute nel cloud e scambio di dati con il back-end non è completamente ottimizzato. Quando il componente viene aggiornato per supportare Windows, abbiamo bisogno rimuovere solo il tag OnPlatform nel codice XAML illustrato in precedenza per rendere visibili i controlli di accesso.

Autenticazione con il Back-End

Nell'applicazione Altostratus nel suo complesso, Desideravamo illustrare meccanismi messi in archiviazione di alcune preferenze specifiche dell'utente sul back-end in modo che il back-end potrebbe applicare automaticamente tali preferenze quando si gestiscono le richieste HTTP. Per questa applicazione specifica, naturalmente, avremmo potuto raggiungere lo stesso risultato utilizzando solo i parametri URI con le richieste, ma un esempio di questo tipo non fungono da base per scenari più complessi. Memorizzare le preferenze sul server consente inoltre di eseguire il roaming tra i dispositivi dell'utente.

Per funzionare con qualsiasi tipo di dati specifici dell'utente significa che l'autenticazione utente univoco. Ciò è diverso, tranquillità, dall'autorizzazione. L'autenticazione è un modo per identificare un utente e la convalida sono che dichiarano di essere. Autorizzazione, d'altra parte, è correlato alle autorizzazioni che dispone di un utente specifico (ad esempio, amministratore e utente normale e guest).

Per l'autenticazione, è utilizzare social account di accesso a terze parti quali Google e Facebook, anziché implementare un sistema di credenziali e il back-end è un'API tramite il quale l'applicazione client recupera un elenco di provider per la pagina di configurazione dell'interfaccia utente. Il vantaggio di accesso dai social network è che non è necessario gestire le credenziali in tutte o i problemi di protezione e privacy Supervisore; il back-end archivia solo un indirizzo di posta elettronica come nome utente e il client gestisce solo un token di accesso in fase di esecuzione. In caso contrario, il provider non tutto il pesante, tra cui la verifica della posta elettronica, il recupero della password e così via.

Naturalmente, non tutti gli utenti dispone di un account con un provider di accesso dai social network e alcuni utenti non desiderano utilizzare gli account di social networking per motivi di privacy. Inoltre, accesso dai social network potrebbe non essere appropriato per le applicazioni line-of-business; In questi casi è consigliabile Azure Active Directory. Per i nostri scopi, tuttavia, è una scelta logica poiché è necessario semplicemente un modo per autenticare un utente.

Una volta autenticato, un utente è autorizzato a salvare le preferenze sul back-end. Se si desidera implementare altri livelli di autorizzazione (ad esempio la modifica delle preferenze di altri utenti), il back-end può verificare il nome utente su un database di autorizzazioni.

Mediante OAuth2 per l'accesso dai social network in ASP.NET Web API OAuth2 (bit.ly/1SxC1AM) è un framework di autorizzazione che consente agli utenti di concedere l'accesso alle risorse, senza condividere le proprie credenziali. Definisce diversi "credential flussi" che specificano come le credenziali vengono scambiate fra varie entità. API Web ASP.NET utilizza il cosiddetto "flusso di concessione implicita" in cui l'app mobile non raccoglie credenziali né archivia le informazioni riservate. Che l'operazione viene eseguita dal provider di OAuth2 e la libreria ASP.NET Identity (asp.net/identity), rispettivamente.

Per abilitare l'accesso dai social network, è necessario registrare l'applicazione con ognuno dei provider di accesso tramite i portali di sviluppatore. (Un "applicazione" in questo contesto significa che tutte le esperienze di client, inclusi i dispositivi mobili e Web e in particolare non è legato a un'app mobile). Una volta registrato, il provider fornisce un ID univoco di client e un segreto. Vedere bit.ly/1BniZ89 per alcuni esempi.

Utilizziamo questi valori per inizializzare il middleware identità ASP.NET, come illustrato nella Figura 3.

Figura 3 inizializzando il Middleware identità ASP.NET

var fbOpts = new FacebookAuthenticationOptions
{
  AppId = ConfigurationManager.AppSettings["FB_AppId"],
  AppSecret = ConfigurationManager.AppSettings["FB_AppSecret"]
};
fbOpts.Scope.Add("email");
app.UseFacebookAuthentication(fbOpts);
var googleOptions = new GoogleOAuth2AuthenticationOptions()
{
  ClientId = ConfigurationManager.AppSettings["GoogleClientID"],
  ClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"]
};
app.UseGoogleAuthentication(googleOptions);

Le stringhe come "FB_AppID" sono chiavi che fanno riferimento alle impostazioni di ambiente e i file di configurazione dell'applicazione Web, dove vengono archiviati gli ID e i segreti effettivo. Ciò consente l'aggiornamento senza ricompilare e ridistribuire l'applicazione.

Xamarin. auth mediante Gestione credenziali flussoin generale, il processo di autenticazione social implica un'ampia gamma di handshake tra l'applicazione, il back-end e il provider. Fortunatamente, il componente xamarin. auth (disponibile nell'archivio del componente Xamarin), gestisce la maggior parte di questo oggetto per l'applicazione. Sono inclusi utilizzo del controllo del browser e fornendo hook di callback in modo che l'applicazione può rispondere quando l'autorizzazione è completo.

Impostazione predefinita, xamarin. auth è installata l'app client eseguire alcune parti di danza l'autorizzazione, ovvero che l'applicazione memorizza l'ID client e il segreto. Che è leggermente diversa dal flusso di ASP.NET, ma xamarin. auth presenta una gerarchia di classe corretto factoring. La classe Xamarin.Auth.OAuth2Authenticator deriva da WebRedirectAuthenticator, che offre funzionalità di base, è necessario e si rende necessaria scrivere solo una piccola quantità di codice aggiuntivo, disponibile nei file di LoginPageRenderer.cs nei progetti Android e iOS (perché xamarin. auth non supporta ancora Windows). Per ulteriori informazioni su ciò che facciamo, vedere il post di blog in tinyurl.com/kboathalto.

Quindi, l'applicazione client include semplicemente una classe LoginPage da cui deriva il base ContentPage di Xamarin.Forms, che consente di spostarci agevolmente disponibili. Questa classe espone due metodi, CompleteLoginAsync e CancelAsync, che vengono chiamate dal codice LoginPageRenderer in base eseguite dall'utente nell'interfaccia Web del provider.

L'invio di richieste autenticate dopo aver eseguito l'accesso, l'applicazione client dispone di un token di accesso. Per rendere una richiesta autenticata, include semplicemente tale token in un'intestazione di autorizzazione analogo al seguente:

GET http://hostname/api/UserPreferences HTTP/1.1
Authorization: Bearer I6zW8Dk...
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko

In questo caso, "Portatore" indica le autorizzazioni tramite i token di connessione, dopo cui proviene la stringa del token lunga, opaca.

Utilizziamo la libreria System.Net.Http.HttpClient per tutte le richieste REST con un gestore di messaggi personalizzati per aggiungere l'intestazione di autenticazione a ogni richiesta. Gestori di messaggi sono componenti plug-in che consentono di esaminare e modificare i messaggi di richiesta e risposta HTTP. Per ulteriori informazioni, vedere bit.ly/1MyMMB8.

Il gestore di messaggi viene implementato nella classe AuthenticationMessageHandler (webapi.cs) e viene installato quando si crea l'istanza di HttpClient:

_httpClient = HttpClientFactory.Create(
  handler, new AuthenticationMessageHandler(provider));

L'interfaccia ITokenProvider è un modo per il gestore ottenere l'accesso token da app (implementata nella classe UserPreferences model.cs). Viene chiamato il metodo SendAsync per ogni richiesta HTTP. come Figura 4 illustrato, aggiungerà l'intestazione di autorizzazione se il provider di token da utilizzare.

Figura 4 aggiunta l'intestazione di autorizzazione

public interface ITokenProvider
{
  string AccessToken { get; }
}
class AuthenticationMessageHandler : DelegatingHandler
{
  ITokenProvider _provider;
  public AuthenticationMessageHandler(ITokenProvider provider)
  {
     _provider = provider;
  }
  protected override Task<HttpResponseMessage>
    SendAsync(HttpRequestMessage request,
    System.Threading.CancellationToken cancellationToken)
  {
    var token = _provider.AccessToken;
    if (!String.IsNullOrEmpty(token))
    {
      request.Headers.Authorization =
        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    }
    return base.SendAsync(request, cancellationToken);
  }
}

Sul back-end, come descritto nella parte 1 di questo articolo, se si riceve un token con una richiesta, il token viene utilizzato per recuperare le preferenze dell'utente e applicare automaticamente al resto della richiesta. Ad esempio, se l'utente ha impostato il limite di conversazione a 25 anziché il valore predefinito pari a 100, un massimo di 25 elementi verrà restituito con una richiesta, il salvataggio della larghezza di banda di rete.

Creazione di una Cache non in linea per i dati di Back-End

Un grande vantaggio di un'applicazione per dispositivi mobili tramite il Web per dispositivi mobili è la flessibilità necessaria per supportare l'utilizzo offline. Un'applicazione per dispositivi mobili, per definizione, è sempre presente sul dispositivo dell'utente e può utilizzare una varietà di opzioni di archiviazione dati, ad esempio SQLite, per mantenere una cache di dati non in linea, piuttosto che basarsi su meccanismi basati su browser.

L'interfaccia utente del client per dispositivi mobili Altostratus, infatti, semplicemente funziona con i dati che vengono gestiti in un database SQLite locale, rendendo l'applicazione completamente funzionale senza connessione. Quando la connettività è presente, i processi in background recupero dati aggiornati dal back-end per aggiornare il database. Aggiorna gli oggetti modello di dati che si trovano di sopra del database, che a sua volta vengono attivati gli aggiornamenti dell'interfaccia utente tramite l'associazione dati (è possibile visualizzare questo nuovo Figura 2). In questo modo è un'architettura molto simile a illustrati nella parte 1, dove i processi in corso Web raccogliere, normalizzare e memorizzare i dati in un database di SQL Server in modo che l'API Web può gestire le richieste direttamente dal database back-end.

Supporto offline per Altostratus include tre attività distinte:

  • Inserimento di un file di database pre-popolato direttamente nel pacchetto dell'app per fornire i dati di utilizzo immediatamente alla prima esecuzione senza la necessità di connettività.
  • Implementazione di processi di sincronizzazione unidirezionale per ogni parte del modello di dati che ottiene emersi nell'interfaccia utente: le conversazioni (elementi), categorie, i provider di autenticazione e le preferenze dell'utente.
  • Associazione di sincronizzazione per i trigger appropriati oltre il pulsante Aggiorna nell'interfaccia utente.

Esaminiamo ciascuno di essi, a sua volta.

Creazione di un Database popolato preliminarmente è possibile che un utente di installazione di un'applicazione da un negozio online ma non eseguito un secondo momento quando il dispositivo è offline. La domanda è: da eseguire l'applicazione di esempio, "Spiacente, non è possibile ottenere qualcosa di utile a meno che non si è in linea?" Oppure si preferisce l'applicazione per gestire questi casi, in modo intelligente?

Per illustrare il secondo approccio, il client Altostratus include un database SQLite prepopolato direttamente nel relativo pacchetto di applicazione in ogni piattaforma (che si trova nella cartella risorse/raw del progetto ogni piattaforma). Alla prima esecuzione, il client copia del file del database in una posizione di lettura e scrittura sul dispositivo e quindi compatibile da qui in modo esclusivo. Poiché la copia dei file è univoco per ogni piattaforma, utilizziamo la funzionalità Xamarin.Forms.DependencyService per risolvere un'implementazione specifica di un'interfaccia che definiamo chiamato ISQLite in fase di esecuzione. In questo caso dal costruttore DataAccessLayer (DataAccess.cs), che quindi chiama ISQLite.GetDatabasePath per recuperare il percorso specifico della piattaforma del file di database copiato in lettura-scrittura, come illustrato nella Figura 5.

Figura 5, il rilevamento del percorso specifico della piattaforma del File di Database

public DataAccessLayer(SQLiteAsyncConnection db = null)
{
  if (db == null)
  {
    String path = DependencyService.Get<ISQLite>().GetDatabasePath();
    db = new SQLiteAsyncConnection(path);               
    // Alternate use to use the synchronous SQLite API:
    // database = SQLiteConnection(path);               
  }
  database = db;
  _current = this;
}

Per creare il database iniziale, la soluzione Altostratus contiene una piccola applicazione console Win32 denominata DBInitialize. Utilizza la stessa PCL condiviso dell'applicazione per utilizzare il database, pertanto non è mai un problema della presenza di una mancata corrispondenza, secondo base di codice. DBInitialize, tuttavia, non è necessario utilizzare il DependencyService: Si può semplicemente creare direttamente un file e aprire una connessione:

string path = "Altostratus.db3";
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(path);
var dbInit = new DataAccessLayer(conn);

A questo punto, DBInitialize chiama DataAccessLayer.InitAsync per creare le tabelle (operazione che l'applicazione non deve mai il database di prepopolato) e utilizza gli altri metodi DataAccessLayer per ottenere dati dal back-end. Si noti che con chiamate asincrone, DBInitialize solo utilizza. Attesa; Poiché è un'applicazione console e non deve preoccuparsi di risposta dell'interfaccia utente:

DataModel model = new DataModel(dbInit);
model.InitAsync().Wait();
model.SyncCategories().Wait();
model.SyncAuthProviders().Wait();
model.SyncItems().Wait();

Per consentire agli utenti un aspetto da esaminare, utilizza un timer per inserire un punto sullo schermo ogni mezzo secondo.

Si noti che è opportuno sempre cercare il database prepopolato con uno strumento come Browser DB SQLite (bit.ly/1OCkm8Y) prima di eseguire il pull nel progetto. È possibile che uno o più delle richieste Web hanno esito negativo, nel qual caso il database di non essere valido. È possibile creare tale logica in DBInitialize quindi Elimina il database e viene visualizzato un errore. In questo caso, solo guardiamo per i messaggi di errore e il programma viene eseguito anche in questo caso, se necessario.

Potrebbe chiedere, "il contenuto di un database prepopolato analizzerò obsoleto relativamente rapida? Non voglio gli utenti dell'applicazione per visualizzare i dati non aggiornati realmente alla prima esecuzione!" Questo, ovviamente, sarà il caso se non vengono aggiornati regolarmente l'applicazione. Pertanto è opportuno eseguire il commit degli aggiornamenti periodici app che includono un database con i dati correnti ragionevolmente (a seconda della natura dei dati).

Se l'utente è già installata l'app, l'aggiornamento non avrà alcun effetto poiché il codice che consente di copiare il file di database nel pacchetto controlla se esiste già una copia di lettura / scrittura e che vengono utilizzati solo. Tuttavia, se l'esistenza del file è il solo controllo, un utente che non è stata eseguita l'applicazione per un periodo di tempo finiva avviando l'applicazione con i dati meno recenti rispetto a quelli effettivamente in un pacchetto aggiornato più di recente. Si può verificare se il timestamp del database della cache è antecedente a quella presente nel pacchetto e sovrascrivere la cache con la copia più recente. Questo non che è implementati in Altostratus, tuttavia, in quanto è anche necessario conservare le informazioni di preferenze utente dal database esistente.

Sincronizzazione della Cache non in linea con il Back-End come accennato prima, il client Altostratus viene sempre eseguito nel relativo database della cache. Tutte le richieste Web back-end (ad eccezione di caricamento nuove preferenze dell'utente) si verificano nel contesto di sincronizzazione della cache. Il meccanismo di questo viene implementato come parte della classe DataModel, in particolare tramite i quattro metodi di sync.cs: SyncSettings (che delega a endConfiguration Configuration.ApplyBack in model.cs), SyncCategories, SyncAuthProviders e SyncItems. Chiaramente il componente di base del gruppo è SyncItems, ma vi spiegherò che cosa attiva tutti nella sezione successiva.

Si noti che Altostratus Sincronizza i dati in una sola direzione, dal back-end per la cache locale. Inoltre, poiché sappiamo che i dati che ci interessano non cambiano tutto rapidamente (di battesimo la pianificazione per i processi di back-end Web), ci interessa solo la coerenza finale con l'archivio dati back-end, anziché aggiornare nell'ordine di minuti o secondi.

Ogni processo di sincronizzazione è essenzialmente lo stesso: Recuperare i dati correnti dal back-end, aggiornare il database locale con nuovi valori, rimuovere eventuali valori precedenti dal database e quindi ripopolare gli oggetti del modello di dati per attivare gli aggiornamenti dell'interfaccia utente.

Per gli elementi, è più lunga perché SyncItems può essere richiamata dall'interfaccia utente e si desidera impedire che utenti entusiasti eccessiva fare clic sul pulsante più volte. La proprietà privata DataModel.syncTask indica se è presente una sincronizzazione elemento attivo; SyncItems ignora una richiesta di ripetere se syncTask è diverso da null. Inoltre, poiché una richiesta di elemento potrebbe richiedere alcuni minuti e prevede più grandi set di dati, si desidera essere in grado di annullare una sincronizzazione elemento se il dispositivo è offline. A tale scopo, si salva un System.Threading.CancellationToken per l'attività.

Il metodo privato SyncItemsCore, illustrato nella Figura 6, è il fulcro del processo. Recupera il timestamp dell'ultima sincronizzazione del database e che include con la richiesta Web.

Figura 6 metodo SyncItemsCore privato

private async Task<SyncResult> SyncItemsCore()
{
  SyncResult result = SyncResult.Success;
  HttpResponseMessage response;
  Timestamp t = await DataAccessLayer.Current.GetTimestampAsync();
  String newRequestTimestamp =
    DateTime.UtcNow.ToString(WebAPIConstants.ItemsFeedTimestampFormat);
  response = await WebAPI.GetItems(t, syncToken);
  if (!response.IsSuccessStatusCode)
  {
    return SyncResult.Failed;
  }
  t = new Timestamp() { Stamp = newRequestTimestamp };
  await DataAccessLayer.Current.SetTimestampAsync(t);
  if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
  {
    return SyncResult.NoContent;
  }
  var items = await response.Content.ReadAsAsync<IEnumerable<FeedItem>>();
  await ProcessItems(items);
  // Sync is done, refresh the ListView data source.
  await PopulateGroupedItemsFromDB();
  return result;
}

In questo modo il back-end restituisce solo gli elementi che sono nuovi o aggiornati dopo l'ora specificata. Di conseguenza, il client ottiene solo i dati che effettivamente necessari, conservazione potenzialmente l'utente limitato piano dati. Questo significa anche il client esegue meno lavoro per elaborare i dati da ogni richiesta, anche l'energia della batteria e riduce al minimo il traffico di rete. Se esso non sembra molto, la gestione di cinque conversazioni per categoria anziché, ad esempio, 50, con ogni richiesta è una riduzione del 90%. Da 20 a 30 sincronizzazioni al giorno, questo può facilmente aggiungere fino a centinaia di megabyte in un mese per solo l'applicazione di uno. In breve, i clienti apprezzeranno sicuramente gli sforzi che necessari per ottimizzare il traffico!

Una volta la richiesta viene restituita, il metodo ProcessItems aggiunge tutti gli elementi nel database, eseguire la pulitura poco dei titoli (ad esempio rimuovendo inglesi) ed estrarre i primi 100 caratteri del corpo per una descrizione da visualizzare nell'elenco principale. La pulizia del titolo è di back-end, invece, tale che potrebbe risparmiare un po' di tempo di elaborazione sul client. Abbiamo scelto di lasciarlo sul client, poiché altre situazioni potrebbero essere necessario effettuare regolazioni specifiche della piattaforma. Potremmo Avremo inoltre il back-end creare le descrizioni di 100 caratteri, vale a dire il salvataggio di un client minima elaborazione ma aumentando il traffico di rete. Si tratta probabilmente di un compromesso anche con i dati che utilizziamo, e poiché l'interfaccia utente è in definitiva la responsabilità del client, è consigliabile lasciare il client nel controllo di questo passaggio. (Per ulteriori informazioni su questa e due altre considerazioni sull'interfaccia utente, vedere il post del blog tinyurl.com/kboathaltoxtra.)

Una volta gli elementi sono stati aggiunti al database, i gruppi di modelli di dati vengono aggiornati tramite PopulateGroupedItemsFromDB. Qui è importante tenere presente che il database è probabilmente più elementi di quelli necessari per l'impostazione limite di conversazione corrente dell'utente. PopulateGroupedItemsFromDB conti per l'oggetto applicando tale limite direttamente alla query di database.

Nel tempo, tuttavia, non vogliamo il database per mantenere l'espansione mantenendo una serie di elementi che non verrà mai visualizzata nuovamente. A tale scopo, SyncItems chiama un metodo DataAccessLayer.ApplyConversationLimit per eliminare selettivamente le vecchi elementi dal database finché il numero di elementi corrisponde a un limite specificato. Poiché la dimensione dei singoli elementi all'interno del set di dati Altostratus è relativamente piccola, utilizziamo il limite massimo di conversazione di 100 indipendentemente dall'impostazione corrente dell'utente. In questo modo, se l'utente solleva tale limite, è necessario richiedere nuovamente i dati dal back-end. In presenza di più elementi di dati più grandi, tuttavia, potrebbe avere senso più aggressiva riforma del database e richiedere di nuovo gli elementi se necessari.

Trigger di sincronizzazione il pulsante Aggiorna nell'interfaccia utente è chiaramente il principale modo una sincronizzazione di elementi viene effettuato, ma quando gli altri processi di sincronizzazione eseguita? E non vi sono altri trigger per la sincronizzazione di un elemento?

È difficile rispondere a queste domande per quanto riguarda il codice, in quanto tutte le chiamate ai metodi di sincronizzazione * si verificano in un'unica posizione, il metodo HomeViewModel.Sync. Tuttavia, questo metodo e un punto di ingresso secondario, HomeViewModel.CheckTimeAndSync, vengono chiamati da diverse altre posizioni. Qui è riportato un riepilogo di quando, dove e come chiamate di sincronizzazione sono parametri con un valore dall'enumerazione SyncExtent:

  • All'avvio, il costruttore HomeViewModel chiama Sync(SyncExtent.All), utilizzando un modello fire-and-forget in modo che la sincronizzazione avviene interamente in background. Il modello qui significa semplicemente salvare il valore restituito da un metodo asincrono in una variabile locale per escludere un avviso del compilatore sull'utilizzo non attende.
  • All'interno del gestore per evento ConnectivityChanged della connettività plug-in, chiamiamo sincronizzazione se la periferica era non in linea quando è stata effettuata una chiamata precedente (utilizzando la stessa misura come richiesto quindi).
  • Se l'utente visita la pagina di configurazione e apporta modifiche alle categorie di attivi o il limite di conversazione, o accede al server back-end e, pertanto, applica le impostazioni di back-end, che viene memorizzata dal flag DataModel.Configuration.HasChanged. Quando l'utente torna alla home page, il gestore HomePage.OnAppearing chiama HomeViewModel.CheckRefresh, che verifica la HasChanged e chiama Sync(SyncExtent.Items), se necessario.
  • Le chiamate di evento (app.cs) App.OnResume CheckTimeAndSync, che applica la logica per determinare cosa deve essere inviata dipendono da quanto tempo l'applicazione è stata sospesa. Chiaramente, queste condizioni sono altamente dipende dalla natura dei dati e le operazioni di back-end.
  • Infine, sul pulsante Aggiorna chiama CheckTimeAndSync con un flag per eseguire sempre almeno un elemento di sincronizzazione. CheckTimeAndSync viene utilizzato il pulsante Aggiorna, poiché è possibile, anche se piuttosto raro, che un utente ha lasciato l'applicazione in esecuzione in primo piano per più di mezz'ora o anche un giorno, nel qual caso il pulsante Aggiorna inoltre necessario eseguire le altre sincronizzazioni come facciamo in fase di ripresa.

Un vantaggio di consolidare tutto in HomeViewModel.Sync è che è possibile impostare la proprietà pubblica di HomeViewModel.IsSyncing al momento opportuno. Questa proprietà è associato a dati alle proprietà IsVisible sia IsRunning di un Xamarin.Forms.ActivityIndicator in Home.xaml. Il semplice fatto di impostare questo flag controlla la visibilità di tale indicatore.

Compilazione con Xamarin in linea di Visual Studio e TFS

Per il progetto Altostratus, abbiamo utilizzato un ambiente di sviluppo piuttosto comune per il lavoro su più piattaforme: Windows PC con gli emulatori e dispositivi liberi per Android e Windows Phone, insieme a un computer Mac OS X con il simulatore di iOS e dispositivi iOS liberi (vedere Figura 7). Con questo programma, è possibile eseguire tutti sviluppo e debug lavoro direttamente all'interno di Visual Studio sul PC, utilizzando il computer Mac OS X per le compilazioni iOS remoto e il debug. Archivio-ready iOS applicazioni possono quindi essere presentate anche da Macintosh.

Un ambiente di sviluppo di piattaforme comuni per i progetti di Xamarin, nonché quelle che utilizzano altre tecnologie come strumenti di Visual Studio per Apache Cordova
Figura 7 ambiente di sviluppo di piattaforme comuni per i progetti di Xamarin, nonché quelle che utilizzano altre tecnologie come strumenti di Visual Studio per Apache Cordova

Abbiamo adottato in linea di Visual Studio per la collaborazione tra team e controllo del codice sorgente e averlo configurato per eseguire le compilazioni di integrazione continuata per il back-end e il client Xamarin. Se avessimo abbiamo subito questo progetto, si sarebbero potrai utilizzare il sistema di generazione più recente in linea di Visual Studio per creare applicazioni di Xamarin direttamente nel controller di compilazione ospitato. È possibile trovare ulteriori dal nostro post di blog in tinyurl.com/kboauthxamvso. In precedenza in 2015, tuttavia, il controller di compilazione ospitato non hanno ancora questo supporto. Fortunatamente, è sufficiente, onestamente!, utilizzare un computer locale che esegue TFS come controller di compilazione per Visual Studio in linea. In tale server è stato installato libero TFS Express edition Xamarin e necessario Android e Windows platform SDK, accertandosi di inserire il SDK Android in un percorso quale c:\android-sdk, che può accedere l'account di compilazione. (Per impostazione predefinita del programma di installazione colloca SDK nell'archivio dell'utente corrente, a cui l'account di compilazione non dispone delle autorizzazioni) Questo aspetto è descritto nella documentazione di Xamarin, "Configurazione di Team Foundation Server per Xamarin," in bit.ly/1OhQPSW.

Dopo aver configurato il server di compilazione completamente, la seguente procedura effettua la connessione in linea di Visual Studio (vedere "Distribuire e configurare un Build Server" all'indirizzo bit.ly/1RJS4QL):

  1. Aprire la Console di amministrazione di TFS.
  2. Nel riquadro di spostamento sinistro, espandere il nome del server e selezionare configurazione di compilazione.
  3. Il servizio di compilazione, fare clic su proprietà per aprire la finestra di dialogo Proprietà servizio di compilazione.
  4. Fare clic su "Arresta il servizio" nella parte superiore della finestra di dialogo.
  5. In comunicazioni, nella casella di gruppo forniscono servizi di generazione per la raccolta di progetti, immettere l'URL della raccolta in linea di Visual Studio, ad esempio l'account https://<your >.visualstudio.com/defaultcollection.
  6. Fare clic sul pulsante Start nella parte inferiore della finestra di dialogo per riavviare il servizio.

Che è tutto! Quando si crea una definizione di compilazione in Visual Studio Team Explorer, la macchina TFS connessa a Visual Studio Online verrà visualizzato nell'elenco dei controller di compilazione disponibili. Selezionando opzione, le compilazioni che si mette in coda da Visual Studio o che sono in coda durante l'archiviazione instradato alla macchina TFS.

Avvolgendo

Ci auguriamo è piaciuto nostra discussione sul progetto Altostratus e che è possibile trovare il codice utile per le proprie applicazioni per dispositivi mobili, connessa al cloud. Il nostro obiettivo con questo progetto è stato ancora una volta, per fornire un chiaro esempio di un'applicazione mobile multipiattaforma con un back-end personalizzato che può eseguire un lavoro significativo per conto del client per ottimizzare il lavoro che deve essere eseguita direttamente nel client. Avendo il sempre in esecuzione il fine di raccogliere dati per conto di tutti i client, si riduce notevolmente la quantità di traffico di rete generato dal client (e l'impatto sui piani dati successiva). Per normalizzare i dati provenienti da origini diverse, è ridotto al minimo la quantità di elaborazione dei dati necessario sul client, che consente di conservare l'alimentazione a batteria mai importante. E per autenticare un utente con il back-end, si è dimostrato come sia possibile memorizzare le preferenze dell'utente non esiste e sono applicati automaticamente alle interazioni del client con il back-end, nuovamente l'ottimizzazione del traffico di rete e requisiti di elaborazione. È inteso per le nostre esigenze specifiche vi sia stata semplici per ottenere lo stesso effetto che si desidera creare un esempio che potrebbe essere scalabile per scenari più complessi.

Ci piacerebbe cosa ne pensate di questo progetto. Inviaci i tuoi commenti

Sincronizzazione non in linea di Azure

Un'alternativa all'implementazione cache offline è la sincronizzazione non in linea di Azure per le tabelle, che fa parte di servizi mobili di Azure. Questo elimina la necessità di scrivere codice sincronizzazione affatto e lavora per effettuare il push delle modifiche dal client al server. Perché utilizza l'archiviazione tabelle, tuttavia, non fornisce un modello di dati relazionali come SQLite.


Kraig Brockschmidt* funziona come uno sviluppatore di contenuti senior per Microsoft ed è incentrato sull'App mobile multipiattaforma. È l'autore di "Applicazioni di programmazione Windows Store con HTML, CSS e JavaScript" (due edizioni) da Microsoft Press e blog su kraigbrockschmidt.com.*

Mike Wasson* è uno sviluppatore di contenuti presso Microsoft. Per molti anni ha documentato le API multimediali Win32. Attualmente scrive articoli su Microsoft Azure e ASP.NET.*

Rick Anderson* funziona come un writer di programmazione senior per Microsoft, specializzato in ASP.NET MVC, Microsoft Azure ed Entity Framework. È possibile seguirlo su Twitter all'indirizzo twitter.com/RickAndMSFT.*

Erik Reitan* è uno sviluppatore di contenuti senior presso Microsoft. Si occupa in Microsoft Azure e ASP.NET. Seguirlo su Twitter all'indirizzo twitter.com/ReitanErik.*

Tom Dykstra* è uno sviluppatore di contenuti senior presso Microsoft, specializzato in Microsoft Azure e ASP.NET.*

Grazie ai seguenti esperti tecnici per la revisione di questo articolo: Michael Collier, Gaster Brady, John de Havilland, Ryan Jones, Vijay Ramakrishnan e Pranav Rastogi