Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
Vorwort
Teil I Grundlagen
1 Android – eine offene, mobile Plattform
2 Hallo Android!
3 Von der Idee zur Veröffentlichung
Teil II Elementare Anwendungsbausteine
4 Wichtige Grundbausteine von Apps
5 Benutzeroberflächen
6 Multitasking
Teil III Gerätefunktionen nutzen
7 Telefonieren und surfen
8 Sensoren, GPS und Bluetooth
Teil IV Dateien und Datenbanken
9 Dateien lesen, schreiben und drucken
10 Datenbanken
Teil V Multimedia und Produktivität
11 Multimedia
12 Kontakte und Organizer
A Einführung in Kotlin
B Jetpack Compose
C Häufig benötigte Codebausteine
D Literaturverzeichnis
E Die Begleitmaterialien
Stichwortverzeichnis

Ihre Meinung?
Spacer
<< zurück
Android 11 von Thomas Künneth
Das Praxisbuch für App-Entwickler
Buch: Android 11

Android 11
Pfeil 7 Telefonieren und surfen
Pfeil 7.1 Telefonieren
Pfeil 7.1.1 Anrufe tätigen und SMS versenden
Pfeil 7.1.2 Auf eingehende Anrufe reagieren
Pfeil 7.2 Telefon- und Netzstatus
Pfeil 7.2.1 Systemeinstellungen auslesen
Pfeil 7.2.2 Netzwerkinformationen anzeigen
Pfeil 7.2.3 Carrier Services
Pfeil 7.3 Das Call Log
Pfeil 7.3.1 Entgangene Anrufe ermitteln
Pfeil 7.3.2 Änderungen vornehmen und erkennen
Pfeil 7.4 Webseiten mit WebView anzeigen
Pfeil 7.4.1 Einen einfachen Webbrowser programmieren
Pfeil 7.4.2 JavaScript nutzen
Pfeil 7.5 Webservices nutzen
Pfeil 7.5.1 Auf Webinhalte zugreifen
Pfeil 7.5.2 Senden von Daten
Pfeil 7.6 Zusammenfassung
 
Zum Seitenanfang

7.4    Webseiten mit WebView anzeigen Zur vorigen ÜberschriftZur nächsten Überschrift

Für das Anzeigen von Webseiten in einer Anwendung gibt es unzählige Einsatzgebiete. Denken Sie an Lizenzvereinbarungen, an Links zur Homepage eines Unternehmens oder an Referenzen auf Wikipedia-Artikel. Möchten Sie ein bestehendes Webangebot durch eine Kalender- oder Kontakte-Integration mit dem Smartphone oder Tablet aufwerten? Haben Sie bestehenden HTML5- und JavaScript-Code, den Sie zu einer vollwertigen App erweitern möchten? All dies ist mit Android sehr einfach realisierbar.

 
Zum Seitenanfang

7.4.1    Einen einfachen Webbrowser programmieren Zur vorigen ÜberschriftZur nächsten Überschrift

Mit den Intents hat Google seiner mobilen Plattform ein äußerst mächtiges und dennoch einfach zu handhabendes Werkzeug mit auf den Weg gegeben. Das Anzeigen einer Webseite ist mit drei Zeilen Quelltext erledigt:

val uri = Uri.parse("https://www.rheinwerk-verlag.de/")
val intent = Intent(Intent.ACTION_VIEW, uri)
startActivity(intent)

Ihre App muss hierfür keine Berechtigungen anfordern, denn sie delegiert das Anzeigen an die Standardanwendung. Oft ist dies für die Darstellung einfacher statischer Inhalte schon ausreichend, allerdings ist auf diese Weise kaum Interaktion mit einer Seite möglich. Ferner sieht der Benutzer, dass er Ihr Programm verlässt. Ist dies nicht gewünscht, so können Sie mit praktisch genauso wenig Aufwand eine Browserkomponente integrieren. Das folgende Layout gehört zur Beispielanwendung WebViewDemo1. Es enthält drei Buttons sowie ein Objekt des Typs android.webkit.WebView.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/buttonIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/intent" />
<Button
android:id="@+id/buttonHtml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/buttonIntent"
android:text="@string/html" />
<Button
android:id="@+id/buttonBase64"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/buttonHtml"
android:text="@string/base64" />
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/buttonBase64"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true" />
</RelativeLayout>

Listing 7.14    Die Datei »activity_main.xml« des Projekts »WebViewDemo1«

Das Laden und Anzeigen der Benutzeroberfläche erfolgt auf die Ihnen vertraute Weise. Die anzuzeigende Webadresse wird der Komponente im Anschluss daran durch Aufruf der Methode loadUrl() übergeben. Dies ist im folgenden Codefragment zu sehen. Schlägt das Laden der Seite fehl, wird übrigens keine Ausnahme ausgelöst.

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webview.loadUrl("https://www.rheinwerk-verlag.de")
...
}

Listing 7.15    Auszug aus der Methode »onCreate()« des Projekts »WebViewDemo1«

Eine »beliebte« Fehlerquelle in diesem Zusammenhang ist das Fehlen der Berechtigung android.permission.INTERNET. Bitte denken Sie daran, sie in der Manifestdatei Ihrer App anzufordern. Da es sich hierbei um eine normale Berechtigung handelt, muss sie im Code nicht explizit angefordert werden.

Um HTML-Seiten anzuzeigen, können Sie statt der Methode loadUrl() auch loadData() verwenden. Sie bietet sich an, wenn die anzuzeigenden Daten programmatisch erzeugt werden.

val html1 = "<html><body><p>Hallo Android</p></body></html>"
webview.loadData(html1, "text/html", null)

Listing 7.16    Eine HTML-Seite mithilfe von Code erstellen

Der dritte Parameter gibt das Encoding an. base64 bedeutet, dass die Daten im ersten Parameter Base64[ 10 ](https://de.wikipedia.org/wiki/Base64)-codiert sind. Alle anderen Werte einschließlich null (wie in meinem Beispiel) legen eine Codierung entsprechend dem URL-Encoding[ 11 ](https://de.wikipedia.org/wiki/URL-Encoding) fest. Reservierte Zeichen wie Leerzeichen, Fragezeichen und Hashtags müssen in ihrer %-Ersatzdarstellung (%20, %3F bzw. %23) erscheinen. Das Erzeugen eines Base64-codierten Strings ist mit der Klasse android.util.Base64 sehr einfach:

val html2 = "<html><body><p>Hallo Welt</p></body></html>"
val base64 = Base64.encodeToString(html2.toByteArray(), Base64.DEFAULT)
webview.loadData(base64, "text/html", "base64")

Listing 7.17    HTML-Code Base64-codiert anzeigen

Die rudimentäre Integration der Browserkomponente in eine App ist also schnell erledigt. Allerdings sind die Interaktionsmöglichkeiten bislang genauso bescheiden wie beim Auslösen eines Intents. Selbstverständlich kann WebView aber viel mehr. Anhand der Beispiel-App WebViewDemo2 zeige ich Ihnen, wie Sie einen einfachen Browser mit Seitenverlauf programmieren. Er ist in Abbildung 7.5 zu sehen.

Die App »WebViewDemo2«

Abbildung 7.5    Die App »WebViewDemo2«

Die Benutzeroberfläche besteht aus einer Navigationsleiste mit Weiter- und Zurück-Schaltflächen, einem Eingabefeld für die Webadresse und natürlich der WebView. Die Klasse WebViewDemo2Activity lädt als Erstes die Layoutdatei activity_main.xml und zeigt sie an. Da das Projekt die Kotlin Android Extensions verwendet, sind die Bedienelemente direkt über die Variablen edittext, prev, next und webview erreichbar. Anschließend werden für die beiden Schaltflächen < und > OnClickListener registriert. Sie leiten die jeweilige Aktion (im Seitenverlauf zurück- oder weiterblättern) an WebView weiter. Diese stellt hierfür die Methoden goBack() und goForward() zur Verfügung. Mit canGoBack() und canGoForward() lässt sich prüfen, ob dies aktuell möglich ist. Ich nutze dies in der Methode updateNavBar(), um die Schaltflächen zu aktivieren bzw. zu deaktivieren. Übrigens wird diese Methode an nur zwei Stellen aufgerufen. Ich komme etwas später darauf zurück.

Um auf das Action-Kommando der virtuellen Tastatur reagieren zu können, wird für das Textfeld ein OnEditorActionListener gesetzt. Die einzige zu implementierende Methode onEditorAction() hat drei Parameter: v (die Komponente, die den Callback ausgelöst hat), actionId (EditorInfo.IME_NULL, wenn die (¢)-Taste gedrückt wurde; ansonsten ein Wert, den Sie in der Layoutdatei definiert haben) und event (ein Ereignis, wenn die (¢)-Taste gedrückt wurde, sonst null). Meine Implementierung liest nur den eingegebenen Text aus und übergibt ihn an loadUrl(). Deshalb tauchen die letzten beiden Parameter im Listing nur als _ auf. onEditorAction() liefert true, wenn sie die Aktion konsumiert hat.

package com.thomaskuenneth.androidbuch.webviewdemo2

import android.os.Bundle
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class WebViewDemo2Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
prev.setOnClickListener { webview.goBack() }
next.setOnClickListener { webview.goForward() }
edittext.setOnEditorActionListener { v, _, _ ->
webview.loadUrl(v.text.toString())
true
}
webview.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView,
r: WebResourceRequest): Boolean {
view.loadUrl(r.url.toString())
return true
}

override fun onPageFinished(view: WebView, url: String) {
updateNavBar()
}

override fun onReceivedError(view: WebView,
request: WebResourceRequest,
error: WebResourceError) {
updateNavBar()
}
}
webview.settings.builtInZoomControls = true
webview.settings.loadWithOverviewMode = true
webview.settings.useWideViewPort = true
if (savedInstanceState != null) {
webview.restoreState(savedInstanceState)
} else {
webview.loadUrl("https://www.rheinwerk-verlag.de/")
}
webview.requestFocus()
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
webview.saveState(outState)
}

private fun updateNavBar() {
prev.isEnabled = webview.canGoBack()
next.isEnabled = webview.canGoForward()
edittext.setText(webview.url)
}
}

Listing 7.18    Die Klasse »WebViewDemo2Activity«

Um auf Ereignisse im Lebenszyklus einer WebView zu reagieren, setzen Sie mit webview.webViewClient = ... ein Objekt, das von der Klasse android.webkit.WebViewClient ableitet. Dessen Methode shouldOverrideUrlLoading() wird aufgerufen, wenn eine URL geladen werden soll (zum Beispiel, weil ein Link angeklickt wurde). Der Rückgabewert true zeigt an, dass sich die Implementierung selbst um die URL kümmern möchte. Bei false tut dies die WebView. Falls Sie nur Seitenaufrufe loggen möchten, könnten Sie die Methode überschreiben, aber false zurückliefern. Streng genommen ist meine Implementierung also unnötig, weil sie das in diesem Fall greifende Verhalten »nachbaut«.

[»]  Hinweis

Wenn für eine WebView kein WebViewClient-Objekt gesetzt wird, reicht die View die URL als Intent an das System weiter. Das Antippen eines Links würde die korrespondierende Seite deshalb im Standardbrowser anzeigen, nicht mehr in Ihrer eingebetteten Komponente.

Die Methode onPageFinished() wird aufgerufen, wenn das Laden einer Seite erfolgreich abgeschlossen wurde. onReceivedError() weist auf einen Fehler hin. In beiden Fällen aktualisiere ich die Navigationsleiste einschließlich des Eingabefeldes. Deshalb muss bei loadUrl() meine Methode updateNavBar() nicht explizit aufgerufen werden.

Damit haben Sie es fast geschafft. settings liefert ein Objekt, über das Sie Ihre WebView konfigurieren können. Beispielsweise legen Sie mit builtInZoomControls fest, ob die eingebaute Zoomfunktion verwendet werden soll. loadWithOverviewMode = true skaliert die Darstellung so, dass die Webseite in der Breite vollständig angezeigt wird. useWideViewPort = true bedeutet, dass die Browserkomponente die Breite aus dem viewport-Metatag der Webseite verwendet, sofern es dort gesetzt ist. Und mit javaScriptEnabled können Sie JavaScript ein- und ausschalten. Diesem Thema widmen wir uns im nächsten Abschnitt.

Vorher aber noch ein Tipp: Um bei Orientierungswechseln des Geräts nicht den Seitenverlauf und die gegenwärtig angezeigte URL zu verlieren, sollten Sie (wie in Listing 7.18 zu sehen) onSaveInstanceState() überschreiben und die WebView-Methode saveState() aufrufen. Das Wiederherstellen erfolgt in onCreate() durch Aufruf von restoreState(), sofern die Variable savedInstanceState nicht null ist. In diesem Fall gibt es nichts zum Wiederherstellen, und Sie setzen die anzuzeigende Seite mit loadUrl().

 
Zum Seitenanfang

7.4.2    JavaScript nutzen Zur vorigen ÜberschriftZur nächsten Überschrift

In diesem Abschnitt zeige ich Ihnen anhand des Beispielprojekts WebViewDemo3 (siehe Abbildung 7.6), wie Sie JavaScript-Code in Ihrer Android-App nutzen. Bitte sehen Sie sich als Erstes die folgende .html-Datei an. Sie definiert eine einfache Seite, die aus einem Label, einem Eingabefeld und einer Schaltfläche besteht.

