Sunteți un dezvoltator .NET care și-a dorit întotdeauna să facă o aplicație mobilă? Sau poate ați încercat să construiți aplicații mobile native cu Android sau iOS, dar nu v-au plăcut limbajele? Ei bine, atunci aveți noroc! Lumea .NET a fost binecuvântată cu Xamarin; un set de instrumente care vă permite să construiți aplicații mobile pentru Android, iOS și Windows în cadrul Visual Studio.

Xamarin are două arome principale: Platforma Xamarin (Xamarin.iOS și Xamarin.Android) și Xamarin.Forms. Cu Xamarin.Forms, marea majoritate a logicii de afaceri și a interfeței cu utilizatorul pot fi scrise în cadrul unui singur proiect partajat care produce aplicații complet funcționale pe toate cele 3 sisteme de operare iOS, Android și Windows (UWP). Platforma Xamarin, pe de altă parte, este în mare măsură o muncă specifică platformei și se aseamănă mai mult cu scrierea aplicațiilor native, dar cu C#.

În acest tutorial, voi examina mai îndeaproape platforma Xamarin și setul de instrumente pentru sistemul de operare Android cunoscut sub numele de Xamarin.Android. Obiectivul general este de a vă permite să creați o aplicație nativă simplă pentru Android, cu autentificarea de bază a utilizatorului inclusă.

Configurați Visual Studio și mediul dumneavoastră

Pentru a urmări acest curs veți avea nevoie de o copie a Visual Studio, plus volumul de lucru „Mobile development with .NET”. Puteți activa această caracteristică de la prima instalare a Visual Studio sau o puteți accesa din meniul ‘Tools -> Get Tools and Features…’ (Instrumente -> Obțineți instrumente și caracteristici…):

Când testați și rulați aplicația aveți posibilitatea de a face acest lucru fie cu un emulator Android care rulează pe mașina dumneavoastră de dezvoltare, fie prin conectarea directă la un dispozitiv Android existent. Nu există o opțiune corectă aici și diferiți dezvoltatori preferă factori de formă diferiți. Dacă alegeți prima opțiune, va trebui să vă asigurați, după ce ați selectat sarcina de lucru, că în panoul din dreapta („Installation details”) sunt selectate căsuțele de selectare pentru Intel Hardware Accelerated Execution Manager și Google Android Emulator (așa cum se vede mai sus).

Verificați mediul Android în Visual Studio

Pentru a verifica dacă totul s-a instalat corespunzător și a fost configurat corect, mergeți la ‘Tools -> Options -> Xamarin -> Android Settings’ și verificați dacă căile Java Development Kit Location și Android SDK Location sunt valide (i.adică au o bifă verde):

Dacă vreuna dintre ele lipsește, va trebui să instalați manual Java Development Kit, respectiv Android SDK.

Crearea unei aplicații Xamarin

Începeți prin a crea un nou proiect și selectați șablonul principal ‘Android App (Xamarin)’ (care se găsește în meniul Android). Pe pagina următoare veți dori să alegeți opțiunea ‘Single View App’ (Aplicație cu o singură vizualizare), deoarece este un șablon de pornire excelent pentru a lucra.

În ceea ce privește versiunea minimă de Android, aceasta este ceva ce ține de alegerea dvs. personală ca dezvoltator. Există un compromis aici între a putea accesa cele mai recente și cele mai bune caracteristici API din versiunile mai noi și a sprijini clienții dvs. care au versiuni mai vechi. Pentru a vă ajuta să luați această decizie, Google publică datele de distribuție a versiunilor platformei pe care le colectează ca parte a tabloului de bord de distribuție la o cadență destul de regulată. Preferința mea personală este între 5.0 sau 6.0, în funcție de faptul dacă este vorba de o aplicație pentru consum public sau de o aplicație comandată doar pentru telefoanele corporative (adică probabil că acestea vor avea cele mai recente actualizări); în acest exemplu, am optat pentru cea de-a doua variantă. Rețineți că această versiune diferă de Target Android Version (Versiunea Android țintă) și că aceasta ar trebui să fie întotdeauna setată la cea mai recentă versiune SDK lansată, deoarece orice versiune mai mică nu va fi acceptată în magazinul Google Play.

