Megosztás a következőn keresztül:


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

Ez az útmutató bemutatja, hogyan használhatja az Android ügyféloldali SDK for Mobile Appst olyan gyakori forgatókönyvek implementálásához, mint 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. A Mobile Apps kiszolgálóoldali SDK-jairól a .NET háttérrendszer SDK használata vagy a Node.js háttérbeli SDK használata című témakörben olvashat bővebben.

Referenciadokumentáció

Az Android-ügyfélkódtár Javadocs API-referenciája a GitHubon található.

Támogatott platformok

Az Androidhoz készült Azure Mobile Apps SDK támogatja a 19–24-es API-szinteket (KitKat-tól Nougatig) a telefonos és táblagépes formatényezők esetében. A hitelesítés különösen egy általános webes keretrendszer-megközelítést használ a hitelesítő adatok gyűjtéséhez. A kiszolgálói forgalom hitelesítése nem működik kis méretű, például órákat tartalmazó eszközökkel.

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

Végezze el a Mobile Apps rövid útmutatójának oktatóanyagát. Ez a feladat biztosítja, hogy az Azure Mobile Apps fejlesztéséhez szükséges összes előfeltétel teljesült. A rövid útmutató emellett segítséget nyújt a fiók konfigurálásában és az első Mobilalkalmazás-háttérrendszer létrehozásához.

Ha úgy dönt, hogy nem végzi el a rövid útmutatót, végezze el a következő feladatokat:

A Gradle buildfájljának frissítése

Mindkét build.gradle fájl módosítása:

  1. Adja hozzá ezt a kódot a Project level build.gradle fájlhoz:

    buildscript {
        repositories {
            jcenter()
            google()
        }
    }
    
    allprojects {
        repositories {
            jcenter()
            google()
        }
    }
    
  2. Adja hozzá ezt a kódot a Modul alkalmazásszintű build.gradle fájlhoz a függőségek címkén belül:

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

    Jelenleg a legújabb verzió a 3.4.0. A támogatott verziók a bintray-on vannak felsorolva.

Internetes engedély engedélyezése

Az Azure-hoz való hozzáféréshez 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ás számára:

  • Adathozzáférés és offline szinkronizálás egy Azure Mobile Apps-szolgáltatással.
  • Az Azure Mobile Apps Server SDK-val írt egyéni API-k meghívása.
  • Hitelesítés Azure-alkalmazás szolgáltatáshitelesítéssel és engedélyezéssel.
  • Leküldéses értesítés regisztrálása a Notification Hubs használatával.

Mindegyik függvényhez először létre kell hoznia egy objektumot MobileServiceClient . Csak egy MobileServiceClient objektumot kell létrehozni a mobilügyfélben (vagyis egy Singleton-mintának kell lennie). Objektum létrehozása MobileServiceClient :

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

Ez <MobileAppUrl> egy sztring vagy egy URL-objektum, amely a mobil háttérrendszerre mutat. Ha Azure-alkalmazás szolgáltatást használ a mobil háttérrendszer üzemeltetéséhez, győződjön meg arról, hogy az URL biztonságos https:// verzióját használja.

Az ügyfélnek hozzá kell férnie a tevékenységhez vagy a környezethez – a this példában szereplő paraméterhez. A MobileServiceClient-konstrukciónak a onCreate() fájlban hivatkozott tevékenység metódusán belül kell történnie AndroidManifest.xml .

Ajánlott eljárásként elvont kiszolgálói kommunikációt kell saját (egytonmintás) osztályba helyeznie. Ebben az esetben a konstruktoron belül kell átadnia a tevékenységet a szolgáltatás megfelelő konfigurálásához. Példa:

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 meghívhatja AzureServiceAdapter.Initialize(this); a onCreate() fő tevékenység metódusát. A szolgáltatásadapterre mutató hivatkozás beszerzéséhez minden más, az ügyfélhez AzureServiceAdapter.getInstance(); való hozzáférésre szoruló módszer.

Adatműveletek

Az Azure Mobile Apps SDK lényege, hogy hozzáférést biztosítson az SQL Azure-ban a Mobile App háttérrendszerében tárolt adatokhoz. Ezeket az adatokat szigorúan beírt osztályokkal (előnyben részesített) vagy nem beírt lekérdezésekkel (nem ajánlott) érheti el. A szakasz nagy része erősen gépelt osztályok használatával foglalkozik.