Die App »WebViewDemo3«

Abbildung 7.6    Die App »WebViewDemo3«

Klicken Sie die Schaltfläche an, wird die Funktion hello() aufgerufen. Diese löscht den Seiteninhalt und grüßt den Anwender. hello() wird in einem <script />-Tag definiert. Der Wert dessen Attributs type folgt dabei dem RFC 4329, »Scripting Media Types«. Dort wird das im Netz noch häufig anzutreffende text/javascript als obsolete gekennzeichnet.

<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
</head>
<body>
<h1>Hallo.</h1>
<form>
<label for="name">Bitte geben Sie Ihren Namen ein.</label>
<input type="text" id="name" value="">
<input type="submit" value="Weiter" onclick="hello()">
</form>
<script type="application/javascript">
    function hello() {
var input = document.getElementById("name");
document.write("Hallo, " + input.value);
}
  </script>
</body>
</html>

Listing 7.19    Die Datei »test1.html« des Projekts »WebViewDemo3«

Sie können die Seite ausprobieren, indem Sie die Datei zum Beispiel mit Chrome öffnen. Klicken Sie hierzu test1.html in Android Studio mit der rechten Maustaste an, und wählen Sie dann Open in BrowserChrome. Auf diese Weise können Sie sehr bequem Ihren JavaScript-Code debuggen. Alle modernen Browser haben mächtige Entwicklerwerkzeuge an Bord.

Aber wo befindet sich test1.html eigentlich? Sie können Ihren Apps Dateien »beilegen«, indem Sie diese in das Verzeichnis assets kopieren. Dieser Ordner ist aber nicht automatisch vorhanden, Sie müssen ihn gegebenenfalls von Hand hinzufügen. Öffnen Sie hierzu das Werkzeugfenster Project, und wechseln Sie in die gleichnamige Sicht Project. Unter app/src/main finden Sie java und res. Klicken Sie main mit der rechten Maustaste an, und wählen Sie dann NewDirectory. Geben Sie »assets« ein, und schließen Sie den Dialog mit OK.

Lassen Sie uns nun einen Blick auf die Activity werfen, die die .html-Datei lädt und anzeigt. Die Klasse WebViewDemo3Activity ist sehr kurz. Nach dem Laden und Anzeigen der Benutzeroberfläche wird mit settings.javaScriptEnabled = true die JavaScript-Fähigkeit der Browserkomponente aktiviert. Anschließend lädt loadUrl() die Webseite. Interessant ist dabei die URL, die wir der Methode übergeben: Dem Protokoll file: folgt der absolute Pfad /android_asset/test1.html. Damit wird die Datei test1.html im assets-Verzeichnis referenziert. Dieses ist übrigens nicht global sichtbar, auch wenn der absolute Pfad das suggeriert.

package com.thomaskuenneth.androidbuch.webviewdemo3

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class WebViewDemo3Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webview.settings.javaScriptEnabled = true
webview.loadUrl("file:/android_asset/test1.html")
}
}

Listing 7.20    Die Klasse »WebViewDemo3Activity«

Die Webseite erscheint zwar in einer Activity, führt sonst aber ein Eigenleben und kommuniziert nicht mit dem Rest der App. Dabei wäre es doch praktisch, auf Funktionen des Wirtssystems zuzugreifen. Denken Sie an Texte in unterschiedlichen Sprachen oder an den Zugriff auf Kontakte und Kalender. JavaScript lässt sich über Interfaces problemlos mit nativem Code verbinden. Wie das geht, zeige ich Ihnen nun.

Mit JavaScript-Code kommunizieren

Bitte werfen Sie als Erstes einen Blick auf die Klasse WebAppInterface. Sie definiert die beiden Methoden getHeadline() und message(). Beide sind mit @JavascriptInterface annotiert. Auf diese Weise kennzeichnen Sie Methoden, die in JavaScript zur Verfügung stehen sollen.

package com.thomaskuenneth.androidbuch.webviewdemo3

import android.content.Context
import android.webkit.JavascriptInterface
import android.widget.Toast

class WebAppInterface(private val context: Context) {
@JavascriptInterface
fun getHeadline(): String {
return context.getString(R.string.headline)
}

@JavascriptInterface
fun message(m: String) {
val toast = Toast.makeText(context, m, Toast.LENGTH_LONG)
toast.show()
}
}

Listing 7.21    Die Klasse »WebAppInterface«

getHeadline() liefert einen String, der in der Datei strings.xml mit der ID headline definiert wurde. Er kann deshalb in verschiedenen Sprachen vorliegen. Die Methode message() zeigt eine Nachricht in Form eines Toasts an. Dies ist in Abbildung 7.7 zu sehen. Ausführliche Informationen zu solchen Texteinblendungen finden Sie in Abschnitt 5.3.1 »Toast und Snackbar«.

Die überarbeitete Version der App »WebViewDemo3«

Abbildung 7.7    Die überarbeitete Version der App »WebViewDemo3«

Um ein Interface mit JavaScript zu verbinden, rufen Sie einfach die WebView-Methode addJavascriptInterface() auf und übergeben ihr das Objekt sowie einen beliebigen Namen, über den die Schnittstelle im JavaScript-Code referenziert wird:

webview.addJavascriptInterface(WebAppInterface(this), "Android")

this bezieht sich auf die Activity, die die WebView enthält; im Beispiel WebViewDemo3 ist dies die Klasse WebViewDemo3Activity. Die in Listing 7.22 abgedruckte Datei test2.html nutzt das Interface Android (der zweite Parameter von addJavascriptInterface()). Um das auszuprobieren, müssen Sie die URL beim Aufruf der Methode loadUrl() entsprechend anpassen.

<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
</head>
<body>
<h1 id="headline"> </h1>
<form>
<label for="name">Bitte geben Sie Ihren Namen ein.</label>
<input type="text" id="name" value="">
<input type="submit" value="Weiter" onclick="hello()">
</form>
<script type="application/javascript">
      var headline = document.getElementById("headline");
headline.innerText = Android.getHeadline();

function hello() {
var input = document.getElementById("name");
Android.message("Hallo, " + input.value);
}
    </script>
</body>
</html>

Listing 7.22    »test2.html«

Ist Ihnen aufgefallen, dass die Überschrift im h1-Tag leer ist? Sie wird durch die Zuweisung headline.innerText = Android.getHeadline(); gesetzt. getHeadline() ist hierbei eine der Methoden in WebAppInterface. Der Aufruf der zweiten Methode, message(), findet in der Funktion hello() statt. Übrigens müssen Sie Ihre selbst definierten Interfaces JavaScript-seitig nicht initialisieren, sie stehen ohne weiteres Zutun automatisch zur Verfügung. Beachten Sie aber, dass das an JavaScript gebundene Objekt in einem anderen Thread als dem ausgeführt wird, in dem es erzeugt wurde.

Bevor Sie die geänderte App starten können, müssen Sie den Quelltext ein bisschen erweitern und anpassen, zum Beispiel für die WebView einen WebViewClient setzen. Das ist nötig, damit das Anklicken von Links oder das Absenden von Formularen innerhalb der eigenen App verarbeitet wird. Andernfalls erhalten Sie zur Laufzeit eine FileUriExposedException.

import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
...
webview.addJavascriptInterface(WebAppInterface(this), "Android")
val client = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView,
request: WebResourceRequest
): Boolean {
return false
}
}
webview.webViewClient = client

webview.loadUrl("file:///android_asset/test2.html")

Listing 7.23    Einen »WebViewClient« setzen

[»]  Hinweis

Das Bereitstellen von Funktionen via addJavascriptInterface() stellt ein potenzielles Sicherheitsrisiko dar, wenn es einem Angreifer gelingt, in Ihre WebView Code einzuschleusen, der Ihre Schnittstelle missbräuchlich nutzt. Aus diesem Grund zeigt Android Studio auch eine Warnung an. Wichtig ist deshalb, dass Sie alle übergebenen Parameter sorgfältig prüfen.

Idealerweise zeigt die WebView auch nur solche Webseiten an, die vollständig Ihrer Kontrolle unterliegen. Nutzen Sie für das Ansurfen beliebiger Ziele stattdessen den Standardbrowser. Feuern Sie hierzu ein Intent, das Sie mit Intent(Intent.ACTION_VIEW, uri) erzeugt haben. WebView ist ein mächtiges Werkzeug, um Webseiten in Ihre App zu integrieren. Wie Sie ganz gezielt Ressourcen herunterladen und wie Sie auf bereitgestellte Dienste zugreifen, sehen Sie im folgenden Abschnitt.

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
Zur Rheinwerk-Konferenz für Kotlin
 Buchempfehlungen
Zum Rheinwerk-Shop: Kotlin

Kotlin


Zum Rheinwerk-Shop: Praxisbuch Usability und UX

Praxisbuch Usability und UX


Zum Rheinwerk-Shop: Flutter und Dart

Flutter und Dart


Zum Rheinwerk-Shop: App-Design

App-Design


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2023
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern