Tilgang til innfødte funksjoner med Xamarin.Forms

1. Stille inn scenen

Når det gjelder å skrive mobile applikasjoner, er det viktig å integrere med de plattformspesifikke funksjonene som er tilgjengelige for deg når det er fornuftig. Hvis du for eksempel skrev en navigasjonsapp, ville det være fornuftig for deg å bruke geolocation-funksjonene til enheten og plattformen. Hvis du opprettet en app for å hjelpe personer med nedsatt syn, vil du ønsker å integrere med alle tekst-til-tale-funksjoner som også var tilgjengelige.

Det er utviklerne som utnytter disse funksjonene som setter seg selv og deres apps bortsett fra resten. Disse enkle tingene tar bare en vanlig app og gjør det bra. Men hva skjer når du vil dra nytte av disse funksjonene, men du har bestemt deg for å vedta Xamarin.Forms som din kryssplattformsmekanisme? Må du gi opp håp på disse funksjonene bare fordi du bestemte deg for at appen din må være på tvers av plattformen, og du vil kunne dele så mye logikk og brukergrensesnittkode som mulig? Absolutt ikke.

Disse typer spørsmål fører uunngåelig til problemer for utviklere som vedtar nyere teknologier som Xamarin.Forms. Før utgivelsen av Xamarin.Forms, da du jobbet direkte med Xamarin.iOS, var Xamarin.Android og Windows Phone prosjektmaler, det var ganske enkelt å få tilgang til disse typer funksjoner. Fra Xamarin-perspektivet, hvis du kunne finne eksemplar C # - eller til og med morsmål og SDK-dokumentasjon - for en bestemt funksjon, kan du bare kartlegge koden din til de opprinnelige konseptene, fordi Xamarin gjorde en så fantastisk jobb med å oversette de samme innfødte konseptene på de plattformene i C # språk konstruksjoner. Windows Phone-funksjoner var enda enklere fordi det ikke var nødvendig med oversettelse. Alt du måtte gjøre var å lese dokumentasjonen.

Heldigvis for oss som utviklere har Xamarin lagt mye tid og krefter i å designe en mekanisme for oss å få tilgang til disse samme funksjonene, selv om vi velger å bruke deres Xamarin.Forms abstraksjonslag. Denne mekanismen er kjent som DependencyService.

2. DependencyService Oversikt

Ved første øyekast, et navn som DependencyService kan virke litt skremmende. Det høres ut som en fin programmeringsterminologi som bare eliten få forstår. Hvis du noen gang har jobbet med Dependency Injection (DI) eller Inversion of Controller (IoC) beholdere, bør du føle deg hjemme med DependencyService. Hvis du ikke har det, forsikrer jeg deg om at det er et veldig enkelt konsept å forstå når du bryter det ned i komponentene.

Hva er DependencyService?

På det er mest grunnleggende, DependencyService er en klasse. Det er en klasse hvis eneste hensikt med eksistens er å tillate deg å registrere et hvilket som helst antall klasser i hele søknaden din. Ved registrering mener jeg at du tar en hvilken som helst klasse du har og gjør det kjent for tjenesten. Først når DependencyService vet om en klasse, det kan gå og hente en forekomst av den klassen når det er nødvendig. Det er den andre hensikten med DependencyService. Hvis du bestemmer deg for et tilfelle av en klasse som er registrert i DependencyService, Du kan be om eller få en forekomst av det.

Når du virkelig kommer ned i mutter og bolter på DependencyService, Dette er en svært bred generalisering. Men fra utviklerens synspunkt er det nesten alt du trenger å vite. Det er imidlertid et annet konsept du må være oppmerksom på når du arbeider med DependencyService, grensesnitt. Når det kommer til DependencyService og alt dette registrerer og henter, gjør du det vanligvis med hensyn til grensesnitt. Dette betyr at når du registrerer en klasse, registrerer du det som en implementering av et bestemt grensesnitt. Og når du henter en klasse, spør du faktisk DependencyService for en implementering av det grensesnittet. På dette punktet bryr du deg ikke helt hva implementeringen er, du vil bare ha en klasse som implementerer dette grensesnittet.

Hvordan gjør DependencyService Arbeid?

