Szerző: Sicz-Mesziár János

Platform integráció Androidon

Amikor egy mobilalkalmazás ötleteléséről és megtervezéséről beszélünk, akkor nem árt ha tudjuk, hogy milyen integrációs lehetőségek vannak az adott platformmal. Érdemes átgondolni, hogy magán az alkalmazáson túl milyen funkciókkal, operációs rendszer szintű szolgáltatásokkal tudunk együttműködni. Növeli a felhasználói elégedettséget, mivel sokkal kidolgozottabb és minőségibb alkalmazás érzetét adja. Emellett pedig pozitívan mutatkozik meg az alkalmazás használati statisztikákban.

A cikkben az Android rendszerben levő integrációs lehetőségeket szeretném megmutatni, ami reményeim szerint segítséget nyújthat az alkalmazáskoncepciók kialakításakor, hogy az közelebb kerüljön a felhasználóhoz és jobban illeszkedjen a mindennapi használathoz.

platform_integration.jpg

A félreértések elkerülése végett szeretném hangsúlyozni, hogy az itt leírtak bár az Android rendszerrel kapcsolatosak, ugyanakkor nem kizárt, hogy iOS-en is vagy éppen más platformokon is valamilyen formában megvalósíthatóak.


Alapértelmezett funkciók

Az Android esetében vannak olyan szolgáltatások vagy funkciók, amelyek automatikusan működni fognak, amint a legfrissebb Android SDK-val fordítjuk le az alkalmazást. Ugyanakkor ez nem jelenti azt, hogy nincs vele feladat. Sokszor érdemes vagy éppen kell is közreműködni a siker érdekében.

Adaptive icon

Android 8.0 (Oreo) megjelenésével együtt érkezett az úgynevezett adaptív ikon támogatás. Ez azt jelenti, hogy ha a Kezdőoldal alkalmazás (Launcher app) ezt támogatja, akkor az alkalmazások indító ikonjának a formája felhasználó által változtatható. Ahhoz, hogy ez jól nézzen ki picit érdemes vele foglalkozni. Az Android alkalmazásban külön kell a háttér (background) és az előtér (foreground) képet meghatározni egy bizonyos biztonsági sávot (safe zone) betartva. Az ikon formálása során csak a háttérkép kerül maszkolásra. Ha ezzel nem törődünk, akkor a fordítás során fehér háttérkép mellett előtér képnek az eredeti (régi) ikon kerül. Ez pedig nem feltétlen szokott jól kinézni.

Hivatalos dokumentáció itt:
https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive

Kapcsoló blog cikkek angol nyelven:
https://medium.com/google-design/understanding-android-adaptive-icons-cee8a9de93e2
https://medium.com/google-design/designing-adaptive-icons-515af294c783
https://medium.com/google-developers/implementing-adaptive-icons-1e4d1795470e

Runtime permission

Android 6.0 (Marshmallow) megjelenésekor pótolták az egyik legnagyobb hiányosságát a platformnak. A különböző erőforrásokhoz kért jogosultságokat futásidőben kérjük el a felhasználótól. Erről külön-külön dönthet, valamint később meg is változtathatja döntését.

A régi működés szerint az alkalmazás telepítéskor kellett minden jogosultságkérést elfogadni különben nem települt fel az alkalmazás. A mindent vagy semmit elv igen kedvező volt a fejlesztőknek, mert garantálta, hogy mire a megírt kód lefut (telepítés után tud csak) addigra a felhasználó minden engedélyt megadott. Ugyanakkor több hátránya is volt ennek, mivel egyrészt ez visszaélésre is lehetőséget adott, másrészt sok esetben hátrányos megítélés alá került egy-egy alkalmazás. Kedvenc példám egy SMS Backup alkalmazás, amely a kontaktlistázhoz és a hívásnapóhoz is hozzá akar férni, mivel azt is tudja exportálni. Ha én csak SMS-ket szeretnék menteni, akkor miért kellene engedélyt adnom a hívásnaplóhoz? Mivel ez zavar máris nem töltöm le az alkalmazást, holott a kívánt feladatot maradéktalanul el tudná végezni.

