• No results found

5.3 D ATA OCH LOGIKLAGER

5.3.4 Autentisering

För att hämta data från innehålls-API:et krävs ingen autentisering, detta API är helt öppet och begränsad dokumentation finns för allmän beskådning. För att spela upp video via Playback-API:et krävs dock först en kedja av autentiseringsanrop mot både Autentiserings-Playback-API:et och Playback-API:et. Metoder för detta finns i applikationens Helper-klass. Dessa autentiseringar presenteras i följande avsnitt.

Login

Den första autentisering som sker är mot Autentiserings-API:et och kallas förenklat login. Här anropas API:et med användaruppgifter, operatörsuppgifter och landskod, går detta väl returneras två auth-cookies samt ett SumoUserId som identifierar användaren hos Playback-API:et; dessa måste sedan bifogas vid alla kommande anrop för att t.ex. spela video.

Misslyckas anropet returneras ett http-meddelande med information och statuskod som beskriver varför loginförsöket förkastades.

Dessa auth-cookies, SumoUserId, användaruppgifter samt ett DateTime för inloggingstillfället sparas sedan undan i ett objekt kallat UserInformation (se figur 5-5). UserInformation serialiseras och sparas sedan i applikationens LocalSettings (se avsnitt 5.3.5 Data Cache) UserInformation-innehållet bifogas vid varje anrop användaren gör för att spela upp film.

DateTime-objektet sparas för att konventionen hos Autentiserings-API:et är att en användare efter 30 dagar måste genomföra en ny inloggning.

Figur 5-5 UML för UserInformation (av författarna)

20 Play video

1. Login: För att spela upp video krävs som utgångspunkt att användaren gjort ett lyckat login-anrop, som beskrevs ovan.

2. Generera DeviceId: Autentiserings-API:et har även ett igenkänningssystem som hindrar ett konto att brukas på fler än fyra unika enheter (datorer, surfplattor etc.).

Igenkänningssystemet bygger på att varje anrop som görs mot API:et måste bifoga en unik nyckel som identifierar just den enheten; detta kallas DeviceId. Denna nyckel genereras vid varje anrop som en textsträng sammanslagen av enhetens processor-id, ram-minnets storlek, hårddiskens serienummer samt bios-nummer. Metoden som genererar denna sträng är till mycket stor del baserad på kod funnen på ett forum (Canderso, Possible to get network MAC address in .NET Metro app?, 2012).

3. StartStream: Nu görs ett API-anrop mot Autentiserings-API:et som kallas StartStream.

Här bifogas innehållet i UserInformation, DeviceId samt Id på den Asset (film, serie) användaren vill spela upp.

a. OK: Går detta väl returneras OK, samt ett TimeSpan-objekt som säger vart i filmen användaren senast tittade. Har användaren inte tittat på filmen förut är detta objekt satt till 00:00:00 vilket visar att videon ska ses från början.

b. Error: Ett antal fel kan också uppstå vid start av ström och då returneras info samt statuskod som presenterar detta, dessa fel innefattar:

i. Fel i användaruppgifter såsom username, password, countrycode etc.

ii. Användaren har ej rätt att se detta material, pga. regionsbestämmelser eller dylikt.

iii. Kontot används på annan plats, någon spelar redan video.

iv. Kontot har redan fyra enheter registrerade och den enhet som gjorde anropet finns inte bland dessa.

4. Hämta Videolänkar: Nu görs ett anrop mot Playback-API:et tillika OVP-leverantören.

Till anropet bifogas auth-cookies men inga användaruppgifter, tillbaka skickas ett Playback-Objekt innehållande en URL till Smooth Streams videon, samt en URL för DRM-licensen. Har användaren felaktiga auth-cookies returneras info och statuskod som beskriver felet.

5. Returnera länkar: Smooth Streams- och Licens-URL:en samt TimeSpan-objektet för vart i videon användaren befinner sig returneras tillbaka till den kallande event-hanteraren.

21 Keep Alive och StopStream

Mot Autentiserings-API:et behöver ett keep-alive paket skickas i intervallet var 60:e sekund, detta görs dels för att uppdatera TimeSpan-objektet i databasen som vet vart i filmen användaren är, men också för att spåra om ett konto streamar video eller inte (Se punkt 3-b-iii i listan på sida 20). Keep-alive paketet skickas till Autentiserings-API:et och är uppbyggt på samma sätt och har samma innehåll som StartStream-anropet, med skillnaden att ett TimeSpan-objekt bifogas med aktuell position i video.

