Finish chapter 6.3.3

This commit is contained in:
wiecktobi 2020-06-08 19:28:59 +02:00
parent 1cc688bed0
commit 5b2d6a7cfe

View File

@ -54,10 +54,9 @@
\subsection{Authentifizierung} \subsection{Authentifizierung}
Zur Authentifizierung benutzen wir JWT, welches bei jeder Anfrage ans Backend mit geschickt werden muss. Das Token erhält man beim Einloggen mit den richtigen Daten und muss persistiert werden, bis sich der Benutzer ausloggt. Dazu speichere ich das Token im privaten Speicher der App. In allen weiteren Activities kann dann auf den Speicher zugegriffen werden und das Token beim Erstellen des \verb|AuthenticationInterceptor|s mitgegeben werden. Beim Ausloggen wird einfach die Datei mit dem Token aus dem Speicher gelöscht. \\ Zur Authentifizierung benutzen wir JWT, welches bei jeder Anfrage ans Backend mit geschickt werden muss. Das Token erhält man beim Einloggen mit den richtigen Daten und muss persistiert werden, bis sich der Benutzer ausloggt. Dazu speichere ich das Token im privaten Speicher der App. In allen weiteren Activities kann dann auf den Speicher zugegriffen werden und das Token beim Erstellen des \verb|AuthenticationInterceptor|s mitgegeben werden. Beim Ausloggen wird einfach die Datei mit dem Token aus dem Speicher gelöscht. \\
Der \verb|AuthenticationInterceptor| ist Kind von der \verb|Interceptor|-Klasse aus der \verb|okhttp3|-Bibliothek, welche in Retrofit eingebunden ist. Mithilfe des Interceptors können REST-Abfragen Header-Daten mitgegeben werden. In unserem Fall ist das das \verb|Authorization|-Feld mit dem Token. Der \verb|AuthenticationInterceptor| ist Kind von der \verb|Interceptor|-Klasse aus der \verb|okhttp3|-Bibliothek, welche in Retrofit eingebunden ist. Mithilfe des Interceptors können REST-Abfragen Header-Daten mitgegeben werden. In unserem Fall ist das das \verb|Authorization|-Feld mit dem Token.
\begin{verbatim} \begin{lstlisting}
class AuthenticationInterceptor(pToken: String) : Interceptor { class AuthenticationInterceptor(pToken: String) : Interceptor {
private val token = pToken private val token = pToken
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request() val original = chain.request()
val builder = original.newBuilder() val builder = original.newBuilder()
@ -66,23 +65,69 @@
return chain.proceed(request) return chain.proceed(request)
} }
} }
\end{verbatim} \end{lstlisting}
Der Interceptor wird dem HTTP-Client hinzugefügt, welcher später bei der Erzeugung des Retrofit-Builders notwendig ist. Der Interceptor wird dem HTTP-Client hinzugefügt, welcher später bei der Erzeugung des Retrofit-Builders notwendig ist.
\begin{verbatim} \begin{lstlisting}
val httpClient = OkHttpClient.Builder() val httpClient = OkHttpClient.Builder()
val interceptor = AuthenticationInterceptor(token) val interceptor = AuthenticationInterceptor(token)
httpClient.addInterceptor(interceptor) httpClient.addInterceptor(interceptor)
\end{verbatim} \end{lstlisting}
\subsection{Anzeige der Daten in der Main Activity}\label{subsec:AnzeigeDaten} \subsection{Anzeige der Daten in der Main Activity}\label{subsec:AnzeigeDaten}
Die Daten werden per REST-Aufruf mithilfe vom Retrofit-Framework vom Backend geholt. Um Anfragen zusenden benötigt man einen Retrofit-Builder. Diesem wird die anzufragende URL, ein JSON-Konverter und ein HTTP-Client mitgegeben. Aus diesem Builder und einer Service-Klasse, in der die Methoden definiert sind, wird ein Objekt erzeugt mit dem die Methoden aufrufbar sind. Die Daten werden per REST-Aufruf mithilfe vom Retrofit-Framework vom Backend geholt. Um Anfragen zusenden benötigt man einen Retrofit-Builder. Diesem wird die anzufragende URL, ein JSON-Konverter und ein HTTP-Client mitgegeben. Aus diesem Builder und einer Service-Klasse, in der die Methoden definiert sind, wird ein Objekt erzeugt mit dem die Methoden aufrufbar sind.
\begin{lstlisting}
val builder = Retrofit.Builder() val builder = Retrofit.Builder()
.baseUrl("http://plesk.icaotix.de:5000") .baseUrl("http://plesk.icaotix.de:5000")
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build()) .client(httpClient.build())
val retrofit = builder.build() val retrofit = builder.build()
service = retrofit.create(GeofenceService::class.java) service = retrofit.create(GeofenceService::class.java)
\end{lstlisting}
Die Klasse \verb|GeofenceService| dient, wie oben beschrieben, zur definition der Endpunkte in From von Methodenaufrufen. Dort wird definiert, ob es ein \verb|POST| oder \verb|GET| Entpunkt ist, wie der Pfad lautet und was für Parameter mitgegeben werden.
\begin{lstlisting}
@POST("/login")
fun login(@Body login_data: ValuesUserLogin): Call<Void>
@GET("whoami")
fun getUser(): Call<ValuesUser>
@GET("accounts/search/findByUsername")
fun getAccounts(@Query("username") username : String): Call<EmbeddedAccounts>
\end{lstlisting}
Der Rückgabewert der Methoden ist immer vom Typ \verb|Call|. Wenn aus dem Body Werte gelesen werden sollen, muss eine Art Skelett-Klasse angelegt werden mit den relevanten Feldern. Die Klasse \verb|ValuesUser| stellt Werte der Antwort bereit, wie z. B. den Vornamen.
\begin{lstlisting}
class ValuesUser(firstname: String) {
@SerializedName("firstname")
var firstname = firstname
}
\end{lstlisting}
Der Aufruf der Methode erfolgt Asynchron. Deshalb darf sich nicht auf das Ergebnis des Aufrufs direkt danach verlassen werden, sonst bekommt man eine Null-Pointer-Excetion. Die Methode \verb|enqueue| besitzt ein Callback-Objekt als Parameter, welches \verb|onResponse| und \verb|onFailure| überschreibt. Dort wird entsprechend definiert was in den jeweiligen Fällen ausgeführt werden soll.
\begin{lstlisting}
val call = service.getUser()
call.enqueue(object : Callback<ValuesUser> {
override fun onResponse(call: Call<ValuesUser>, response: Response<ValuesUser>) {
if (response.isSuccessful) {
val firstname = response.body()?.firstname
lbl_username.text = "Hello " + firstname
} else {
println("Response not successful: ${response.code()}")
}
}
override fun onFailure(call: Call<ValuesUser>, t: Throwable) {
println("Response 'whoami' failed. " + t.message)
}
})
\end{lstlisting}
\bigskip
In dieser Art und Weise werden alle Anfragen ans Backend gehandhabt. Dazu zählen:
\begin{itemize}
\item Abfragen der Location-Daten zu dem Benutzer für den Geofence
\item Befüllen des Dropdown-Menüs mit den Timetrack-Accounts des Benutzers
\item Anzeigen der Beschreibung und der Vergütung
\item Befüllen des RecyclerViews mit den heutigen Einträgen
\item Auslösen des Start-/Stopp-Events
\item Einloggen
\end{itemize}
\subsection{Geofencing} \subsection{Geofencing}
\section{Funktionen der App} \section{Funktionen der App}