A futásidejű engedélykérés esetében telepítéskor nem kell elfogadni semmit, hanem az alkalmzás használata során kell a felhasználótól engedélyt kérni. Ez pedig fejlesztést jelent, mivel ez nem olyan amit kód módosítás nélkül meg lehetne csinálni. Kezelni kell az olyan eseteket is, mint:

  • elutasításra kerül az adott kérelem
  • több jogosultság együttes engedélye kell, de egyiket sem fogadja el, vagy csak egy részét
  • ismét az adott funkcióhoz ér, így ismét engedélyt kérnénk ezért egy idő után véglegesíti döntését

platform_integration_-_run_time_permission.jpg

A fenti képen a SmartCity alkalmazás engedélykérése látszik Android 4.2 alatt (bal oldalt) és Android 8.0 alatt (jobb oldalt).

Mostanra már a Runtime Permission implementálása egy nem megúszható dolog lett. 2018 novemberéig működik az a megoldás, hogy ha régebbi SDK verzióval (< API 23) fordítjuk az alkalmazást, akkor még régi szabályok szerint megy minden. Viszont, hogy ezzel ne éljenek vissza a fejlesztők és inkább az előrehaladást válasszák a Google bejelentette, hogy 2018 novemberét követően a régi SDK-val fordított alkalmazást nem lehet publikálni a Play Árhuzába. Új alkalmazás közzététele esetén már 2018 augusztusában élni fog ez a megkötés.

Bővebb információ a hivatalos Android fejlesztői blogon:
https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html

Fejlesztőknek pedig az alábbi megoldás könnyítheti meg az életét:
https://github.com/permissions-dispatcher/PermissionsDispatcher

Notification Channel

Android 8.0 (Oreo) bevezette az úgynevezett Notification Channel funkciót, ami az értesítési sávon megjelenő értesítések kliens oldali kategorizálását jelenti. Ha a fordítás során legalább az API 26-ot célzod meg, akkor ezt bizony meg kell csinálni, mert egyébként Oreo alatt nem jelennek meg az értesítések. Azon kívül, hogy egy ponton túl kötelezettségé válik szeretnék rámutatni, hogy miért is jó ez.

A kódolás során minden értesítést be kell sorolni egy értesítési csatornába. Például így:

// ... get your a notification manager instance by NotificationCompat as usual
// Set default channel on Android O and above: MANDATORY
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
	NotificationChannel channel = new NotificationChannel(
			NOTIFICATION_CHANNEL_ID,
			getString(R.string.application_name),
			NotificationManager.IMPORTANCE_HIGH
	);
	channel.enableLights(true);
	channel.setLightColor(getColor(R.color.dh_magenta));
	channel.enableVibration(true);
	channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_SECRET);
	mNotificationManager.createNotificationChannel(channel);
}
// Rest of your code ...

Ha jobban belegondolunk, akkor az értesítési csatorna információi, mint például annak neve, azonosítója akár szerver oldalról is jöhet egy push notification (FCM, GCM) formájában. Azaz, akár teljesen új csatornákat (kategóriákat) is létre lehet hozni anélkül, hogy új verziót kellene publikálni a Play Áruházba. Például hírek esetében rovatonkénti csatorna kialakítása. A felhasználóknak meg azért jó, mert ezek után megtehetik, hogy csatornánként kapcsolják ki az értesítést vagy állítanak be egyéni csengőhangot. Mindezt az adott alkalmazás rendszer szintű beállítási felületén. Tehát dönthet arról, hogy csak bizonyos csatornák értesítéseit nem szeretné megkapni, ezzel megszüntetve még egy "mindent vagy semmit" elvet.

Split screen

Android 7.0 (Nougat) kiadásakor gondoltak a nagyobb kijelzővel rendelkező készülékek (tablet, TV) jobb kihasználására is. A split screen néven futó újítás lényege, hogy egy időben két aktív alkalmazás is futhat a képernyőn. Ez picit megtöri az Android korábbi azon filozófiáját, hogy egy időben egyszerre csak egy alkalmazás van előtérben. Ez a funkció ismét olyan, amit automatikusan megnyerünk, ha friss SDK-val fordítunk.

 platform_integration_-_split_screen.jpg

SmartCity alkalmazás osztott képernyőn, bal oldalt az alkalmazás egy aktív tervezéssel, míg jobb oldalt a honlap Chrome böngészőben.

Amiért érdemes foglalkozni vele az az, hogy felkészítjük más méretekre is az alkalmazásunkat. (Egyes készülékgyártók akár ki is kényszeríthetik, pl Samsung, OnePlus) Próbáljuk nem elengedni a fektetett nézet (landscape) megvalósítását! Valamint teszteljük le alaposan, hogy az alkalmazás életciklusát korrektül kezeljük és az állapotokat is megőrizzük! Nem utolsó sorban nyilatkozzunk arról, hogy milyen split-screen módokat támogatunk:

android:resizeableActivity=["true" | "false"]
android:supportsPictureInPicture=["true" | "false"]

Emellett a layout használatával finomíthatunk a méreteken is:

<activity android:name=".MyActivity">
    <layout android:defaultHeight="500dp"
          android:defaultWidth="600dp"
          android:gravity="top|end"
          android:minHeight="450dp"
          android:minWidth="300dp" />
</activity>

Természetesen a fentieken túl még akadhat teendő így mindenképpen teszteljük az alkalmazásunkat!

Scoped Directory Access

A hagyományos működés szerint kérhetünk engedélyt a külső tárhely vonatkozásában írási (WRITE_EXTERNAL_STORAGE) és olvasási (READ_EXTERNAL_STORAGE) jogot. Ha átgondoljuk, akkor a fentiekhez hasonlóan ez is egy "mindent vagy semmit" elv. A Scoped Directory Access eljárás lényege, hogy a third-party alkalmazásnak csak egy adott könyvtárhoz adjunk hozzáférést. Például a fotó megtekintő alkalmazás csak a letöltött fájlokat nézhesse meg.

Ennek megvalósításáról itt olvashatsz többet:
https://developer.android.com/training/articles/scoped-directory-access


További integrációs lehetőségek

Itt szeretnék megemlíteni olyan további integrációs lehetőségeket, amelyeket nem kapunk meg automatikusan, hanem bizony tennünk is kell érte.

RTL támogatás

A jobbról balra (Right-to-Left), azaz a fordított kézírás támogatását jelenti. Ez Android esetében a szöveg megjelenítésén túl kiterjed a dobozok elrendezésére (layout) is. Fejlesztői szempontból ha megértjük a koncepciót, akkor már nincs is sok dolgunk. A legfőbb szabály, hogy left helyett start, a right helyett end kifejezést használjunk ahol csak lehet. Alább pár példa:

gravity="left" > gravity="start"
gravity="right" > gravity="end"
layout_gravity="left" > layout_gravity="start"
layout_gravity="right" > layout_gravity="end"

marginLeft > marginStart
marginRight > marginEnd
paddingLeft > paddingStart
paddingRight > paddingEnd
drawableLeft > drawableStart
drawableRight > drawableEnd

alignParentLeft > alignParentStart
alignParentRight > alignParentEnd
toLeftOf > toStartOf
toRightOf > toEndOf

Amint RTL környezetben fut az alkalmazásunk nem csak a szöveg lesz jobbra igazított, hanem a felületi elemek elrendezése is meg tud fordulni. Például, ha egy lista elem úgy épül fel, hogy balról jobbra nézve van egy ikon majd egy szöveg, akkor RTL környezetben ez úgy alakul, hogy szöveg, majd ikon.

platform_integration_-_rtl.jpg

Képernyőképek SmartCity applikációnkról balról jobbra és jobbról balra írásmódban.

A fentiek után még a szövegekkel, az ikonokkal és esetleg az animációkkal érdemes még picit foglalkozni. A szövegek fordított megjelenését nem a gravity attribútum fogja meghatározni, hanem egy külön erre a célra definiált textDirection érték. Az animációk akkor igényelnek további beavatkozást, ha a mozgás iránya kifejez valamit. Az ikonok esetében akkor van dolgunk, ha annak tartalma horizontális irányt tekintve nem mindegy hogyan áll. Például a bal felső sarokban tipikusan megtalálható vissza gomb is ilyen. Attól, hogy átkerülne jobb oldalra még nem teljes a megoldás, mert a nyíl maga továbbra is balra fog mutatni. 

Két dolgot tehetünk ebben az esetben az ikon jellegétől függően:

1. Raszteres képek (PNG, JPEG) esetében tudunk alternatív minősítővel ellátott könyvtárat létrehozni. Például drawable-ldrtl mappába teszük a tükrözött változatot.

2. Vektoros képek esetében a VectorDrawable-nek meg lehet adni egy android:autoMirrored="true" attribútumot, így automatikusan tükrözni fogja a képet.

Account Manager

A legtöbb alkalmazásra igaz, hogy valamilyen kliens alkalmazás és az üzleti logika szerver oldalt van. Ez pedig magával hozza azt, hogy valamilyen formában authentikálnunk, azaz azonosítanunk kell magunkat, például egy bejelentkezést követően. A fejlesztők gyakran saját megvalósításban gondolkodnak az alapoktól kezdve. Saját felület, saját menedzser osztályok, saját authentikációs kommunikáció néha szabványosan, néha egyedi módon.

Pedig az Android nyújt egy AccountManager API-t pont azért, hogy ez valamennyire egységesen valósulhasson meg. Az AccountManager használatának több előnye is van:

  • Form automatikus kitöltésének támogatása az auto-fill framework által
  • Felhasználóhoz kötött egyedi azonosító (ID) megszerzése nem eszközhöz kötött
  • Szinkronizáció a szerverrel több lehetséges ütemezésben és módon

Linkek a témakört illetően:
https://developer.android.com/training/id-auth/identify
https://developer.android.com/training/sync-adapters/creating-sync-adapter

Security funkciók

Android Keystore System

A legfontossabb információk védelmét jelenti. Egyrészt célja, hogy megelőzze a jogosulatlan hozzáférést, másrészt igyekszik megakadályozni, hogy az alkalmazás használata közben kinyerjék az azonosító kulcsokat a készülékből. Android 9.0 (Pie) óta hardveres titkosító modult is lehet már használni.

Bővebben itt:
https://developer.android.com/training/articles/keystore

Biometric Prompt

A Biometric Prompt lényege, hogy Android 9.0 (Pie) után az Android 6.0 (Marshmallow) alatt megjelent ujjlenyomat olvasást felváltja az egységesített biometrikus azonosító dialógus. Ez egy rendszer szintű szolgáltatássá válik, ahol a fejlesztők magasabb szinten kihasználhatják a biometrikus azonosítás adta előnyöket. Emellett cél, hogy az ujjlenyomaton kívül több biometrikus azonosítás meglétekor (pl írisz) is bevethető anélkül, hogy a fejlesztőknek a kódhoz hozzá kellene nyúlni.

Bővebben itt:
https://android-developers.googleblog.com/2018/06/better-biometrics-in-android-p.html
https://developer.android.com/reference/android/hardware/biometrics/BiometricPrompt

Deep link & App link

Lehetőség van rá, hogy egy linkre maga az alkalmazás reagáljon és ne a böngésző. Ez azért is lehet jó, mert átjárást biztosít a weboldal és a natív alkalmazások között. Ezen az úton akár paramétereket is átadhatunk, amely például a tartalmat egyértelműen azonosítja.

Az Android alkalmazásnak valamilyen formában nyilatkoznia kell róla, hogy milyen típusú tartalmat vagy linket képes kezelni. Ezt akár egyéni protokoll vagy séma definiálásával is megteheti, például:

myapp://userlist/user?id=12345

A link birtokában pontosan tudjuk azonosítani, hogy melyik felületnek milyen adattal kell betöltődnie. A megvalósítás menetéről bővebb információt ezen a linken találhatunk:
https://developer.android.com/training/app-links/deep-linking

A saját URL sémának az a hátránya, hogy amíg ezt Android alatt lehet értelmezni, addig a más operációs rendszer alatt futtatott böngésző nem tud vele mit kezdeni. Ezért a HTTP alapú linkek kezelése sokkal előremutatóbb lehet. Ugyanakkor lássuk be, hogy mi akadálya van annak, hogy egy alkalmazás azt állítsa magáról, hogy ő kezeli mondjuk a http://google.com domainbeli linkeket. Ha több alkalmazás is tud ugyanolyan típusú adatot kezelni, vagy több alkalmazás is azt állítja kezeli az adott sémát és protokollt, akkor a felhasználónak felugrik egy választó ablak. Ezeknek a problémaköröknek az egyértelmű feloldása az App Link, mely Android 6.0 (Marshmallow) óta érhető el.

Az Android App Links célja, hogy ha az alkalmazásfejlesztő bizonyítani tudja a domain jogos felhasználását, így a fenti problémákra egyből adott a megoldás. Nem kell megkérdezni melyik alkalmazás kezeli a domaint és nem élhetnek vissza más domain nevek használatával. A hitelesítés módja, hogy az adott oldalon elhelyezünk egy JSON fájlt, amelyet a Android rendszer keresni fog, amennyiben az alkalmazás helyesen van felkonfigurálva.

Bővebben a hitelesítési folyamatról itt:
https://developer.android.com/training/app-links/verify-site-associations

Firebase App Indexing

Az alkalmazás integrálása a Google kereső szolgáltatásába. A keresések találati oldaláról azonnal elindulhat az alkalmazásunk a megfelelő képernyővel és tartalommal. Segíti a felhasználókat abban, hogy az appban levő tartalamakat közvetlenül elérjék és könnyen megtalálják. (Többek között ezért is érdemes a Deep link és App link rendbetétele.) Néhány terület ahol jól jöhet az App Indexing:

  • Keresési eredményekben való megjelenés
  • Közvetlen telepítési gomb, amikor a kezdőoldalunk jön ki eredményként
  • Automatikus szövegkiegészítés
  • Google Assistant támogatás
  • Célzott reklámok pontosabbak

Demó videó:
https://www.youtube.com/watch?v=C35OSHlTNwA

Link a megvalósításhoz és részletesebb leíráshoz:
https://firebase.google.com/docs/app-indexing/

Launcher szolgáltatások

A Kezdőképernyő alkalmazás vagy eredeti nevén a Launcher alkalmazás nem elválaszthatatlan része az Android rendszernek. Igazából ugyanúgy egy Android alkalmazás, ami egy *.apk fájlból települ fel és bárki szabadon fejleszthet és publikálhat ilyet. Ugyanakkor a Google értelemszerűen adott egy alapértelmezett Launcher alkalmazást is az AOSP keretében. Amin már túl is lépett, és azóta napvilágot látott a Google Now Launcher (a Nexus széria részeként) és a Pixel Launcher (Pixel széria részeként), amelyek sok-sok új funkciót hoztak a felhasználóknak.

Azokra szeretnék kitérni, amelyeket a fejlesztők is fel tudnak használni:

1) App Widget

Legrégebb óta elérhető funkció. Lényege, hogy az indító ikonok helyére funkcióval rendelkező egyéni mini felületeket fejleszthetünk. Például zenelejátszó, időjárás megjelenítő és így tovább. Azzal érdemes számolni, hogy némileg korlátozottabb lehetőségekkel és eltérő működési modellel bír. Hogy drasztikusan ne hasson a fogyasztásra korlátok közé van szorítva, például alapértelmezetten ritkán frissülnek a Widgetek felületei.

Megvalósításról itt tájékozódhatsz:
https://developer.android.com/guide/topics/appwidgets/overview

2) App shortcut

Android 7.1 (Nougat) megjelenésével egy időben került be a Pixel Launcher alkalmazásba az App Shortcut támogatás. Ha hosszan nyomjuk az ujjunkat az alkalmazás ikonon (elmozdulás nélkül), akkor megjelenik egy kisebb helyi menü. Ez lehet előre definiált azaz statikus vagy futásidőben változó, dinamikus. Lehetővé teszi, hogy az app adott funkciója induljon el célzottan. Például ha megnézzük a Gmail appot, akkor a levélíráshoz nem kell előbb betölteni a beérkező levelek listáját. Minden ilyen App shourtcut kitehető külön indító ikonként is a Launcherre.

Megvalósításáról itt tájékozódhatsz:
https://developer.android.com/guide/topics/ui/shortcuts

IME szolgáltatások

Elsőre nem is gondolnánk, hogy egy billentyűzet vagy úgy eleve az adatbevitel kapcsán (Input Method Editor) bármi teendőnk lenne egy alkalmazás fejlesztésekor. Pedig van pár olyan eset, amikor hozzátudunk tenni a használhatóbb alkalmazás érdekében.

1) Input type

A szövegbeviteli mező (EditText) helyes attribútumainak beállítása sokat hozzátehet az élményhez. Az inputType értékének meghatározása például kihat arra, hogy a billentyűzet milyen layout kiosztással jelenjen meg. Vegyünk pár konkrét példát. Az inputType="number" esetén a csak számokat tartalmazó nagy gombos billentyűzet fog betöltődni, amin lássuk be sokkal könnyebb bevinni pár számjegyet. De az sem utolsó, ha megadjuk, hogy szöveget viszünk fel de e-mail címet várunk. Ugyanis ebben az esetben a @ jel vagy egy .com gomb plusz elemként jelenhet meg a szoftveres billentyűzeten.

platform_integration_-_keyboard_input_type.jpg

Szemléltető ábrákat a hivatalos dokumentációból vettem:
https://developer.android.com/training/keyboard-input/style

Ez a megközelítés ugyanúgy igaz, ha natív alkalmazás helyett a webes frontend fejlesztésről beszélünk. Az HTML <input /> mező helyes type attribútum beállítása sokat ad hozzá a felhasználói élményhez. Lásd kapcsolódó stackoverlfow bejegyzés.

2) Keyboard navigation

Egy űrlap kitöltése során felértékelődik a billentyűzettel való irányíthatóság. Ez különösen igaz ha Android TV fut a céleszközön, ahol a távirányítóval való navigálás még inkább hangsúlyos. Mit lehet tenni ez ügyben?

Az egyik lehetőség, hogy a tab navigációt rendezzük az alábbi attribútumok használatával:

android:nextFocusForward
android:nextFocusUp
android:nextFocusDown
android:nextFocusLeft
android:nextFocusRight

A másik lehetőség a Input method action, ahol az android:imeOptions az alábbi értékeket veheti fel:
https://developer.android.com/reference/android/widget/TextView#attr_android:imeOptions

3) Auto-fill

Az Auto-fill framework már korábban említve lett. A felhasználó számára kevesebb kitöltési időt és kevesebb hibázási lehetőséget jelent. Az Android 8.0 (Oreo) óta elérhető funkcióról annyit érdemes tudni, hogy erre is lehet készülni az alkalmazás fejlesztése során. Néhány attribútum megadásával tudathatjuk a rendszerrel, hogy egy adott beviteli mező milyen jelentőséggel bír a framework számára.

android:autofillHints="password"
android:importantForAutofill="auto|no|yes|noExcludeDescendants|yesExcludeDescendants"

Külön érdemes kitérni arra, hogy amennyiben egyéni felületi komponenst készítünk úgy lehetőségünk van az auto-fill framework funkcióit integrálni.

További információk a hivatalos dokumentációban:
https://developer.android.com/guide/topics/text/autofill

Third-party alkalmazás indítása

A platformmal való integrálódás legkönnyebb formája ha megfelelő third-party alkalmazásokat indítunk el. A teljesség igénye nélkül kigyűjtöttem párat. Vegyük az alkalmazások tipikus Kapcsolat vagy Elérhetőség menüpontját. Általában ez a felület valamilyen elérhetőségi adatokat szokott tartalmazni. Sokkal interaktívabb és felhasználóbarátabb, ha a puszta megjelenítés helyett funkcionálisan is segítenék a kapcsolatfelvételt.

URL séma alkalmazásával

Miután már hallottunk a Deep linkről és a URL séma alkalmazásának lehetőségéről a most következő megoldásokat könnyen megértjük és tudjuk őket alkalmazni. Nincs más dolgunk, mint a szabvány szerinti linket összeállítani és azzal alkalmazást indítani.

  • Email írás indítása előre definiált címzett listával és levél tárggyal, RFC-2368:
    mailto:info@yourdomain.hu?subject=Alkalmazás észrevételek
  • Hívás indítása az RFC-3966 sztenderd szerint:
    tel:+36??/???-????
    De az alábbiak valamelyikével is találkozhattunk már:
    call:callto:, sip:, sips:
  • SMS írása
    sms:+36??/???-????
  • Térkép és navigáció indítása az RFC-5870 szerint:
    geo:latitude,longitude?z=zoom
    geo:latitude,longitude?q=query
    geo:0,0?q=my+street+address
    geo:0,0?q=latitude,longitude(label)
  • Alkalmazás Play Store adatlapjának linkelése és megnyitása:
    market://details?id=<package_name>
    http://play.google.com/store/apps/details?id=<package_name>

Kód alkalmazásával

Ebben az esetben egy picit többet kell tenni, mint egy link összefűzése. Sok esetben csak azért, mert várunk valamilyen visszatérési értéket, visszafele kompatibilitást akarjuk biztosítani vagy csak egyszerűen hibatűrőek akarunk lenni és alternatív megoldást nyújtani, ha nem sikerül megnyitni.

Az alapértelmezett kamera alkalmazás indítása és visszatérés képpel:

public void startCamera() {
	Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
	startActivityForResult(cameraIntent, 1234);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1234) {
          Bitmap image = (Bitmap) data.getExtras().get("data");
          ImageView imageview = (ImageView) findViewById(R.id.imageview); 
          imageview.setImageBitmap(image);
    }
}

Galéria képválasztó indítása és visszatérés képpel:

public void startGallery() {
	Intent galleryIntent = new Intent(
		Intent.ACTION_PICK,
		android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
	);
	startActivityForResult(galleryIntent , 1234);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
	if (requestCode == 1234) {
        if (null != data) {
            imageUri = data.getData();
            //Do whatever that you desire
        }
    }
}

Fotó megtekintése az alapértelmezett képmegjelenítővel:

public void showPhoto(File file){
    Intent galleryIntent = new Intent(Intent.ACTION_VIEW, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
	galleryIntent.setDataAndType(Uri.fromFile(file), "image/*");
	galleryIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	startActivity(galleryIntent);
}

Calendar esemény hozzáadása, visszafele kompatibilis módon:

public boolean openCalendarAdd(Context context, Date begin, Date end, String title, String description, String location, int availability) {
	if (context == null) return false;
	if (begin == null) return false;

	Intent intent;
	if (end == null) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(begin);
		cal.add(Calendar.MINUTE, 30);
		end = cal.getTime();
	}

	if (Build.VERSION.SDK_INT >= 14) {
		intent = new Intent(Intent.ACTION_INSERT)
				.setData(CalendarContract.Events.CONTENT_URI)
				.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, begin.getTime())
				.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end.getTime())
				.putExtra(CalendarContract.Events.TITLE, title)
				.putExtra(CalendarContract.Events.DESCRIPTION, description)
				.putExtra(CalendarContract.Events.EVENT_LOCATION, location)
				.putExtra(CalendarContract.Events.AVAILABILITY, availability)
				.putExtra(CalendarContract.Events.ALL_DAY, false);
		return startActivity(context, intent);
	} else {
		intent = new Intent(Intent.ACTION_EDIT);
		intent.setType("vnd.android.cursor.item/event");
		intent.putExtra("beginTime", begin.getTime());
		intent.putExtra("endTime", end.getTime());
		intent.putExtra("title", title);
		intent.putExtra("description", description);
		intent.putExtra("eventLocation", location);
		intent.putExtra("availability", availability);
		intent.putExtra("allDay", false);
	}
	return startActivity(context, intent);
}

Youtube videó megnyitása a Youtube alkalmazással ha telepítve van, egyébként böngészőben:

public boolean openYoutubeVideo(Context context, String videoID) {
	Intent youtubeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:" + videoID));
	youtubeIntent.setClassName("com.google.android.youtube", "com.google.android.youtube.WatchActivity");
	youtubeIntent.putExtra("VIDEO_ID", videoID);
	if (!startActivity(context, youtubeIntent)) {
		Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://m.youtube.com/watch?v=" + videoID));
		return startActivity(context, intent);
	}
	return true;
}

 

Hiányzó third-party alkalmazás

A jól kidolgozott mobilalkalmazások fel vannak készítve arra is, hogy nem minden esetben lesz feltelepítve olyan third-party app, amely kezelni tudja a tartalmunkat. Például egy tablet esetében a hívás indítás vagy SMS küldés nem feltétlen támogatott és ilyenkor nincs hozzávaló alkalmazás sem. De sokkal gyakoribb példa lehet, hogy ha az alkalmazásunk letölt egy PDF fájlt, akkor azt nem feltétlen fogjuk tudni megnyitni mivel nincs egyetlen PDF olvasó app sem.

Amikor egy alkalmazás indításának igényéhez (Intent) a rendszer nem talál megfelelő telepített alkalmazást, amely kezelni tudná, akkor egy ActivityNotFoundException hibát fog dobni. Ezt természetesen el lehet kapni és értesíteni tudjuk a felhasználót, hogy ez a művelet most nem végrehajtható. Ugyanakkor mi az alkalmazásaink esetében ennél eggyel tovább szoktunk menni. Problémák helyett szeretünk megoldásokat adni az UX jegyében. Ha nincs megfelelő PDF olvasó, akkor fel szoktuk ajánlani, hogy a Play Áruházban tud keresni egy neki tetszőt. Egy gombnyomással átirányítjuk az alábbi URL séma használatával:

http://play.google.com/store/search?q=pdf+reader&c=apps


Bár a fenti összefoglaló nem teljes, azért remélem, hogy sikerült új szempontokat is behoznom az alkalmazás funkciók megtervezéséhez. Minden évben jön valamilyen újítás a Google részéről így érdemes ebből a szempontból naprakésznek maradni. Ott van még a viselhető eszközöket támogató Android Wear, ahol az integráció még fontosabb lehet például a Voice Command megvalósításával. Emellett egyre jobban terjed az Android Auto is, ami szintén új igényeket fog támasztani az alkalmazásokkal szemben. Ha a legjobbat szeretnénk a vége mindig az, hogy meg kell ismernünk a keretrendszer sajátosságait.

Ha tetszett a cikk oszd meg másokkal is.