Ügyféladatosztályok definiálása

Az SQL Azure-táblákból származó adatok eléréséhez definiáljon olyan ügyféladatosztályokat, amelyek megfelelnek a Mobile App háttérrendszer tábláinak. A témakör példái egy MyDataTable nevű táblát feltételeznek, amelynek oszlopai a következők:

  • id
  • text
  • kész

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

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

Adjon hozzá getter és setter metódusokat minden egyes hozzáadott mezőhöz. Ha az SQL Azure-tábla több oszlopot tartalmaz, a megfelelő mezőket hozzá kell adnia ehhez az osztályhoz. Ha például a DTO (adatátviteli objektum) egy egész szám prioritási oszlopával rendelkezik, akkor hozzáadhatja ezt a mezőt a getter és a setter 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 a Mobile Apps-háttérrendszerben, olvassa el a How to: Define a table controller (.NET backend) (.NET backend) vagy Define Tables using a Dynamic Schema (Node.js backend) című témakört.

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

  • 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ásának kell lennie.
  • DateTimeOffset updatedAt: Az utolsó frissítés dátuma/időpontja. Az updatedAt mezőt a kiszolgáló állítja be, és az ügyfélkód soha nem állíthatja be.
  • DateTimeOffset createdAt: Az objektum létrehozásának dátuma/ideje. A createdAt mezőt a kiszolgáló állítja be, és soha ne állítsa be az ügyfélkód.
  • byte[] version: Általában sztringként jelenik meg, 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 törölték. Ne használja deleted tulajdonságként az osztályban.

Az id mező kötelező. A updatedAt mező és version a mező offline szinkronizáláshoz (növekményes szinkronizáláshoz és ütközésfeloldáshoz) használatos. A createdAt mező egy referenciamező, amelyet az ügyfél nem használ. A nevek a tulajdonságok "kereszthuzalos" nevei, és nem állíthatók. A gson-kódtár használatával azonban létrehozhat leképezést az objektum és a "vezetékközi" nevek között. Példa:

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 meghívásával a MobileServiceClienten. Ennek a módszernek 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);
}

Az alábbi kódban az mClient a MobileServiceClient objektumra mutató hivatkozás. A rendszer az első túlterhelést használja, ahol az osztály neve és a tábla neve megegyezik, és a rövid útmutatóban használt:

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

A második túlterhelés akkor használatos, 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 szerezze be a táblahivatkozást. Ezután hajtsa végre a lekérdezést a táblahivatkozáson. A lekérdezés a következők bármely kombinációjából áll:

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

Eredmények szűrése

A lekérdezés általános formája:

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érrendszeren. A lekérdezés OData v3-lekérdezéssé lesz konvertálva, mielőtt a Mobile Apps háttérrendszerbe továbbítanák. A Mobile Apps háttérrendszere nyugtán sql utasítássá alakítja a lekérdezést, mielőtt végrehajtja azt az SQL Azure-példányon. Mivel a hálózati tevékenység egy ideig tart, a .execute() metódus egy ListenableFuture<E>.

Visszaadott adatok szűrése

Az alábbi lekérdezés végrehajtása a ToDoItem tábla összes elemét adja vissza, ahol a teljes érték 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 mutató hivatkozás.

Definiáljon egy szűrőt a táblahivatkozás where metódushívásával. A where metódust egy mezőmetódus követi, amelyet a logikai predikátumot meghatározó metódus követ. 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ő). Ezek a módszerek lehetővé teszik a szám- és sztringmezők adott értékekhez való összehasonlítását.

Dátumokra is szűrhet. A következő módszerek segítségével összehasonlíthatja a dátum teljes mezőjét vagy a dátum egyes részeit: év, hónap, nap, óra, perc és másodperc. Az alábbi példa egy szűrőt ad hozzá azokhoz az elemekhez, amelyeknek a határideje 2013.

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

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

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

A következő operátori metódusok támogatottak a számmezőkben: hozzáadás, al, mul, div, mod, padló, mennyezet és kerek. Az alábbi példa olyan táblázatsorokat szűr, ahol az időtartam páros szám.

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

A predikátumokat kombinálhatja a következő logikai módszerekkel: és vagy nem. Az alábbi példa két fenti példát egyesít.

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

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

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 ismertetését és példákat az Android-ügyfél-lekérdezési modell gazdagságának feltárása című témakörben találja.

Visszaadott adatok rendezése

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

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

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

Adott oszlopok kijelölése

Az alábbi kód bemutatja, hogyan adhat vissza minden elemet a ToDoItems táblából, de csak a teljes és a szöveges mezőket jeleníti meg. Az mToDoTable a korábban létrehozott háttértáblára mutató hivatkozás.

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

A kiválasztási függvény paraméterei a visszaadni kívánt táblaoszlopok sztringnevei. A kiválasztási metódusnak olyan metódusokat kell követnie, mint a where és orderBy. Ezt olyan lapozási módszerek követik, mint a kihagyás és a felül.

Adatok visszaszolgáltatása lapokban

Az adatok mindig a lapokban lesznek visszaadva. A visszaadott rekordok maximális számát a kiszolgáló állítja be. Ha az ügyfél több rekordot kér, akkor a kiszolgáló a rekordok maximális számát adja vissza. Alapértelmezés szerint a kiszolgálón a maximális oldalméret 50 rekord.

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áblára mutató hivatkozás:

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

Íme egy lekérdezés, amely kihagyja az első öt elemet, majd a következő öt elemet adja vissza:

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

Ha egy táblában minden rekordot be szeretne szerezni, implementáljon egy kódot az összes oldal iterációjához:

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

Az ezzel a módszerrel létrehozott összes rekordra vonatkozó kérés legalább két kérést hoz létre a Mobile Apps háttérrendszeréhez.

Tipp.

A megfelelő oldalméret kiválasztása egyensúlyt teremt a memóriahasználat és a kérés során, a sávszélesség-használat és az adatok fogadásának késleltetése között. Az alapértelmezett (50 rekord) minden eszközhöz megfelelő. Ha kizárólag nagyobb memóriaeszközökön dolgozik, akár 500-ra is nőhet. Megállapítottuk, hogy az oldalméret 500 rekordnál nagyobb növelése elfogadhatatlan késéseket és nagy memóriaproblémákat eredményez.

Útmutató: Lekérdezési metódusok összefűzése

A háttértáblák lekérdezéséhez használt módszerek összefűzhetők. A láncolási lekérdezési módszerek lehetővé teszik a szűrt sorok adott oszlopainak kijelölését, amelyek rendezve és lapozottan vannak rendezve. Összetett logikai szűrőket is létrehozhat. Minden lekérdezési módszer egy lekérdezési objektumot ad vissza. A metódusok sorozatának befejezéséhez és a lekérdezés tényleges futtatásához hívja meg a végrehajtási metódust. Példa:

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

  1. Szűrési (hol) metódusok.
  2. Rendezési (orderBy) metódusok.
  3. Kiválasztási (kiválasztási) metódusok.
  4. lapozási (kihagyási és felső) 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
  • Az adapter, amely összeköti a kettőt.

A mintakódban a Mobile Apps SQL Azure-táblából származó adatokat egy tömbbe adjuk vissza. Ez a tevékenység az adatalkalmazások gyakori mintája. Az adatbázis-lekérdezések gyakran egy sorgyűjteményt adnak vissza, amelyet az ügyfél egy listában vagy tömbben kap. Ebben a mintá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ő össze van kötve egy adapterrel, amely ebben a kódban a ArrayAdapter<ToDoItem> osztály kiterjesztése.

Az elrendezés definiálása

Az elrendezést xml-kódrészletek határozzák meg. Meglévő elrendezés esetén a következő kód azt a ListView-t jelöli, amelyet a kiszolgáló adataival fel szeretnénk tö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 a lista egy egyes sorának elrendezésének azonosítóját adja meg. Ez a kód egy jelölőnégyzetet és annak társított szövegét adja meg, és a listában szereplő minden elemhez egyszer példányosodik. Ez az elrendezés nem jeleníti meg az azonosító mezőt, és egy összetettebb elrendezés további mezőket adna meg a megjelenítésben. Ez a kód a row_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 definiálása

Mivel a nézet adatforrása a ToDoItem tömbje, az adaptert egy ArrayAdapter<ToDoItem> osztályból osztályba soroljuk. Ez az alosztály minden ToDoItemhez létrehoz egy nézetet a row_list_to_do elrendezés használatával. A kódban a következő osztályt határozzuk meg, amely a ArrayAdapter<E> osztály kiterjesztése:

public class ToDoItemAdapter extends ArrayAdapter<ToDoItem> {
}

Bírálja felül az adapterek getView metódusát. Példa:

    @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 következő módon hozjuk létre a tevékenységünkben:

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

A ToDoItemAdapter konstruktor második paramétere az elrendezésre mutató hivatkozás. Most már példányosíthatjuk a ListView-t , és hozzárendelhetjük az adaptert a ListView-hoz.

    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 szerezhet be elemeket a táblában, é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 a ToDoItem tábla módosításakor. Mivel a módosítások rekord alapján történik, gyűjtemény helyett egyetlen sort kell kezelnie. Amikor beszúr egy elemet, hívja meg a hozzáadási metódust az adapteren; törléskor hívja meg az eltávolítási metódust.

Az Android gyorsútmutató-projektben egy teljes példát talál.

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

Példányosíthatja a ToDoItem osztály egy példányát, és beállíthatja 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érrendszeren beállított egyéb értékeket (például a createdAt, updatedAtés version mezőket).

A Mobile Apps-táblákhoz egy azonosító nevű elsődleges kulcsoszlop szükséges. Ennek az oszlopnak sztringnek kell lennie. Az azonosító oszlop alapértelmezett értéke egy GUID. Egyéb egyedi értékeket is megadhat, például e-mail-címeket vagy felhasználóneveket. Ha nincs megadva sztringazonosító érték a beszúrt rekordhoz, a háttérrendszer létrehoz egy új GUID azonosítót.

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

  • Az azonosítók anélkül hozhatók létre, hogy oda-vissza utaznak az adatbázisba.
  • A rekordok egyszerűbben 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.

A kapcsolat nélküli szinkronizálás támogatásához sztringazonosító értékek szükségesek . Miután a háttéradatbázisban tárolta, nem módosíthatja az azonosítót.

Adatok frissítése mobilalkalmazásban

A 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 sorára mutató hivatkozás, amely módosította azt. 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 keresése azonosító szerint

Keressen egy adott azonosítómezővel rendelkező elemet a lookUp() metódussal:

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

Útmutató: Nem beírt adatok használata

A nem beírt programozási modell pontosan szabályozza a JSON-szerializálást. Vannak olyan gyakori forgatókönyvek, amelyekben előfordulhat, hogy nem beírt programozási modellt szeretne használni. Ha például a háttértábla sok oszlopot tartalmaz, és csak az oszlopok egy részhalmazára kell hivatkoznia. A gépelt modellhez meg kell határoznia az adatosztály Mobile Apps háttérrendszerében definiált összes oszlopot. Az adatok elérésére szolgáló API-hívások többsége hasonló a gépelt programozási hívásokhoz. A fő különbség az, hogy a nem beírt modellben a MobileServiceJsonTable objektum metódusait hívja meg a MobileServiceTable objektum helyett.

Nem beírt táblapéldány létrehozása

A gépelt modellhez hasonlóan először egy táblahivatkozást kap, de ebben az esetben ez egy MobileServicesJsonTable objektum. A hivatkozás lekéré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 ugyanazzal az API-val rendelkezik, mint a gépelt programozási modell esetében. Bizonyos esetekben a metódusok nem gépelt paramétert használnak begépelt paraméter helyett.

Beszúrás nem beírt táblába

Az alábbi kód bemutatja, hogyan kell beszúrni. 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 a beszúrás() használatával szúrja be a nem beírt objektumot a táblába.

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

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

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

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

Az alábbi kód bemutatja, hogyan törölhet egy példányt, ebben az esetben ugyanazzal a JsonObject-példánysal, amelyet az előző beszúrási példában hoztak létre. A kód megegyezik a beírt esettel, de a metódus eltérő aláírással rendelkezik, mivel egy JsonObjectre hivatkozik.

mToDoTable
    .delete(insertedItem);

A példányokat közvetlenül is törölheti az azonosítójával:

mToDoTable.delete(ID);

Nem beírt 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, szelektíven csak a tábla egyes oszlopait kérdezheti le.

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 gépelt modellhez elérhető szűrési, szűrési és lapozási módszerek azonos készlete érhető el a nem beírt modellhez.

Offline szinkronizálás implementálása

Az Azure Mobile Apps ügyféloldali SDK az adatok offline szinkronizálását is megvalósítja egy SQLite-adatbázis használatával a kiszolgálóadatok helyi tárolásához. Az offline táblákon végrehajtott műveletekhez nincs szükség mobilkapcsolatra. Az offline szinkronizálás segít a rugalmasságban és a teljesítményben az ütközésmegoldás összetettebb logikájának rovására. Az Azure Mobile Apps ügyféloldali SDK a következő funkciókat valósítja meg:

  • Növekményes szinkronizálás: Csak a frissített és az új rekordok töltődnek le, így sávszélességet és memóriahasználatot takaríthat meg.
  • Optimista egyidejűség: A műveletek sikeresnek számítanak. Az ütközések feloldását a rendszer elhalasztja, amíg a frissítéseket nem hajtja végre 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 horgokkal figyelmezteti a felhasználót.
  • Helyreállítható törlés: A törölt rekordok törölve vannak megjelölve, így más eszközök frissíthetik 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 lekérése az offline gyorsítótártáblára

Online tábla esetén a ..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 adatok beszúrását, az adatok frissítését és az adatok törlését) egyformán jól működik az online és offline táblákon.

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

A szinkronizálás az alkalmazáson belül van. Íme egy példa 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ódus egy lekérdezésnevet ad meg, akkor a .pull(query, queryname) növekményes szinkronizálás csak azokat a rekordokat adja vissza, amelyeket az utolsó sikeres lekérés óta hoztak létre vagy módosítottak.

Ütközések kezelése offline szinkronizálás közben

Ha egy művelet során .push() ütközés történik, MobileServiceConflictException a rendszer egy hibát ad ki. A kiszolgáló által kiadott elem beágyazva van a kivételbe, és lekérhető .getItem() a kivétel alapján. Állítsa be a leküldést a MobileServiceSyncContext objektum következő elemeinek meghívásával:

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

Miután az összes ütközést tetszés szerint megjelölte, hívja .push() újra az összes ütközés feloldásához.

Egyéni API meghívása

Az egyéni API-k segítségével olyan egyéni végpontokat határozhat meg, amelyek olyan kiszolgálófunkciókat fednek le, amelyek nem képeznek le beszúrási, frissítési, törlési vagy olvasási műveletet. Egyéni API használatával nagyobb mértékben szabályozhatja az üzenetkezelést, beleértve a HTTP-üzenetfejlécek olvasását és beállítását, valamint a JSON-tól eltérő üzenettörzs-formátum definiálását.

Egy Android-ügyfélen meghívja 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égpont, 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 a invokeApi metódust az ügyfélen, amely post kérést küld az új egyéni API-nak. Az egyéni API által visszaadott eredmény megjelenik egy üzenet párbeszédpanelen, ahogy a hibák is. Az invokeApi más verziói lehetővé teszik, hogy opcionálisan küldjön egy objektumot a kérelem törzsében, adja meg a HTTP-metódust, és küldje el a lekérdezési paramétereket a kéréssel. Az invokeApi nem gépelt verziói is elérhetők.

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.

Az App Service támogatja az alkalmazásfelhasználók hitelesítését különböző külső identitásszolgáltatókkal: Facebook, Google, Microsoft Account, Twitter és Azure Active Directory. A táblákra vonatkozó engedélyeket úgy állíthatja be, hogy az adott műveletekhez való hozzáférést csak hitelesített felhasználókra korlátozza. A hitelesített felhasználók identitásával is implementálhat engedélyezési szabályokat a háttérrendszerben.

Két hitelesítési folyamat támogatott: egy kiszolgálói folyamat és egy ügyfélfolyamat . A kiszolgálói folyamat a legegyszerűbb hitelesítési élményt nyújtja, mivel az identitásszolgáltatók webes felületére támaszkodik. A kiszolgálói folyamat hitelesítésének megvalósításához nincs szükség további SDK-kra. A kiszolgálói forgalom hitelesítése nem biztosít mély integrációt a mobileszközbe, és csak a koncepciós forgatókönyvek ellenőrzéséhez ajánlott.

Az ügyfélfolyamat lehetővé teszi az eszközspecifikus képességek, például az egyszeri bejelentkezés mélyebb integrációját, mivel az identitásszolgáltató által biztosított SDK-kra támaszkodik. Integrálhatja például a Facebook SDK-t a mobilalkalmazásba. A mobilügyfél felcseréli a Facebook-alkalmazást, és megerősíti a bejelentkezést, mielőtt visszacseréli a mobilalkalmazásra.

Négy lépésre van szükség a hitelesítés engedélyezéséhez az alkalmazásban:

  • Regisztrálja az alkalmazást hitelesítésre egy identitásszolgáltatónál.
  • Konfigurálja az App Service-háttérrendszert.
  • A táblaengedélyek korlátozása csak az App Service-háttérrendszer hitelesített felhasználóira.
  • Adjon hozzá hitelesítési kódot az alkalmazáshoz.

A táblákra vonatkozó engedélyeket úgy állíthatja be, hogy az adott műveletekhez való hozzáférést csak hitelesített felhasználókra korlátozza. A hitelesített felhasználó SID-jének használatával is módosíthatja a kéréseket. További információkért tekintse át a hitelesítés első lépéseit és a Kiszolgáló SDK HOWTO dokumentációját.

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

Az alábbi kód elindítja a kiszolgálói 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égosztá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 definiált érték a metódushoz és a login() metóduson belül lesz használva onActivityResult() . Tetszőleges egyedi számot választhat, ha ugyanazt a számot használja a metódus és a login() onActivityResult() metódus. Ha az ügyfélkódot egy szolgáltatásadapterre absztraktálja (ahogy korábban is láthattuk), hívja meg a megfelelő metódusokat a szolgáltatásadapteren.

A projektet egyéni feladatokhoz 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őhöz 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 fájlt az build.gradle alkalmazás fájljához:

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 vegye fel com.android.support:customtabs:28.0.0 a fájlt a függőségek listájára 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 MobileServiceUserből a getUserId metódus használatával. Az aszinkron bejelentkezési API-knak a Futures használatával történő meghívására vonatkozó példaért tekintse meg a hitelesítés első lépéseit.

Figyelmeztetés

Az említett URL-séma megkülönbözteti a kis- és nagybetűkre vonatkozó adatokat. Győződjön meg arról, hogy az egyezéses eset összes előfordulása {url_scheme_of_you_app} .

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

A hitelesítési jogkivonatok gyorsítótárazásához helyileg kell tárolnia a felhasználói azonosítót és a hitelesítési jogkivonatot az eszközön. Az alkalmazás következő indításakor ellenőrzi a gyorsítótárat, és ha ezek az értékek szerepelnek, kihagyhatja a bejelentkezési eljárást, és újrahidratálhatja az ügyfelet ezekkel az adatokkal. Ezek az adatok azonban bizalmasak, és biztonsági okokból titkosítva kell tárolni őket, 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 tekintheti meg.

Ha lejárt jogkivonatot próbál használni, 401 jogosulatlan választ kap. A hitelesítési hibákat szűrőkkel kezelheti. Szűrők elfogják az App Service háttérrendszeréhez érkező kéréseket. A szűrőkód egy 401-hez teszteli a választ, elindítja a bejelentkezési folyamatot, majd folytatja a 401-et létrehozó kérést.

Jogkivonatok frissítése

A Azure-alkalmazás szolgáltatáshitelesítés és -engedélyezés által visszaadott jogkivonat élettartama egy óra. Ezt követően újra meg kell adnia a felhasználót. Ha egy hosszú élettartamú jogkivonatot használ, amelyet ügyfélfolyamat-hitelesítéssel kapott, akkor ugyanazzal a jogkivonattal újrahitelesítheti Azure-alkalmazás szolgáltatáshitelesítést és engedélyezést. Egy másik Azure-alkalmazás szolgáltatásjogkivonat jön létre egy új élettartammal.

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

  • Az Azure Active Directory esetében konfiguráljon egy ügyfélkulcsot az Azure Active Directory-alkalmazáshoz. Az Azure Active Directory-hitelesítés konfigurálásakor adja meg az ügyfélkulcsot a Azure-alkalmazás szolgáltatásban. Híváskor .login()adja át paraméterként a következőt response_type=code id_token :

    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 esetében adja meg paraméterként a access_type=offline 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);
    
  • Microsoft-fiók esetén válassza ki a hatókörtwl.offline_access.

Jogkivonat frissítéséhez 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ó 401 válaszát, és megpróbálja frissíteni a felhasználói jogkivonatot.

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

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

  • Úgy konfigurálja Azure-alkalmazás szolgáltatáshitelesítést és -engedélyezést, ahogyan a kiszolgálói forgalom hitelesítését tenné.

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

  • Hívja meg a metódust az .login() alábbiak szerint (result a következőnek 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 kód példáját a következő szakaszban.

Cserélje le a metódust onSuccess() 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 hajtott végre, akkor az egyéni hitelesítésszolgáltató címkéjét is használhatja.

Felhasználók hitelesítése az Active Directory hitelesítési kódtárral (ADAL)

Az Active Directory Authentication Library (ADAL) használatával bejelentkeztetheti a felhasználókat az alkalmazásba az Azure Active Directory használatával. Az ügyfélfolyamat-bejelentkezés használata gyakran előnyösebb a loginAsync() metódusok használata során, mivel natívabb UX-érzetet biztosít, és további testreszabást tesz lehetővé.

  1. Konfigurálja a mobilalkalmazás háttérrendszerét az AAD-bejelentkezéshez az App Service active Directory-beli bejelentkezési oktatóanyagának követésével. Győződjön meg arról, hogy végrehajtja a natív ügyfélalkalmazás regisztrálásának opcionális lépését.

  2. Telepítse az ADAL-t a build.gradle fájl módosításával, hogy az 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á az alábbi kódot az alkalmazáshoz a következő csere végrehajtásával:

    • Cserélje le az INSERT-AUTHORITY-HERE elemet annak a bérlőnek a nevére, amelyben az alkalmazást kiépítette. A formátumnak a következőnek kell lennie https://login.microsoftonline.com/contoso.onmicrosoft.com: .
    • Cserélje le az INSERT-RESOURCE-ID-HERE elemet a mobilalkalmazás háttérrendszeréhez tartozó ügyfélazonosítóra. Az ügyfél-azonosítót a portálOn az Azure Active Directory beállításai alatt található Speciális lapon szerezheti be.
    • Cserélje le az INSERT-CLIENT-ID-HERE elemet a natív ügyfélalkalmazásból másolt ügyfélazonosítóra.
    • Cserélje le az INSERT-REDIRECT-URI-HERE elemet a webhely /.auth/login/done végpontjára a HTTPS-séma használatával. Ennek az értéknek hasonlónak kell lennie a .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);
    }
}

Az ügyfél-kiszolgáló kommunikációjának módosítása

Az ügyfélkapcsolat általában egy alapszintű HTTP-kapcsolat az Android SDK-hoz mellékelt mögöttes HTTP-kódtár használatával. Ennek több oka is van:

  • Másik HTTP-kódtárat szeretne használni az időtúllépések módosításához.
  • Meg szeretne adni egy folyamatjelző sávot.
  • Egyéni fejlécet szeretne hozzáadni az API felügyeleti funkcióinak támogatásához.
  • Egy sikertelen választ szeretne elfogni, hogy megvalósíthassa az újrahitelesítést.
  • A háttérkérelmeket egy elemzési szolgáltatásba szeretné naplózni.

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

Az ügyfélhivatkozás létrehozása után azonnal hívja meg a .setAndroidHttpClientFactory() metódust. Ha például a kapcsolat időtúllépését 60 másodpercre szeretné állítani (az alapértelmezett 10 másodperc helyett):

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ő implementálása

A kérések elfogását implementálhatja egy ServiceFilter. Például a következő frissítés egy előre létrehozott folyamatjelző sávot frissít:

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 az alábbi módon 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 a következőhöz ProgressFilterhasonlóan:

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 érvényes konverziós stratégiát adhat meg. Az Android-ügyfélkódtár gson használatával szerializálja a Java-objektumokat JSON-adatokba, mielőtt az adatokat elküldené Azure-alkalmazás szolgáltatásnak. A következő kód a setFieldNamingStrategy() metódust használja a stratégia beállításához. 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. Alakítson ki egy konverziós stratégiát, amely csökkenti a legtöbb mező széljegyzeteinek szükségességét SerializedName() .

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 a MobileServiceClient használatával történő mobilügyfél-referencia létrehozása előtt kell végrehajtani.