După ce ați creat acest lucru, tot ce rămâne de făcut este să importați pachetele NuGet necesare. Pentru acest tutorial veți avea nevoie de:

  • Xamarin.OpenId.AppAuth.Android – Pentru a autentifica utilizatorul veți folosi standardul OpenID Connect (o îmbunătățire a OAuth 2.0). Cel mai simplu mod de a implementa un cod client care respectă această specificație este prin utilizarea SDK-ului de client AppAuth pentru Android și, în mod util, Xamarin a portat un pachet al acestei funcționalități disponibil pentru a fi utilizat.
  • System.IdentityModel.Tokens.Jwt – Metoda de autentificare folosește aici JSON Web Tokens. Pentru a extrage datele necesare din aceste token-uri veți avea nevoie de acest pachet.

În plus, veți avea nevoie și de aceste două pachete, deoarece AppAuth se bazează pe ele:

  • Xamarin.Android.Support.v4
  • Xamarin.Android.Support.CustomTabs

Familiarizați-vă cu proiectul Xamarin

Dacă nu ați mai lucrat niciodată cu Android, unul dintre principiile cheie pe care trebuie să vi le însușiți este conceptul de activitate. Activitățile sunt componente utilizate pentru a vă afișa interfața cu utilizatorul; în forma lor cea mai elementară, vă puteți gândi la Activități ca fiind egale cu paginile dintr-o aplicație între care utilizatorul poate naviga. În cod, o Activitate este reprezentată de o clasă, însă, la fel ca o pagină în ASP.NET, puteți (și aproape întotdeauna o veți face) să îi asociați un fișier de prezentare bazat pe XML (un fișier .axml) pentru un design afișabil. Toate proiectele noi creează un fișier „MainActivity.cs” și „activity_main.axml” pentru a începe ca prima activitate (adică pagina) care se execută la deschiderea aplicației. Aceasta poate fi schimbată în orice altă activitate prin utilizarea proprietății MainLauncher = true din atributul Activity al clasei.

Resursele sunt concepute pentru a fi gestionate în propriul lor director și urmează o convenție de denumire oarecum strictă. V-aș recomanda cu tărie să stocați cât mai multe resurse în acest director, deoarece simplifică reutilizarea acestor variabile pentru dezvoltarea dvs. continuă. În directorul „values” al directorului Resources se află fișierele cu scopuri specifice:

  • Strings.xml – Găzduiește toate șirurile orientate către utilizator. Acesta este deosebit de important de utilizat, deoarece vă permite să vă localizați șirurile pentru o audiență globală.
  • Styles.xml – Unde veți găsi atributele pentru stilizarea obiectelor de proiectare; gândiți-vă la el ca la un fișier CSS.
  • Colors.xml – Un loc pentru a stoca referințele la culorile pe care le utilizați cel mai frecvent ca parte a stilizării dumneavoastră.
  • Dimens.xml – După cum sugerează și numele, locul în care definiți dimensiunile stabilite pentru aspectul aplicației dumneavoastră.

Celelalte directoare notabile nu urmează nicio convenție de denumire pentru fișierele lor, dar trebuie să conțină anumite tipuri de fișiere:

  • Layout – Locul de stocare a fișierelor dumneavoastră .axml. Aceste fișiere definesc machete complete de activitate, componente de machetare pe care le generați și le completați programatic, machete ale căsuțelor de dialog (de alertă) etc.
  • Menu – Unde veți găsi definițiile meniurilor și ale elementelor acestora. Acestea sunt fișiere .xml care au menu ca element rădăcină și item elemente copil, dintre care pot fi grupate împreună cu elemente group. Cele mai frecvente meniuri pe care le veți întâlni sunt meniul de depășire (de la butonul cu trei puncte verticale) sau meniul de navigare (de la butonul „hamburger” de pe pagina principală).
  • Mipmap – Unde doriți să definiți imaginile care trebuie să fie redimensionate în funcție de densitatea ecranului, adică cele la care fac referire alte aplicații și care nu sunt utilizate intern. Pictograma aplicației este cel mai obișnuit conținut pe care îl veți pune în directoarele mipmap.
  • Drawable – Nu este standard într-un șablon de proiect implicit, dar poate fi creat de dumneavoastră. Acesta este locul în care stocați imaginile/conținutul desenabil care urmează să fie utilizat în cadrul aplicației, de exemplu, ecranul de întâmpinare, modele personalizate de bare de progres, pictograme utilizate în cadrul aplicației etc.

