Delen via


De Azure Mobile Apps SDK voor Android gebruiken

Deze handleiding laat zien hoe u de Android-client-SDK voor Mobile Apps gebruikt om algemene scenario's te implementeren, 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 Werken met de .NET-back-end-SDK of de Node.js back-end-SDK gebruiken voor meer informatie over de SDK aan de serverzijde voor mobiele apps.

Referentiedocumentatie

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

Ondersteunde platforms

De Azure Mobile Apps SDK voor Android ondersteunt API-niveaus 19 tot en met 24 (KitKat tot en met Nougat) voor vormfactoren voor telefoons en tablets. Verificatie maakt met name gebruik van een algemene benadering van het webframework om referenties te verzamelen. Verificatie van serverstromen werkt niet met kleine formulierfactorapparaten zoals horloges.

Installatie en vereisten

Voltooi de quickstart voor Mobile Apps. Aan deze taak wordt voldaan aan alle vereisten voor het ontwikkelen van Azure Mobile Apps. 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, voert u de volgende taken uit:

Het Gradle-buildbestand bijwerken

Beide build.gradle-bestanden wijzigen:

  1. Voeg deze code toe aan het build.gradle-bestand op projectniveau:

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

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

    Momenteel is de nieuwste versie 3.4.0. De ondersteunde versies worden vermeld op bintray.

Internetmachtiging inschakelen

Voor toegang tot Azure moet voor uw app de internetmachtiging zijn ingeschakeld. 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 serviceverificatie en autorisatie.
  • Registratie van pushmeldingen met Notification Hubs.

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

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

Dit <MobileAppUrl> is een tekenreeks of een URL-object dat verwijst naar uw mobiele back-end. Als u Azure-app Service gebruikt om uw mobiele back-end te hosten, moet u ervoor zorgen dat u de beveiligde https:// versie van de URL gebruikt.

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

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

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 de onCreate() methode van uw hoofdactiviteit aanroepenAzureServiceAdapter.Initialize(this);. Alle andere methoden die toegang tot de client AzureServiceAdapter.getInstance(); nodig hebben om een verwijzing naar de serviceadapter te verkrijgen.

Gegevensbewerkingen

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

Clientgegevensklassen definiëren

Als u toegang wilt krijgen 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 uitgegaan dat een tabel met de naam MyDataTable, die de volgende kolommen bevat:

  • id
  • sms verzenden
  • voltooid

Het bijbehorende getypte clientobject 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-tabel meer kolommen bevat, voegt u de bijbehorende velden toe aan deze klasse. Als de DTO (gegevensoverdrachtobject) bijvoorbeeld een kolom prioriteit met een geheel getal had, 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 Een tabelcontroller (.NET-back-end) definiëren of Tabellen definiëren met behulp van een dynamisch schema (Node.js back-end) voor meer informatie over het maken van extra tabellen in uw Mobile Apps-back-end.

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

  • String id: De wereldwijd unieke id voor de record. Als best practice kunt u de id de tekenreeksweergave van een UUID-object maken.
  • DateTimeOffset updatedAt: de datum/tijd van de laatste update. Het veld updatedAt wordt ingesteld door de server en mag nooit worden ingesteld door de 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 opgeschoond. Gebruik deze eigenschap niet deleted als eigenschap in uw klas.

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

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 tabelreferentie maken

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

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 waarbij 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

Haal eerst een tabelreferentie op. Voer vervolgens een query uit op de tabelreferentie. Een query is een combinatie van:

De componenten moeten in de voorgaande volgorde worden gepresenteerd.

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

In het voorgaande voorbeeld worden alle resultaten geretourneerd (tot het maximale paginaformaat dat door de server is ingesteld). De .execute() methode voert de query uit op de back-end. De query wordt geconverteerd naar een OData v3-query voordat deze naar de back-end van Mobile Apps wordt doorgestuurd. Na ontvangst converteert de back-end van Mobile Apps de query naar een SQL-instructie voordat deze wordt uitgevoerd op het SQL Azure-exemplaar. Omdat de netwerkactiviteit enige tijd in beslag neemt, retourneert de .execute() methode een ListenableFuture<E>.

Geretourneerde gegevens filteren

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

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

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

Definieer een filter met behulp van de methode-aanroep van de tabelreferentie. De where-methode wordt gevolgd door een veldmethode gevolgd door een methode waarmee het logische predicaat wordt opgegeven. Mogelijke predicaatmethoden zijn eq (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 numerieke 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 lengte. In het volgende voorbeeld worden tabelrijen gefilterd waarbij de tekstkolom begint met PRI0.

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

De volgende operatormethoden worden ondersteund voor numerieke velden: toevoegen, sub, mul, div, mod, vloer, plafond en ronde. In het volgende voorbeeld worden tabelrijen gefilterd 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 niet. 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 groeperen en nesten:

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

Zie Verkennen van de rijkdom van het Querymodel van de Android-client voor gedetailleerdere discussies en voorbeelden van filteren.

Geretourneerde gegevens sorteren

De volgende code retourneert alle items uit een tabel met ToDoItems , gesorteerd op oplopend 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 orderBy-methode is een tekenreeks die gelijk is aan de naam van het veld waarop moet worden gesorteerd. De tweede parameter gebruikt de opsomming QueryOrder om op te geven of u oplopend of aflopend wilt sorteren. Als u filtert met behulp van de where-methode, moet de where-methode worden aangeroepen vóór de orderBy-methode.

Specifieke kolommen selecteren

De volgende code illustreert hoe u alle items uit een tabel met ToDoItems retourneert, maar alleen de volledige velden en tekstvelden weergeeft. 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 selectiefunctie zijn de tekenreeksnamen van de kolommen van de tabel die u wilt retourneren. De select-methode moet methoden volgen, zoals waar en orderBy. Dit kan worden gevolgd door pagingmethoden 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 het maximale paginaformaat op de server 50 records.

In het eerste voorbeeld ziet u hoe u de vijf bovenste items in 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 volgt 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 ophalen, implementeert u code om alle pagina's te herhalen:

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);

Een aanvraag voor alle records met deze methode maakt minimaal twee aanvragen naar de back-end van Mobile Apps.

Tip

Het kiezen van het juiste paginaformaat is een balans tussen het geheugengebruik terwijl de aanvraag plaatsvindt, het bandbreedtegebruik en de 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 maximaal 500. We hebben vastgesteld dat het verhogen van het paginaformaat meer dan 500 records leidt tot onaanvaardbare vertragingen en grote geheugenproblemen.

Procedure: Querymethoden samenvoegen

De methoden die worden gebruikt bij het uitvoeren van query's op back-endtabellen, kunnen worden samengevoegd. Met ketenquerymethoden kunt u specifieke kolommen met gefilterde rijen selecteren die zijn gesorteerd en gepaginad. 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. Voorbeeld:

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 gekoppelde querymethoden moeten als volgt worden gerangschikt:

  1. Filtermethoden (where).
  2. Sorteermethoden (orderBy).
  3. Selectiemethoden (selecteren).
  4. pagingsmethoden (overslaan en top).

Gegevens binden aan de gebruikersinterface

Gegevensbinding omvat drie onderdelen:

  • De gegevensbron
  • De schermindeling
  • De adapter die de twee aan elkaar koppelt.

In onze voorbeeldcode retourneren we de gegevens uit de Sql Azure-tabel Mobile Apps 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 ophaalt. In dit voorbeeld is de matrix de gegevensbron. De code geeft een schermindeling op waarmee de weergave wordt gedefinieerd van de gegevens die op het apparaat worden weergegeven. De twee zijn gekoppeld aan een adapter, die in deze code een uitbreiding is van de klasse ArrayAdapter<ToDoItem> .

De indeling definiëren

De indeling wordt gedefinieerd door verschillende codefragmenten van XML-code. 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 kenmerk listitem de id van de indeling voor een afzonderlijke rij in de lijst op. Met deze code geeft u een selectievakje en de bijbehorende tekst op en wordt één keer geïnstantieerd voor elk item in de lijst. In deze indeling wordt het id-veld niet weergegeven en in een complexere indeling worden extra velden in de weergave opgegeven. Deze code bevindt zich in het bestand row_list_to_do.xml .

<?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, subklassen we onze adapter van een MatrixAdapter<ToDoItem-klasse> . Deze subklasse produceert een weergave voor elke ToDoItem met behulp van de row_list_to_do-indeling . In onze code definiëren we de volgende klasse die een uitbreiding is van de klasse ArrayAdapter<E> :

public class ToDoItemAdapter extends ArrayAdapter<ToDoItem> {
}

Overschrijf de getView-methode voor adapters. Voorbeeld:

    @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 ToDoItemAdapter-constructor is een verwijzing naar de indeling. We kunnen nu de ListView instantiëren en de adapter toewijzen aan de ListView.

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

De adapter gebruiken om verbinding te maken met de gebruikersinterface

U bent nu klaar om gegevensbinding te gebruiken. De volgende code laat zien hoe u items in de tabel opgeeft 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. Aangezien wijzigingen per record worden uitgevoerd, verwerkt u één rij in plaats van een verzameling. Wanneer u een item invoegt, roept u de methode voor toevoegen op de adapter aan. Roep bij het verwijderen de verwijdermethode aan.

U vindt een volledig voorbeeld in het Android-snelstartproject.

Gegevens invoegen in de back-end

Instantie van de klasse ToDoItem instantiëren en de eigenschappen instellen.

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 zijn ingevoegd in de back-endtabel, inclusief de id en eventuele andere waarden (zoals de createdAtupdatedAt, en version velden) die zijn ingesteld op de back-end.

Mobile Apps-tabellen vereisen een primaire sleutelkolom met de naam id. Deze kolom moet een tekenreeks zijn. De standaardwaarde van de kolom ID is een GUID. U kunt andere unieke waarden opgeven, zoals e-mailadressen of gebruikersnamen. Wanneer er geen tekenreeks-id-waarde 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 eenvoudiger 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 ondersteuning voor offlinesynchronisatie. U kunt een id niet 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 methode update().

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

In dit voorbeeld is het item een verwijzing naar een rij in de tabel ToDoItem , die enkele wijzigingen heeft 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 van de rij op te geven dat u wilt verwijderen.

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

Een specifiek item opzoeken op id

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

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

Procedure: Werken met niet-getypte gegevens

Het niet-getypte programmeermodel biedt u exacte controle over JSON-serialisatie. Er zijn enkele veelvoorkomende scenario's waarin u mogelijk een niet-getypt programmeermodel wilt gebruiken. Als uw back-endtabel bijvoorbeeld veel kolommen bevat en u alleen naar een subset van de kolommen hoeft te verwijzen. Voor het getypte model moet u alle kolommen definiëren die zijn gedefinieerd in de back-end van Mobile Apps in uw gegevensklasse. 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 op het object MobileServiceJsonTable , in plaats van het Object MobileServiceTable .

Een exemplaar van een niet-getypte tabel maken

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

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

Zodra u een exemplaar van de MobileServiceJsonTable hebt gemaakt, is er vrijwel dezelfde API beschikbaar als met het getypte programmeermodel. In sommige gevallen nemen de methoden een niet-getypte parameter in plaats van een getypte parameter.

Invoegen in een niet-getypte tabel

De volgende code laat zien hoe u een invoeging uitvoert. 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 ophalen, 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 voorbeeld van het invoegen . 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 ophaalt. Omdat u een JSON-tabel gebruikt, kunt u selectief slechts enkele kolommen van de tabel 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 pagingmethoden die beschikbaar zijn voor het getypte model, zijn beschikbaar voor het niet-getypte model.

Offlinesynchronisatie implementeren

De Client-SDK van Azure Mobile Apps implementeert ook offlinesynchronisatie 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 mobiele connectiviteit niet vereist. Offlinesynchronisatie helpt bij tolerantie en prestaties ten koste van complexere logica voor conflictoplossing. De Client-SDK van Azure Mobile Apps implementeert de volgende functies:

  • Incrementele synchronisatie: alleen bijgewerkte en nieuwe records worden gedownload, waardoor bandbreedte en geheugenverbruik worden bespaard.
  • 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.
  • Voorlopig verwijderen: verwijderde records worden gemarkeerd als verwijderd, zodat andere apparaten hun offlinecache kunnen bijwerken.

Offlinesynchronisatie initialiseren

Elke offlinetabel moet worden gedefinieerd in de offlinecache voordat u deze gebruikt. 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 ophalen

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

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

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

De lokale offlinecache synchroniseren

Synchronisatie valt onder het beheer van uw app. Hier volgt 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 opgegeven voor de .pull(query, queryname) methode, wordt incrementele synchronisatie gebruikt om alleen records te retourneren die zijn gemaakt of gewijzigd sinds de laatste geslaagde pull.

Conflicten verwerken tijdens offlinesynchronisatie

Als er een conflict optreedt tijdens een .push() bewerking, wordt er een MobileServiceConflictException gegenereerd. Het door de server uitgegeven item is ingesloten in de uitzondering en kan worden opgehaald door .getItem() op 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 .push() u 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 maken die niet is toegewezen aan een invoeg-, update-, verwijder- of leesbewerking. Met behulp van een aangepaste API kunt u meer controle hebben over berichten, waaronder het lezen en instellen van HTTP-berichtkoppen en het definiëren van een andere indeling voor de berichttekst 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 aanroept met de naam completeAll, waarmee een verzamelingsklasse met de naam MarkAllResult wordt geretourneerd.

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, waarmee een POST-aanvraag wordt verzonden naar de nieuwe aangepaste API. Het resultaat dat door de aangepaste API wordt geretourneerd, wordt weergegeven in een berichtdialoogvenster, net als eventuele fouten. Met andere versies van invokeApi kunt u desgewenst een object verzenden in de aanvraagbody, de HTTP-methode opgeven en queryparameters verzenden met de aanvraag. Niet-getypte versies van invokeApi zijn ook beschikbaar.

Verificatie toevoegen aan uw app

Zelfstudies beschrijven al gedetailleerd hoe u deze functies toevoegt.

App Service ondersteunt 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 instellen voor tabellen 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. Serverstroomverificatie biedt geen diepgaande integratie in het mobiele apparaat en wordt alleen aanbevolen voor scenario's voor het testen van concepten.

De clientstroom biedt een diepere integratie met apparaatspecifieke mogelijkheden, zoals eenmalige aanmelding, omdat deze afhankelijk is van SDK's van de id-provider. U kunt bijvoorbeeld de Facebook-SDK integreren in uw mobiele toepassing. De mobiele client wisselt over naar de Facebook-app en bevestigt uw aanmelding voordat u teruggaat 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 uw App Service-back-end.
  • Beperk tabelmachtigingen alleen voor geverifieerde gebruikers in de App Service-back-end.
  • Voeg verificatiecode toe aan uw app.

U kunt machtigingen instellen voor tabellen 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. Raadpleeg voor meer informatie Aan de slag met verificatie en de howto-documentatie van de Server SDK.

Verificatie: Serverstroom

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 klasse Main Activity:

// 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 gedefinieerde 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 binnen de login() methode en de onActivityResult() methode. Als u de clientcode abstraheert in een serviceadapter (zoals eerder weergegeven), moet u de juiste methoden voor de serviceadapter aanroepen.

U moet het project ook configureren voor aangepastetabs. Geef eerst een omleidings-URL op. Voeg het volgende fragment 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 toe com.android.support:customtabs:28.0.0 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 op van de aangemelde gebruiker van een MobileServiceUser met behulp van de methode getUserId . Zie Aan de slag met verificatie voor een voorbeeld van het gebruik van Futures om de asynchrone aanmeldings-API's aan te roepen.

Waarschuwing

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

Verificatietokens voor cache

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

Wanneer u een verlopen token probeert te gebruiken, ontvangt u een 401 niet-geautoriseerd antwoord. U kunt verificatiefouten afhandelen met behulp van filters. Filtert onderscheppingsaanvragen naar de App Service-back-end. De filtercode test het antwoord voor een 401, activeert het aanmeldingsproces en hervat vervolgens de aanvraag die de 401 heeft gegenereerd.

Vernieuwingstokens gebruiken

Het token dat wordt geretourneerd door Azure-app serviceverificatie en autorisatie heeft een gedefinieerde levensduur van één uur. Na deze periode moet u de gebruiker opnieuw verifiëren. Als u een token met een lange levensduur gebruikt dat u hebt ontvangen via clientstroomverificatie, kunt u zich opnieuw verifiëren met Azure-app serviceverificatie en -autorisatie met hetzelfde token. Er wordt nog een Azure-app Service-token gegenereerd met een nieuwe levensduur.

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

  • Configureer voor Azure Active Directory een clientgeheim voor de Azure Active Directory-app. Geef het clientgeheim op in de Azure-app Service bij het configureren van Azure Active Directory-verificatie. Wanneer u aanroept .login(), geeft u door response_type=code id_token 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 access_type=offline parameter door:

    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 het bereik voor het Microsoft-account.wl.offline_access

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

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

Maak als best practice een filter dat een 401-antwoord van de server detecteert en probeert het gebruikerstoken te vernieuwen.

Aanmelden met clientstroomverificatie

Het algemene proces voor het aanmelden met clientstroomverificatie is als volgt:

  • Configureer Azure-app serviceverificatie en autorisatie zoals u serverstroomverificatie zou doen.

  • Integreer de SDK van de verificatieprovider voor verificatie om een toegangstoken te produceren.

  • Roep de .login() methode als volgt aan (result moet een 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 tag aangepaste 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 een aanmelding bij een clientstroom verdient vaak de voorkeur aan het gebruik van de loginAsync() methoden, omdat het een meer systeemeigen UX-gevoel biedt en extra aanpassingen mogelijk maakt.

  1. Configureer de back-end van uw mobiele app voor AAD-aanmelding door de zelfstudie App Service configureren voor Active Directory-aanmelding te volgen. Zorg ervoor dat u de optionele stap voor het registreren van een systeemeigen clienttoepassing voltooit.

  2. Installeer ADAL door uw build.gradle-bestand te wijzigen om de volgende definities op te nemen:

    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 gemaakt:

    • 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 op het tabblad Geavanceerd onder Azure Active Directory-instellingen in de portal.
    • Vervang INSERT-CLIENT-ID-HERE door de client-id die u hebt gekopieerd uit de systeemeigen clienttoepassing.
    • Vervang INSERT-REDIRECT-URI-HERE door het eindpunt /.auth/login/done 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 client-servercommunicatie aanpassen

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

  • U wilt een alternatieve HTTP-bibliotheek gebruiken om time-outs aan te passen.
  • U wilt een voortgangsbalk opgeven.
  • U wilt een aangepaste header toevoegen ter ondersteuning van API Management-functionaliteit.
  • U wilt een mislukt antwoord onderscheppen, zodat u verificatie opnieuw kunt implementeren.
  • U wilt back-endaanvragen registreren bij een analyseservice.

Een alternatieve HTTP-bibliotheek gebruiken

Roep de .setAndroidHttpClientFactory() methode onmiddellijk aan nadat u de clientreferentie hebt gemaakt. Als u bijvoorbeeld de time-out voor de verbinding wilt instellen op 60 seconden (in plaats van de standaardtijd van 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 snijpunt van elke aanvraag implementeren door een ServiceFilter. Met de volgende updates 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 Azure-app Service worden verzonden. 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 vervolgens het volgende teken in kleine letters voor elke veldnaam. Zo wordt 'mId' bijvoorbeeld omgezet in 'id'. Implementeer een conversiestrategie om de noodzaak van aantekeningen op SerializedName() 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 mobileServiceClient.