De Azure Mobile Apps SDK voor Android gebruiken

In deze handleiding ziet u hoe u de Android-client-SDK gebruikt Mobile Apps voor het implementeren van algemene scenario's, zoals:

  • Query's uitvoeren op gegevens (invoegen, bijwerken en verwijderen).
  • Verificatie.
  • Fouten afhandelen.
  • De client aanpassen.

Deze handleiding is gericht op de Android SDK aan de clientzijde. Zie Work with .NET backend SDK (Werken met .NET back-end S Mobile Apps DK ) of How to use the Node.js backend SDK (Werken met .NET back-end-SDK) voor meer informatie over de SDK's aan de serverzijde voor Node.js.

Referentiedocumentatie

U vindt de Javadocs API-verwijzing voor de Android-clientbibliotheek op GitHub.

Ondersteunde platformen

De Azure Mobile Apps-SDK voor Android ondersteunt API-niveaus 19 tot en met 24 (KitKat via Nougat) voor formulierfactoren voor telefoons en tablets. Verificatie maakt met name gebruik van een algemene web framework-benadering voor het verzamelen van referenties. Verificatie van serverstromen werkt niet met kleine apparaten met een kleine vormfactor, zoals een horloge.

Installatie en vereisten

Voltooi de Mobile Apps quickstart . Deze taak zorgt ervoor dat aan alle vereisten voor het ontwikkelen van Azure-Mobile Apps is voldaan. De quickstart helpt u ook bij het configureren van uw account en het maken van uw eerste back-end voor mobiele apps.

Als u besluit de quickstart-zelfstudie niet te voltooien, moet u de volgende taken uitvoeren:

Het Gradle-buildbestand bijwerken

Wijzig beide build.gradle-bestanden :

  1. Voeg deze code toe aan Projectbuild.gradle-bestand op Project niveau:

    buildscript {
        repositories {
            jcenter()
            google()
        }
    }
    
    allprojects {
        repositories {
            jcenter()
            google()
        }
    }
    
  2. Voeg deze code toe aan het build.gradle-bestand op module-app-niveau in de tag dependencies:

    implementation 'com.microsoft.azure:azure-mobile-android:3.4.0@aar'
    

    Momenteel is de meest recente versie 3.4.0. De ondersteunde versies worden vermeld in bintray.

Internetmachtiging inschakelen

Voor toegang tot Azure moet de machtiging INTERNET zijn ingeschakeld voor uw app. Als deze nog niet is ingeschakeld, voegt u de volgende coderegel toe aan uw AndroidManifest.xml bestand:

<uses-permission android:name="android.permission.INTERNET" />

Een clientverbinding maken

Azure Mobile Apps biedt vier functies voor uw mobiele toepassing:

  • Gegevenstoegang en offlinesynchronisatie met een Azure Mobile Apps Service.
  • Roep aangepaste API's aan die zijn geschreven met de Azure Mobile Apps Server SDK.
  • Verificatie met Azure App Service verificatie en autorisatie.
  • Registratie van pushmeldingen met Notification Hubs.

Voor elk van deze functies moet u eerst een MobileServiceClient -object maken. Er mag MobileServiceClient slechts één object worden gemaakt binnen uw mobiele client (dat wil zeggen, het moet een Singleton-patroon zijn). Een object MobileServiceClient maken:

MobileServiceClient mClient = new MobileServiceClient(
    "<MobileAppUrl>",       // Replace with the Site URL
    this);                  // Your application Context

De <MobileAppUrl> is een tekenreeks of een URL-object dat naar uw mobiele back-end wijst. Als u gebruik Azure App Service voor het hosten van uw mobiele back-end, moet u ervoor zorgen dat u de https:// beveiligde versie van de URL gebruikt.

De client vereist ook toegang tot de activiteit of context: de this parameter in het voorbeeld. De Constructie van MobileServiceClient moet plaatsvinden binnen de methode onCreate() van de activiteit waarnaar in het bestand wordt AndroidManifest.xml verwezen.

Als best practice moet u servercommunicatie abstraheeren in een eigen klasse (singleton-pattern). In dit geval moet u de activiteit binnen de constructor doorgeven om de service op de juiste wijze te configureren. Bijvoorbeeld:

package com.example.appname.services;

import android.content.Context;
import com.microsoft.windowsazure.mobileservices.*;

public class AzureServiceAdapter {
    private String mMobileBackendUrl = "https://myappname.azurewebsites.net";
    private Context mContext;
    private MobileServiceClient mClient;
    private static AzureServiceAdapter mInstance = null;

    private AzureServiceAdapter(Context context) {
        mContext = context;
        mClient = new MobileServiceClient(mMobileBackendUrl, mContext);
    }

    public static void Initialize(Context context) {
        if (mInstance == null) {
            mInstance = new AzureServiceAdapter(context);
        } else {
            throw new IllegalStateException("AzureServiceAdapter is already initialized");
        }
    }

    public static AzureServiceAdapter getInstance() {
        if (mInstance == null) {
            throw new IllegalStateException("AzureServiceAdapter is not initialized");
        }
        return mInstance;
    }

    public MobileServiceClient getClient() {
        return mClient;
    }

    // Place any public methods that operate on mClient here.
}

U kunt nu aanroepen AzureServiceAdapter.Initialize(this); in de onCreate() methode van uw hoofdactiviteit. Andere methoden die toegang tot de client nodig hebben, gebruiken om AzureServiceAdapter.getInstance(); een verwijzing naar de serviceadapter te verkrijgen.

Gegevensbewerkingen

De kern van de Azure Mobile Apps SDK is het bieden van toegang tot gegevens die zijn opgeslagen in SQL Azure back-end van de mobiele app. U hebt toegang tot deze gegevens met behulp van sterk getypte klassen (voorkeur) of niet-getypeerd query's (niet aanbevolen). Het merendeel van deze sectie gaat over het gebruik van sterk getypeerd klassen.

Clientgegevensklassen definiëren

Voor toegang tot gegevens uit SQL Azure tabellen definieert u clientgegevensklassen die overeenkomen met de tabellen in de back-end van de mobiele app. In voorbeelden in dit onderwerp wordt ervan uitgenomen dat een tabel met de naam MyDataTable de volgende kolommen heeft:

  • id
  • tekst
  • voltooid

Het bijbehorende getypeerd object aan de clientzijde bevindt zich in een bestand met de naam MyDataTable.java:

public class ToDoItem {
    private String id;
    private String text;
    private Boolean complete;
}

Voeg getter- en settermethoden toe voor elk veld dat u toevoegt. Als uw SQL Azure meer kolommen bevat, voegt u de bijbehorende velden toe aan deze klasse. Als de DTO (object voor gegevensoverdracht) bijvoorbeeld een geheel getal prioriteitskolom heeft, kunt u dit veld toevoegen, samen met de getter- en settermethoden:

private Integer priority;

/**
* Returns the item priority
*/
public Integer getPriority() {
    return mPriority;
}

/**
* Sets the item priority
*
* @param priority
*            priority to set
*/
public final void setPriority(Integer priority) {
    mPriority = priority;
}

Zie How to: Define a table controller (.NET backend) (Een tabelcontroller definiëren (.NET-back-end) of Define Tables using a Dynamic Schema (Node.js back-end) voor meer informatie over het maken van aanvullende tabellen in uw Mobile Apps-back-end.

Een Azure Mobile Apps back-endtabel definieert vijf speciale velden, waarvan er vier beschikbaar zijn voor clients:

  • String id: De wereldwijd unieke id voor de record. Maak als best practice id de tekenreeksweergave van een UUID-object .
  • DateTimeOffset updatedAt: De datum/tijd van de laatste update. Het veld updatedAt wordt ingesteld door de server en mag nooit worden ingesteld door uw clientcode.
  • DateTimeOffset createdAt: De datum/tijd waarop het object is gemaakt. Het veld createdAt wordt ingesteld door de server en mag nooit worden ingesteld door uw clientcode.
  • byte[] version: Normaal gesproken weergegeven als een tekenreeks, wordt de versie ook ingesteld door de server.
  • boolean deleted: Geeft aan dat de record is verwijderd, maar nog niet is verwijderd. Gebruik niet als deleted een eigenschap in uw klasse.

Het veld id is vereist. Het updatedAt veld en het version veld worden gebruikt voor offline synchronisatie (respectievelijk voor incrementele synchronisatie en conflictoplossing). Het createdAt veld is een referentieveld en wordt niet gebruikt door de client. De namen zijn 'over-the-wire' namen van de eigenschappen en zijn niet aanpasbaar. U kunt echter een toewijzing maken tussen uw object en de 'across-the-wire'-namen met behulp van de gson-bibliotheek . Bijvoorbeeld:

package com.example.zumoappname;

import com.microsoft.windowsazure.mobileservices.table.DateTimeOffset;

public class ToDoItem
{
    @com.google.gson.annotations.SerializedName("id")
    private String mId;
    public String getId() { return mId; }
    public final void setId(String id) { mId = id; }

    @com.google.gson.annotations.SerializedName("complete")
    private boolean mComplete;
    public boolean isComplete() { return mComplete; }
    public void setComplete(boolean complete) { mComplete = complete; }

    @com.google.gson.annotations.SerializedName("text")
    private String mText;
    public String getText() { return mText; }
    public final void setText(String text) { mText = text; }

    @com.google.gson.annotations.SerializedName("createdAt")
    private DateTimeOffset mCreatedAt;
    public DateTimeOffset getCreatedAt() { return mCreatedAt; }
    protected void setCreatedAt(DateTimeOffset createdAt) { mCreatedAt = createdAt; }

    @com.google.gson.annotations.SerializedName("updatedAt")
    private DateTimeOffset mUpdatedAt;
    public DateTimeOffset getUpdatedAt() { return mUpdatedAt; }
    protected void setUpdatedAt(DateTimeOffset updatedAt) { mUpdatedAt = updatedAt; }

    @com.google.gson.annotations.SerializedName("version")
    private String mVersion;
    public String getVersion() { return mVersion; }
    public final void setVersion(String version) { mVersion = version; }

    public ToDoItem() { }

    public ToDoItem(String id, String text) {
        this.setId(id);
        this.setText(text);
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof ToDoItem && ((ToDoItem) o).mId == mId;
    }

    @Override
    public String toString() {
        return getText();
    }
}

Een tabelverwijzing maken

Als u toegang wilt krijgen tot een tabel, maakt u eerst een MobileServiceTable-object door de methode getTable op de MobileServiceClient aan te roepen. Deze methode heeft twee overloads:

public class MobileServiceClient {
    public <E> MobileServiceTable<E> getTable(Class<E> clazz);
    public <E> MobileServiceTable<E> getTable(String name, Class<E> clazz);
}

In de volgende code is mClient een verwijzing naar uw MobileServiceClient-object. De eerste overbelasting wordt gebruikt wanneer de klassenaam en de tabelnaam hetzelfde zijn en de naam die wordt gebruikt in de quickstart:

MobileServiceTable<ToDoItem> mToDoTable = mClient.getTable(ToDoItem.class);

De tweede overbelasting wordt gebruikt wanneer de tabelnaam verschilt van de klassenaam: de eerste parameter is de tabelnaam.

MobileServiceTable<ToDoItem> mToDoTable = mClient.getTable("ToDoItemBackup", ToDoItem.class);

Een query uitvoeren op een back-endtabel

Verkrijg eerst een tabelverwijzing. Voer vervolgens een query uit op de tabelverwijzing. Een query is een combinatie van:

De -component moet in de voorgaande volgorde worden weergegeven.

Filterresultaten

De algemene vorm van een query is:

List<MyDataTable> results = mDataTable
    // More filters here
    .execute()          // Returns a ListenableFuture<E>
    .get()              // Converts the async into a sync result

Het voorgaande voorbeeld retourneert alle resultaten (tot de maximale paginagrootte die is ingesteld door de server). Met .execute() de methode wordt de query uitgevoerd op de back-end. De query wordt geconverteerd naar een OData v3-query voordat deze wordt Mobile Apps back-end. Bij ontvangst converteert Mobile Apps back-SQL query naar een SQL-instructie voordat deze wordt uitgevoerd op het SQL Azure exemplaar. Omdat netwerkactiviteit enige tijd in duren, retourneert de .execute() methode een ListenableFuture<E>.

Geretourneerde gegevens filteren

De volgende queryuitvoering retourneert alle items uit de tabel ToDoItem , waarbij complete gelijk is aan false.

List<ToDoItem> result = mToDoTable
    .where()
    .field("complete").eq(false)
    .execute()
    .get();

mToDoTable is de verwijzing naar de tabel voor mobiele service die we eerder hebben gemaakt.

Definieer een filter met behulp van de methode where-aanroep voor de tabelverwijzing. De methode where wordt gevolgd door een veldmethode gevolgd door een methode waarmee het logische predicaat wordt opgegeven. Mogelijke predicaatmethoden zijn eq (is gelijk aan), ne (niet gelijk aan), gt (groter dan), ge (groter dan of gelijk aan), lt (kleiner dan), le (kleiner dan of gelijk aan). Met deze methoden kunt u getal- en tekenreeksvelden vergelijken met specifieke waarden.

U kunt filteren op datums. Met de volgende methoden kunt u het hele datumveld of delen van de datum vergelijken: jaar, maand, dag, uur, minuut en seconde. In het volgende voorbeeld wordt een filter toegevoegd voor items waarvan de einddatum gelijk is aan 2013.

List<ToDoItem> results = MToDoTable
    .where()
    .year("due").eq(2013)
    .execute()
    .get();

De volgende methoden ondersteunen complexe filters voor tekenreeksvelden: startsWith, endsWith, concat, subString, indexOf, replace, toLower, toUpper, trim en length. In het volgende voorbeeld wordt gefilterd op tabelrijen waarbij de tekstkolom begint met PRI0.

List<ToDoItem> results = mToDoTable
    .where()
    .startsWith("text", "PRI0")
    .execute()
    .get();

De volgende operatormethoden worden ondersteund op getalvelden: add, sub, mul, div, mod, floor, ceiling en round. In het volgende voorbeeld wordt gefilterd op tabelrijen waarbij de duur een even getal is.

List<ToDoItem> results = mToDoTable
    .where()
    .field("duration").mod(2).eq(0)
    .execute()
    .get();

U kunt predicaten combineren met deze logische methoden: en, of enniet. In het volgende voorbeeld worden twee van de voorgaande voorbeelden gecombineerd.

List<ToDoItem> results = mToDoTable
    .where()
    .year("due").eq(2013).and().startsWith("text", "PRI0")
    .execute()
    .get();

Logische operators groepen en nesten:

List<ToDoItem> results = mToDoTable
    .where()
    .year("due").eq(2013)
    .and(
        startsWith("text", "PRI0")
        .or()
        .field("duration").gt(10)
    )
    .execute().get();

Zie Exploring the richness of the Android client query model (De uitgebreidheid van het Android-clientquerymodel verkennen) voor gedetailleerdere discussies en voorbeelden van filteren.

Geretourneerde gegevens sorteren

De volgende code retourneert alle items uit een tabel met ToDoItems , oplopend gesorteerd op het tekstveld . mToDoTable is de verwijzing naar de back-endtabel die u eerder hebt gemaakt:

List<ToDoItem> results = mToDoTable
    .orderBy("text", QueryOrder.Ascending)
    .execute()
    .get();

De eerste parameter van de methode orderBy is een tekenreeks die gelijk is aan de naam van het veld waarop moet worden gesorteerd. De tweede parameter gebruikt de queryorder-enumeratie om op te geven of oplopend of aflopend moet worden gesorteerd. Als u filtert met behulp van de methode where , moet de methode where worden aangeroepen vóór de methode orderBy .

Specifieke kolommen selecteren

De volgende code laat zien hoe u alle items uit een tabel met ToDoItems retourneert, maar alleen de volledige velden en tekstvelden weest. mToDoTable is de verwijzing naar de back-endtabel die we eerder hebben gemaakt.

List<ToDoItemNarrow> result = mToDoTable
    .select("complete", "text")
    .execute()
    .get();

De parameters voor de select-functie zijn de tekenreeksnamen van de kolommen van de tabel die u wilt retourneren. De select-methode moet methoden volgen zoals where en orderBy. Dit kan worden gevolgd door pagineringsmethoden zoals skip en top.

Gegevens retourneren op pagina's

Gegevens worden ALTIJD geretourneerd op pagina's. Het maximum aantal records dat wordt geretourneerd, wordt ingesteld door de server. Als de client meer records aanvraagt, retourneert de server het maximum aantal records. Standaard is de maximale paginagrootte op de server 50 records.

In het eerste voorbeeld ziet u hoe u de top vijf items uit een tabel selecteert. De query retourneert de items uit een tabel met ToDoItems. mToDoTable is de verwijzing naar de back-endtabel die u eerder hebt gemaakt:

List<ToDoItem> result = mToDoTable
    .top(5)
    .execute()
    .get();

Hier is een query die de eerste vijf items overslaat en vervolgens de volgende vijf retourneert:

List<ToDoItem> result = mToDoTable
    .skip(5).top(5)
    .execute()
    .get();

Als u alle records in een tabel wilt op halen, implementeert u code om alle pagina's te itereren:

List<MyDataModel> results = new ArrayList<>();
int nResults;
do {
    int currentCount = results.size();
    List<MyDataModel> pagedResults = mDataTable
        .skip(currentCount).top(500)
        .execute().get();
    nResults = pagedResults.size();
    if (nResults > 0) {
        results.addAll(pagedResults);
    }
} while (nResults > 0);

Met een aanvraag voor alle records die deze methode gebruiken, worden minimaal twee aanvragen voor de Mobile Apps back-Mobile Apps gemaakt.

Tip

Het kiezen van de juiste paginagrootte is een balans tussen het geheugengebruik terwijl de aanvraag zich voordeed, bandbreedtegebruik en vertraging bij het volledig ontvangen van de gegevens. De standaardwaarde (50 records) is geschikt voor alle apparaten. Als u uitsluitend werkt op grotere geheugenapparaten, verhoogt u tot 500. We hebben geconstateerd dat het vergroten van de paginagrootte tot meer dan 500 records leidt tot onacceptabele vertragingen en grote geheugenproblemen.

Hoe: Querymethoden samenvoegen

De methoden die worden gebruikt voor het uitvoeren van query's op back-endtabellen kunnen worden samenvoegd. Door querymethoden te ketenen, kunt u specifieke kolommen met gefilterde rijen selecteren die worden gesorteerd en gepagina's worden weergegeven. U kunt complexe logische filters maken. Elke querymethode retourneert een Query-object. Als u de reeks methoden wilt beëindigen en de query daadwerkelijk wilt uitvoeren, roept u de methode execute aan. Bijvoorbeeld:

List<ToDoItem> results = mToDoTable
        .where()
        .year("due").eq(2013)
        .and(
            startsWith("text", "PRI0").or().field("duration").gt(10)
        )
        .orderBy(duration, QueryOrder.Ascending)
        .select("id", "complete", "text", "duration")
        .skip(200).top(100)
        .execute()
        .get();

De ketenquerymethoden moeten als volgt worden geordend:

  1. Filteren (waar) methoden.
  2. Sorteringsmethoden (orderBy).
  3. Selectiemethoden (selecteren).
  4. pagineringsmethoden (overslaan en bovenaan).

Gegevens verbinden met de gebruikersinterface

Gegevensbinding omvat drie onderdelen:

  • De gegevensbron
  • De schermindeling
  • De adapter die de twee met elkaar verbindt.

In onze voorbeeldcode retourneren we de gegevens uit de Mobile Apps SQL Azure tabel ToDoItem in een matrix. Deze activiteit is een algemeen patroon voor gegevenstoepassingen. Databasequery's retourneren vaak een verzameling rijen die de client in een lijst of matrix krijgt. In dit voorbeeld is de matrix de gegevensbron. De code geeft een schermindeling aan die de weergave definieert van de gegevens die op het apparaat worden weergegeven. De twee zijn verbonden met een adapter, die in deze code een uitbreiding is van de klasse ArrayAdapterToDoItem<>.

De indeling definiëren

De indeling wordt gedefinieerd door verschillende codefragmenten van XML. Gezien een bestaande indeling vertegenwoordigt de volgende code de ListView die we willen vullen met onze servergegevens.

    <ListView
        android:id="@+id/listViewToDo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:listitem="@layout/row_list_to_do" >
    </ListView>

In de voorgaande code geeft het listitem-kenmerk de id van de indeling voor een afzonderlijke rij in de lijst op. Deze code geeft een selectievakje en de bijbehorende tekst aan en wordt eenmaal voor elk item in de lijst gemaakt. In deze indeling wordt het id-veld niet weergegeven en in een complexere indeling worden aanvullende velden in de weergave opgegeven. Deze code staat in het row_list_to_do.xml bestand.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <CheckBox
        android:id="@+id/checkToDoItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/checkbox_text" />
</LinearLayout>

De adapter definiëren

Omdat de gegevensbron van onze weergave een matrix van ToDoItem is, wordt de adapter in een subklasse van een ArrayAdapterToDoItem-klasse<> geclassificeerd. Deze subklasse produceert een weergave voor elke ToDoItem met behulp van row_list_to_do indeling. In onze code definiëren we de volgende klasse die een uitbreiding is van de klasse ArrayAdapterE<>:

public class ToDoItemAdapter extends ArrayAdapter<ToDoItem> {
}

Overschrijven de adapters getView-methode . Bijvoorbeeld:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;

        final ToDoItem currentItem = getItem(position);

        if (row == null) {
            LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
            row = inflater.inflate(R.layout.row_list_to_do, parent, false);
        }
        row.setTag(currentItem);

        final CheckBox checkBox = (CheckBox) row.findViewById(R.id.checkToDoItem);
        checkBox.setText(currentItem.getText());
        checkBox.setChecked(false);
        checkBox.setEnabled(true);

        checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                if (checkBox.isChecked()) {
                    checkBox.setEnabled(false);
                    if (mContext instanceof ToDoActivity) {
                        ToDoActivity activity = (ToDoActivity) mContext;
                        activity.checkItem(currentItem);
                    }
                }
            }
        });
        return row;
    }

We maken als volgt een exemplaar van deze klasse in onze activiteit:

    ToDoItemAdapter mAdapter;
    mAdapter = new ToDoItemAdapter(this, R.layout.row_list_to_do);

De tweede parameter voor de constructor ToDoItemAdapter is een verwijzing naar de indeling. We kunnen nu een instantie van de ListView maken en de adapter toewijzen aan de ListView.

    ListView listViewToDo = (ListView) findViewById(R.id.listViewToDo);
    listViewToDo.setAdapter(mAdapter);

De adapter gebruiken om te verbinden met de gebruikersinterface

U bent nu klaar om gegevensbinding te gebruiken. De volgende code laat zien hoe u items in de tabel op kunt halen en de lokale adapter vult met de geretourneerde items.

    public void showAll(View view) {
        AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    final List<ToDoItem> results = mToDoTable.execute().get();
                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            mAdapter.clear();
                            for (ToDoItem item : results) {
                                mAdapter.add(item);
                            }
                        }
                    });
                } catch (Exception exception) {
                    createAndShowDialog(exception, "Error");
                }
                return null;
            }
        };
        runAsyncTask(task);
    }

Roep de adapter aan wanneer u de ToDoItem-tabel wijzigt. Omdat wijzigingen per record worden uitgevoerd, verwerkt u één rij in plaats van een verzameling. Wanneer u een item invoegt, roept u de methode toevoegen aan op de adapter; Roep bij het verwijderen de methode remove aan .

U vindt een volledig voorbeeld in de Android-snelstart Project.

Gegevens invoegen in de back-end

Instantieer een exemplaar van de klasse ToDoItem en stel de eigenschappen ervan in.

ToDoItem item = new ToDoItem();
item.text = "Test Program";
item.complete = false;

Gebruik vervolgens insert() om een object in te voegen:

ToDoItem entity = mToDoTable
    .insert(item)       // Returns a ListenableFuture<ToDoItem>
    .get();

De geretourneerde entiteit komt overeen met de gegevens die in de back-endtabel zijn ingevoegd, inclusief de id en eventuele andere waarden (createdAtzoals de velden , updatedAtversion en) die zijn ingesteld op de back-end.

Mobile Apps tabellen is een primaire sleutelkolom met de naam id vereist. Deze kolom moet een tekenreeks zijn. De standaardwaarde van de kolom ID is een GUID. U kunt andere unieke waarden, zoals e-mailadressen of gebruikersnamen, verstrekken. Wanneer er geen tekenreeks-id wordt opgegeven voor een ingevoegde record, genereert de back-end een nieuwe GUID.

Tekenreeks-id-waarden bieden de volgende voordelen:

  • ID's kunnen worden gegenereerd zonder een retour naar de database te maken.
  • Records zijn gemakkelijker samen te voegen vanuit verschillende tabellen of databases.
  • Id-waarden kunnen beter worden geïntegreerd met de logica van een toepassing.

Tekenreeks-id-waarden zijn VEREIST voor offline synchronisatieondersteuning. U kunt een id niet meer wijzigen zodra deze is opgeslagen in de back-enddatabase.

Gegevens bijwerken in een mobiele app

Als u gegevens in een tabel wilt bijwerken, geeft u het nieuwe object door aan de update()- methode.

mToDoTable
    .update(item)   // Returns a ListenableFuture<ToDoItem>
    .get();

In dit voorbeeld is item een verwijzing naar een rij in de tabel ToDoItem , waarin enkele wijzigingen zijn aangebracht. De rij met dezelfde id wordt bijgewerkt.

Gegevens verwijderen in een mobiele app

De volgende code laat zien hoe u gegevens uit een tabel verwijdert door het gegevensobject op te geven.

mToDoTable
    .delete(item);

U kunt een item ook verwijderen door het id-veld op te geven van de rij die u wilt verwijderen.

String myRowId = "2FA404AB-E458-44CD-BC1B-3BC847EF0902";
mToDoTable
    .delete(myRowId);

Een specifiek item zoeken op id

Zoek een item met een specifiek id-veld met de lookUp()- methode:

ToDoItem result = mToDoTable
    .lookUp("0380BAFB-BCFF-443C-B7D5-30199F730335")
    .get();

Werken met niet-getypte gegevens

Het niet-getypeerd programmeermodel geeft u exacte controle over JSON-serialisatie. Er zijn enkele veelvoorkomende scenario's waarin u mogelijk een niet-getypeerd programmeermodel wilt gebruiken. Als uw back-endtabel bijvoorbeeld veel kolommen bevat en u alleen hoeft te verwijzen naar een subset van de kolommen. Voor het getypeerd model moet u alle kolommen definiëren die in de back-Mobile Apps in uw gegevensklasse zijn gedefinieerd. De meeste API-aanroepen voor toegang tot gegevens zijn vergelijkbaar met de getypte programmeeroproepen. Het belangrijkste verschil is dat u in het niet-getypte model methoden aanroept voor het object MobileServiceJsonTable in plaats van het object MobileServiceTable .

Een exemplaar van een niet-getypte tabel maken

Net als bij het getypeerd model begint u met het verkrijgen van een tabelverwijzing, maar in dit geval is het een MobileServicesJsonTable-object . Haal de verwijzing op door de methode getTable aan te roepen op een exemplaar van de client:

private MobileServiceJsonTable mJsonToDoTable;
//...
mJsonToDoTable = mClient.getTable("ToDoItem");

Zodra u een instantie van de MobileServiceJsonTable hebt gemaakt, is vrijwel dezelfde API beschikbaar als bij het getypeerd programmeermodel. In sommige gevallen gebruiken de methoden een niet-getypte parameter in plaats van een getypeerd parameter.

Invoegen in een niet-getypte tabel

De volgende code laat zien hoe u een invoeging kunt uitvoeren. De eerste stap is het maken van een JsonObject, dat deel uitmaakt van de gson-bibliotheek .

JsonObject jsonItem = new JsonObject();
jsonItem.addProperty("text", "Wake up");
jsonItem.addProperty("complete", false);

Gebruik vervolgens insert() om het niet-getypte object in de tabel in te voegen.

JsonObject insertedItem = mJsonToDoTable
    .insert(jsonItem)
    .get();

Als u de id van het ingevoegde object wilt weten, gebruikt u de methode getAsJsonPrimitive( ).

String id = insertedItem.getAsJsonPrimitive("id").getAsString();

Verwijderen uit een niet-getypte tabel

De volgende code laat zien hoe u een exemplaar verwijdert, in dit geval hetzelfde exemplaar van een JsonObject dat is gemaakt in het vorige invoegvoorbeeld . De code is hetzelfde als bij de getypte case, maar de methode heeft een andere handtekening omdat deze verwijst naar een JsonObject.

mToDoTable
    .delete(insertedItem);

U kunt een exemplaar ook rechtstreeks verwijderen met behulp van de id:

mToDoTable.delete(ID);

Alle rijen uit een niet-getypte tabel retourneren

De volgende code laat zien hoe u een hele tabel kunt ophalen. Omdat u een JSON-tabel gebruikt, kunt u slechts enkele kolommen van de tabel selectief ophalen.

public void showAllUntyped(View view) {
    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            try {
                final JsonElement result = mJsonToDoTable.execute().get();
                final JsonArray results = result.getAsJsonArray();
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        mAdapter.clear();
                        for (JsonElement item : results) {
                            String ID = item.getAsJsonObject().getAsJsonPrimitive("id").getAsString();
                            String mText = item.getAsJsonObject().getAsJsonPrimitive("text").getAsString();
                            Boolean mComplete = item.getAsJsonObject().getAsJsonPrimitive("complete").getAsBoolean();
                            ToDoItem mToDoItem = new ToDoItem();
                            mToDoItem.setId(ID);
                            mToDoItem.setText(mText);
                            mToDoItem.setComplete(mComplete);
                            mAdapter.add(mToDoItem);
                        }
                    }
                });
            } catch (Exception exception) {
                createAndShowDialog(exception, "Error");
            }
            return null;
        }
    }.execute();
}

Dezelfde set filter-, filter- en pagineringsmethoden die beschikbaar zijn voor het getypeerd model zijn beschikbaar voor het niet-getypeerd model.

Offlinesynchronisatie implementeren

De Azure Mobile Apps Client SDK implementeert ook offline synchronisatie van gegevens met behulp van een SQLite-database om een kopie van de servergegevens lokaal op te slaan. Voor bewerkingen die worden uitgevoerd op een offlinetabel, is geen mobiele verbinding vereist. Offlinesynchronisatie helpt bij tolerantie en prestaties, ten koste van complexere logica voor conflictoplossing. De Azure Mobile Apps Client SDK implementeert de volgende functies:

  • Incrementele synchronisatie: alleen bijgewerkte en nieuwe records worden gedownload, waardoor bandbreedte en geheugenverbruik worden bespaart.
  • Optimistische gelijktijdigheid: Er wordt van uitgegaan dat bewerkingen slagen. Conflictoplossing wordt uitgesteld totdat updates op de server worden uitgevoerd.
  • Conflictoplossing: de SDK detecteert wanneer er een conflicterende wijziging is aangebracht op de server en biedt hooks om de gebruiker te waarschuwen.
  • Soft Delete: verwijderde records worden gemarkeerd als verwijderd, zodat andere apparaten hun offline cache kunnen bijwerken.

Offlinesynchronisatie initialiseren

Elke offlinetabel moet worden gedefinieerd in de offlinecache vóór gebruik. Normaal gesproken wordt de tabeldefinitie direct na het maken van de client uitgevoerd:

AsyncTask<Void, Void, Void> initializeStore(MobileServiceClient mClient)
    throws MobileServiceLocalStoreException, ExecutionException, InterruptedException
{
    AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
        @Override
        protected void doInBackground(Void... params) {
            try {
                MobileServiceSyncContext syncContext = mClient.getSyncContext();
                if (syncContext.isInitialized()) {
                    return null;
                }
                SQLiteLocalStore localStore = new SQLiteLocalStore(mClient.getContext(), "offlineStore", null, 1);

                // Create a table definition.  As a best practice, store this with the model definition and return it via
                // a static method
                Map<String, ColumnDataType> toDoItemDefinition = new HashMap<String, ColumnDataType>();
                toDoItemDefinition.put("id", ColumnDataType.String);
                toDoItemDefinition.put("complete", ColumnDataType.Boolean);
                toDoItemDefinition.put("text", ColumnDataType.String);
                toDoItemDefinition.put("version", ColumnDataType.String);
                toDoItemDefinition.put("updatedAt", ColumnDataType.DateTimeOffset);

                // Now define the table in the local store
                localStore.defineTable("ToDoItem", toDoItemDefinition);

                // Specify a sync handler for conflict resolution
                SimpleSyncHandler handler = new SimpleSyncHandler();

                // Initialize the local store
                syncContext.initialize(localStore, handler).get();
            } catch (final Exception e) {
                createAndShowDialogFromTask(e, "Error");
            }
            return null;
        }
    };
    return runAsyncTask(task);
}

Een verwijzing naar de offlinecachetabel verkrijgen

Voor een onlinetabel gebruikt u .getTable(). Gebruik voor een offlinetabel .getSyncTable():

MobileServiceSyncTable<ToDoItem> mToDoTable = mClient.getSyncTable("ToDoItem", ToDoItem.class);

Alle methoden die beschikbaar zijn voor onlinetabellen (inclusief filteren, sorteren, pagineren, gegevens invoegen, gegevens bijwerken en verwijderen) werken net zo goed voor online- en offlinetabellen.

De lokale offlinecache synchroniseren

Synchronisatie valt onder het beheer van uw app. Hier is een voorbeeld van een synchronisatiemethode:

private AsyncTask<Void, Void, Void> sync(MobileServiceClient mClient) {
    AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>(){
        @Override
        protected Void doInBackground(Void... params) {
            try {
                MobileServiceSyncContext syncContext = mClient.getSyncContext();
                syncContext.push().get();
                mToDoTable.pull(null, "todoitem").get();
            } catch (final Exception e) {
                createAndShowDialogFromTask(e, "Error");
            }
            return null;
        }
    };
    return runAsyncTask(task);
}

Als er een querynaam wordt .pull(query, queryname) opgegeven voor de methode, wordt incrementele synchronisatie gebruikt om alleen records te retourneren die zijn gemaakt of gewijzigd sinds de laatste voltooide pull.

Conflicten afhandelen tijdens offline synchronisatie

Als er tijdens een bewerking een .push() conflict wordt veroorzaakt, wordt MobileServiceConflictException er een veroorzaakt. Het door de server uitgegeven item is ingesloten in de uitzondering en kan worden opgehaald door .getItem() bij de uitzondering. Pas de push aan door de volgende items aan te roepen op het object MobileServiceSyncContext:

  • .cancelAndDiscardItem()
  • .cancelAndUpdateItem()
  • .updateOperationAndItem()

Zodra alle conflicten zijn gemarkeerd zoals u wilt, roept u .push() opnieuw aan om alle conflicten op te lossen.

Een aangepaste API aanroepen

Met een aangepaste API kunt u aangepaste eindpunten definiëren die serverfunctionaliteit beschikbaar stellen die niet is toe te voegen aan een invoeg-, update-, verwijder- of leesbewerking. Met behulp van een aangepaste API hebt u meer controle over berichten, waaronder het lezen en instellen van HTTP-berichtheaders en het definiëren van een andere berichttekstindeling dan JSON.

Vanuit een Android-client roept u de invokeApi-methode aan om het aangepaste API-eindpunt aan te roepen. In het volgende voorbeeld ziet u hoe u een API-eindpunt met de naam completeAll aanroept, dat een verzamelingsklasse met de naam MarkAllResult retourneert.

public void completeItem(View view) {
    ListenableFuture<MarkAllResult> result = mClient.invokeApi("completeAll", MarkAllResult.class);
    Futures.addCallback(result, new FutureCallback<MarkAllResult>() {
        @Override
        public void onFailure(Throwable exc) {
            createAndShowDialog((Exception) exc, "Error");
        }

        @Override
        public void onSuccess(MarkAllResult result) {
            createAndShowDialog(result.getCount() + " item(s) marked as complete.", "Completed Items");
            refreshItemsFromTable();
        }
    });
}

De invokeApi-methode wordt aangeroepen op de client, die een POST-aanvraag naar de nieuwe aangepaste API verzendt. Het resultaat dat door de aangepaste API wordt geretourneerd, wordt weergegeven in een berichtvenster, net als eventuele fouten. Met andere versies van invokeApi kunt u eventueel een object in de aanvraag body verzenden, de HTTP-methode opgeven en queryparameters verzenden met de aanvraag. Untyped versies van invokeApi worden ook geleverd.

Verificatie toevoegen aan uw app

In zelfstudies wordt al in detail beschreven hoe u deze functies toevoegt.

App Service biedt ondersteuning voor het verifiëren van app-gebruikers met behulp van verschillende externe id-providers: Facebook, Google, Microsoft-account, Twitter en Azure Active Directory. U kunt machtigingen voor tabellen instellen om de toegang voor specifieke bewerkingen te beperken tot alleen geverifieerde gebruikers. U kunt ook de identiteit van geverifieerde gebruikers gebruiken om autorisatieregels in uw back-end te implementeren.

Er worden twee verificatiestromen ondersteund: een serverstroom en een clientstroom . De serverstroom biedt de eenvoudigste verificatie-ervaring, omdat deze afhankelijk is van de webinterface van id-providers. Er zijn geen extra SDK's vereist voor het implementeren van serverstroomverificatie. Verificatie van serverstromen biedt geen diepgaande integratie in het mobiele apparaat en wordt alleen aanbevolen voor proof-of-concept-scenario's.

De clientstroom maakt een uitgebreidere integratie mogelijk met apparaatspecifieke mogelijkheden, zoals een aanmelding, omdat deze afhankelijk is van SDK's die worden geleverd door de id-provider. U kunt bijvoorbeeld de Facebook-SDK integreren in uw mobiele toepassing. De mobiele client wordt overgewisseld naar de Facebook-app en bevestigt uw aanmelding voordat u terugwisselt naar uw mobiele app.

Er zijn vier stappen vereist om verificatie in te schakelen in uw app:

  • Registreer uw app voor verificatie bij een id-provider.
  • Configureer App Service back-end.
  • Beperk tabelmachtigingen alleen voor geverifieerde gebruikers op App Service back-App Service.
  • Voeg verificatiecode toe aan uw app.

U kunt machtigingen voor tabellen instellen om de toegang voor specifieke bewerkingen te beperken tot alleen geverifieerde gebruikers. U kunt ook de SID van een geverifieerde gebruiker gebruiken om aanvragen te wijzigen. Voor meer informatie bekijkt u Aan de slag met verificatie en de documentatie server-SDK-HOWTO.

Verificatie: Server Flow

Met de volgende code wordt een aanmeldingsproces voor de serverstroom gestart met behulp van de Google-provider. Aanvullende configuratie is vereist vanwege de beveiligingsvereisten voor de Google-provider:

MobileServiceUser user = mClient.login(MobileServiceAuthenticationProvider.Google, "{url_scheme_of_your_app}", GOOGLE_LOGIN_REQUEST_CODE);

Voeg bovendien de volgende methode toe aan de hoofdklasse Activiteit:

// You can choose any unique number here to differentiate auth providers from each other. Note this is the same code at login() and onActivityResult().
public static final int GOOGLE_LOGIN_REQUEST_CODE = 1;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // When request completes
    if (resultCode == RESULT_OK) {
        // Check the request code matches the one we send in the login request
        if (requestCode == GOOGLE_LOGIN_REQUEST_CODE) {
            MobileServiceActivityResult result = mClient.onActivityResult(data);
            if (result.isLoggedIn()) {
                // login succeeded
                createAndShowDialog(String.format("You are now logged in - %1$2s", mClient.getCurrentUser().getUserId()), "Success");
                createTable();
            } else {
                // login failed, check the error message
                String errorMessage = result.getErrorMessage();
                createAndShowDialog(errorMessage, "Error");
            }
        }
    }
}

De GOOGLE_LOGIN_REQUEST_CODE die is gedefinieerd in uw hoofdactiviteit wordt gebruikt voor de login() methode en binnen de onActivityResult() methode . U kunt een uniek getal kiezen, zolang hetzelfde getal wordt gebruikt in de login() methode en de onActivityResult() methode . Als u de clientcode abstraheert in een serviceadapter (zoals eerder weergegeven), moet u de juiste methoden aanroepen op de serviceadapter.

U moet ook het project configureren voor customtabs. Geef eerst een omleidings-URL op. Voeg het volgende codefragment toe aan AndroidManifest.xml:

<activity android:name="com.microsoft.windowsazure.mobileservices.authentication.RedirectUrlActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="{url_scheme_of_your_app}" android:host="easyauth.callback"/>
    </intent-filter>
</activity>

Voeg de redirectUriScheme toe aan het build.gradle bestand voor uw toepassing:

android {
    buildTypes {
        release {
            // … …
            manifestPlaceholders = ['redirectUriScheme': '{url_scheme_of_your_app}://easyauth.callback']
        }
        debug {
            // … …
            manifestPlaceholders = ['redirectUriScheme': '{url_scheme_of_your_app}://easyauth.callback']
        }
    }
}

Voeg ten slotte com.android.support:customtabs:28.0.0 toe aan de lijst met afhankelijkheden in het build.gradle bestand:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.code.gson:gson:2.3'
    implementation 'com.google.guava:guava:18.0'
    implementation 'com.android.support:customtabs:28.0.0'
    implementation 'com.squareup.okhttp:okhttp:2.5.0'
    implementation 'com.microsoft.azure:azure-mobile-android:3.4.0@aar'
    implementation 'com.microsoft.azure:azure-notifications-handler:1.0.1@jar'
}

Haal de id van de aangemelde gebruiker op bij een MobileServiceUser met behulp van de methode getUserId . Zie Voor een voorbeeld van hoe u Futures gebruikt om de asynchrone aanmeldings-API's aan te roepen, Aan de slag met verificatie.

Waarschuwing

Het vermelde URL-schema is casegevoelig. Zorg ervoor dat alle exemplaren van overeenkomstcases {url_scheme_of_you_app} .

Verificatietokens in cache

Caching verificatietokens moet u de gebruikers-id en het verificatietoken lokaal op het apparaat opslaan. De volgende keer dat de app wordt gestart, controleert u de cache. Als deze waarden aanwezig zijn, kunt u de aanmeldprocedure overslaan en de client rehydrateren met deze gegevens. Deze gegevens zijn echter gevoelig en moeten voor de veiligheid versleuteld worden opgeslagen als de telefoon wordt gestolen. U ziet een volledig voorbeeld van het in de cache cachen van verificatietokens in de sectie Cacheverificatietokens.

Wanneer u een verlopen token probeert te gebruiken, ontvangt u een 401-respons door onbevoegden . U kunt verificatiefouten afhandelen met behulp van filters. Filters onderscheppen aanvragen naar de App Service back-end. De filtercode test het antwoord op een 401, activeert het aanmeldingsproces en hervat vervolgens de aanvraag die de 401 heeft gegenereerd.

Vernieuwingstokens gebruiken

Het token dat wordt geretourneerd Azure App Service verificatie en autorisatie heeft een gedefinieerde levensduur van één uur. Na deze periode moet u de gebruiker opnieuw authenticeren. Als u een token met lange duur gebruikt dat u hebt ontvangen via clientstroomverificatie, kunt u zich opnieuw met Azure App Service-verificatie en -autorisatie met hetzelfde token. Een Azure App Service-token wordt gegenereerd met een nieuwe levensduur.

U kunt de provider ook registreren voor het gebruik van vernieuwingstokens. Een vernieuwings-token is niet altijd beschikbaar. Aanvullende configuratie is vereist:

  • Configureer Azure Active Directory clientgeheim voor de Azure Active Directory app. Geef het clientgeheim op in de Azure App Service bij het configureren Azure Active Directory verificatie. Bij het aanroepen .login()van geeft u response_type=code id_token door als een parameter:

    HashMap<String, String> parameters = new HashMap<String, String>();
    parameters.put("response_type", "code id_token");
    MobileServiceUser user = mClient.login
        MobileServiceAuthenticationProvider.AzureActiveDirectory,
        "{url_scheme_of_your_app}",
        AAD_LOGIN_REQUEST_CODE,
        parameters);
    
  • Geef voor Google de door access_type=offline als parameter:

    HashMap<String, String> parameters = new HashMap<String, String>();
    parameters.put("access_type", "offline");
    MobileServiceUser user = mClient.login
        MobileServiceAuthenticationProvider.Google,
        "{url_scheme_of_your_app}",
        GOOGLE_LOGIN_REQUEST_CODE,
        parameters);
    
  • Selecteer voor Microsoft-account het wl.offline_access bereik.

Als u een token wilt vernieuwen, roept u aan .refreshUser():

MobileServiceUser user = mClient
    .refreshUser()  // async - returns a ListenableFuture<MobileServiceUser>
    .get();

Maak best practice filter dat een 401-respons van de server detecteert en probeert het gebruiker-token te vernieuwen.

Aanmelden met clientstroomverificatie

Het algemene proces voor aanmelden met clientstroomverificatie is als volgt:

  • Configureer Azure App Service verificatie en autorisatie zoals u serverstroomverificatie zou doen.

  • Integreer de verificatieprovider-SDK voor verificatie om een toegang token te produceren.

  • Roep de .login() methode als volgt aan ( moetresult een zijn AuthenticationResult):

    JSONObject payload = new JSONObject();
    payload.put("access_token", result.getAccessToken());
    ListenableFuture<MobileServiceUser> mLogin = mClient.login("{provider}", payload.toString());
    Futures.addCallback(mLogin, new FutureCallback<MobileServiceUser>() {
        @Override
        public void onFailure(Throwable exc) {
            exc.printStackTrace();
        }
        @Override
        public void onSuccess(MobileServiceUser user) {
            Log.d(TAG, "Login Complete");
        }
    });
    

Zie het volledige codevoorbeeld in de volgende sectie.

Vervang de onSuccess() methode door de code die u wilt gebruiken bij een geslaagde aanmelding. De {provider} tekenreeks is een geldige provider: aad (Azure Active Directory), facebook, google, microsoftaccount of twitter. Als u aangepaste verificatie hebt geïmplementeerd, kunt u ook de aangepaste tag van de verificatieprovider gebruiken.

Gebruikers verifiëren met de Active Directory Authentication Library (ADAL)

U kunt de Active Directory Authentication Library (ADAL) gebruiken om gebruikers aan te melden bij uw toepassing met behulp van Azure Active Directory. Het gebruik van aanmelding via een clientstroom verdient vaak loginAsync() de voorkeur boven het gebruik van de methoden, omdat dit een systeemeigen UX-gevoel biedt en extra aanpassingen mogelijk maakt.

  1. Configureer uw back-AAD voor mobiele apps voor aanmelding door de zelfstudie How to configure App Service for Active Directory login te volgen. Zorg ervoor dat u de optionele stap voor het registreren van een native clienttoepassing voltooit.

  2. Installeer ADAL door het bestand build.gradle zo te wijzigen dat het de volgende definities bevat:

    repositories {
        mavenCentral()
        flatDir {
            dirs 'libs'
        }
        maven {
            url "YourLocalMavenRepoPath\\.m2\\repository"
        }
    }
    packagingOptions {
        exclude 'META-INF/MSFTSIG.RSA'
        exclude 'META-INF/MSFTSIG.SF'
    }
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation('com.microsoft.aad:adal:1.16.1') {
            exclude group: 'com.android.support'
        } // Recent version is 1.16.1
        implementation 'com.android.support:support-v4:28.0.0'
    }
    
  3. Voeg de volgende code toe aan uw toepassing, waardoor de volgende vervangingen worden gebruikt:

    • Vervang INSERT-AUTHORITY-HERE door de naam van de tenant waarin u uw toepassing hebt ingericht. De indeling moet zijn https://login.microsoftonline.com/contoso.onmicrosoft.com.
    • Vervang INSERT-RESOURCE-ID-HERE door de client-id voor de back-end van uw mobiele app. U kunt de client-id verkrijgen via het tabblad Geavanceerdonder Azure Active Directory Instellingen in de portal.
    • Vervang INSERT-CLIENT-ID-HERE door de client-id die u hebt gekopieerd uit de native clienttoepassing.
    • Vervang INSERT-REDIRECT-URI-HERE door het /.auth/login/done-eindpunt van uw site met behulp van het HTTPS-schema. Deze waarde moet vergelijkbaar zijn met https://contoso.azurewebsites.net/.auth/login/done.
private AuthenticationContext mContext;

private void authenticate() {
    String authority = "INSERT-AUTHORITY-HERE";
    String resourceId = "INSERT-RESOURCE-ID-HERE";
    String clientId = "INSERT-CLIENT-ID-HERE";
    String redirectUri = "INSERT-REDIRECT-URI-HERE";
    try {
        mContext = new AuthenticationContext(this, authority, true);
        mContext.acquireToken(this, resourceId, clientId, redirectUri, PromptBehavior.Auto, "", callback);
    } catch (Exception exc) {
        exc.printStackTrace();
    }
}

private AuthenticationCallback<AuthenticationResult> callback = new AuthenticationCallback<AuthenticationResult>() {
    @Override
    public void onError(Exception exc) {
        if (exc instanceof AuthenticationException) {
            Log.d(TAG, "Cancelled");
        } else {
            Log.d(TAG, "Authentication error:" + exc.getMessage());
        }
    }

    @Override
    public void onSuccess(AuthenticationResult result) {
        if (result == null || result.getAccessToken() == null
                || result.getAccessToken().isEmpty()) {
            Log.d(TAG, "Token is empty");
        } else {
            try {
                JSONObject payload = new JSONObject();
                payload.put("access_token", result.getAccessToken());
                ListenableFuture<MobileServiceUser> mLogin = mClient.login("aad", payload.toString());
                Futures.addCallback(mLogin, new FutureCallback<MobileServiceUser>() {
                    @Override
                    public void onFailure(Throwable exc) {
                        exc.printStackTrace();
                    }
                    @Override
                    public void onSuccess(MobileServiceUser user) {
                        Log.d(TAG, "Login Complete");
                    }
                });
            }
            catch (Exception exc){
                Log.d(TAG, "Authentication error:" + exc.getMessage());
            }
        }
    }
};

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (mContext != null) {
        mContext.onActivityResult(requestCode, resultCode, data);
    }
}

De communicatie Client-Server aanpassen

De clientverbinding is normaal gesproken een eenvoudige HTTP-verbinding met behulp van de onderliggende HTTP-bibliotheek die wordt geleverd met de Android SDK. Er zijn verschillende redenen waarom u dit zou willen wijzigen:

  • U wilt een alternatieve HTTP-bibliotheek gebruiken om time-outs aan te passen.
  • U wilt een voortgangsbalk verstrekken.
  • U wilt een aangepaste header toevoegen ter ondersteuning van api-beheerfunctionaliteit.
  • U wilt een mislukte reactie onderscheppen, zodat u opnieuwauthenticatie kunt implementeren.
  • U wilt back-end-aanvragen bij een analyseservice aanmelden.

Een alternatieve HTTP-bibliotheek gebruiken

Roep de methode .setAndroidHttpClientFactory() aan onmiddellijk na het maken van uw clientverwijzing. Als u bijvoorbeeld de time-out voor de verbinding wilt instellen op 60 seconden (in plaats van de standaard 10 seconden):

mClient = new MobileServiceClient("https://myappname.azurewebsites.net");
mClient.setAndroidHttpClientFactory(new OkHttpClientFactory() {
    @Override
    public OkHttpClient createOkHttpClient() {
        OkHttpClient client = new OkHttpClient();
        client.setReadTimeout(60, TimeUnit.SECONDS);
        client.setWriteTimeout(60, TimeUnit.SECONDS);
        return client;
    }
});

Een voortgangsfilter implementeren

U kunt een onderschepping van elke aanvraag implementeren door een te implementeren ServiceFilter. Met de volgende wordt bijvoorbeeld een vooraf gemaakte voortgangsbalk bijgewerkt:

private class ProgressFilter implements ServiceFilter {
    @Override
    public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback next) {
        final SettableFuture<ServiceFilterResponse> resultFuture = SettableFuture.create();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.VISIBLE);
            }
        });

        ListenableFuture<ServiceFilterResponse> future = next.onNext(request);
        Futures.addCallback(future, new FutureCallback<ServiceFilterResponse>() {
            @Override
            public void onFailure(Throwable e) {
                resultFuture.setException(e);
            }
            @Override
            public void onSuccess(ServiceFilterResponse response) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (mProgressBar != null)
                            mProgressBar.setVisibility(ProgressBar.GONE);
                    }
                });
                resultFuture.set(response);
            }
        });
        return resultFuture;
    }
}

U kunt dit filter als volgt aan de client koppelen:

mClient = new MobileServiceClient(applicationUrl).withFilter(new ProgressFilter());

Aanvraagheaders aanpassen

Gebruik het volgende ServiceFilter en koppel het filter op dezelfde manier als de ProgressFilter:

private class CustomHeaderFilter implements ServiceFilter {
    @Override
    public ListenableFuture<ServiceFilterResponse> handleRequest(ServiceFilterRequest request, NextServiceFilterCallback next) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                request.addHeader("X-APIM-Router", "mobileBackend");
            }
        });
        SettableFuture<ServiceFilterResponse> result = SettableFuture.create();
        try {
            ServiceFilterResponse response = next.onNext(request).get();
            result.set(response);
        } catch (Exception exc) {
            result.setException(exc);
        }
    }
}

Automatische serialisatie configureren

U kunt een conversiestrategie opgeven die van toepassing is op elke kolom met behulp van de gson-API . De Android-clientbibliotheek gebruikt gson achter de schermen om Java-objecten te serialiseren naar JSON-gegevens voordat de gegevens naar de Azure App Service. In de volgende code wordt de methode setFieldNamingStrategy() gebruikt om de strategie in te stellen. In dit voorbeeld wordt het eerste teken (een 'm' ) verwijderd en wordt voor elke veldnaam het volgende teken in kleine gevallen verwijderd. Het zou bijvoorbeeld 'mId' veranderen in 'id'. Implementeert een conversiestrategie om de noodzaak van SerializedName() aantekeningen op de meeste velden te verminderen.

FieldNamingStrategy namingStrategy = new FieldNamingStrategy() {
    public String translateName(File field) {
        String name = field.getName();
        return Character.toLowerCase(name.charAt(1)) + name.substring(2);
    }
}

client.setGsonBuilder(
    MobileServiceClient
        .createMobileServiceGsonBuilder()
        .setFieldNamingStrategy(namingStrategy)
);

Deze code moet worden uitgevoerd voordat u een referentie voor een mobiele client maakt met behulp van de MobileServiceClient.