În cele din urmă, dacă aveți fișiere de conținut brut pe care doriți să le utilizați ca parte a aplicației (de exemplu, un fișier de text sau de font), atunci directorul Assets este locul în care trebuie să le plasați. Ca Assets, aceste fișiere vor fi implementate împreună cu aplicația dvs. pentru ca dvs. să le puteți accesa cu Asset Manager.

Pentru a afla mai multe despre Assets și Resources și cum să le folosiți, există fișiere text „About” (Despre) la îndemână în fiecare director al unui proiect nou creat.

Adaugați autentificarea utilizatorului la Xamarin cu OpenID Connect

Majoritatea aplicațiilor din zilele noastre necesită o formă de identificare a utilizatorului pentru a permite dezvoltatorului să ofere experiențe personalizate și, la rândul său, pentru a permite utilizatorului să își păstreze datele pe mai multe dispozitive/instalații. În plus, există și problema controlului accesului care ar putea fi util pentru a autoriza un subset de utilizatori pentru funcționalități suplimentare. Bineînțeles, aceasta poate fi o sarcină destul de laborioasă, mai ales dacă vă ocupați de crearea de aplicații și veți avea nevoie de un sistem nou pentru fiecare dintre ele. Din fericire, cu Okta puteți configura o aplicație în doar câteva minute și apoi toată munca grea este făcută pentru dumneavoastră! Serviciul Okta este compatibil cu OAuth 2.0 și este un furnizor certificat OpenID Connect, astfel încât funcționează perfect cu clientul AppAuth SDK pentru toate nevoile dumneavoastră de autentificare și autorizare.

Configurați aplicația Okta

În primul rând, ar trebui să configurați o nouă aplicație în contul dumneavoastră Okta pentru acest proiect. Dacă nu aveți încă unul, este foarte ușor să creați un nou cont de dezvoltator pentru totdeauna gratuit.

După ce acest lucru este complet și v-ați conectat la tabloul de bord al dezvoltatorului, notați URL-ul Org, deoarece vom avea nevoie de el mai târziu:

Din tabloul de bord, mergeți la fila „Applications” (Aplicații) și de acolo „Add Application” (Adaugă aplicație). Creați o aplicație nativă pentru Android, așa că cel mai bine este să alegeți șablonul de platformă ‘Native’.

Din această pagină adăugați un nume pentru aplicația dvs. și lăsați toate celelalte ca fiind implicite. După ce ați salvat notați URI-urile de redirecționare a login-ului și ID-ul de client, deoarece veți avea nevoie de acestea în continuare.

Pentru a putea folosi aceste trei valori de la Okta cu ușurință în viitor, v-aș recomanda să le puneți în propria lor clasă statică în cadrul unui nou director pentru logica de autentificare:

public static class Configuration{ public const string ClientId = "{yourClientId}"; public const string LoginRedirectUri = "{yourRedirectUri}"; public const string OrgUrl = "https://{yourOktaDomain}";}

Crearea furnizorului de autentificare

Să scoatem din drum codul boilerplate. Trebuie să configurați aplicația pentru a o informa cu privire la schema URI de redirecționare. Schema este URI-ul dvs. de redirecționare pentru autentificare (în forma standard de nume de domeniu inversat) fără cale. De exemplu, din captura de ecran de mai sus, schema mea ar fi ‘com.oktapreview.dev-123456’.

Cel mai simplu mod de a face acest lucru este să inserați fragmentul de filtru de intenție de mai jos în fișierul AndroidManifest.xml din dosarul Properties al soluției dvs. Adăugați următorul XML în cadrul etichetei Application și schimbați valoarea schemei cu valoarea dvs. proprie:

<activity android:name="net.openid.appauth.RedirectUriReceiverActivity"> <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="{yourRedirectRriScheme}" /> </intent-filter></activity>

De asemenea, trebuie să definiți modelul pentru rezultatul autorizării dvs. cu o clasă simplă. Deși nu voi folosi toate valorile pe care le-am scris mai jos în cadrul codului, vă voi arăta cum să le populez pentru a le folosi ulterior. Deoarece aceasta face parte din modelul aplicației dumneavoastră, creați un folder numit Models și adăugați o clasă AuthorizationResult.cs în interiorul acestuia. Apoi, adăugați următorul cod:

public class AuthorizationResult{ public string AccessToken { get; set; } public string IdentityToken { get; set; } public bool IsAuthorized { get; set; } public string RefreshToken { get; set; } public string Scope { get; set; }}

Android nu are o stare globală cu care să puteți lucra și, prin urmare, dacă doriți să treceți valori simple între activități, cel mai bun mod de a face acest lucru este cu funcționalitatea Extras de pe obiectul Intent. Un Intent este o clasă predefinită în Android și un alt concept de bază care trebuie înțeles. Este abstractizarea unei operații care urmează să fie efectuată (adică „intențiile” dvs.), iar pentru a trece mai departe la o altă activitate trebuie să creați o instanță a acestei clase cu activitatea la care „intenționați” să mergeți. Proprietățile Extras de pe obiectul Intent sunt, de fapt, doar un dicționar de chei către valorile obiectului și sunt accesate prin metode Put și tipizate Get.

În timp ce aceste metode mențin utilizarea relativ clară și ușoară, personal îmi place să păstrez tot accesul la ele în cadrul propriei clase (mai exact, o clasă de extensii), pentru a menține o mai bună separare a preocupărilor. Acest lucru este extrem de util, deoarece nu este nevoie să accesați cheile între clase și puteți asigura siguranța tipurilor atunci când puneți și obțineți aceste valori. În furnizorul dvs. de autorizații veți dori: să stocați AuthState, să puteți verifica dacă este acolo și să o returnați dacă este. Creați un folder nou numit Extensions în rădăcina soluției. Apoi adăugați o nouă clasă numită IntentExtensions.cs. Faceți clasa public și static, apoi adăugați următorul cod în interiorul clasei:

public const string AuthStateKey = "authState";public static string GetAuthStateExtra(this Intent intent){ return intent.GetStringExtra(AuthStateKey);}public static bool HasAuthStateExtra(this Intent intent){ return intent.HasExtra(AuthStateKey);}public static void PutAuthStateExtra(this Intent intent, AuthState authState){ intent.PutExtra(AuthStateKey, authState.JsonSerializeString());}public static bool TryGetAuthStateFromExtra(this Intent intent, out AuthState authState){ authState = null; if (!intent.HasAuthStateExtra()) { return false; } try { authState = AuthState.JsonDeserialize(intent.GetAuthStateExtra()); } catch (JSONException) { return false; } return authState != null;}

Acum este momentul să definiți furnizorul de autorizații, AuthorizationProvider.cs în folderul Authentication pe care l-ați creat înainte pentru clasa Configuration.cs. În primul rând, eliminați toate declarațiile using din interiorul clasei nou create, apoi declarați configurația ca variabile static readonly:

private static readonly Uri ConfigurationEndpoint = Uri.Parse($"{Configuration.OrgUrl}/oauth2/default/.well-known/openid-configuration");private static readonly string Scopes = new { "openid", "profile", "email", "offline_access" };

Finalul de configurare este un standard în OpenID ca final de descoperire pentru a găsi tot ceea ce este suportat. Rețineți aici că am scris că acest lucru este folosind numele furnizorului „implicit”. Dacă aveți un alt furnizor, veți dori să schimbați acest lucru aici. De asemenea, rețineți că acest lucru utilizează aroma Android.Net a clasei Uri, și nu versiunea System – va trebui să adăugați prima la utilizările dvs. sau să calificați complet tipul pentru ca acest lucru să funcționeze. Variabila Scopes, ca orice alt sistem OpenID, definește ceea ce suntem autorizați să accesăm.

În continuare trebuie să vă declarați variabilele membre:

private AuthorizationRequest authorizationRequest;private PendingIntent completedIntent;private AuthState authorizationState;private readonly AuthorizationService authorizationService;private readonly Context context;private readonly TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();

O scurtă explicație pentru fiecare:

  • Solicitarea de autorizare și intenția finalizată sunt parametri creați pentru a fi utilizați la efectuarea apelului de autorizare. Le-am scris aici ca variabile globale pentru a minimiza cantitatea de trecere a parametrilor în diferite metode.
  • Variabila authorizationState, așa cum se numește, definește starea actuală de autorizare dată.
  • Variabila authorizationService conține o instanță a serviciului de autorizare.
  • Variabila context de aici este a activității de apelare, astfel încât să o puteți referi atunci când este necesar.
  • În cele din urmă, taskCompletionSource vă permite să efectuați toate aceste apeluri în mod asincron și apoi să vă întoarceți odată finalizate.

Acum ar trebui să definiți valorile acestor variabile readonly în constructorul dvs. și să declarați metodele publice pe care codul dvs. le va apela:

public AuthorizationProvider(Context context){ authorizationService = new AuthorizationService(context); this.context = context;}public async Task<AuthorizationResult> SignInAsync(){ ...}public void NotifyCallback(Intent intent){ ...}

Metoda SignInAsync este, așa cum probabil ați ghicit, o metodă asincronă pentru a înregistra un utilizator. Aceasta returnează clasa AuthorizationResult pe care ați scris-o mai devreme. NotifyCallback, pe de altă parte, este pentru ca activitatea apelantă, odată ce s-a întors de la pagina externă de înregistrare, să apeleze înapoi la furnizorul de autorizații și să-l anunțe că a terminat. Metoda de autentificare am împărțit-o în mai multe subrutine și arată astfel:

AuthorizationServiceConfiguration serviceConfiguration = await AuthorizationServiceConfiguration.FetchFromUrlAsync(ConfigurationEndpoint);BuildAuthorizationRequest(serviceConfiguration);BuildCompletedIntent(serviceConfiguration);return await RequestAuthorization();

În aceasta ați definit configurația serviciului, ați construit cererea de autorizare și intenția de apelare odată ce autorizarea a fost finalizată, iar apoi așteptați cererea de autorizare. Pentru a construi cererea de autorizare se procedează după cum urmează:

private void BuildAuthorizationRequest(AuthorizationServiceConfiguration serviceConfiguration){ AuthorizationRequest.Builder builder = new AuthorizationRequest.Builder( serviceConfiguration, Configuration.ClientId, ResponseTypeValues.Code, Uri.Parse(Configuration.LoginRedirectUri)); builder.SetScope(string.Join(" ", Scopes)); authorizationRequest = builder.Build();}

Tratamentul acestei metode este de a face abstracție de munca AuthorizationRequest.Builder și de a crea cererea. În continuare, trebuie să construiți Intent pentru când operațiunea s-a încheiat:

private void BuildCompletedIntent(AuthorizationServiceConfiguration serviceConfiguration){ Intent intent = new Intent(context, typeof(MainActivity)); intent.PutAuthStateExtra(new AuthState()); completedIntent = PendingIntent.GetActivity(context, authorizationRequest.GetHashCode(), intent, 0);}

„Intenția” pe care doriți să o realizați aici este să vă întoarceți la MainActivity cu un nou AuthState atașat. În cele din urmă, în acest flux, trebuie să ne ocupăm de executarea cererii:

private async Task<AuthorizationResult> RequestAuthorization(){ authorizationService.PerformAuthorizationRequest(authorizationRequest, completedIntent); await taskCompletionSource.Task; return new AuthorizationResult() { AccessToken = authorizationState?.AccessToken, IdentityToken = authorizationState?.IdToken, IsAuthorized = authorizationState?.IsAuthorized ?? false, RefreshToken = authorizationState?.RefreshToken, Scope = authorizationState?.Scope };}

Pentru că PerformAuthorizationRequest este sincronă și returnează void, codul așteaptă membrul taskCompletionSource, știind că acesta va fi setat doar după ce a fost recuperat un răspuns. În același moment, știți că starea de autorizare va fi populată (dacă totul a reușit) și, prin urmare, puteți returna valorile lor ca parte a AuthorizationResult.

Cea de-a doua metodă publică NotifyCallback, așa cum am menționat mai devreme, este cea la care doriți ca clasa MainActivity să apeleze clasa MainActivity, odată ce completedIntent dvs. de mai sus este executată. În această metodă doriți să verificați răspunsul, să actualizați starea în mod corespunzător și, dacă are succes, să efectuați o cerere de schimb de token-uri:

if (!intent.TryGetAuthStateFromExtra(out authorizationState)){ taskCompletionSource.SetResult(false); return;}AuthorizationResponse authorizationResponse = AuthorizationResponse.FromIntent(intent);AuthorizationException authorizationException = AuthorizationException.FromIntent(intent);authorizationState.Update(authorizationResponse, authorizationException);if (authorizationException != null){ taskCompletionSource.SetResult(false); return;}authorizationService.PerformTokenRequest(authorizationResponse.CreateTokenExchangeRequest(), ReceivedTokenResponse);

Aici puteți vedea că în cazurile de eșec am setat rezultatul taskCompletionSource la false, iar acest lucru va debloca metoda RequestAuthorization de mai sus. De asemenea, metoda PerformTokenRequest preia un delegat, ReceivedTokenResponse, care va fi executat după ce se va finaliza. Această metodă este următoarea:

private void ReceivedTokenResponse(TokenResponse tokenResponse, AuthorizationException authorizationException){ authorizationState.Update(tokenResponse, authorizationException); taskCompletionSource.SetResult(true);}

În acest moment ar trebui să aveți toate datele de autorizare de care aveți nevoie și astfel puteți actualiza starea în mod corespunzător (unde veți găsi valorile pe care să le returnați de la metoda sign in) și să setați rezultatul pentru a debloca sarcina taskCompletionSource.

Implementați autentificarea în interfața Xamarin

Ca o curățare, dacă doriți, nu ezitați să eliminați toate trimiterile la „Floating Action Bar” (scrisă și sub numele de „FAB”) din cadrul fișierelor de clasă/axml ale activității principale, deoarece sunt o umflătură inutilă în acest stadiu.

Pentru a permite utilizatorului să se autentifice, trebuie acum să implementați această funcționalitate în interfața de utilizare. Având în vedere designul implicit, cel mai intuitiv mod de a face acest lucru ar fi să adăugați un element la meniul overflow din colțul din dreapta sus. Puteți face acest lucru prin editarea fișierului menu_main.xml din folderul „Resources -> menu” și adăugarea acestui element ca un copil al tag-ului menu:

<item android:id="@+id/action_signin" android:orderInCategory="100" android:title="@string/action_signin" app:showAsAction="never" />

Cu acest cod ați creat o nouă opțiune cu un titlu care urmează să fie definit în fișierul de resurse string. După cum am menționat anterior, în Android este cea mai bună practică să puneți tot textul orientat către utilizator în fișierul string resources. Pentru a declara aceste date, editați fișierul strings.xml din folderul ‘Resources -> values’ și adăugați aceste linii:

<string name="action_signin">Sign In</string><string name="welcome_message_format">Hi, %1$s!</string>

Nu numai că am declarat aici un șir de caractere pentru butonul ‘Sign In’, dar am adăugat mai sus și un șir de caractere pentru un mesaj de bun venit adresat utilizatorului după ce acesta s-a logat. Echivalentul codului C# de this string would be „Bună, {0}!”`, unde locul rezervat este de tip string.

Rețineți că, la toate actualizările acestor fișiere bazate pe resurse, clasa Resource.designer.cs va fi regenerată automat cu noi ID-uri pentru fiecare obiect creat, la care se poate face referire în cadrul codului dumneavoastră. Dacă acest lucru nu funcționează pentru un anumit fișier, atunci selectați-l în Solution Explorer și uitați-vă la fereastra Properties (Proprietăți). Asigurați-vă că proprietatea CustomTool este setată la valoarea MSBuild:UpdateGeneratedFiles, deoarece este posibil ca aceasta să lipsească și să împiedice fișierul de proiectare să o recunoască drept resursă.

În continuare, adăugați un ProgressBar la fișierul de aspect existent activity_main.axml:

<ProgressBar android:id="@+id/signin_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:paddingBottom="12dp" android:visibility="gone" />

Acest ProgressBar (sau spinner, după caz), are un ID pe care îl puteți referi cu codul și este configurat să stea în jurul centrului ecranului. Vizibilitatea este setată la dispărut deocamdată, dar odată ce codul de autorizare este în funcțiune, îl puteți seta la vizibil și informa utilizatorul că aplicația este ocupată.

Acum aveți un buton pentru a deschide autentificarea și un spinner de progres pentru a informa utilizatorul că aplicația este ocupată, este timpul să le folosiți. În cadrul clasei MainActivity adăugați următoarea proprietate la atributul Activity (deasupra antetului clasei):

LaunchMode = LaunchMode.SingleTask

Această proprietate asigură că există o singură instanță a clasei MainActivity și că nu veți continua să deschideți altele noi. După ce ați făcut acest lucru, adăugați o variabilă membră statică pentru AuthorizationProvder pe care ați scris-o mai sus și creați o instanță a acesteia în cadrul suprascrierii existente a metodei OnCreate. Rețineți că acest lucru trebuie făcut după codul existent în cadrul metodei:

private static AuthorizationProvider authorizationProvider;protected override void OnCreate(Bundle savedInstanceState){ ... authorizationProvider = new AuthorizationProvider(this);}

În continuare, suprascrieți metoda OnNewIntent. Scopul este ca atunci când este creată o nouă intenție a acestei clase (adică atunci când se întoarce fereastra de autentificare externă), să apelați metoda NotifyCallback din AuthorizationProvider. De asemenea, aici este inclusă și o verificare rapidă pentru a vă asigura că este fluxul așteptat:

protected override void OnNewIntent(Intent intent){ base.OnNewIntent(intent); if (intent != null && intent.Data.Path.Equals("/callback", StringComparison.OrdinalIgnoreCase)) { authorizationProvider.NotifyCallback(intent); }}

Acum adăugați codul din spatele elementului de meniu pe care l-ați adăugat. În suprascrierea existentă a metodei OnOptionsItemSelected, adăugați o instrucțiune if cu un apel la o nouă metodă care se va ocupa de procesul de conectare după cum urmează:

if (id == Resource.Id.action_signin){ OnSignInAttempted(); return true;}

Această nouă metodă va începe prin a face vizibil ProgressBar pe care l-ați adăugat cu câteva momente în urmă; pentru a prelua orice componentă din fișierul de prezentare, utilizați metoda generică FindViewById și introduceți ID-ul componentei ca argument. După aceasta, efectuați un apel la metoda SignInAsync și așteptați rezultatul acesteia. După ce apelul a fost returnat, rezultatul este verificat ca fiind autorizat. În cazul în care această autorizare a eșuat, indiferent de motiv, apare un dialog de eroare, iar rotița de progres dispare din nou. Voi lăsa deocamdată detalierea cazului de succes pentru că tot trebuie să mergeți undeva în acest caz:

private async void OnSignInAttempted(){ ProgressBar signInProgress = FindViewById<ProgressBar>(Resource.Id.signin_progress); signInProgress.Visibility = ViewStates.Visible; AuthorizationResult authorizationResult = await authorizationProvider.SignInAsync(); if (!string.IsNullOrWhiteSpace(authorizationResult.AccessToken) && authorizationResult.IsAuthorized) { // Placeholder: Success case } else { // Display an error to the user AlertDialog authorizationErrorDialog = new AlertDialog.Builder(this) .SetTitle("Error!") .SetMessage("We were unable to authorize you.") .Create(); authorizationErrorDialog.Show(); signInProgress.Visibility = ViewStates.Gone; }}

Când utilizatorul este autentificat, ar trebui să îl redirecționați către următoarea pagină a experienței dumneavoastră. Dacă vă amintiți mai devreme, fiecare pagină este reprezentată de o activitate și, prin urmare, trebuie să creați una nouă acum.

Pentru a începe, în folderul „Resources -> layout” va trebui să creați noul fișier de layout al activității „activity_dashboard.axml”. Cel mai simplu mod de a face acest lucru este să accesați opțiunea New Item… din meniul contextual și să selectați șablonul „Android Layout”. În cadrul noului fișier layout adăugați o componentă simplă TextView pentru a afișa un text ca acesta:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <TextView android:id="@+id/welcome_message" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /></LinearLayout>

În acest fragment aveți o componentă TextView cu un ID referențiabil care este centrată în mijlocul paginii, din care se va afișa un mesaj de bun venit. În continuare, creați o clasă de activitate corespunzătoare „DashboardActivity” prin intermediul opțiunii „New Item…” din meniul contextual din proiectul din exploratorul de soluții și prin selectarea șablonului „Activity”. Pentru a lega această clasă de fișierul său de layout, trebuie să apelați funcția SetContentView în metoda generată OnCreate() (sub invocarea metodei de bază moștenite):

SetContentView(Resource.Layout.activity_dashboard);

Pentru a personaliza mesajul de bun venit, veți dori să treceți numele utilizatorului în noua dvs. activitate. Dacă vă amintiți mai devreme, cel mai bun mod de a face acest lucru a fost cu Extras pe intenție și ați creat o clasă de extensii pentru a gestiona acest lucru. La fel ca înainte, adăugați noi metode pentru „Put” și „Get” ale unui extra „name” în fișierul IntentExtensions.cs pe care l-ați creat mai sus:

private const string NameKey = "Name";public static void PutNameExtra(this Intent intent, string name){ intent.PutExtra(NameKey, name);}public static string GetNameExtra(this Intent intent){ return intent.GetStringExtra(NameKey);}

Acum, folosind această funcționalitate extinsă, după apelul către SetContentView pe care l-ați făcut în metoda OnCreate(), recuperați numele utilizatorului și setați textul componentei TextView în mod corespunzător:

string name = Intent.GetNameExtra();TextView welcomeMessage = FindViewById<TextView>(Resource.Id.welcome_message);welcomeMessage.Text = Resources.GetString(Resource.String.welcome_message_format, name);

În acest extras, la recuperarea instanței TextView, valoarea acesteia este setată la mesajul dumneavoastră de bun venit, al cărui conținut este creat cu ajutorul echivalentului Android Resources din string.Format().

Cu aceasta, activitatea tabloului de bord este completă, iar acum trebuie să apelați la ea. În locul pentru cazul de succes pe care l-am lăsat deschis din metoda OnSignInAttempted, puteți realiza acest lucru prin adăugarea următorului cod:

JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();JwtSecurityToken jsonToken = tokenHandler.ReadJwtToken(authorizationResult.IdentityToken);IEnumerable<Claim> claims = jsonToken?.Payload?.Claims;string name = claims?.FirstOrDefault(x => x.Type == "name")?.Value;Intent dashboardIntent = new Intent(this, typeof(DashboardActivity));dashboardIntent.PutNameExtra(name);StartActivity(dashboardIntent);Finish();

Primul bloc citește token-ul și recuperează numele utilizatorului (dacă există). În al doilea se creează un nou Intent pentru activitatea tabloului de bord, numele utilizatorului este stocat în acest Intent folosind metoda de extensie definită mai sus și apoi activitatea este pornită (adică se navighează către). Pentru a împiedica utilizatorul să navigheze înapoi la această pagină după aceea, codul se încheie prin apelarea metodei Finish().

Executați aplicația Android

Acum este timpul să vă lansați aplicația folosind dispozitivul ales!

Dacă depanați folosind emulatorul, acest lucru ar trebui să fie la fel de simplu ca și apăsarea F5 de care va deschide și va încărca mai întâi emulatorul, iar apoi codul va fi implementat în acesta. Ca o notă secundară, nu trebuie să închideți emulatorul între încercările de rulare/depanare, deoarece acesta trebuie doar să redeplaseze aplicația.

Dacă depanați folosind un dispozitiv care nu a mai fost folosit în acest scop, va trebui să configurați mai întâi dispozitivul. Faceți acest lucru activând opțiunile dezvoltatorului și, în noul meniu, activând „Android debugging” (Depanare Android) sub antetul „Debugging” (Depanare). După aceasta, trebuie doar să conectați dispozitivul, să acceptați dialogul de pe dispozitiv care confirmă că aceasta este o conexiune de depanare sigură și ar trebui să puteți implementa și rula aplicația cu F5. Rețineți că dispozitivele fizice au prioritate mai mare decât emulatorul și vor trece la acesta ca opțiune de depanare implicită atunci când sunt conectate.

După ce aplicația dvs. a fost implementată și încărcată, veți fi întâmpinat de șablonul implicit de o singură pagină. Deschideți meniul din colțul din dreapta sus pentru a vă autentifica și, odată ce v-ați introdus detaliile, ar trebui să reveniți la această pagină cu bara de progres care se învârte înainte de a fi trimis automat la pagina tabloului de bord cu mesajul de bun venit:

Învățați mai multe despre Xamarin, OpenID Connect și autentificarea securizată

Dacă ați urmat toți acești pași, aveți acum o aplicație Android de bază construită folosind Xamarin.Android, cu o autentificare a utilizatorului complet funcțională bazată pe OpenID și serviciul Okta. De aici puteți extinde cu ușurință activitatea tabloului de bord pentru a vă implementa funcționalitatea.

Pentru a vedea codul din această postare în întregime, mergeți pe pagina noastră GitHub.

Dacă acest tutorial v-a deschis apetitul pentru dezvoltarea Xamarin și doriți să aflați mai multe, atunci vă sugerez cu tărie să aruncați o privire la aceste alte articole excelente:

  • Adaugați managementul identității la aplicația dvs. Android
  • Adaugați autentificarea la aplicația Xamarin.Forms cu OpenID Connect
  • Crearea unei aplicații pentru iOS și Android cu Xamarin

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.