När en användare stänger ner, stoppar en video eller när den spelat klart skickas ett StopStream-anrop till Autentiserings-API:et som meddelar att användaren avslutar video-strömmen, även här bifogas TimeSpan-objektet med vart i video användaren befann sig, detta används för att i mediaspelaren kunna återuppta tittande (se avsnitt 5.5 Mediaspelare). En sammanställning av Play-Video, Keep-Alive och StopStream förfarandet finns att se till höger i figur 5-6.

Figur 5-6 Flödesschema för Play-Video förfarande (av författarna)

22 5.3.5 Data Cache

WinRT erbjuder cache-metodik i begränsad form, därför skrevs under projektet egen funktionalitet för att hantera cache av data och bilder, denna funktionalitet placerades i en klass som kallades LocalStorage. LocalStorage visade sig dock i vissa avseenden inte kunna leverera samma prestanda som ett open source bibliotek, Q42.WinRT (GitHub, Q42.WinRT, 2013). Detta avsnitt går igenom varför applikationen kräver en cache, hur WinRT’s inbyggda cachelösningar fungerar samt hur den egenskrivna lösningen fungerar. En vidare utvärdering finns i (avsnitt 6.3 WinRT Data Caching).

Cache av data och bilderna från API:erna bestämdes tidigt vara ett krav, vid en eventuell lansering av applikationen skulle Web-API:erna annars bli snabbt överbelastade om varje navigering i användargränssnittet genererade nya API-anrop. Utöver att minska belastning på API:erna laddar användargränssnittet bilder och information snabbare från cache, vilket gör att applikationen känns mer responsiv.

WinRT erbjuder ingen persistent cache av bilder, däremot cachas bilder i minnet under den instans av applikationen som körs (Bart Wullems, Caching Images in WinRT, 2012), men detta sparar endast prestanda kortsiktigt eftersom nästa körning av applikationen måste belasta bild-API:et igen.

WinRT erbjuder cache av data i fyra olika former: LocalSettings, RoamingSettings, LocalFolder och RoamingFolder.

 LocalSettings (Microsoft, applicationData.LocalSettings | localSettings property, 2013) erbjuder persistent lagring av data lokalt på värdmaskinen. Lagringen är av typ Dictionary<String,Object>; en sträng agerar nyckel åt ett objekt, där objektet måste vara serialiserbart (Microsoft, Serialization (C# and Visual Basic), 2013) och inga dubbletter av nyckeln får finnas i Dictionary-instansen. Lagringen av informationen sköts av WinRT och programmeraren behöver endast hämta data identifierat av en nyckel. Maxstorlek för en nyckel är 255 tecken, datamängden i ett objekt får ej överstiga 8 Kilobyte och totala storleken för LocalSettings får ej överstiga 64 Kilobyte.

 RoamingSettings (Microsoft, applikationData.RoamingSettings | RoamingSettings property, 2013) fungerar på samma sätt som LocalSettings med undantaget att WinRT i bakgrunden laddar upp datat i molnet (Windows Azure) (Microsoft, Part2: Part 2:

Manage app lifecycle and state (Windows Store apps using C#/VB and XAML), 2013).

 LocalFolder (Microsoft, applikationData.LocalFolder | localFolder property, 2013) erbjuder en mapp lokalt på hårddisk där programmeraren kan spara filer av godtycklig typ, men denne måste till skillnad från Local- och RoamingSettings själv sköta filhantering, serialisering av objekt osv.

 RoamingFolder (Microsoft, applikationData.RoamingFolder | roaminglFolder property, 2013) erbjuder samma funktionalitet som LocalFolder men med undantaget att WinRT laddar upp mappen i molnet.

23

Användningsområdet för Local- och RoamingSettings är enligt Microsoft själva främst att spara undan information som framhärdar en applikations tillstånd mellan sidbyten och state-changes, detta tas upp i (avsnitt 5.3.8 applikationens olika tillstånd) och (avsnitt 5.3.9 Navigering).

Implementation av egen data cache

Vid planering av applikationen togs först beslut om att cacha data i LocalSettings. Ganska snart upptäcktes dock att datamängderna från innehålls-API:et översteg LocalSettings lagringskapacitet, vilket medförde att alternativa cache-metodiker behövde utvecklas. Två lösningsförslag togs fram; dels ett open-source bibliotek kallat Q42.WinRT, dels alternativet att skriva egen metodik för cachen. Beslut togs att skriva egen cache-metodik, dels i inlärningssyfte men också som en del av analysen inom data-caching i Windows 8 applikationer. Lösningen är baserad på en idé framtagen av Eric Vogel (Eric Vogel, Putting It Together, 2012).

Lösningen går ut på att lagra JSON-strängarna som erhålls från innehålls-API:et i ett objekt som fick namnet DataCacheObject, se figur 5-7. DataCacheObject består av en JSON-sträng, ett DateTime-objekt som beskriver när DateTime-objektet cachades samt en Type som anger vilken typ av objekt som cachats.

Dessa DataCacheObjects lagras sedan i en Dictionary<String, Object>, där nyckeln unikt identifierar innehållet. Hjälpmetoder definierades sedan i en statisk klass kallad LocalStorage, denna hade metoder för att läsa, skriva och kontrollera innehåll i cachen/Dictionary:et.

Dictionary-objektet och dess hjälpmetoder var statiska för att kunna anropas genom hela applikationen.

Då LocalSettings inte kunde lagra de datamängder applikationen krävde fanns alternativen Roaming- och LocalFolder kvar. Eftersom cachen även skulle förbättra prestanda i applikationen föll alternativet RoamingFolder bort, då det kräver nätverkskommunikation med molnet, istället valdes LocalFolder som lagringsalternativ för att cacha datat. Själva lagringen löstes genom att vid applikationens avslut spara Dictionary-objektet innehållande cachen till fil med hjälp av en en DataContractSerializer (Microsoft, Data Contract Serializer, 2013), som på samma sätt återskapar sagda Dictionary vid uppstart av applikationen.

Figur 5-7 UML för DataCacheObject

24 Implementation av egen bild cache

Då WinRT inte har någon persistent lösning för att cacha bilder fick egen funktionalitet för detta skrivas. Beslut hade redan tagits om att skriva egen cache-metodik, vilket gjorde att det enda lösningsförslaget som kunde tas fram var att spara bilderna i applikationens LocalFolder.

Bilder som inte redan finns i LocalFolder laddas alltså ner från API:et endast första gången, nästkommande gång bilden tillfrågas läses den in lokalt. Bilder ansågs också kunna cachas permanent, alltså att inget utgångsdatum för dem behövde sättas.

En bild presenteras i modellen som en Resource (se avsnitt 5.3.1 Modeller), en Resource har ett Id i form av en GUID. Utifrån denna GUID utformades ett arkiveringssystem som består av en mappstruktur. Denna mappstruktur går ut på att Guid:ens tre första chars utgör sökvägen i applikationens LocalFolder. Ett exempel:

En bilds id (GUID) är: 39e76c2e-9f33-4b9d-b47b-66e00b7807b8. Sökvägen till bilden blir då LocalFolder/3/9/e/bildformat.img. Detta gjordes för att i längden korta ner söktider, med tiden kan bildarkivet tänkas innehålla tusentals bilder vilket kommer försämra prestanda när LocalFolder-mappen ska sökas igenom. Varje bild kan också levereras i olika format från bild-API:et, dock förblir bildens Guid detsamma, vilket gör att alla bilder som hör till en viss serie eller film kommer placeras i samma mapp.

25 5.3.6 Hämta innehåll

I Helper-klassen finns metoder som hämtar och returnerar data från innehålls-API:et till Controllern, som i sin tur fyller på vyn med innehållet, se figur 5-8 nedan.

Data-Request är ett metodanrop från en event-hanterare i UI:et om nytt innehåll, t.ex. att användaren byter Genre. Genren hämtas från cache eller API:et, deserialiseras från JSON till objekt och returneras sedan.

Figur 5-8 Flödesschema för ett Data-Request (av författarna)

26 5.3.7 Hämta bild

Varje film eller serie i applikationen presenteras också med en bild som hämtas från Bild-API:et. Som utgångsläge sätts ett XAML-Image objekts källa till en URI och kan vara en webb- eller lokal adress, det här utgjorde ett problem vid implementation då det skulle leda till att Image-elementet hade en URI till bild-API:et, vilket i sin tur leder till att bilden kommer laddas ner på nytt varje gång applikationen körs. Problemet löstes genom att fånga ett event som kallas Loaded; som triggas för varje Image-objekt som laddas in i användargränssnittet. I detta event anropades en Helper-metod som utför den metodik som beskrevs ovan i (avsnitt 5.3.5 Data Cache). Ett exempel kan ses i figur 5-9 nedan.

Figur 5-9 Flödesschema för Image-Request (av författarna)

27 5.3.8 Applikationens olika tillstånd

En Windows 8 Store applikation kan befinna sig i tre olika tillstånd: kör, suspenderad och körs ej (Microsoft, applikation lifecycle (Windows Store apps), 2012).

Figur 5-10 En Windows Store applikation livscykel (av författarna)

En applikation som körs kan hamna i ett suspenderat tillstånd om till exempel en användare väljer att byta till en annan applikation. När en användare byter tillbaka till en suspenderad applikation kommer denna att återupptas om inte applikationen har blivit borttagen ur minnet på grund av att Windows behövde de resurserna, om detta har skett är applikationen i ett körs ej tillstånd och kommer på nytt bli aktiverad och på så sett hamna i tillståndet kör (se figur 5-10).

Det är viktigt att en applikation hanterar övergångarna mellan olika tillstånd, när en användare har navigerat till en annan applikation och sedan navigerar tillbaka vill denne att ursprungsapplikationen är i det läge den lämnades i. Om en applikation återupptas kommer den vara i samma läge som när den lämnades men om applikationen har plockats bort ur minnet av Windows kommer den att aktiveras på nytt, det är i detta läge viktigt att data som kan hjälpa till att återställa applikationen har sparats persistent under suspenderingen.

Att spara undan data innan applikationen hamnar i ett suspenderat tillstånd görs genom att registrera en event-hanterarare för suspendering-eventet, i denna metod skrivs koden för att spara det data som behöver sparas. Genom att sedan registrera en annan event-hanterare för aktiverings-eventet kan man återställa applikationen genom det data som sparats under suspenderingen. Det går i event-hanteraren för aktivering att kontrollera om en användare aktivt stängde applikationen eller om Windows behövde resurser och därför stängde applikationen, detta är en fördel i de fall olika åtgärder ska tas beroende på hur applikationen

28

stängdes. T.ex. kan innehåll i ett textfält sparas undan när Windows stänger ner applikationen, medan detta inte behövs när en användare aktivt tar beslut att stänga ner.

Under projektet användes event-hanterare för suspendering och aktivering t.ex. för att spara och ladda cachad data till och från fil.

5.3.9 Navigering

Då applikationer generellt består av mer än en sida krävs det att applikationen implementerar navigering. I applikationen som utvecklats utnyttjas några av de page templates som Visual Studio tillhandahåller. När man i Visual Studios skapar en ny sida i sitt projekt kan man välja att använda någon av dessa page templates och får då automatiskt viss grundfunktionalitet, bland annat kommer sidan att stödja grundläggande navigering.

För att hantera navigering används klassen Frame, (Microsoft, Frame class, 2013), som implementerar metoderna Navigate, GoBack och GoForward. Navigate-metoden tar två argument, typen på den sida som applikationen ska navigera till samt ett objekt av primitiv data, det sistnämnda är valfritt.

I applikationen som utvecklats kan en användare navigera vidare genom att i applikationens huvudsida klicka på en film eller Play-knapp. Klickar en användare på en film, navigerar applikationen till en detaljsida och klickar användaren på Play-knappen kommer applikationen navigera till en sida för att spela upp filmen. På detaljsidan och mediaspelarsidan kan en användare välja att navigera tillbaka via en GoBack-knapp eller navigera tillbaka genom att klicka på en av kategorierna film, serier, barn eller dokumentärer.

Navigerar användaren tillbaka genom att klicka på GoBack-knappen kommer huvudsidan vara densamma som användaren lämnade men om användaren navigerar via någon av kategorierna ska den visa filmer inom den valda kategorin samt att den knapp som svarar mot den valda kategorin ska vara iklickad.

För att kunna bygga upp huvudsidan så som den såg ut vid navigering via GoBack metoden sparas namnet på den kategori som användaren senast valt i LocalSettings. För att underlätta nedsparandet av data vid navigering finns event-hanterarna OnNavigatedFrom och SaveState, dessa metoder körs alltid innan den nya sidan visas. På samma sätt kan OnNavigatedTo och LoadState användas på den nya sidan för att hämta sparad data.

5.4 Felhantering

I en Windows 8 Store applikation kommer exceptions som genereras i code-behind att kastas tillbaka till XAML-ramverket som anropade koden. Här kommer ett UnhandledException event att höjas och applikationen kommer sedan att stängas utan att användaren meddelas vad som hände.

En lösning på problemet var att implementera en event-hanterare för UnhandledException och i den meddela användaren att något gått fel och sedan stänga applikationen. Det går att sätta attributet Handled till true i event-hanteraren och på så sett få applikationen att köra vidare men det rekommenderas inte av Microsoft, då en UnhandledException event-hanterare oftast

29

inte har tillräckligt med information om kastat exception samt att applikationen kan vara i ett inkonsistent tillstånd (Microsoft, Aplication.UnhandledException event, 2013).

En bättre lösning på problemet är att fånga exceptions i code-behind och det är denna lösning som har använts. Fördelen med att hantera exceptions innan det når XAML-ramverket är att applikationen kan meddela användaren om vad som gick fel, hantera felet och i de flesta fall kan applikationen fortsätta att köra.

För att på ett enkelt sätt visa en användare att något gick fel används klassen MessageDialog (Microsoft, MessageDialog class, 2013). I sitt grundutförande kommer en MessageDialog visa ett meddelande tillsammans med en knapp för att stänga dialogen. I applikationen som har utvecklats beskriver meddelandet vad som gick fel och när användaren stänger dialogen kommer applikationen att navigera till huvudsidan.

5.5 Mediaspelaren

Då applikationens mediaspelare skulle stödja både PlayReady och Smooth Streams krävdes ytterligare funktionalitet utöver den som XAML objektet MediaElement och WinRT levererar. I sitt grundutförande kan inte någon form av ABR strömmas men genom att implementera funktionaliteten i Smooth Stream Client SDK, som i grunden fungerar som en unwrapper för Smooth Stream formatet, kan Windows 8 förstå, tolka och spela upp Smooth Streams (Mingfei Yan, Building video applikation on Windows 8 – things you want to know, 2013).

Ett alternativ som fanns var att själva implementera funktionaliteten i Smooth Streaming Client SDK och bygga spelaren från grunden. Detta ansågs dock som en för stor uppgift inom projektets tidsramar och efter rekommendation från (Anders Thun, Microsoft) bestämdes det att Player Framework skulle användas. Player Framework är en open source mediaspelare för Windows 8, HTML5, Silverlight och Windows Phone, som har support för ABR strömning via Smooth Streaming Client SDK (Microsoft, Player Framework, 2013).

5.5.1 Implementation av mediaspelare

Genom att installera Player Framework i projektet kan man implementera ett Player Framework mediaplayer XAML-objekt. Genom ett sådant objekt kan man definiera insticksmoduler och en av dessa moduler är stödet för ABR strömning. För att spela upp en Smooth Stream anger man en URI till filmens manifest-fil som objektets source attribut. En Manifest-fil innehåller metadata om videon i fråga. Denna URI till manifestfilen levererades av metoder i Helper-klassen, läs mer om Play-Video i (avsnitt 5.3.4 Autentisering).

Applikationen stödjer ”återupptagande av tittande” på video som tidigare setts på det kontot som är inloggat. Är det TimeStamp som levereras skilt från 00:00:00 kommer användaren kunna välja om den vill se videon från början eller återuppta där den senast tittade.

30 5.5.2 Implementation av PlayReady

Allt material som levereras via Playback-API:et är skyddat med DRM tekniken PlayReady. I grundutförande finns inte stöd för att hantera PlayReady i en Windows 8 Store applikation.

För att lösa detta användes Micrsoft PlayReady Client SDK for Windows Store apps, vilket är ett ramverk för att hantera PlayReady-skyddat material (Microsoft, Microsoft PlayReady Cilen SDK for Windows Store apps, 2013).

Vid implementationen av PlayReady SDK:en användes exempelkod som Microsoft distribuerar via MSDN (Microsoft, Simple PlayReady sample for Windows 8 Store apps, 2013). Denna kod visade sig vara välfungerande och ytterst få justeringar behövdes för att applikationen skulle kunna spela upp det skyddade materialet. URI:en till DRM-lincensen levererades i projektet av metoder i Helper-klassen, läs mer om Play-Video i (avsnitt 5.3.4 Autentisering).

31

6 Utvärdering och analys

I kommande avsnitt redovisas de utvärderingar och analyser som utförts under projektet, ställt utifrån uppgiften och dess frågeställningar.

6.1 Komplexitet för utvecklaren att lära sig verktyg och miljöer

En av fördelarna med Windows 8 utveckling är möjligheten att välja bland olika uppsättningar programmeringsspråk. Om man har erfarenhet inom något av de språken som kan väljas slipper man komplexiteten i att lära sig ett helt nytt programmeringsspråk.

Något som uppmärksammats under projektets gång är också att Microsoft tillhandahåller mycket material om hur man snabbt kommer igång med att utveckla Windows 8 applikationer, både vad gäller planering, design, implementation och distribution av

Något som uppmärksammats under projektets gång är också att Microsoft tillhandahåller mycket material om hur man snabbt kommer igång med att utveckla Windows 8 applikationer, både vad gäller planering, design, implementation och distribution av

Related documents