Nå som du har en grunnleggende forståelse på et konseptnivå av hva DependencyService er, la oss grave litt dypere og se hvordan det egentlig virker.

For å bruke DependencyService, du trenger tre ting:

  1. grensesnitt: Et grensesnitt er rett og slett en konstruksjon som definerer hva medlemmene må være tilstede i en hvilken som helst klasse som velger å gjennomføre eller være enig i denne kontrakten.
  2. Registrering: Registrering er bare mekanismen for å la DependencyService vet at en bestemt klasse ønsker å bli registrert og kunne hente seg senere.
  3. Plassering: Dette konseptet er ofte knyttet til et mønster i programvareutvikling kjennetegnet som Service Locator mønster. Dette betyr ganske enkelt at du kan gå til et enkelt sted, DependencyService, og be om noen funksjonalitet, en klasse, uten å måtte umiddelbart ordne en ny forekomst.

La oss grave inn i hvert av disse konseptene i litt mer detaljert.

3. Grensesnitt

Grensesnitt er svært vanlige forekomster i de fleste objektorientert programmering (OOP) språk i disse dager. Ved hjelp av et grensesnitt kan du definere en kontrakt som inneholder en rekke egenskaper, metoder, arrangementer, etc., som må implementeres av enhver klasse som er enig i kontrakten.

Her er et veldig enkelt eksempel på et grensesnitt og en klasse som implementerer det grensesnittet.

offentlig grensesnitt IFileGrabber streng GetFileContents (strengfilUri);  offentlig SimpleGrabber: IFileGrabber offentlig streng GetFileContents (string fileUri) return GetFileFromFileSystem (fileUri); 

Dette virker som et veldig enkelt eksempel, men det tjener formålet ganske bra. De IFileGrabber grensesnitt definerer en enkelt metode, GetFileContents. De SimpleGrabber klassen godtar eller implementerer IFileGrabber grensesnitt, noe som betyr at det må inneholde en implementering for den ene metoden.

Nå, i stedet for å måtte implementere annen kode i søknaden din direkte mot en konkret klasse, SimpleGrabber, Du kan begynne å referere til IFileGrabber grensesnittet i stedet. Tenk deg at du har en annen klasse i søknaden din som ser slik ut:

offentlig klasse DataRetriever private IFileGrabber _fileGrabber; offentlig DataRetriever (IFileGrabber fileGrabber) _fileGrabber = fileGrabber offentlig streng GetFileContents (string fileUri) return _fileGrabber.GetFileContents (fileUri); 

Ved å bruke IFileGrabber grensesnitt i stedet for en konkret klasse, har du muligheten til å opprette andre mekanismer for å hente filer fra forskjellige steder og DataRetriever klassen ville ikke bry seg. La oss anta at vi har en annen klasse som ser slik ut:

offentlig klasse NetworkGrabber: IFileGrabber public string GetFileContents (string fileUri) return GetFileFromNetwork (fileUri); 

Du bryr deg nå mindre om hvordan klassen eller GetFileContents Metoden er implementert, du vet bare at i det minste medlemmene som er definert i grensesnittet er til stede, og det betyr at du kan fortsette å kode bort ved hjelp av bare det grensesnittet som referanse. Dette er et utrolig viktig konsept når det gjelder DependencyService.

4. Registrering

I sammenheng med DependencyService, Xamarin har gjort prosessen med å registrere en klasse ganske enkelt. Siden du allerede har definert grensesnittet ditt og minst en klasse som implementerer det, kan du registrere det i DependencyService bruker en veldig enkel montering attributt.

La oss fortsette å bruke eksemplet ovenfor og registrere SimpleGrabber klasse. Klasset definisjonen vil nå se slik ut:

[assembly: Xamarin.Forms.Dependency (typeof (SimpleFileGrabber)) // En navneområdedeklarasjon som kan eksistere offentlig SimpleGrabber: IFileGrabber public string GetFileContents (string fileUri) return GetFileFromFileSystem (fileUri); 

Alt du trenger å gjøre er å legge til monteringsreferansen over klassedisplayet ditt og utenfor en hvilken som helst namespace-definisjon som også kan inneholde den filen. Ved å gjøre denne enkle oppgaven, har du registrert SimpleGrabber klasse som en implementering av IFileGrabber grensesnitt.

Når du registrerer en klasse, må denne klassen inneholde en parameterløs konstruktør i rekkefølge for DependencyService å ordne det. I mitt eksempel ovenfor har jeg ikke definert en konstruktør, så kompilatoren vil som standard lage en parameterløs konstruktør for meg.

5. Beliggenhet

Det siste stykket av puslespillet blir en forekomst av en registrert klasse. Dette er faktisk den enkleste delen av hele prosessen. For å hente en forekomst av en registrert klasse, bruker du bare DependencyService klasse og det er generisk Få <> () metode. Her er et enkelt eksempel:

offentlig klasse FileHelper offentlig streng GetFileContents (strengfilUri) return DependencyService.Get() .GetFileContents (fileUri); 

I dette tilfellet, i løpet av tiden, bryr du deg ikke om hvor DependencyService får den konkrete klassen som implementerer IFileGrabber grensesnitt. Alt du bryr deg om er at klassen implementerer IFileGrabber grensesnitt.

6. Bruk av DependencyService

Nå som du har en konseptuell forståelse av hva DependencyService er og hvordan du bruker det, la oss lage et enkelt program for å sette det til bruk.

For dette eksempelet vil jeg bruke Xamarin Studio 5, men vær så snill å bruke Visual Studio 2013 hvis du ønsker det. Start med å opprette en ny løsning. I Ny løsning dialogboksen, under C # kategori til venstre, velg Mobile Apps prosjektfamilie. På høyre side velger du enten Tom App (Xamarin.Forms Portable) eller Blank App (Xamarin.Forms Delt) prosjektmal. Koden og den resulterende applikasjonen vil være den samme uansett hvilken mal du velger.

I dette eksemplet vil jeg bruke Bærbart klassebibliotek (PCL) versjon av malen. Gi et navn til prosjektet. Jeg skal navngi løsningen og første prosjektet DependencyServiceSample. Klikk deretter på OK knapp.

Denne prosessen vil skape tre separate prosjekter:

  • DependencyServiceSample - Delt bibliotek (PCL)
  • DependencyServiceSample.Android - Android-prosjektet
  • DependencyServiceSample.iOS - iOS-prosjektet

Xamarin Studio støtter ikke å opprette Windows Phone-prosjekter. Hvis du bruker Visual Studio, vil denne prosessen skape fire prosjekter. Det vil skape de tre prosjektene ovenfor, samt et Windows Phone-prosjekt som heter DependencyServiceSample.WinPhone.

I det delte biblioteket (DependencyServiceSample), opprett en ny grensesnittfil og navn den ISampleInterface og gi den følgende implementering:

namespace DependencyServiceSample public interface ISampleInterface string GetData (); 

Det er en standard utseende grensesnittfil som definerer en enkel metode som heter GetData som kommer tilbake a string. Igjen er det viktige poenget å forstå at fra det perspektivet av den delte koden filen, bryr seg ikke hva implementeringen av dette grensesnittet ser ut. Det eneste som betyr noe er at uansett implementering er gitt for dette grensesnittet, har det en metode som heter GetData som kommer tilbake a string.

Deretter endrer vi App.cs fil for å bruke DependencyService å få en forekomst av ISampleInterface å bruke i din Xamarin.Forms app. Endre  GetMainPage metode for å se ut som følgende:

offentlig statisk side GetMainPage () returner nytt ContentPage Content = new Label Text = DependencyService.Get() .GetData (), VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.CenterAndExpand,,; 

Legg merke til at den eneste forskjellen er at Tekst eiendom av Merkelapp har blitt endret til følgende linje:

DependencyService.Get() .GetData ()

På denne måten bruker du DependencyService klasse og generisk Få <> () metode for å hente uansett implementering av ISampleInterface implementeres i det plattformspesifikke prosjektet som for tiden kjører. Når den forekomsten er hentet, ringer du til GetData metode for å få tilbake en streng og sette Tekst eiendom av Merkelapp.

Det siste trinnet har to deler (tre hvis du bruker Visual Studio). På dette punktet må du implementere ISampleInterface grensesnitt i alle de plattformspesifikke prosjektene i løsningen.

La oss starte i DependencyServiceSample.Android applikasjon. Alt du trenger å gjøre er å opprette en ny klassefil i prosjektet og gi det noe navn du liker. Jeg har kalt min Sample_Android. Bytt standard implementering med følgende:

bruker system; bruker DependencyServiceSample.Android; [samling: Xamarin.Forms.Dependency (typeof (Sample_Android)) namespace DependencyServiceSample.Android offentlig klasse Sample_Android: ISampleInterface #region ISampleInterface implementering offentlig streng GetData () return "Jeg kom fra Android-prosjektet!";  #endregion 

Dette er en enkel klasse som implementerer ISampleInterface grensesnitt og implementering er å bare returnere a string sier at det kommer fra Android-prosjektet. Den eneste forskjellen er bruken av montering Tilordnet øverst på filen som registre denne klassen med DependencyService slik at den kan hentes senere.

La oss nå lage en annen implementering av dette grensesnittet i iOS-prosjektet. Opprett en ny klasse i iOS-prosjektet, nev det Sample_iOS, og erstatt standard implementering med følgende:

bruker system; bruker DependencyServiceSample.iOS; [samling: Xamarin.Forms.Dependency (typeof (Sample_iOS)) namespace DependencyServiceSample.iOS offentlig klasse Sample_iOS: ISampleInterface #region ISampleInterface implementering offentlig streng GetData () return "Jeg kom fra iOS-prosjektet!";  #endregion 

Implementeringen er akkurat den samme som Android-versjonen, bortsett fra at den returnerer en annen streng som sier at den kommer fra iOS-prosjektet denne gangen. Det siste trinnet er å kjøre programmet og se om du får resultatet du forventer.

Her er resultatet av iOS-programmet som kjører.

  

Her er resultatet av Android-applikasjonen som kjører.

Som du kan se, løper begge programene vellykket. Ikke bare løper de, men de kjører vellykket fra et delt Xamarin.Forms-prosjekt som styrer brukergrensesnittet. Fra den brukergrensesnittkoden i Xamarin.Forms, kan du nå dyppe direkte inn i plattformspesifikke prosjekter for å få tilgang til innfødt kode.

7. Hvor skal jeg hen?

Nå som du har ferdigheter til å bruke DependencyService for å få tilgang til innfødt funksjonalitet fra Xamarin. Form, himmelen er grensen. Du kan fortsette å skrive enkle implementeringer som du har gjort i denne opplæringen, eller du kan begynne å tappe inn i flere interessante funksjoner på plattformene.

En av de mest interessante ressursene for å ta en titt på for å integrere i din DependencyService er oppskrifter delen av Xamarin nettsiden. Her finner du plattformsspesifikke implementeringer for å få tilgang til en rekke funksjoner, inkludert:

  • Nettverk
  • Audio
  • video
  • geolocation
  • akselerometre

Alle disse funksjonene er til din disposisjon når det gjelder Xamarin.Forms applikasjoner. Med DependencyService, Disse funksjonene kan innkalles øyeblikkelig.

Konklusjon

Nå som du vet og forstår DependencyService, du trenger ikke lenger å føle deg skremt når du trenger tilgang til plattformspesifikke funksjoner fra et Xamarin.Forms-program. Du har nå verktøyene som lar deg tappe inn i de fantastiske innfødte egenskapene til enhetene som til slutt lar deg skille appene dine fra resten i appbutikkerne.

Neste trinn: Se på kurset

Hvis du vil lære mer om Xamarin, så sjekk ut kurset vårt. Bygg Multi-Platform Apps med C # i Xamarin. 

I løpet av kurset lærer du hvordan du oppretter et kryssplattformsprogram fra en enkelt kodebase som vil kjøre på tre forskjellige plattformer: iOS, Android og Windows Phone 8. Tror det ikke kan gjøres? På bare en liten stund vil du gjøre det selv. La oss komme på jobb.

Du kan ta det straks med en helt gratis 14 dagers prøve av et Tuts + abonnement. Ta en titt på abonnementsalternativene våre for å komme i gang, eller hvis du bare er interessert i dette kurset, kan du kjøpe det individuelt for $ 15! Her er en forhåndsvisning for å komme i gang: