• Save
Das Lego-Prinzip
Upcoming SlideShare
Loading in...5
×
 

Das Lego-Prinzip

on

  • 1,514 views

 

Statistics

Views

Total Views
1,514
Slideshare-icon Views on SlideShare
1,409
Embed Views
105

Actions

Likes
1
Downloads
0
Comments
0

1 Embed 105

http://www.openknowledge.de 105

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Das Lego-Prinzip Das Lego-Prinzip Presentation Transcript

    • Ausgabe 1/2012 EXKLUSIV FÜR ABONNENTEN: DAS GROSSE ANDROID-POSTER! android 360 www.android360.de Deutschland € 9,80 Österreich € 11,70 Schweiz sFr 17,50 Luxemburg € 11,90 Mobile Development, Marketing, Business magazin Modulare Android-Anwendungen | App-Store-Optimierung | Enterprise-Integration | ActionBar | Fragments Das LEGO Android-Apps: Modulare Prinzip Zeit und Geld sparen! ge Jede Mern tests N EU: Hardwa e App-Store-Optimierung Tipps und Tricks für mehr Downloads Android Enterprise Integration Mit dem Androiden ins Büro Frei-Haus-Lieferung des Print-Magazins! Das ActionBar-Pattern Alle Ausgaben online Auf dem Weg zur einheitlichen Navigation immer und überall verfügbar! Flexibles UI-Design Offline-PDF-Export Android-UI-Fragmentego: mobiletechmag.de/abocall: +49(0)6123 92 38 -239 (Mo–Fr, 8 –17 Uhr)
    • ANDROID DEVELOPMENT | PUTTING TOGETHER Modulare Android-Anwendungen Das LEGO Die meisten Android-Anwendungen sind leider nach wie vor stark monolithisch aufgebaut. Das erschwert nicht nur die sinnvolle Wieder- verwendung einzelner Anwendungsbestand- Prinzip teile, sondern bringt auch automatisch unnöti- gen Entwicklungsaufwand mit sich. Dabei ist eine der Stärken von Android gerade die Möglich- keit zur modularen und somit wiederverwendba- ren Anwendungsentwicklung. Activities, Services, BroadcastReceiver, Intents und Permissions heißen die dafür notwendigen Building Blocks, POSTER DRY das zu nutzende Pattern. Thema von Arne Limburg und Lars Röwekamp36 android 360 1 | 2012 www.android360.de
    • PUTTING TOGETHER | ANDROID DEVELOPMENTDie Android-Plattform bietet von Haus aus einige Mög-lichkeiten, bestehende Funktionalität anderer Anwen-dungen zu nutzen oder eigene Funktionalität anderenAnwendungen zur Verfügung zu stellen. Warum sollteman zum Beispiel eine eigene Activity zur Eingabe undzum Versenden von E-Mails implementieren, wenn esbereits eine entsprechende App gibt, die diese Aufgabeübernehmen kann? Oder warum sollte man nicht deneigenen RSS-Feed-Browser anderen Anwendungen zurVerfügung stellen?Building BlocksUm zu verstehen, wie die einzelnen Teile einer Anwen-dung modularisiert und somit innerhalb der Anwendun-gen oder durch dritte optimal wiederverwendet werdenkönnen, sollte man zunächst einmal die wesentlichenKomponenten beziehungsweise Bausteine einer An-droid-App und deren Zusammenspiel begriffen haben[1]. Glücklicherweise ist die Liste der wesentlichen An- Abb. 1: Zusammenspiel der Building Blocksdroid Building Blocks überschaubar (Kasten: „BuildingBlocks“, I und II): Anwendung selbst vor. Soll nun zum Beispiel eine Ac- tivity der Anwendung eine andere Activity innerhalb• Activity: Repräsentiert einen einzelnen Screen inklusi- derselben Anwendung aufrufen, also ein View-Wechsel ve User-Interface-Logik. stattfinden, oder soll eine Activity der Anwendung via• Service: Kapselt lang laufende Hintergrundaktionen Service auf einen entfernten Server zugreifen, um von oder Remote-Prozesse und besitzt kein User Interface. dort Daten abzurufen, die mithilfe eines ContentProvi-• ContentProvider: Dient zur Verwaltung von Daten ders verwaltet werden, würde dieses über den Mecha- jeglicher Art (Kontakte, Musik, Kalender, eigene nismus der Intents angestoßen werden. Zu abstrakt? Daten etc.), auf die ein eventueller Zugriff von außen Dann stellen wir uns einmal folgende Situation vor ermöglicht werden kann. (Abb. 4). Eine Activity zeigt eine Liste von RSS Feed• BroadcastReceiver: Allgemeiner Listener für globale Headern an (1). Wählt der Anwender eines der Listen- Nachrichten, die häufig vom System selbst versandt elemente aus (2), aktiviert die Listen-Activity via Intent werden (Battery is low, Screen turned off etc.). (3) eine zweite Activity zur Darstellung des RSS Feed URL in einer Browser-View (4). Interessant an diesemDrei der vier oben vorgestellten Komponenten, Acti- Szenario ist vor allem, dass die aufrufende Activity undvities, Services und BroadcastReceiver, werden durch die aufgerufene Activity nur recht lose miteinander ge-einen einheitlichen Mechanismus, die Intents, aktiviert. koppelt sind. Die aufrufende Activity erstellt ein IntentDie vierte Komponente, ContentProvider, folgt einem mit der Klasse der gewünschten Ziel-Activity und demetwas anderen Aufrufmuster. Dazu aber später mehr. URL des zu ladenden RSS-Feed-Elements und aktiviert im Anschluss die Browser-View mithilfe des Intents:• Intent: Aka „Intention“, also Absicht, etwas zu tun. Asynchrone Nachrichten zur losen Kopplung der Intent intent = new Intent(this, MyBrowserActivity.class); Android Building Blocks Activity, Service und Broad- intent.putExtra("RSS_DETAIL_URI", Uri.parse(rssFeed.getUri())); castReceiver. startActivity(intent);Die eben skizzierten Bausteine bilden gemeinsam mit In dem eben gezeigten Beispiel verwenden wir ein expli-den Intents die Grundlage lose gekoppelter Android- zites Intent, das heißt, wir geben die aufzurufende Acti-Anwendungen. Bevor wir uns anschauen, wie das an- vity beziehungsweise ihre Klasse explizit beim Erstellenwendungsübergreifend genutzt werden kann (Abb. 1), des Intent-Objekts an und übergeben benötigte Zusatz-klären wir zunächst, wie die Komponenten innerhalb informationen via Intent-Extras. Wie die Intent-Extraseiner Anwendung zusammenspielen. zu verarbeiten sind, weiß die Ziel-Activity. Die mögli- chen Extras sind Bestandteil ihrer Aufrufschnittstelle.Putting Together – Teil I Die eben gezeigte Art des Aufrufs ist natürlich nur dannEine typische Android-Anwendung besteht aus einer möglich, wenn uns die Klasse der Ziel-Activity und dieReihe von Activities als Repräsentation der UI und UI- erwarteten Zusatzinformationen bekannt sind, was inLogik sowie optional aus Services, ContentProvider der Regel nur innerhalb der eigenen Anwendung(en) derund BroadcastReceiver. Bei einer „monolithischen“ Fall sein wird. Unser Ziel, Funktionalität aus anderenAnwendung finden wir alle diese Blöcke innerhalb der Anwendungen aufrufen zu können, um so einen mög-www.android360.de 1 | 2012 android 360 37
    • ANDROID DEVELOPMENT | PUTTING TOGETHER lichst hohen Grad der Wiederverwendung zu erreichen, • Data: URI der Daten, auf denen die Aktion ausge- wäre somit nur teilweise erreicht. Aber zum Glück gibt führt werden soll. Data gibt dabei sowohl den Daten- es da noch eine Alternative. typ als auch den Verweis auf die Daten selbst an. • Category: Zusätzliche Information für die Kompo- Putting Together – Teil II nente, die zur Behandlung der Daten vom System Die zweite Variante der Intents erlaubt den Aufruf von ausgewählt werden soll. Android-Komponenten (Activity, Service, BroadcastRe- ceiver) ohne explizite Angabe der Zielklasse (Intent Tar- In unserem Beispiel könnte ein Aufruf via impliziten get). Stattdessen definiert das Intent eine auszuführende Intent wie folgt aussehen: Aktion (Intent Action), in unserem Fall das Anzeigen von (Web-)Inhalten, und eventuell notwendiger Zusatzinfor- Intent intent = new Intent(); mationen, in unserem Fall einen zugehörigen URL. Da intent.setAction(Intent.ACTION_VIEW); die Zielkomponente nicht direkt angegeben wird, son- intent.setCategory(Intent.CATEGORY_DEFAULT); dern sich implizit aus den folgenden Intent-Parametern intent.setData(Uri.parse(rssFeed.getUri()); ergibt, spricht man auch von einem impliziten Intent: startActivity(intent); • Action: Aktion, die ausgeführt werden soll. Das kann Die Entscheidung, welche Komponenten letztendlich eine von Android vordefinierte oder eine selbst defi- zur Abarbeitung der gewünschten Aktion herangezogen nierte Action sein. werden, liegt beim System. Gibt es mehrere gleichwer- Building Blocks I Activity: Die Activity ist eine Anwendungskomponente zur visuellen Interaktion mit dem Nutzer. Sie ist für die Darstel- lungslogik des User Interface sowie die Entgegennahme und Verarbeitung der Nutzereingaben verantwortlich und besitzt einen eigenen Lifecycle (Abb. 2). Eine Anwendung besteht in der Regel aus mehreren Actvities, die lose miteinander gekop- pelt sind und sich gegenseitig via Intents aufrufen. Listing 1: Activity Lifecycle public class ExampleActivity extends Activity { // Activity wurde erzeugt Abb. 2: Activity Lifecycle public void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState); } // Eine andere Activity bekommt den Fokus ODER das Device wurde // Activity wird gleich sichtbar // in Standby-Modus versetzt ODER ein Dialog ueberlagert die Activity protected void onStart() { protected void onPause() {   super.onStart(); super.onPause();    } } // Activity ist gestoppt worden und wird neu gestartet // Die Activity ist nicht mehr sichtbar und "stopped" protected void onRestart() { protected void onStop() { super.onRestart(); super.onStop();    } } // Activity ist sichtbar   // Activity wird zerstoert. protected void onResume() { protected void onDestroy() {    super.onResume();     super.onDestroy(); }  } }38 android 360 1 | 2012 www.android360.de
    • PUTTING TOGETHER | ANDROID DEVELOPMENTtige Kandidaten zur Abarbeitung der Aktion, wird demAnwender eine Auswahlliste der potenziellen Kandida-ten angezeigt (Abb. 8). Bleibt nur noch zu klären, woherdas System weiß, welche Komponenten potenziell zurAbarbeitung des Intents in Frage kommen.Intents und Intent-FilterGehen wir noch einmal einen kleinen Schritt zurück.Intents [2] stellen zunächst nur Absichten dar, etwas zutun. Dies kann zum Beispiel die Absicht sein:• eine Webseite in einem Browser darzustellen• eine Adresse aus den Kontakten auszuwählen• eine E-Mail zu versenden• über einen Service RSS Feeds abzurufen usw. Abb. 4: Intent-MechanismusWir haben bereits weiter oben gesehen, wie ein Intent lichkeit zur Angabe des MIME Types der zu nutzendenseine „Absicht“ mithilfe von Action, Data und Ca- Daten. Kommen wir nun noch einmal auf unsere Fragetegory definieren kann. Hinzu kommt noch die Mög- zurück, woher das System weiß, welche Komponente Service: Der Service ist eine Anwendungskomponente zur Ab- arbeitung langlaufender Hintergrund-Tasks. Ein Service besitzt kein User Interface und wird durch eine andere Anwendungs- komponente gestartet. Services können in zwei Formen auftre- ten, die zum Teil unterschiedliche Lifecycles besitzen (Abb. 3): 1. Started: Der Service wurde durch eine andere Anwendungs- komponente gestartet, läuft eigenständig und beendet sich von selbst nach Abarbeitung seiner Aufgabe. 2. Bound: Der Service wurde an eine Anwendungskomponente via bindService() gebunden und bietet eine Client-Service- Schnittstelle zur Kommunikation. Der Service endet, sobald keine Komponente mehr an ihn gebunden ist. Listing 2: Service Lifecycle public class ExampleService extends Service { // regelt das Verhalten beim "kill" des Service int mStartMode;       Abb. 3: Service Lifecycles // Interface für "binding" Clients   public IBinder onBind(Intent intent) {   IBinder mBinder;       return mBinder;  } // regelt, ob onRebind() genutzt werden soll     boolean mAllowRebind;   // Client "binded" sich an Service via bindService()   public boolean onUnbind(Intent intent) { // Service wurde erzeugt     return mAllowRebind;   public void onCreate() { ... }  }     // Service startet nach Aufruf von startService()  // Client "binded" sich nach onUnbind() an Service   public int onStartCommand(Intent intent, int flags, int startId) {    public void onRebind(Intent intent) { ... }    return mStartMode;   } // Service wird nicht weiter verwendet und zerstoert   public void onDestroy() { ... }   // Client "binded" sich an Service via bindService() }www.android360.de 1 | 2012 android 360 39
    • ANDROID DEVELOPMENT | PUTTING TOGETHER es wählen soll. Wenn beim Erstellen eines Intents die welche „Absicht“ die Komponente verwendet werden zu verwendende Klasse beziehungsweise Komponente kann. Dabei gilt dieser Filter zunächst erst einmal sys- explizit angegeben wird, ist das Intent Routing, also temweit und ist somit nicht auf die eigene Anwendung die Auswahl der Komponente, die verwendet werden beschränkt. Wenn auch nicht bewusst, so hat doch jeder soll, für das Android-System nicht weiter schwer. Et- Android-Entwickler schon einmal einen solchen Intent- was komplizierter wird es dagegen, wenn ein implizites Filter verwendet: Intent genutzt wird. In diesem Fall muss das Android- System die Entscheidung auf Basis zusätzlicher Kon- <activity android:name=".MainActivity" android:label="Browser"> figurationsdaten fällen. Wie genau funktioniert das? <intent-filter> Android-Komponenten können bei ihrer Deklaration     <action android:name="android.intent.action.MAIN" /> in der Konfigurationsdatei AndroidManifest.xml einen     <category android:name="android.intent.category.LAUNCH" /> oder mehrere Intent-Filter angeben. Die Filter definieren </intent-filter> dabei, für welchen Anwendungsfall beziehungsweise für </activity> Building Blocks II ContentProvider: Der ContentProvider speichert und lädt Daten jeglicher Art und stellt sie den Anwendungen mittels REST-ähnlichem Zugriffs-URI zur Verfügung. ContentProvider sind die einzige Möglichkeit, Datenquellen und deren Daten anwendungsübergreifend zu teilen (Abb. 5). Android bietet et- liche ContentProvider für Standarddatentypen wie Audio, Video, Kontakte, Kalender etc. Zur Bereitstellung eigener Daten lassen sich weitere ContentProvider implementieren. Abb. 5: ContentProvider Listing 3: ContentProvider public class ExampleContentProvider extends ContentProvider {   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // Eindeutiger Name des Providers ... public final static String PROVIDER_NAME = return cursor; "de.openknowledge.provider.Example"; }  // Uri zum Zugriff auf die Daten // Einfuegen eines neuen Datensatzes public final static Uri CONTENT_URI = public Cursor insert(Uri uri, ContentValues) { Uri.parse("content://"+ PROVIDER_NAME + "/ ... examples") return cursor; }  ... // Update eines bestehenden Datensatzes // Liefert den MIME Type des angegebenen URI public Cursor update(Uri uri, ContentValues, String selection, public String getType(Uri uri) { String[] selectionArgs) { ... ... return mimeType; return cursor; } }     // Provider wurde erzeugt und wird gestartet // Loeschen eines bestehenden Datensatzes public String onCreate() { public Cursor delete(Uri uri, String selection, ... String[] selectionArgs) { return uri; ... } return cursor; }  // Abfrage des Clients, die einen Cursor als Ergebnis liefert }40 android 360 1 | 2012 www.android360.de
    • PUTTING TOGETHER | ANDROID DEVELOPMENTDie Absicht wäre in diesem Fall, die MainActivity als Alle diese Beispiele haben eines gemeinsam: Eine Ac-Start Activity der Anwendung zu verwenden und sie tivity der eigenen Anwendung ruft eine Activity einerzu starten, sobald ein User die Anwendung auswählt. anderen Anwendung auf und damit auch die darin ge-Das wird durch die Kombination von Action (MAIN) kapselte Funktionalität. Der Anwender wechselt alsound Category (LAUNCHER) eindeutig definiert. Über- vorübergehend in eine andere Anwendung, um danntragen auf unser Beispiel würde folgender Eintrag in- wieder in die eigene Anwendung zurückzuspringen.nerhalb der AndroidManifest.xml dafür sorgen, dass Was ist aber, wenn man anstelle einer Activity, die denunsere MyBrowserActivity als potenzieller Kandidat Zugriff auf einen Service oder einen ContentProviderzur Darstellung einer Webseite vom Android-System in kapselt, diese nicht visuellen Komponenten direktBetracht gezogen wird: aufrufen beziehungsweise nutzen möchte, um so zum Beispiel die Auswahl eines Kontakts aus der Liste der <activity android:name=".MyBrowserActivity" android:label="Browser"> Kontakte in einem eigenen UI darzustellen? Handelt <intent-filter> es sich um einen Service, dann ist das Vorgehen mehr     <action android:name="android.intent.action.VIEW" /> oder minder gleich zu dem bisher gezeigten Vorgehen.     <category android:name="android.intent.category.DEFAULT" /> Auch hier wird ein passendes Intent zum Starten oder     <data android:scheme="http" /> Binden des Service erzeugt und dann, und jetzt kommt </intent-filter> der Unterschied, via startService(intent) beziehungs- </activity> weise bindService(intent, ...) gestartet/gebunden. Et- was anders sieht es dagegen bei den ContentProvidernWird nun irgendwo innerhalb der Anwendung, wie wei- aus.ter oben gezeigt, ein Intent mit der Action VIEW unddem URI-Schema http erzeugt, sucht das Android-Sys- Zugriff auf Datentem alle für diese Kombination registrierten Activities Die ContentProvider sind in Android für den (lesen-heraus. Sind das mehr als eine, wird dem Nutzer eine den und schreibenden) Zugriff auf Daten zuständig.entsprechende Auswahlliste angezeigt (Abb. 8). Da die Abfrage komplexer Daten einer mächtigeren Das Konzept der Intents ist sehr mächtig und er- Schnittstelle bedarf, als sie die Intents bieten können,laubt einen hohen Grad der Wiederverwendung. Als wurde in Android für den Zugriff auf Daten ein ande-Beispiele wurden bereits das Anzeigen von Webinhal- rer Mechanismus gewählt: Daten werden ähnlich wieten im Webbrowser, das Erstellen und Versenden ei- in REST als Ressourcen angesehen, auf die über einenner E-Mail via E-Mail-Client oder aber das Auswählen URI (Uniform Resource Identifier) zugegriffen wer-eines Kontakts aus der Kontaktverwaltung genannt. den kann. Ein entsprechender URI für den Zugriff auf BroadcastReceiver: Ein BroadcastReceiver hört auf system- weite Nachrichten, die als Broadcast Intents verschickt werden, und wird bei deren Eintreffen aktiv. Die Nachrichten können sowohl direkt vom Android-System, zum Beispiel „Low Battery“ oder „Screen ausgeschaltet“, als auch von einer eigenen An- wendung, zum Beispiel „Daten vollständig geladen“, ausgelöst werden. Anders als bei den klassischen Intents, die immer auch eine Reaktion erwarten, funktionieren die Broadcast Intents nach dem „Fire & Forget“-Prinzip. Ob ein Broadcast Intent von einem entsprechenden Receiver verarbeitet wird oder nicht, hat keinen direkten Einfluss auf den weiteren Workflowverlauf des Senders. Ein BroadcastReceiver bringt zwar kein eigenes UI mit sich, besitzt aber einen eigenen Lifecycle (Abb. 6) und kann den Anwender durch Status Bar Notifications auf ein eingetrof- fenes Ereignis hinweisen. Alternativ kann der BroadcastReceiver nach Eintreffen eines Broadcast Intents als eine Art Gateway auch einen Service starten oder eine Activity aufrufen: public class ExampleBroadcastReceiver extends BroadcastReceiver {   // BroadcastReceiver erwacht fuer die Abarbeitung des // erwarteten Broadcast Intent zum Leben   public void onReceive(Context context, Intent intent) { ... } Abb. 6: BroadcastReceiver }www.android360.de 1 | 2012 android 360 41
    • ANDROID DEVELOPMENT | PUTTING TOGETHER wollen, sind auch Pfade der Art /feeds/ headers, /feeds/details und /channels möglich. 4. Jeder einzelne Datensatz wird innerhalb eines ContentProvider-Pfads durch eine eindeutige ID identifiziert. Soll sich ein URI also auf einen einzelnen Datensatz beziehen, kann im vierten Teil diese ID angegeben werden. Bezieht sich ein URI auf mehr als einen Datensatz, kann die ID weggelassen werden. Wie findet man nun aber zu einem Content- URI den zugehörigen ContentProvider? Was bei den Intents unter der Haube mittels Intent Resolver geschieht, muss bei einem ContentProvider explizit über den Content Abb. 7: Activity-Aufruf via Implicit Intent Resolver ausgeführt werden. Damit dieser weiß, welchen ContentProvider eine An- wendung anbietet, muss der Provider in deren Manifestdatei eingetragen und der Authority zugeordnet sein: <provider android:name="de.openknowledge.rss. RssProvider"           android:authorities="de.openknowledge.rss"           . . . /> </provider> Der Content Resolver analysiert einen übergebenen Content-URI und leitet die- sen an den korrekten ContentProvider weiter. Den Content Resolver erhält man in einer Activity oder in einem Service über getContentResolver() und greift anschlie- ßend über dessen Methoden (query(…), insert(…), update(...) und delete(…)) di- Abb. 8: Intent Chooser in Action rekt auf die Daten des ContentProviders zu. Der Content Resolver ist übrigens die RSS Feed Header könnte wie folgt aussehen: content:// einzige Möglichkeit, auf Daten (aus einer Datenbank de.openknowledge.rss/headers/123. Der Beispiel-URI oder dem applikationslokalen Dateisystem) einer an- besteht aus vier Teilen: deren Anwendung zuzugreifen. Und das geht auch nur dann, wenn die Anwendung einen entsprechenden 1. content:// ist die Protokollangabe. Durch das Präfix ContentProvider für die Daten nach außen zur Verfü- content teilt man Android mit, dass es sich bei die- gung stellt. Die von Android mitgelieferten Systeman- sem URI um einen handelt, der von einem Content- wendungen gehen genau so vor, sodass es via Content Provider interpretiert werden soll. Resolver möglich ist, zum Beispiel Kontaktdaten aus- 2. de.openknowledge.rss ist die Authority. Mit ihr zulesen und zu ändern oder (seit Android 4) auf Kalen- wird ein konkreter ContentProvider eindeutig iden- derdaten zuzugreifen. tifiziert. 3. /headers ist eine optionale Angabe des Pfads der Security aka „das Scheunentor“ Daten. In unserem Beispiel ist es denkbar, dass wir Schon der gute alte Johann Wolfgang von Goethe sagte die Header und die Details der RSS Feeds separat „Wo Licht ist, da ist auch Schatten“ [3]. So schön es speichern wollen. Dann könnte es neben dem auch sein mag, dass wir die Funktionalität unserer An- /headers-Pfad auch noch einen /details-Pfad geben. wendung anderen Anwendungen zur Verfügung stellen Pfade können auch verschachtelt sein. Wenn wir können, so offen scheint sie durch dieses Konzept für zum Beispiel in unserem ContentProvider neben Angriffe von außen zu sein. Die Frage, die sich somit den Feeds auch noch die Channels verwalten stellt ist, wie wir unsere Anwendung gegen ungewoll-42 android 360 1 | 2012 www.android360.de
    • PUTTING TOGETHER | ANDROID DEVELOPMENTten Missbrauch schützen können. Und wo wir schonbeim Fragen sind, wäre es auch ganz interessant zu er- Mehr zum Themafahren, wie eigentlich das Default-Security-Verhalten Das Thema dieses Artikels und weiterer Artikel POSTERfür die in unserer Anwendung verwendeten Android- dieser Ausgabe wird auch auf dem großen Android- ThemaKomponenten aussieht? Oder anders gefragt: Welche Poster anschaulich dargestellt. Das Poster liegtKomponenten darf unsere Anwendung verwenden und allen Abos bei und wird außerdem zugeschickt, wenn ein neues An-welche unserer Komponenten dürfen von anderen An- droid360-Abo abgeschlossen wird. Die Artikel sind natürlich auch ohnewendungen verwendet werden? Die Antwort auf beide Poster lesbar. Welche Artikel thematisch zum Poster passen, erkennenFragen liefern die Android Permissions, mit deren Hilfe Sie am Posterbutton.Zugriffsrechte innerhalb von Android-Anwendungen http://www.android360.degesteuert werden können [4]. Permissions können zumeinen genutzt werden, um Komponenten vor unerlaub-tem Zugriff zu schützen, und zum anderen, um zu ver- dung angegeben werden. Im folgenden Beispiel soll diehindern, dass eine Anwendung ungewollt auch externe Anwendung auf das Internet zugreifen und SMS emp-Komponenten nutzt. fangen dürfen: Per Default hat eine Anwendung erst einmal keinePermissions, das heißt, sie darf keine Komponenten, <uses-permission android:name="android.permission.INTERNET" />Activities, Services, ContentProvider und Broadcast- <uses-permission android:name="android.permission.RECEIVE_SMS" />Receiver anderer Anwendungen verwenden, die miteiner Permission versehen sind. Um eine solche Kom- Der Benutzer kann nun vor der Installation der An-ponente beziehungsweise ihre Funktionalität nutzen wendung entscheiden, ob er der Anwendung diesezu können, muss der Anwender das erst explizit er- Permission gewähren möchte oder aber unter diesenlauben, und zwar einmalig bei der Installation der Securitybedingungen die Anwendung besser nicht ins-Anwendung. Damit der Benutzer bei der Installation talliert (Abb. 9).weiß, welche Permissions seine Anwendung benötigt, Auf den ersten Blick scheint das Android-System so-müssen sie in der AndroidManifest-Datei der Anwen- mit relativ sicher zu sein. Vorausgesetzt natürlich, der Anzeige Anzeigewww.android360.de 1 | 2012 android 360 43
    • ANDROID DEVELOPMENT | PUTTING TOGETHER flection geladen und im Anschluss zum Beispiel durch ein passendes Intent gestartet werden. Sind keine Per- missions für die Klasse hinterlegt, kommt es auch nicht zu einer SecurityException. Was ziehen wir also für Konsequenzen daraus für unsere Anwendung: Auch wir müssen uns Gedanken machen, welche unserer Komponenten von anderen Anwendungen verwendet werden dürfen und welche wir lieber nur intern ver- wenden wollen. Um spezifische Permissions für unsere Komponenten vergeben zu können, müssen wir sie zu- nächst in der AndroidManifest-Datei deklarieren: <permission android:name="de.openknowledge.rss.MY_BROWSER_ACTIVITY"         android:label="@string/perm_lab_start_my_browser"         android:description="@string/perm_desc_start_my_browser"         android:permissionGroup="android.permission-group.NETWORK"         android:protectionLevel="dangerous" /> Das wichtigste Attribut innerhalb der Deklaration ist android:name. Mit diesem Attribut wird der Name der Permission definiert, über den sie später identifi- ziert und verwendet werden kann. Die beiden Attribute android:label und android:description sind rein infor- mativ und sollen dem Benutzer (z. B. bei der Installati- on) aussagekräftige Informationen über die Permission liefern. Auch das Attribut android:permissionGroup hat eher informativen Charakter. Es hilft dem Android-Sys- tem, die Permission einzuordnen und dem Benutzer eine entsprechende Meldung anzuzeigen. Deutlich interes- santer ist da schon das Attribut android:protectionLevel. Es kann die Werte normal, dangerous, signature und signatureOrSystem erhalten und definiert, wie sich An- Abb. 9: Android Installation Security Check droid verhalten soll, wenn die zugehörige Permission angewendet wird: Nutzer geht verantwortungsvoll bei der Installation von Anwendungen vor. Allerdings sind auch Android- • normal: Es wird überprüft, ob die aufrufende Anwen- Komponenten per Default nicht mit Permissions ver- dung die Permission hat. Wenn ja, darf die Kompo- sehen. Wenn also, was leider häufig der Fall ist, der nente aufgerufen werden. Entwickler einer Anwendung nicht explizit Permissions • dangerous: Der Benutzer wird bei jedem Aufruf der für die Komponenten der Anwendung deklariert hat, Komponente gefragt, ob die aufrufende Anwendung dürfen alle ihre Komponenten von anderen Anwen- die Permission tatsächlich erhalten darf. Über diesen dungen verwendet werden. Wieso ist das so? Die oben Mechanismus können wir also als Entwickler einer gezeigte Angabe von uses-permission ist nur dann not- Komponente sicherstellen, dass der Benutzer bei wendig, wenn man auf Komponenten zugreifen möch- jedem Aufruf unserer Komponente um Erlaubnis te, die selbst Permissions deklarieren. Ist das nicht der gefragt wird. Fall, können die Komponenten ohne Probleme, also • signature: Nur Anwendungen, die mit demselben ohne jede Sicherheitsprüfung genutzt werden. Für un- Zertifikat wie unsere Anwendung signiert wurden, ser Beispiel bedeutet das, dass jede andere Anwendung dürfen die Komponente aufrufen. unsere MyBrowserActivity verwenden könnte, da wir • signatureOrSystem: Ist nur für die interne Verwen- bisher keine Permission für diese Komponente ange- dung geeignet und sollte von Anwendungsentwick- geben haben. Nun könnte man natürlich denken, dass lern nicht vergeben werden. das kein wirkliches Problem darstellt, da ja keine ande- re Anwendung weiß, welche Komponenten in unserer Nachdem wir unsere eigene Permission deklariert haben, Anwendung „leben“. Ganz so einfach ist es aber leider können wir sie nun auch vergeben. Dazu muss lediglich nicht. Mithilfe der Klasse PackageManager lässt sich den Elementen, mit denen wir unsere Komponenten in- recht einfach herausfinden, welche Komponenten im nerhalb der AndroidManifest.xml-Konfigurationsdatei System registriert wurden. Hat man erst einmal diese deklariert haben, das Attribut android:permission hin- Information, können die zugehörigen Klassen per Re- zugefügt werden:44 android 360 1 | 2012 www.android360.de
    • PUTTING TOGETHER | ANDROID DEVELOPMENT <activity android:name=".MyBrowserActivity" android:label="Browser" android:permission="de.openknowledge.rss.MY_BROWSER_ACTIVITY"> <intent-filter> ... </intent-filter> </activity>Das gilt sowohl für Activities als auch für Services und BroadcastReceiver. Dieeinzige Ausnahme bildet auch hier wieder der ContentProvider, für den zweivordefinierte Permissions für Lese- (android:readPermission) und Schreibzugriffe(android:writePermission) zur Verfügung stehen. Mithilfe des eben gezeigten deklarativen Ansatzes können eigene Kompo-nenten recht einfach vor dem ungewollten Zugriff von außen geschützt wer-den. Es kann allerdings durchaus Situationen geben, in denen diese recht grobeGranularität der Permissions nicht ausreicht. Prinzipiell kann daher jederzeitauch über die Methode Context.checkPermission(…) eine applikationsseitigeÜberprüfung einer Permission erfolgen. Das ist zum Beispiel dann sinnvoll,wenn eingeschränkte Zugriffsrechte nur für eine bestimmte Methode geltensollen. Möchte man den Datenzugriff über einen ContentProvider feingranu-larer schützen, ist auch das möglich, und zwar über URI-basierte Permissions.FazitAndroid bietet von Hause aus die Möglichkeit zur modularen und somit wie-derverwendbaren Anwendungsentwicklung. Activities, Services, BroadcastRe-ceiver und ContentProvider anderer Anwendungen können problemlos in dereigenen Anwendung angesprochen und genutzt werden und vice versa. Lässtman sich auf dieses offene Konzept von Android ein, kann dank Wiederver-wendung eine Menge Zeit und Arbeit gespart werden. Allerdings sollte man Anzeigedabei auf keinen Fall die notwendige Security aus den Augen verlieren, dannklappt’s auch mit dem „Nachbarn“. Es gibt mittlerweile auch einige Projektewie OpenIntents [5], die versuchen, allgemeine Activity-Schnittstellen zusam-menzutragen, um so deren potenzielle Wiederverwendung zu forcieren. Schönwäre es natürlich, wenn es hier zu einem zentralisierten Ansatz, zum Beispieldurch Google, käme. Lars Röwekamp ist Geschäftsführer der open knowledge GmbH und berät seit mehr als zehn Jahren Kunden in internationalen Projekten rund um das Thema Enterprise Computing (Twitter: @mobileLarson). Arne Limburg ist Softwarearchitekt bei der open knowledge GmbH in Oldenburg. Er verfügt über lang- jährige Erfahrung als Entwickler, Architekt und Consultant im Java-Umfeld und ist auch seit der ersten Stunde im Android-Umfeld aktiv.Links & Literatur[1] Android Application Fundamentals: http://bit.ly/bvkbja[2] Intents und Intent-Filter: http://bit.ly/4ywpD6[3] Johann Wolfgang von Goethe: Zitat aus „Götz von Berlichingen“[4] Security und Permissions: http://bit.ly/DttQQ[5] OpenIntents: http://openintents.orgwww.android360.de 1 | 2012 android 360 45