Az Androidhoz készült Azure Mobile Apps SDK használata

Ez az útmutató bemutatja, hogyan használhatja az Android Mobile Apps SDK-t a gyakori forgatókönyvek megvalósításához, például:

  • Adatok lekérdezése (beszúrás, frissítés és törlés).
  • Hitelesítés.
  • Hibák kezelése.
  • Az ügyfél testreszabása.

Ez az útmutató az ügyféloldali Android SDK-val foglalkozik. További információ a Mobile Apps kiszolgálóoldali SDK-król: A .NET háttér-SDK használata vagy A Node.js háttér-SDK használata.

Referenciadokumentáció

Az Android-ügyféloldali kódtár Javadocs API-referenciáját a következő GitHub.

Támogatott platformok

Az Androidhoz készült Azure Mobile Apps SDK a 19–24 (KitKat–Nougat) API-szinteket támogatja a telefonos és táblagépes formátumok esetében. A hitelesítés egy általános webes keretrendszer-megközelítést alkalmaz a hitelesítő adatok gyűjtése során. A kiszolgálói folyamat hitelesítése nem működik kis mérettényezős eszközökkel, például órákkal.

Beállítás és előfeltételek

A rövid Mobile Apps oktatóanyag befejezése . Ez a feladat biztosítja az Azure-szolgáltatások fejlesztésének Mobile Apps előfeltételeit. A rövid útmutató a fiók konfigurálásában és az első Mobile App-háttéralkalmazás létrehozásában is segít.

Ha úgy dönt, hogy nem befejezi a gyors üzembe helyezési oktatóanyagot, a következő feladatokat kell elvégeznie:

A Gradle buildfájl frissítése

Módosítsa mindkét build.gradle fájlt :

  1. Adja hozzá ezt a kódot Projectbuild.gradle fájlhoz:

    buildscript {
        repositories {
            jcenter()
            google()
        }
    }
    
    allprojects {
        repositories {
            jcenter()
            google()
        }
    }
    
  2. Adja hozzá ezt a kódot a module app level build.gradle fájlhoz a dependencies címkén belül:

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

    A legújabb verzió jelenleg a 3.4.0-s. A támogatott verziók listája a bintray oldalon található.

Internetes engedély engedélyezése

Az Azure eléréséhez az alkalmazásnak engedélyeznie kell az INTERNET engedélyt. Ha még nincs engedélyezve, adja hozzá a következő kódsort a AndroidManifest.xml fájlhoz:

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

Ügyfélkapcsolat létrehozása

Az Azure Mobile Apps négy funkciót biztosít a mobilalkalmazáshoz:

  • Adatelérés és offline szinkronizálás Azure Mobile Apps szolgáltatással.
  • Hívja meg az Azure Mobile Apps Server SDK-val írt egyéni API-kat.
  • Hitelesítés Azure App Service hitelesítéssel.
  • Leküldéses értesítés regisztrációja Notification Hubs.

Ezen függvények mindegyikéhez először létre kell hoznia egy MobileServiceClient objektumot. Csak egy MobileServiceClient objektumot kell létrehozni a mobil ügyfélen belül (ez azt jelenti, hogy egyszeri mintának kell lennie). Objektum létrehozása MobileServiceClient :

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

A <MobileAppUrl> egy sztring vagy egy URL-objektum, amely a mobil háttérre mutat. Ha mobil-háttér Azure App Service használja, győződjön meg arról, https:// hogy az URL-cím biztonságos verzióját használja.

Az ügyfélnek hozzáférésre van szüksége a tevékenységhez vagy a környezethez is – a this példában megadott paraméterhez. A MobileServiceClient konstrukciónak onCreate() a fájlban hivatkozott tevékenység metódusában kell AndroidManifest.xml történnie.

Az ajánlott eljárás a kiszolgálói kommunikáció absztrakciója a saját (egyszeres mintázatú) osztályba. Ebben az esetben a konstruktoron belül kell átadnia a tevékenységet a szolgáltatás megfelelő konfigurálás érdekében. Például:

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.
}

Most már hívhatja AzureServiceAdapter.Initialize(this); a metódust onCreate() a fő tevékenység metódusában. Az ügyfélhez való AzureServiceAdapter.getInstance(); hozzáférést szükséges egyéb módszerek a szolgáltatásadapterre való hivatkozás beszerzéséhez használják.

Adatműveletek

Az Azure Mobile Apps SDK lényege, hogy hozzáférést biztosítson a SQL Azure-háttéralkalmazásban tárolt adatokhoz. Ezek az adatok erősen típusos osztályok (előnyben részesített) vagy nem típusos lekérdezések (nem ajánlott) használatával elérést használhatja. A szakasz nagy része az erősen típusos osztályok használatával foglalkozik.

Ügyféladatosztályok definiálása

Az adatok a SQL Azure való eléréséhez definiálja a Mobile App-háttéralkalmazás tábláinak megfelelő ügyféladatosztályokat. A témakör példái egy MyDataTable nevű táblát feltételeznek, amely a következő oszlopokat tartalmazza:

  • id
  • szöveg
  • Teljes

A megfelelő típusos ügyféloldali objektum egy MyDataTable.java nevű fájlban található:

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

Adja hozzá a getter és setter metódusokat minden egyes hozzáadt mezőhöz. Ha a SQL Azure tábla több oszlopot tartalmaz, akkor a megfelelő mezőket kell hozzáadnia ehhez az osztályhoz. Ha például a DTO (adatátviteli objektum) egész szám prioritása oszlopban volt, akkor hozzáadhatja ezt a mezőt a bekereső és beállító metódusokkal együtt:

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

Ha további táblákat szeretne létrehozni az Mobile Apps-háttérkiszolgálón, tekintse meg a táblázatvezérlő (.NET-háttér) definiálásával vagy a táblák dinamikus sémával (Node.js háttér használatával) való definiálási útmutatóját.

Az Azure Mobile Apps háttértáblája öt speciális mezőt határoz meg, amelyek közül négy elérhető az ügyfelek számára:

  • String id: A rekord globálisan egyedi azonosítója. Ajánlott eljárásként az azonosítót egy UUID-objektum Sztring ábrázolásaként kell megszabadulni .
  • DateTimeOffset updatedAt: Az utolsó frissítés dátuma/időpontja. A updatedAt mezőt a kiszolgáló adja meg, és az ügyfélkód nem állíthatja be.
  • DateTimeOffset createdAt: Az objektum létrehozási dátuma/időpontja. A createdAt mezőt a kiszolgáló állíthatja be, és az ügyfélkód nem állíthatja be.
  • byte[] version: Általában sztringként van ábrázolva, a verziót a kiszolgáló is beállítja.
  • boolean deleted: Azt jelzi, hogy a rekordot törölték, de még nem véglegesen törölték. Ne használja tulajdonságként deleted az osztályban.

Az id mező kötelező. A updatedAt mező és version a mező offline szinkronizáláshoz használatos (növekményes szinkronizáláshoz és ütközésfeloldáshoz). A createdAt mező egy referenciamező, amelyet az ügyfél nem használ. A nevek a tulajdonságok "vezetéken keresztüli" nevei, és nem módosíthatók. A GSON-kódtár használatával azonban létrehozhat egy leképezést az objektum és a "vezetékek közötti" nevek között. Például:

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

Táblahivatkozás létrehozása

Egy tábla eléréséhez először hozzon létre egy MobileServiceTable objektumot a getTable metódus a MobileServiceClient objektumon való hívásával. Ennek a metódusnak két túlterhelése van:

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

A következő kódban az mClient a MobileServiceClient objektumra hivatkozik. Az első túlterhelést akkor használja a rendszer, ha az osztály és a tábla neve azonos, és a rövid útmutatóban ezt használja:

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

A második túlterhelést akkor használja a rendszer, ha a tábla neve eltér az osztály nevétől: az első paraméter a tábla neve.

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

Háttértábla lekérdezése

Először szerezzen be egy táblahivatkozást. Ezután hajtson végre egy lekérdezést a táblahivatkozáson. A lekérdezés a következő bármely kombinációja lehet:

A záradékokat az előző sorrendben kell bemutatni.

Eredmények szűrése

A lekérdezések általános formája a következő:

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

Az előző példa az összes eredményt visszaadja (a kiszolgáló által beállított maximális oldalméretig). A .execute() metódus végrehajtja a lekérdezést a háttéren. A rendszer OData v3-lekérdezésre konvertálja a lekérdezést, mielőtt Mobile Apps háttérrendszerbe. A nyugta után a Mobile Apps a lekérdezést egy SQL-utasításká konvertálja, mielőtt végrehajtja azt a SQL Azure példányon. Mivel a hálózati tevékenység némi időt vesz igénybe, .execute() a metódus egy értéket ad vissza ListenableFuture<E>.

Visszaadott adatok szűrése

A következő lekérdezés-végrehajtás a ToDoItem tábla összes olyan elemét visszaadja, ahol a complete értéke false (hamis).

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

Az mToDoTable a korábban létrehozott mobilszolgáltatás-táblára való hivatkozás.

Definiálhat egy szűrőt a táblahivatkozás where metódushívásával. A where metódust egy mező metódusa követi, majd egy metódus, amely meghatározza a logikai predikátumot. A lehetséges predikátum módszerek közé tartozik az eq (egyenlő), ne (nem egyenlő), gt (nagyobb, mint), ge (nagyobb vagy egyenlő), lt (kisebb mint), le (kisebb vagy egyenlő). Ezekkel a metódusokkal összehasonlíthatja a szám- és sztringmezőket adott értékekkel.

Dátumokra szűrhet. Az alábbi módszerekkel összehasonlíthatja a teljes dátummezőt vagy a dátum egyes részeit: év, hónap, nap, óra, perc és másodperc. Az alábbi példa hozzáad egy szűrőt az olyan elemekhez , amelyeknek a határidője 2013.

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

A következő metódusok támogatják a sztringmezők összetett szűrőit: startsWith, endsWith, concat, subString, indexOf, replace, toLower, toUpper, trim és length. Az alábbi példa olyan táblasorokat szűr, ahol a szöveges oszlop a "PRI0" szöveggel kezdődik.

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

Számmezők esetén a következő operátori metódusok támogatottak: add, sub, mul, div, mod, floor, ceiling és round. Az alábbi példa olyan táblasorokat szűr , ahol az időtartam egy egyenletes szám.

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

A predikátumokat a következő logikai metódusokkal kombinálhatja: és vagy sem. Az alábbi példa az előző példák közül kettőt kombinál.

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

Logikai operátorok csoportosítása és beágyazás:

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

A szűrés részletes leírásáért és a szűrés példáiért lásd: Exploring the richness of the Android client query model (Az Android-ügyfél lekérdezési modelljének felfedezése).

Visszaadott adatok rendezése

Az alábbi kód a ToDoItems tábla összes elemét adja vissza a szövegmező szerint növekvő sorrendbe rendezve . Az mToDoTable a korábban létrehozott háttértábla hivatkozása:

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

Az orderBy metódus első paramétere egy sztring, amely megegyezik annak a mezőnek a nevével, amely alapján rendezni kell. A második paraméter a QueryOrder enumerálással határozza meg, hogy növekvő vagy csökkenő sorrendet kell-e rendezni. Ha a where metódussal szűr, a where metódust az orderBy metódus előtt kell meghívni .

Adott oszlopok kiválasztása

Az alábbi kód bemutatja, hogyan lehet visszaadni a ToDoItems tábla összes elemét, de csak a teljes és a szöveges mezőket jeleníti meg. Az mToDoTable a korábban létrehozott háttértábla hivatkozása.

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

A select függvény paraméterei a visszaadni kívánt tábla oszlopainak sztringnevét jelentik. A select metódusnak olyan metódusokat kell követnie, mint a where és az orderBy. Ezt olyan lapozási metódusok követik, mint a skip ésa top.

Adatok visszaadása oldalakon

Az adatokat a rendszer MINDIG visszaadja oldalakon. A visszaadott rekordok maximális számát a kiszolgáló adja meg. Ha az ügyfél több rekordot kér, akkor a kiszolgáló visszaadja a rekordok maximális számát. Alapértelmezés szerint a kiszolgálón legfeljebb 50 oldalméret lehet.

Az első példa bemutatja, hogyan választhatja ki az első öt elemet egy táblából. A lekérdezés a ToDoItems tábla elemeit adja vissza. Az mToDoTable a korábban létrehozott háttértábla hivatkozása:

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

Lássunk egy lekérdezést, amely kihagyja az első öt elemet, majd visszaadja a következő öt elemet:

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

Ha egy tábla összes rekordját le szeretné kapni, implementáljon egy kódot, amely az összes oldalon iterál:

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

A metódust használó összes rekordra vonatkozó kérés legalább két kérést hoz létre a Mobile Apps háttérhez.

Tipp

A megfelelő oldalméret kiválasztása egyensúlyban van a kérés közbeni memóriahasználat, a sávszélesség-használat és az adatok teljes fogadásának késése között. Az alapértelmezett (50 rekord) minden eszköz számára megfelelő. Ha kizárólag nagyobb méretű memóriaeszközökön működik, növelje az 500-ast. Azt találtuk, hogy az oldalméret 500 rekordnál nagyobb növelése elfogadhatatlan késést és nagy memória-problémákat okozhat.

How to: Concatenate query methods

A háttértáblák lekérdezéséhez használt metódusok össze lehet őket össze concatened. A lekérdezési metódusok láncolása lehetővé teszi a szűrt sorok adott oszlopainak kiválasztását, amelyek rendezve és lapozással vannak meglapolva. Összetett logikai szűrőket is létrehozhat. Minden lekérdezési metódus egy Lekérdezés objektumot ad vissza. A metódusok sorozatának végét és a lekérdezés ténylegesen futtatását az execute metódus hívásával hajtjuk végre. Például:

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

A láncolt lekérdezési metódusokat az alábbiak szerint kell rendezetten lennie:

  1. Szűrési (where) metódusok.
  2. Rendezési (orderBy) metódusok.
  3. Kijelölési (select) metódusok.
  4. lapozási (skip és top) metódusok.

Adatok kötése a felhasználói felülethez

Az adatkötés három összetevőből áll:

  • Az adatforrás
  • A képernyő elrendezése
  • A kettő egymáshoz csatlakozó adaptere.

A mintakódban a ToDoItem tábla Mobile Apps SQL Azure egy tömbbe adatokat ad vissza. Ez a tevékenység gyakori minta az adatalkalmazások esetében. Az adatbázis-lekérdezések gyakran olyan sorgyűjteményt adnak vissza, amelybe az ügyfél egy listában vagy tömbben kerül. Ebben a példában a tömb az adatforrás. A kód egy képernyőelrendezést határoz meg, amely meghatározza az eszközön megjelenő adatok nézetét. A kettő egy adapterrel van összekötve, amely ebben a kódban az ArrayAdapterToDoItem< osztály kiterjesztése> .

Az elrendezés meghatározása

Az elrendezést számos XML-kódrészlet definiálja. Egy meglévő elrendezést használva az alábbi kód azt a ListView nézetet jelöli, amelybe a kiszolgálóadatokat szeretnénk feltölteni.

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

Az előző kódban a listitem attribútum határozza meg a lista egy adott sorának elrendezésének azonosítóját. Ez a kód megad egy jelölőnégyzetet és a hozzá tartozó szöveget, és egyszer példányosítja a lista minden elemét. Ez az elrendezés nem jeleníti meg az id mezőt, és egy összetettebb elrendezés további mezőket adna meg. Ez a kód arow_list_to_do.xml fájlban található.

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

Az adapter meghatározása

Mivel a nézet adatforrása a ToDoItem tömbje, az adaptert egy ArrayAdapterToDoItem< osztályból alosztályba soroljuk> . Ez az alosztály minden ToDoItemhez létrehoz egy Nézetet a row_list_to_do használatával . A kódban a következő osztályt definiáljuk, amely az ArrayAdapterE< osztály kiterjesztése> :

public class ToDoItemAdapter extends ArrayAdapter<ToDoItem> {
}

Bírálja felül a getView metódus adapterét . Például:

    @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;
    }

Ennek az osztálynak egy példányát a tevékenységünkben a következőképpen hozhatjuk létre:

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

A ToDoItemAdapter konstruktor második paramétere az elrendezésre való hivatkozás. Most már példányosodhat a ListView, és hozzárendelheti az adaptert a ListView nézethez.

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

Az adapter használata a felhasználói felülethez való kötéshez

Most már készen áll az adatkötés használatára. Az alábbi kód bemutatja, hogyan töltheti le a táblában lévő elemeket, és hogyan töltheti ki a helyi adaptert a visszaadott elemekkel.

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

Hívja meg az adaptert minden alkalommal, amikor módosítja a ToDoItem táblát . Mivel a módosítások rekord alapján történik, gyűjtemény helyett egyetlen sort kell kezelnie. Elem beszúrásakor hívja meg az add metódust az adapteren; törléskor hívja meg a remove metódust .

Teljes példát az Android gyors üzembe helyezési útmutatója Project.

Adatok beszúrása a háttérbe

Példányositsa a ToDoItem osztály egy példányát, és állítsa be annak tulajdonságait.

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

Ezután az insert() használatával szúrjon be egy objektumot:

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

A visszaadott entitás megegyezik a háttértáblába beszúrt adatokkal, tartalmazza az azonosítót és a háttéren beállított egyéb értékeket (createdAtpéldául , updatedAtversion és mezőket).

Mobile Apps táblákhoz szükség van egy id nevű elsődleges kulcsoszlopra. Ennek az oszlopnak sztringnek kell lennie. Az id oszlop alapértelmezett értéke egy GUID. Egyéb egyedi értékeket is meg lehet adni, például e-mail-címeket vagy felhasználóneveket. Ha nem ad meg sztringazonosító értéket egy beszúrt rekordhoz, a háttér egy új GUID-t hoz létre.

A sztringazonosító értékek a következő előnyöket biztosítják:

  • Az adatbázis-adatforgalom nélkül is létre lehet majd generálni az adatokat.
  • A rekordok könnyebben egyesíthetők különböző táblákból vagy adatbázisokból.
  • Az azonosítóértékek jobban integrálhatók az alkalmazás logikájával.

Az offline szinkronizálás támogatásához sztringazonosító-értékek szükségesek. Az azonosítók nem változtathatóak meg, ha a háttéradatbázisban tárolják őket.

Adatok frissítése mobilalkalmazásban

Egy tábla adatainak frissítéséhez adja át az új objektumot az update() metódusnak .

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

Ebben a példában az elem a ToDoItem tábla egy sorra hivatkozik, amelyben módosításokat is végrehajtottak. Az azonos azonosítójú sor frissül.

Adatok törlése mobilalkalmazásban

Az alábbi kód bemutatja, hogyan törölhet adatokat egy táblából az adatobjektum megadásával.

mToDoTable
    .delete(item);

Egy elemet a törölni kívánt sor azonosító mezőjének megadásával is törölhet.

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

Adott elem ki keresse azonosító alapján

A lookUp() metódussal keresse meg az adott azonosítómezővel kapcsolatos elemet:

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

How to: Work with untyped data (Hogyan lehet: Nem típusos adatok használata)

A nem típusos programozási modell pontosan szabályozhatja a JSON-szerializálást. Vannak olyan gyakori helyzetek, amikor nem típusos programozási modellt szeretne használni. Ha például a háttértábla sok oszlopot tartalmaz, és csak az oszlopok egy részére kell hivatkozni. A típusos modellhez meg kell határoznia az adatosztály háttérbeli Mobile Apps a modellben meghatározott összes oszlopot. Az adatok eléréséhez szükséges API-hívások nagy része hasonló a típusos programozási hívásokhoz. A fő különbség az, hogy a nem típusos modellben metódusokat hív meg a MobileServiceJsonTable objektumon a MobileServiceTable objektum helyett.

Nem típusos tábla példányának létrehozása

A típusos modellhez hasonlóan először egy táblahivatkozást kap, de ebben az esetben ez egy MobileServicesJsonTable objektum. A hivatkozás beszerzéséhez hívja meg a getTable metódust az ügyfél egy példányán:

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

Miután létrehozta a MobileServiceJsonTable egy példányát, gyakorlatilag ugyanaz az API áll rendelkezésre, mint a típusos programozási modellben. Bizonyos esetekben a metódusok nem típusos paramétert, hanem nem típusos paramétert alkalmaznak.

Beszúrás nem típusos táblába

Az alábbi kód beszúrásokat mutat be. Az első lépés egy JsonObject létrehozása, amely a gson kódtár része.

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

Ezután az insert() használatával szúrja be a nem típusos objektumot a táblába.

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

Ha le kell szereznie a beszúrt objektum azonosítóját, használja a getAsJsonPrimitive() metódust .

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

Törlés nem típusos táblából

Az alábbi kód bemutatja, hogyan törölhet egy példányt, ebben az esetben az előző beszúrási példában létrehozott JsonObjectugyanazon példányát . A kód megegyezik a típusos esetével, de a metódus eltérő aláírással rendelkezik, mivel egy JsonObjectre hivatkozik.

mToDoTable
    .delete(insertedItem);

A példányok közvetlenül is törölhetők az azonosítójuk használatával:

mToDoTable.delete(ID);

Egy nem típusos tábla összes sorának visszaadása

Az alábbi kód bemutatja, hogyan lehet lekérni egy teljes táblát. Mivel JSON-táblát használ, csak a tábla egyes oszlopait tudja szelektíven lekérni.

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

A típusos modellhez elérhető szűrési, szűrési és lapozási módszerek azonos készlete érhető el a nem típusos modellhez.

Offline szinkronizálás megvalósítása

Az Azure Mobile Apps Client SDK az adatok offline szinkronizálását is megvalósítja egy SQLite-adatbázis használatával a kiszolgálói adatok másolatának helyi tárolására. Az offline táblán végrehajtott műveletek nem igényelnek mobilkapcsolatot a működéshez. Az offline szinkronizálás az ütközésfeloldás összetettebb logikájának rovására segít a rugalmasságban és a teljesítményben. Az Azure Mobile Apps Client SDK a következő funkciókat valósítja meg:

  • Növekményes szinkronizálás: A rendszer csak a frissített és új rekordokat töltse le, ezzel sávszélesség- és memóriafelhasználást takarít meg.
  • Optimista egyidejűség-ség: A műveletek sikeresnek vannak feltételezve. Az ütközésfeloldás csak akkor halasztható el, ha a frissítések végre nem hajtva a kiszolgálón.
  • Ütközésfeloldás: Az SDK észleli, ha ütköző módosítás történt a kiszolgálón, és olyan hookokat biztosít, amelyek figyelmeztetik a felhasználót.
  • Soft Delete :A törölt rekordok töröltként vannak megjelölve, így más eszközök frissíthetik az offline gyorsítótárukat.

Offline szinkronizálás inicializálása

Használat előtt minden offline táblát meg kell határozni az offline gyorsítótárban. A tábladefiníció általában közvetlenül az ügyfél létrehozása után történik:

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

Hivatkozás beszerzése az offline gyorsítótár táblára

Online tábla esetén használja a következőt: .getTable(). Offline tábla esetén használja a következőt .getSyncTable():

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

Az online táblákhoz elérhető összes módszer (beleértve a szűrést, a rendezést, a lapozást, az adatbeszúrásokat, az adatok frissítését és az adatok törlését) szintén jól működik online és offline táblákon.

A helyi offline gyorsítótár szinkronizálása

A szinkronizálás az alkalmazás vezérlése alatt áll. Példa a szinkronizálási módszerre:

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

Ha a metódushoz .pull(query, queryname) lekérdezésnevet ad meg, akkor a növekményes szinkronizálás csak a legutóbbi sikeres lekérdezés óta létrehozott vagy módosított rekordokat adja vissza.

Ütközések kezelésére offline szinkronizálás során

Ha ütközés történik egy művelet .push() során, a rendszer egy -t MobileServiceConflictException ad vissza. A kiszolgáló által kiadott elem be van ágyazva a kivételbe .getItem() , és lekérhető a kivételből. Módosítsa a leküldést a MobileServiceSyncContext objektum következő elemeinek hívása révén:

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

Miután az összes ütközést a kívántként jelölte meg, .push() hívja meg újra a hívást az összes ütközés feloldásához.

Egyéni API hívása

Az egyéni API-k segítségével olyan egyéni végpontokat definiálhat, amelyek olyan kiszolgálófunkciókat tesz elérhetővé, amelyek nem vannak leképezve beszúrási, frissítési, törlési vagy olvasási műveletre. Egyéni API használatával jobban szabályozhatja az üzenetküldést, beleértve a HTTP-üzenetfejlécek olvasását és beállítását, valamint a JSON-on kívül más üzenet törzsformátumának definiálása.

Android-ügyfélről meghívhatja az invokeApi metódust az egyéni API-végpont meghívásához. Az alábbi példa bemutatja, hogyan hívhat meg egy completeAll nevű API-végpontot, amely egy MarkAllResult nevű gyűjteményosztályt ad vissza.

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

A rendszer meghívja az invokeApi metódust az ügyfélen, amely egy POST kérést küld az új egyéni API-nak. Az egyéni API által visszaadott eredmény is megjelenik egy üzenetablakban, ahogy a hibák is. Az invokeApi más verzióival opcionálisan küldhet egy objektumot a kérelem törzsében, megadhatja a HTTP-metódust, és lekérdezési paramétereket küldhet a kéréssel. Az invokeApi nem típusos verziói is meg vannak biztosítanak.

Hitelesítés hozzáadása az alkalmazáshoz

Az oktatóanyagok már részletesen ismertetik ezeknek a funkcióknak a hozzáadását.

App Service támogatja az alkalmazásfelhasználók hitelesítését különböző külső identitásszolgáltatók használatával: Facebook, Google, Microsoft-fiók, Twitter és Azure Active Directory. Beállíthatja a táblákra vonatkozó engedélyeket, így csak a hitelesített felhasználókra korlátozhatja az adott műveletekhez való hozzáférést. A hitelesített felhasználók identitásával engedélyezési szabályokat is megvalósíthat a háttérben.

Két hitelesítési folyamat támogatott: egy kiszolgálói folyamat és egy ügyfélfolyamat . A kiszolgálói folyamat biztosítja a legegyszerűbb hitelesítési felületet, mivel az identitásszolgáltatók webes felületére támaszkodik. A kiszolgálófolyam-hitelesítés megvalósításához nincs szükség további SDK-kra. A kiszolgálói folyamat hitelesítése nem biztosít részletes integrációt a mobileszközbe, és csak a koncepció igazolása esetén ajánlott.

Az ügyfélfolyam mélyebb integrációt tesz lehetővé az eszközspecifikus képességekkel, például az egyszeri bejelentkezéssel, mivel az identitásszolgáltató által biztosított SZOFTVERDK-kra támaszkodik. Integrálhatja például a Facebook SDK-t a mobilalkalmazásba. A mobilügyfelének fel kell cserélnie a Facebook-alkalmazást, és a mobilalkalmazásra való visszacserélés előtt megerősíti a bejelentkezést.

Az alkalmazásban a hitelesítés engedélyezéséhez négy lépés szükséges:

  • Regisztrálja alkalmazását hitelesítésre egy identitásszolgáltatónál.
  • Konfigurálja App Service háttér-kiszolgálót.
  • A táblaengedélyek korlátozása a hitelesített felhasználókra csak a App Service háttéren.
  • Adja hozzá a hitelesítési kódot az alkalmazáshoz.

Beállíthatja a táblákra vonatkozó engedélyeket, így csak a hitelesített felhasználókra korlátozhatja az adott műveletekhez való hozzáférést. A kérelmek módosításához egy hitelesített felhasználó biztonsági azonosítóját is használhatja. További információt a hitelesítéssel kapcsolatos Első lépések a Server SDK howTO dokumentációjában talál.

Hitelesítés: Kiszolgálói Flow

Az alábbi kód elindítja a kiszolgálófolyamat bejelentkezési folyamatát a Google-szolgáltató használatával. További konfigurációra van szükség a Google-szolgáltató biztonsági követelményei miatt:

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

Emellett adja hozzá a következő metódust a fő Tevékenység osztályhoz:

// 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");
            }
        }
    }
}

A GOOGLE_LOGIN_REQUEST_CODE fő tevékenységben meghatározott metódust a login() metódusban és a metóduson belül használja onActivityResult() a függvény. Bármilyen egyedi számot választhat, login() ha ugyanazt a számot használja a metódusban és a metódusban onActivityResult() . Ha az ügyfélkódot egy szolgáltatásadapterbe kivonatolta (ahogy korábban látható), akkor a megfelelő metódusokat kell hívnia a szolgáltatásadapteren.

A projektet a customtabs beállításhoz is konfigurálnia kell. Először adjon meg egy átirányítási URL-címet. Adja hozzá a következő kódrészletet a következő hez 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>

Adja hozzá a redirectUriScheme et az alkalmazás build.gradle fájljában:

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

Végül adja hozzá com.android.support:customtabs:28.0.0 a következőt a fájl függőségeinek listájához build.gradle :

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'
}

Szerezze be a bejelentkezett felhasználó azonosítóját egy MobileServiceUser felhasználótól a getUserId metódussal . Az aszinkron bejelentkezési API-k Futures használatával történő meghívásával kapcsolatban lásd a hitelesítéssel Első lépések példát.

Figyelmeztetés

Az említett URL-séma megkülönbözteti a kis- és nagybetűket. Győződjön meg arról, hogy az egyező eset minden {url_scheme_of_you_app} előfordulását meg kell egyeznie.

Gyorsítótár-hitelesítési jogkivonatok

Caching hitelesítési jogkivonatok használatához helyileg kell tárolnia a felhasználói azonosítót és a hitelesítési jogkivonatot az eszközön. Amikor az alkalmazás legközelebb elindul, ellenőrzi a gyorsítótárat, és ha ezek az értékek jelen vannak, kihagyhatja a bejelentkezési eljárást, és rehidratálhatja az ügyfelet ezekkel az adatokkal. Ezek az adatok azonban bizalmasak, és a biztonság érdekében titkosítani kell őket arra az esetre, ha ellopják a telefont. A hitelesítési jogkivonatok gyorsítótárazásának teljes példáját a Gyorsítótár-hitelesítési jogkivonatok szakaszban láthatja.

Ha lejárt jogkivonatot próbál használni, egy 401-es jogosulatlan választ kap . A hitelesítési hibák szűrőkkel kezelhetők. A szűrők elfogják a App Service kéréseket. A szűrőkód teszteli a 401-es válaszát, elindítja a bejelentkezési folyamatot, majd folytatja a 401-et generáló kérést.

Frissítési jogkivonatok használata

A hitelesítés és Azure App Service által visszaadott jogkivonat egy órás meghatározott élettartamtal rendelkezik. Ezt az időszakot követően újra hitelesnie kell a felhasználót. Ha ügyfélfolyam-hitelesítéssel kapott hosszú életű jogkivonatot használ, akkor ugyanaz a jogkivonat Azure App Service hitelesítéssel és engedélyezéssel újrahitelesíthet. Egy Azure App Service jogkivonat új élettartammal jön létre.

Regisztrálhatja a szolgáltatót is a Frissítési jogkivonatok használatára. A frissítési jogkivonat nem mindig érhető el. További konfigurációra van szükség:

  • A Azure Active Directory konfigurálja az ügyfél titkos ját a Azure Active Directory alkalmazáshoz. Adja meg az ügyfél titkos kulcsát a Azure App Service hitelesítő Azure Active Directory konfigurálásakor. A hívásakor .login()paraméterként response_type=code id_token adja át a következőt:

    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);
    
  • A Google-hez a paraméterként access_type=offline adja meg a következőt:

    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);
    
  • A Microsoft-fiók mezőben válassza ki a hatókört wl.offline_access .

Jogkivonat frissítéshez hívja meg a következőt .refreshUser():

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

Ajánlott eljárásként hozzon létre egy szűrőt, amely észleli a kiszolgálótól érkezett 401-es választ, és megkísérli frissíteni a felhasználói jogkivonatot.

Bejelentkezés ügyfélfolyam-hitelesítéssel

Az ügyfélfolyamat-hitelesítéssel való bejelentkezés általános folyamata a következő:

  • Konfigurálja Azure App Service hitelesítést és engedélyezést úgy, mint a kiszolgálófolyam-hitelesítést.

  • Integrálja a hitelesítésszolgáltatói SDK-t a hitelesítéshez egy hozzáférési jogkivonat előállításához.

  • Hívja meg .login() a metódust a következőképpen (result egynek kell lennie 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");
        }
    });
    

Tekintse meg a teljes példakódot a következő szakaszban.

Cserélje le onSuccess() a metódust a sikeres bejelentkezéshez használni kívánt kódra. A {provider} sztring érvényes szolgáltató: aad (Azure Active Directory), facebook, google, microsoftaccount vagy twitter. Ha egyéni hitelesítést valósított meg, akkor az egyéni hitelesítésszolgáltató címkét is használhatja.

Felhasználók hitelesítése a Active Directory-hitelesítési tár (ADAL)

A Active Directory-hitelesítési tár (ADAL) használatával bejelentkeztetheti a felhasználókat az alkalmazásba a Azure Active Directory. Az ügyfélfolyam-bejelentkezés használata loginAsync() gyakran előnyösebb a metódusok használata helyett, mivel natívabb felhasználói felületi használatot biztosít, és további testreszabást tesz lehetővé.

  1. Konfigurálja a mobilalkalmazás háttéralkalmazását a AAD való bejelentkezéshez a bejelentkezési útmutató App Service konfigurálás Active Directory használatával. Mindenképpen a natív ügyfélalkalmazás regisztrálásának opcionális lépését kell végrehajtania.

  2. Telepítse az ADAL-t a build.gradle fájl módosításával, hogy tartalmazza a következő definíciókat:

    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. Adja hozzá a következő kódot az alkalmazáshoz, és helyettesítse be a következőt:

    • Cserélje le az INSERT-AUTHORITY-HERE helyére annak a bérlőnek a nevét, amelyben az alkalmazást kiépítte. A formátumnak a következőnek kell lennie: https://login.microsoftonline.com/contoso.onmicrosoft.com.
    • Cserélje le az INSERT-RESOURCE-ID-HERE helyére a mobilalkalmazás háttéralkalmazásának ügyfél-azonosítóját. Az ügyfél-azonosítót a portálon, a portál Azure Active Directory Gépház speciális lapján szerezheti be.
    • Cserélje le az INSERT-CLIENT-ID-HERE helyére a natív ügyfélalkalmazásból másolt ügyfél-azonosítót.
    • Cserélje le az INSERT-REDIRECT-URI-HERE helyére a webhely /.auth/login/done végpontját a HTTPS-séma használatával. Ennek az értéknek a következőhez hasonlónak kell lennie: 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);
    }
}

A kommunikáció Client-Server beállítása

Az ügyfélkapcsolat általában egy alapszintű HTTP-kapcsolat, amely az Android SDK által biztosított mögöttes HTTP-kódtárat használja. Ennek számos oka lehet:

  • Alternatív HTTP-kódtárat szeretne használni az időtúllépések módosításához.
  • Egy folyamatjelző sávot szeretne adni.
  • Egyéni fejlécet szeretne hozzáadni az API Management funkcióinak támogatásához.
  • El szeretne fogni egy sikertelen választ, hogy megvalósítsa az újrahitelesítést.
  • A háttérkéréseket egy elemzési szolgáltatásnak szeretné naplózni.

Alternatív HTTP-kódtár használata

Közvetlenül az .setAndroidHttpClientFactory() ügyfélhivatkozás létrehozása után hívja meg a metódust. Ha például a kapcsolat időkorlátját 60 másodpercre (az alapértelmezett 10 másodperc helyett) állítsa be:

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

Folyamatszűrő megvalósítása

Minden kérést elfoghat egy implementálja ServiceFilter. A következő például egy előre létrehozott folyamatjelző sávot frissíti:

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

Ezt a szűrőt a következőképpen csatolhatja az ügyfélhez:

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

Kérelemfejlécek testreszabása

Használja a következőt, ServiceFilter és csatolja a szűrőt ugyanúgy, mint a :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);
        }
    }
}

Automatikus szerializálás konfigurálása

A gson API használatával minden oszlopra alkalmazható konverziós stratégiát megadhat . Az androidos ügyféloldali kódtár a háttérben a gson használatával szerializálJa a Java-objektumokat JSON-adatokkal, mielőtt az adatokat a rendszer Azure App Service. Az alábbi kód a setFieldNamingStrategy() metódust használja a stratégia beállítására. Ez a példa törli a kezdeti karaktert (egy "m"), majd kisbetűvel a következő karaktert minden mezőnévhez. Az "mId" például "id" lesz. Implementálhat egy konverziós stratégiát, hogy a legtöbb SerializedName() mezőhöz kevesebb jegyzetre van szükség.

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

Ezt a kódot végre kell hajtani, mielőtt mobil ügyfélhivatkozást hoz létre a MobileServiceClient használatával.