Er du en .NET-udvikler, der altid har ønsket at lave en mobilapplikation? Eller måske har du prøvet at bygge native mobilapps med Android eller iOS, men brød dig ikke om sprogene? Jamen så er du heldig! .NET-verdenen er blevet velsignet med Xamarin; et sæt værktøjer, der giver dig mulighed for at bygge mobilapps til Android, iOS og Windows i Visual Studio.

Xamarin har to hovedvarianter: Xamarin-platform (Xamarin.iOS og Xamarin.Android) og Xamarin.Forms. Med Xamarin.Forms kan langt størstedelen af din forretningslogik og brugergrænseflade skrives i ét fælles projekt, der producerer fuldt fungerende apps på alle 3 iOS-, Android- og Windows-operativsystemer (UWP). Xamarin-platformen er derimod meget platformsspecifikt arbejde og minder mere om at skrive native apps, men med C#.

I denne tutorial vil jeg se nærmere på Xamarin-platformen og værktøjssættet til Android-operativsystemet, der er kendt som Xamarin.Android. Det overordnede mål er at sætte dig i stand til at oprette en simpel native Android-app med grundlæggende brugergodkendelse inkluderet.

Sæt Visual Studio og dit miljø op

For at følge med skal du have et eksemplar af Visual Studio samt arbejdsopgaven “Mobile development with .NET”. Du kan enten aktivere denne funktion fra første installation af Visual Studio eller få adgang til den fra menupunktet ‘Tools -> Get Tools and Features…’:

Når du tester og kører din app, har du valget mellem at gøre det med enten en Android-emulator, der kører på din udviklingsmaskine, eller ved at oprette direkte forbindelse til en eksisterende Android-enhed. Der er ikke nogen rigtig løsning her, og forskellige udviklere foretrækker forskellige formfaktorer. Hvis du vælger den førstnævnte mulighed, skal du sikre dig, når du har valgt arbejdsbyrden, at afkrydsningsfelterne for Intel Hardware Accelerated Execution Manager og Google Android Emulator er markeret i højre rude (“Installationsdetaljer”) (som det ses ovenfor).

Verificer dit Android-miljø i Visual Studio

For at verificere, at alt er installeret korrekt og konfigureret korrekt, skal du gå til ‘Tools -> Options -> Xamarin -> Android Settings’ og kontrollere, at dine Java Development Kit Location og Android SDK Location-stier er gyldige (i.dvs. har et grønt flueben):

Hvis en af dem mangler, skal du manuelt installere henholdsvis Java Development Kit eller Android SDK.

Opret en Xamarin-app

Start med at oprette et nyt projekt, og vælg masterskabelonen ‘Android App (Xamarin)’ (findes under menuen Android). På den næste side skal du vælge ‘Single View App’-muligheden, da det er en god startskabelon at arbejde ud fra.

Med hensyn til den minimale Android-version er dette noget, der afhænger af dit personlige valg som udvikler. Der er en afvejning her mellem at kunne få adgang til de nyeste og bedste API-funktioner i nyere versioner og at støtte dine kunder, der har ældre versioner. For at hjælpe dig med at træffe denne beslutning offentliggør Google ret regelmæssigt data om distribution af platformversioner, som de indsamler som en del af deres Distribution dashboard. Min personlige præference er mellem 5.0 eller 6.0 afhængigt af, om der er tale om en app til offentligt forbrug eller en bestilt app kun til virksomhedens telefoner (dvs. de vil sandsynligvis have de seneste opdateringer); i dette eksempel er jeg gået med sidstnævnte. Bemærk, at denne version adskiller sig fra Target Android Version, og den bør altid være indstillet til den senest udgivne SDK-version, da alt andet ikke vil blive accepteret i Google Play-butikken.

Når du har fået oprettet dette, er alt, hvad der er tilbage, at importere de nødvendige NuGet-pakker. Til denne tutorial skal du bruge:

  • Xamarin.OpenId.AppAuth.Android – For at autentificere brugeren skal du bruge OpenID Connect-standarden (en forbedring af OAuth 2.0). Den nemmeste måde at implementere klientkode, der overholder denne specifikation, er ved at bruge AppAuth-klient SDK til Android, og Xamarin har heldigvis porteret en pakke af denne funktionalitet, som du kan bruge.
  • System.IdentityModel.Tokens.Jwt – Godkendelsesmetoden her bruger JSON-webtokens. For at udtrække de nødvendige data fra disse tokens skal du bruge denne pakke.

Dertil kommer, at du også skal bruge disse to pakker, da de er afhængige af AppAuth:

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

Færdiggør dig selv med Xamarin-projektet

Hvis du aldrig har arbejdet med Android før, er et af de vigtigste principper, du skal sætte dig ind i, begrebet en aktivitet. Aktiviteter er komponenter, der bruges til at vise din brugergrænseflade; i deres mest grundlæggende form kan du tænke på aktiviteter som værende lig med sider i en app, som brugeren kan navigere mellem. En aktivitet i kode repræsenteres af en klasse, men ligesom en side i ASP.NET kan du (og vil næsten altid) knytte en XML-baseret layoutfil (en .axml-fil) til den for at opnå et design, der kan vises. Alle nye projekter opretter en “MainActivity.cs”- og “activity_main.axml”-fil til at starte med som den første aktivitet (dvs. side), der skal køres, når appen åbnes. Dette kan ændres til en hvilken som helst anden Activity ved hjælp af egenskaben MainLauncher = true i Activity-attributten for klassen.

Ressourcer er designet til at blive håndteret i deres egen mappe og følger en noget streng navngivningskonvention. Jeg vil kraftigt anbefale, at du gemmer så mange af dine ressourcer som muligt i denne mappe, da det forenkler genbruget af disse variabler i din løbende udvikling. I mappen ‘values’ i mappen Resources er der, hvor du finder filer med specifikke formål:

  • Strings.xml – Værter for alle brugervendte strings. Denne er særlig vigtig at bruge, da den giver dig mulighed for at lokalisere dine strenge til et globalt publikum.
  • Styles.xml – Her finder du attributterne til styling af dine designobjekter; tænk på den som en CSS-fil.
  • Colors.xml – Et sted at gemme referencer til de farver, du bruger hyppigst som en del af din styling.
  • Dimens.xml – Som navnet måske antyder, hvor du definerer faste dimensioner for din apps layout.

De andre bemærkelsesværdige mapper følger ikke nogen navnekonvention for deres filer, men de skal indeholde visse filtyper:

  • Layout – Placering til opbevaring af dine .axml-filer. Disse filer definerer komplette aktivitetslayouts, layoutkomponenter, som du genererer og udfylder programmatisk, layouts af dialogbokse (advarselsbokse) osv.
  • Menu – Her finder du definitioner af menuer og deres elementer. Det er .xml-filer, der har menu som rodelement og item underelementer, hvoraf de kan grupperes sammen med group-elementer. De mest almindelige menuer, du vil støde på, er overløbsmenuen (fra knappen med de tre lodrette prikker) eller navigationsmenuen (fra knappen “hamburger” i hjemmet).
  • Mipmap – Hvor du vil definere billeder, der skal skaleres afhængigt af skærmtætheden, dvs. billeder, der refereres af andre programmer, og som ikke bruges internt. Appens ikon er det mest almindelige indhold, som du vil lægge i mipmap-mapperne.
  • Drawable – Ikke standard i en standardprojektskabelon, men kan oprettes selv. Det er her, du gemmer dine billeder/tegnebart indhold, der skal bruges i appen, f.eks. splash screen, brugerdefinerede design af fremskridtsbjælker, ikoner, der bruges i appen osv.

Sidst, hvis du har nogen rå indholdsfiler, som du vil bruge som en del af din applikation (f.eks. en tekst- eller skrifttypefil), så er det i Assets-mappen, du skal placere dem. Som Assets vil disse filer blive distribueret med din app, så du kan få adgang til dem med Asset Manager.

For at få mere at vide om Assets og Resources, og hvordan du bruger dem, er der praktiske “About”-tekstfiler i hver mappe i et nyoprettet projekt.

Add User Authentication to Xamarin with OpenID Connect

De fleste apps i dag kræver en eller anden form for brugeridentifikation for at gøre det muligt for udvikleren at tilbyde skræddersyede oplevelser og til gengæld gøre det muligt for brugeren at bevare sine data på tværs af enheder/installationer. Derudover er der spørgsmålet om adgangskontrol, som kan være nyttigt for at autorisere en delmængde af brugere til ekstra funktionalitet. Dette kan naturligvis være noget af en besværlig opgave, især hvis du er i gang med at skabe apps, og du har brug for et nyt system til hver eneste af dem. Heldigvis kan du med Okta opsætte en applikation på få minutter, og så er alt det hårde arbejde gjort for dig! Okta-tjenesten er OAuth 2.0-kompatibel og en certificeret OpenID Connect-udbyder og fungerer derfor perfekt sammen med AppAuth-klient SDK’et til alle dine godkendelses- og autorisationsbehov.

Sæt din Okta-applikation op

Først skal du oprette en ny applikation i din Okta-konto til dette projekt. Hvis du ikke har en endnu, er det virkelig nemt at oprette en ny evigt gratis udviklerkonto.

Når det er gjort, og du er logget ind på udvikler-dashboardet, skal du notere Org-URL’en, da vi får brug for den senere:

Fra dashboardet skal du gå til fanen ‘Applikationer’ og derfra til ‘Tilføj applikation’. Du opretter en native Android-applikation, så det er bedst at vælge platformsskabelonen ‘Native’.

Fra denne side skal du tilføje et navn til din applikation og lade alt andet være som standard. Når du har gemt, skal du notere dine Login redirect URI’er og Client ID, da du får brug for disse næste gang.

Så du nemt kan bruge disse tre værdier fra Okta i fremtiden, vil jeg anbefale, at du lægger dem i deres egen statiske klasse i en ny mappe til autentifikationslogikken:

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

Opret autentifikationsudbyderen

Lad os få boilerplate-koden ud af vejen. Du skal konfigurere appen for at informere den om dit redirect URI-skema. Skemaet er din login redirect URI (i standard reverse domain name-form) uden stien. Ud fra ovenstående skærmbillede ville mit skema f.eks. være ‘com.oktapreview.dev-123456’.

Den nemmeste måde at gøre dette på er at indsætte nedenstående intent-filterudsnit i din AndroidManifest.xml-fil i Properties-mappen i din løsning. Tilføj følgende XML inden for Application-tagget, og ændr skemaværdien til din egen:

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

Du skal også definere modellen for resultatet af din autorisation med en simpel klasse. Selvom jeg ikke vil bruge alle de værdier, jeg har skrevet nedenfor i koden, vil jeg vise, hvordan du udfylder dem, så du kan bruge dem bagefter. Da dette er en del af din applikations model, skal du oprette en mappe kaldet Models og tilføje en AuthorizationResult.cs-klasse i den. Tilføj derefter følgende kode:

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 har ikke en global tilstand, som du kan arbejde med, så hvis du ønsker at videregive simple værdier mellem aktiviteter, er den bedste måde at gøre dette på med Extras-funktionaliteten på Intent-objektet. En Intent er en foruddefineret klasse i Android og et andet centralt begreb, som du skal forstå. Det er abstraktionen af en operation, der skal udføres (dvs. dine “hensigter”), og for at navigere videre til en anden aktivitet skal du oprette en instans af denne klasse med den aktivitet, du “har til hensigt” at gå til. Ekstra-egenskaberne på Intent-objektet er i realiteten blot en ordbog med nøgler til objektværdier og tilgås af Put og typiserede Get-metoder.

Mens disse metoder holder brugen relativt klar og nem, kan jeg personligt godt lide at holde al adgang til dem inden for deres egen klasse (for at være præcis, en udvidelsesklasse), for at opretholde en bedre adskillelse af bekymringer. Dette er yderst nyttigt, da du ikke behøver at få adgang til nøglerne på tværs af klasser og kan sikre type-sikkerhed, når du sætter og får disse værdier. I din autorisationsudbyder vil du ønske at: gemme AuthState, være i stand til at kontrollere, om den er der, og returnere den, hvis den er der. Opret en ny mappe med navnet Extensions i roden af løsningen. Tilføj derefter en ny klasse kaldet IntentExtensions.cs. Lav klassen public og static, og tilføj derefter følgende kode inde i klassen:

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

Nu er det tid til at definere autorisationsudbyderen, AuthorizationProvider.cs i den mappe Authentication, som du oprettede før til klassen Configuration.cs. Fjern først alle using-angivelserne inde i den nyoprettede klasse, og deklarer derefter konfigurationen som static readonly-variabler:

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

Konfigurationsslutpunktet er en standard i OpenID som opdagelsesslutpunktet for at finde alt det, der understøttes. Bemærk her jeg har skrevet dette er ved hjælp af “standard” provider navn. Hvis du har en anden udbyder, skal du ændre dette her. Bemærk også, at dette bruger Android.Net-varianten af Uri-klassen og ikke System-versionen – du skal tilføje førstnævnte til dine anvendelser eller fuldt ud kvalificere typen, for at dette kan fungere. Variablen Scopes definerer ligesom ethvert andet OpenID-system, hvad vi er autoriseret til at få adgang til.

Næst skal du deklarere dine medlemsvariabler:

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

En hurtig forklaring på hver enkelt:

  • Autorisationsanmodningen og den afsluttede hensigt er parametre, der oprettes til brug ved udførelse af autorisationsopkaldet. Jeg har skrevet dem som globale variabler her for at minimere mængden af overdragelse af parametre til forskellige metoder.
  • AutorizationState-variablen, som den hedder, definerer den aktuelle givne autorisationstilstand.
  • AutorizationService-variablen indeholder en instans af autorisationstjenesten.
  • Kontekstvariablen her er for den kaldende aktivitet, så du kan henvise til den, når det er nødvendigt.
  • Endeligt giver taskCompletionSource dig mulighed for at foretage alle disse kald asynkront og derefter vende tilbage, når de er færdige.

Nu skal du definere værdierne for disse readonly-variable i din konstruktør og erklære de offentlige metoder, som din kode vil kalde:

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

Metoden SignInAsync er, som du måske har gættet, en asynkron metode til at logge en bruger ind. Den returnerer den AuthorizationResult-klasse, som du skrev tidligere. NotifyCallback på den anden side er for den kaldende aktivitet, når den er vendt tilbage fra den eksterne sign in-side, til at kalde tilbage til autorisationsudbyderen og lade den vide, at den er færdig. Sign in-metoden har jeg delt ud i flere underrutiner, og ser således ud:

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

I dette har du defineret tjenestekonfigurationen, bygget autorisationsanmodningen og hensigten om at kalde, når autoriseringen er gennemført, og derefter afvente anmodningen om autorisering. At opbygge autorisationsanmodningen er som følger:

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

Denne metodes opgave er at abstrahere AuthorizationRequest.Builder arbejdet og oprette anmodningen. Dernæst skal du opbygge Intent til, når operationen er afsluttet:

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

Den “hensigt”, som du ønsker at udføre her, er at vende tilbage til din MainActivity med en ny AuthState tilknyttet. Sidst i dette flow skal du håndtere udførelsen af anmodningen:

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

Da PerformAuthorizationRequest er synkron og returnerer void, afventer koden på taskCompletionSource-leddet, vel vidende at det kun vil blive sat, når der er hentet et svar. På samme tidspunkt ved du, at autorisationstilstanden vil blive udfyldt (hvis alt lykkedes), og derfor kan du returnere deres værdier som en del af AuthorizationResult.

Den anden offentlige metode NotifyCallback er, som jeg nævnte før, det, som du ønsker, at MainActivity-klassen skal kalde tilbage på, når din ovenstående completedIntent er kørt. I denne metode ønsker du at verificere svaret, opdatere tilstanden på passende vis og, hvis det lykkes, udføre en anmodning om tokenudveksling:

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

Her kan du se, at jeg i fejltilfælde sætter resultatet af taskCompletionSource til false, og det vil deblokere RequestAuthorization-metoden ovenfor. Desuden tager PerformTokenRequest-metoden en delegate, ReceivedTokenResponse, ind, som skal køres, når den er afsluttet. Denne metode er som følger:

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

På dette tidspunkt burde du have alle de autorisationsdata, du har brug for, og du kan derfor opdatere tilstanden på passende vis (hvor du finder de værdier, der skal returneres fra sign in-metoden) og indstille resultatet til at deblokere taskCompletionSource-opgaven.

Implementer autentificering i din Xamarin-grænseflade

Som en oprydning, hvis du ønsker det, er du velkommen til at fjerne alle referencer til ‘Floating Action Bar’ (også skrevet som ‘FAB’) i hovedaktivitetsklassen/axml-filerne, da de er unødvendig bloat på dette stadium.

For at give brugeren mulighed for at logge ind skal du nu implementere denne funktionalitet i brugergrænsefladen. I betragtning af standarddesignet ville den mest intuitive måde at gøre dette på være at tilføje et element til overløbsmenuen i øverste højre hjørne. Du kan gøre dette ved at redigere filen menu_main.xml i mappen “Resources -> menu” og tilføje dette element som et underordnet element i menu-tagget:

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

Med denne kode har du oprettet en ny indstilling med en titel, der skal defineres i filen string resources. Som nævnt tidligere i Android er det bedste praksis at placere al brugervendt tekst i string resources-filen. For at deklarere disse data skal du redigere strings.xml-filen i mappen ‘Resources -> values’ og tilføje disse linjer:

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

Nu har jeg ikke kun deklareret en streng til knappen ‘Sign In’ her, men jeg har også ovenfor tilføjet en streng til en velkomstbesked til brugeren, når de har logget ind. Det svarer til C#-koden i this string would be “Hej, {0}!”`, hvor pladsholderen er af typen string.

Bemærk, at med alle opdateringer af disse Ressource-baserede filer vil klassen Resource.designer.cs automatisk blive regenereret med nye ID’er for hvert objekt, du har oprettet, som kan refereres i din kode. Hvis dette ikke virker for en bestemt fil, skal du vælge den i Solution Explorer og kigge på vinduet Egenskaber. Sørg for, at CustomTool-egenskaben er indstillet til værdien MSBuild:UpdateGeneratedFiles, da denne sandsynligvis mangler og forhindrer designerfilen i at genkende den som en ressource.

Føj derefter en ProgressBar til den eksisterende activity_main.axml-layoutfil:

<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" />

Denne ProgressBar (eller spinner, som det er tilfældet), har et ID, som du kan referere til med kode, og er indstillet til at sidde omkring midten af skærmen. Synligheden er indstillet til væk for nu, men når din godkendelseskode er kørt, kan du indstille den til synlig og informere brugeren om, at appen er optaget.

Nu har du en knap til at åbne godkendelsen og en fremskridts-spinner til at informere brugeren om, at appen er optaget, så er det tid til at bruge dem. I din MainActivity-klasse tilføjes følgende egenskab til Activity-attributten (over klassehovedet):

LaunchMode = LaunchMode.SingleTask

Denne egenskab sikrer, at der kun er én instans af MainActivity-klassen, og at du ikke bliver ved med at åbne nye instanser. Når du har gjort dette, skal du tilføje en statisk medlemsvariabel for den AuthorizationProvder, du skrev ovenfor, og oprette en instans af den inden for den eksisterende override af OnCreate-metoden. Bemærk, at dette skal gøres efter den eksisterende kode inden for metoden:

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

Næst skal du override OnNewIntent-metoden. Formålet med dette er, at når der oprettes en ny hensigt af denne klasse (dvs. når det eksterne sign in-vindue vender tilbage), kalder du NotifyCallback-metoden fra AuthorizationProvider. Der er også inkluderet en hurtig kontrol for at sikre, at det er det forventede flow:

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

Tilføj nu koden bag det menupunkt, du har tilføjet. I den eksisterende override af OnOptionsItemSelected-metoden skal du tilføje en if-erklæring med et kald til en ny metode, der håndterer indtastningsprocessen på følgende måde:

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

Denne nye metode starter med at gøre ProgressBar, som du tilføjede for et øjeblik siden, synlig; for at hente en hvilken som helst komponent fra layoutfilen skal du bruge den generiske metode FindViewById og indtaste komponentens ID som argument. Herefter skal du foretage et kald til SignInAsync-metoden og afvente dens resultat. Når opkaldet er vendt tilbage, verificeres resultatet derefter som autoriseret. Hvis denne autorisering af en eller anden grund mislykkedes, vises en fejldialog, og fremdriftsspinneren forsvinder igen. Jeg lader være med at beskrive succestilfældet i detaljer indtil videre, da du stadig skal have et sted at gå hen i det tilfælde:

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

Når brugeren er godkendt, skal du omdirigere ham til næste side i din oplevelse. Hvis du husker tidligere, er hver side repræsenteret af en aktivitet, og derfor skal du oprette en ny nu.

Til at begynde med skal du i mappen “Resources -> layout” oprette den nye aktivitetslayoutfil “activity_dashboard.axml” i mappen “Resources -> layout”. Den nemmeste måde at gøre dette på er ved at gå til indstillingen Nyt element… i kontekstmenuen og vælge skabelonen ‘Android Layout’. I din nye layoutfil tilføjes en simpel TextView-komponent til at vise tekst som denne:

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

I dette uddrag har du en TextView-komponent med et refererbart ID, der er centreret i midten af siden, hvoraf der vil blive vist en velkomstbesked. Derefter opretter du en tilsvarende aktivitetsklasse ‘DashboardActivity’ ved hjælp af indstillingen ‘New Item…’ i kontekstmenuen fra projektet i solution explorer og vælger skabelonen ‘Activity’. For at knytte denne klasse til sin layoutfil skal du kalde funktionen SetContentView i den genererede OnCreate()-metode (under den nedarvede basismetodeinvokation):

SetContentView(Resource.Layout.activity_dashboard);

For at personliggøre din velkomstbesked skal du videregive brugerens navn til din nye aktivitet. Hvis du husker tidligere, var den bedste måde at gøre dette på med Extras on the intent, og du oprettede en udvidelsesklasse til at håndtere dette. Som tidligere skal du tilføje nye metoder til ‘Put’ og ‘Get’ af et ‘name’-ekstraudstyr i IntentExtensions.cs-filen, som du oprettede ovenfor:

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

Nu skal du ved hjælp af denne udvidede funktionalitet, efter det kald til SetContentView, du foretog i OnCreate()-metoden, hente brugerens navn og indstille TextView-komponentens tekst på passende vis:

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

I dette uddrag er værdien af TextView-instansen ved hentning af TextView indstillet til din velkomstmeddelelse, som er oprettet ved hjælp af Android Resources-ækvivalenten til string.Format().

Med dette er din dashboardaktivitet færdig, og du skal nu kalde til den. I pladsholderen for den succescase, som jeg lod stå åben fra OnSignInAttempted-metoden, kan du opnå dette ved at tilføje følgende kode:

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

Den første blok læser tokenet og henter brugerens navn (hvis det findes). I den anden blok oprettes der en ny Intent til dashboardaktiviteten, brugerens navn gemmes i denne Intent ved hjælp af din ovenfor definerede udvidelsesmetode, og derefter startes aktiviteten (dvs. der navigeres til den). For at forhindre brugeren i at navigere tilbage til denne side bagefter, slutter koden med at kalde Finish()-metoden.

Kør din Android-app

Nu er det tid til at starte din applikation ved hjælp af den valgte enhed!

Hvis du debugger ved hjælp af emulatoren, bør dette være så simpelt som at trykke på F5 af, som først åbner og indlæser emulatoren, og derefter udruller koden til den. Som en sidebemærkning behøver du ikke at lukke emulatoren mellem kør/fejlsøgningsforsøg, da den kun skal genudrulle appen.

Hvis du fejlsøger ved hjælp af en enhed, der ikke har været brugt til dette formål før, skal du først konfigurere enheden. Det gør du ved at aktivere udviklerindstillingerne og i den nye menu slå ‘Android debugging’ til under overskriften ‘Debugging’. Herefter skal du blot tilslutte enheden, acceptere dialogboksen på din enhed, der bekræfter, at der er tale om en sikker debuggingforbindelse, og så burde du være i stand til at distribuere og køre din app med F5. Bemærk, at fysiske enheder har højere prioritet end emulatoren og vil skifte til den som standarddebuggingmulighed, når de er tilsluttet.

Når din app er implementeret og indlæst, vil du blive mødt af standardskabelonen med en enkelt side. Åbn menuen i øverste højre hjørne for at logge ind, og når du har indtastet dine oplysninger, bør du vende tilbage til denne side med den snurrende fremskridtslinje, inden du automatisk sendes til dashboard-siden med din velkomstbesked:

Lær mere om Xamarin, OpenID Connect og sikker godkendelse

Hvis du har fulgt alle disse trin, har du nu en grundlæggende Android-app, der er bygget med Xamarin.Android, med fuldt fungerende brugergodkendelse baseret på OpenID og Okta-tjenesten. Herfra kan du nemt udvide dashboardaktiviteten for at implementere din funktionalitet.

For at se koden fra dette indlæg i sin helhed skal du gå over på vores GitHub-side.

Hvis denne tutorial har vakt din appetit på Xamarin-udvikling, og du gerne vil lære mere, så vil jeg kraftigt anbefale dig at tage et kig på disse andre gode artikler:

  • Tilføj identitetsstyring til din Android-app
  • Tilføj autentificering til din Xamarin.Forms-app med OpenID Connect
  • Byg en app til iOS og Android med Xamarin

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.