Android
This chapter deals with the Android specific properties of the AusweisApp SDK. The AusweisApp core is encapsulated into an Android service which is running in the background without a user interface. This service is interfaced via an Android specific interprocess communication (IPC) mechanism. The basics of this mechanism - the Android Interface Definition Language (AIDL) - are introduced in the following section. Subsequent sections deal with the SDK interface itself and explain which steps are necessary in order to communicate with the AusweisApp SDK.
The AusweisApp is available as an AAR package that can automatically be fetched by Android’s default build system gradle.
See also
For Android there is also the AusweisApp SDK Wrapper which is a software library that offers a high-level interface to the AusweisApp SDK.
Important
The AAR package is available in maven central for free. If you need enterprise support feel free to contact us.
Important
Please note that only Android devices that feature Extended Length NFC communication are supported by the SDK. This can be checked via the Android API methods getMaxTransceiveLength() and isExtendedLengthApduSupported().
SDK
The AusweisApp SDK is distributed as an AAR package that contains native arm64-v8a, x86_64 and armeabi-v7a libraries only. The AAR package is available in the default repository of Android. The following listing shows the required mavenCentral in build.gradle.
buildscript {
repositories {
mavenCentral()
}
}
The AusweisApp SDK will be fetched automatically as a dependency by your app/build.gradle file. It is recommended to always use the latest version (2.2.2) of AusweisApp.
dependencies {
implementation 'com.governikus:ausweisapp:x.y.z'
}
Note
All artifacts are signed with the following key (available on all public key servers): 0x699BF3055B0A49224EFDE7C72D7479A531451088
See also
The AAR package provides an AndroidManifest.xml to register required permissions and the background service. If your own AndroidManifest has conflicts with our provided file you can add some attributes to resolve those conflicts.
https://developer.android.com/studio/build/manifest-merge.html
App Bundle
The AusweisApp SDK uses native libraries which need to be extracted when used in an App Bundle, otherwise the SDK will not work correctly.
Add the following statement to your app’s build.gradle file:
android { packagingOptions { jniLibs { useLegacyPackaging = true } } }
Logging
The AusweisApp SDK uses default logging of Android and has its own log file. It is recommended to collect that log file if an error occurs in your application to receive better support.
The log file is in your application path:
/data/data/your.application.name/files/AusweisApp.XXXXXX.log
The XXXXXX characters will be replaced by an automatically generated portion of the filename to avoid conflicts with previous instances.
A new log file will be created for each new instance of the AusweisApp and will be deleted after a correct shutdown. In case of old or multiple log files, it is highly probable that the previous instance crashed.
The AusweisApp deletes any log files that are older than 14 days.
Initialization of the Android Application
The AusweisApp SDK creates a fork of the Android “main” Application if started. Due to this, the Application is instantiated a second time. Thus, it must ensure that any initialization (e.g. Firebase connections) is only carried out once. To do so the following snippet may prove useful:
public class MyAwesomeApp extends Application
{
private static final String AA2_PROCESS = "ausweisapp2_service";
@Override
public void onCreate()
{
super.onCreate();
if (isAA2Process())
return;
// Perform one-time initialization of YOUR app, e.g. Firebase connection
}
private boolean isAA2Process()
{
return Application.getProcessName().endsWith(AA2_PROCESS);
}
}
Import the AIDL files
Android provides an interprocess communication (IPC) mechanism which is based on messages consisting of primitive types. In order to abstract from this very basic mechanism, there is the Android Interface Definition Language (AIDL). It allows the definition of Java like interfaces. The Android SDK generates the necessary interface implementations from supplied AIDL files in order to perform IPC, as if this function had been called directly in the current process.
In order to interact with the AusweisApp SDK there are two AIDL interfaces. The first one is given to the client application by the SDK and allows the client to establish a session with the SDK, to send JSON commands to the SDK and to pass discovered NFC tags to the SDK.
The second AIDL interface is given to the SDK by the client application. It enables the client to receive the initial session parameters as well as JSON messages from the SDK. Furthermore it has a function which is called when an existing connection with the SDK is dropped by the SDK. Both interfaces are listed below and you need to import them into your build environment.
Interface
package com.governikus.ausweisapp2;
import com.governikus.ausweisapp2.IAusweisApp2SdkCallback;
import android.nfc.Tag;
interface IAusweisApp2Sdk
{
boolean connectSdk(IAusweisApp2SdkCallback pCallback);
boolean send(String pSessionId, String pMessageFromClient);
boolean updateNfcTag(String pSessionId, in Tag pTag);
}
Callback
package com.governikus.ausweisapp2;
interface IAusweisApp2SdkCallback
{
void sessionIdGenerated(String pSessionId, boolean pIsSecureSessionId);
void receive(String pJson);
void sdkDisconnected();
}
Background service
The AusweisApp SDK is an embedded background service in your own application.
Binding to the service
In order to start the AusweisApp SDK it is necessary to bind to the Android service supplied by the SDK. This binding fulfils two purposes:
First it starts the SDK.
Second it enables the client to establish an IPC connection as mentioned above.
Due to the nature of an Android service, there can be only one instance of the SDK running. If multiple clients in your application bind to the service, they are interacting with the same instance of the service. The service is terminated once all previously bound clients are unbound.
To differentiate between different connected clients, virtual sessions are used once the binding is completed. These sessions are discussed in a separate section, section Create session to AusweisApp.
Create connection
First of all, in order to bind to the service, one needs to instantiate an Android ServiceConnection. Subsequently, the object is passed to the Android API and the contained methods are invoked by Android on service connection and disconnection.
import android.content.ServiceConnection;
// [...]
ServiceConnection mConnection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName className, IBinder service)
{
// ... details below
}
@Override
public void onServiceDisconnected(ComponentName className)
{
// ... details below
}
}
Bind service to raw connection
In order to perform the actual binding a directed Intent, which identifies the AusweisApp SDK, is created. This Intent is sent to the Android API along with the ServiceConnection created above. This API call either starts up the SDK if it is the first client, or connects to the running SDK instance if there is already another client bound.
You need to pass your own package name as the AusweisApp SDK is a background service of your application.
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
// [...]
String pkg = getApplicationContext().getPackageName();
String name = "com.governikus.ausweisapp2.START_SERVICE";
Intent serviceIntent = new Intent(name);
serviceIntent.setPackage(pkg);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
Initializing the AIDL connection
Once the Android service of the AusweisApp SDK is successfully started and bound to by the client, the Android system calls the onServiceConnected method of the ServiceConnection created and supplied above. This method receives an instance of the IBinder Android service interface.
The IBinder is then used by the client application to initialize the auto generated AIDL stub in order to use the AIDL IPC mechanism. The used stub is supposed to be auto generated by the Android SDK if you have properly configured your build environment.
The stub initialization returns an instance of IAusweisApp2Sdk which is used to interact with the SDK. The example below stores this instance in the member variable mSdk.
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
import com.governikus.ausweisapp2.IAusweisApp2Sdk;
// [...]
IAusweisApp2Sdk mSdk;
ServiceConnection mConnection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName className, IBinder service)
{
try {
mSdk = IAusweisApp2Sdk.Stub.asInterface(service);
} catch (ClassCastException|RemoteException e) {
// ...
}
}
@Override
public void onServiceDisconnected(ComponentName className)
{
mSdk = null;
}
}
See also
Create session to AusweisApp
Once your client is bound to the AusweisApp SDK service and you have initialized the AIDL IPC mechanism, you are ready to use the actual SDK API.
Since the Android system does not allow to limit the number of clients which can connect to a service, the SDK API uses custom sessions to manage the connected clients. There is a maximum of one established session at a time.
In order to open a session with the SDK you need to pass an instance of IAusweisApp2SdkCallback to the connectSdk function of your previously acquired instance of IAusweisApp2Sdk. If your callback is accepted, the function returns true. Otherwise there is a problem with your supplied callback. Sessions will be disconnected once the IBinder instance of the connected client is invalidated, another communication error occurs or another Client connects. Please see Disconnect from SDK for instructions to gracefully disconnect from the SDK.
As mentioned above: If there already is a connected client and a second client attempts to connect, the first client is disconnected and the second client is granted exclusive access to the SDK. The first client is informed via its callback by sdkDisconnected. The second client is presented a fresh environment and it has no access to any data of the first client.
If you have successfully established a session, the sessionIdGenerated function of your callback is invoked. With this invocation you receive two arguments. pIsSecureSessionId is true if the SDK was able to gather enough entropy in order to generate a secure random session ID. If it is false, there is no session ID passed. There is nothing you can do about such an error. It results from a problem with the random number generator, which in turn is very likely the result of an ongoing local attack. The device should be considered manipulated and the user should be informed.
On success pSessionId holds the actual session ID generated by the SDK. This ID is used to identify your session and you need to pass it to all future SDK function invocations of this session.
The listing below shows an example for an instantiation of IAusweisApp2SdkCallback and establishing a session.
import com.governikus.ausweisapp2.IAusweisApp2Sdk;
import com.governikus.ausweisapp2.IAusweisApp2SdkCallback;
// [...]
LocalCallback mCallback = new LocalCallback();
class LocalCallback extends IAusweisApp2SdkCallback.Stub
{
public String mSessionID = null;
@Override
public void sessionIdGenerated(
String pSessionId, boolean pIsSecureSessionId) throws RemoteException
{
mSessionID = pSessionId;
}
@Override
public void receive(String pJson) throws RemoteException
{
// handle message from SDK
}
}
// [...]
try
{
if (!mSdk.connectSdk(mCallback))
{
// already connected? Handle error...
}
}
catch (RemoteException e)
{
// handle exception
}
Send command
In order to send a JSON command to the AusweisApp SDK, you need to invoke the send function of your instance of IAusweisApp2Sdk. For this command to be processed by the SDK you need to supply the session ID which you have previously received. The listing below shows an example.
String cmd = "{\"cmd\": \"GET_INFO\"}";
try
{
if (!mSdk.send(mCallback.mSessionID, cmd))
{
// disconnected? Handle error...
}
}
catch (RemoteException e)
{
// handle exception
}
Receive message
Messages from the AusweisApp SDK are passed to you via the same instance of IAusweisApp2SdkCallback in which you have received the session ID. The receive method is called each time the SDK sends a message.
See also
Disconnect from SDK
In order to disconnect from the AusweisApp SDK you need to invalidate your instance of IBinder. There are two possibilities to do this. The first one is to unbind from the SDK Android service to undo your binding, like shown in the code listing below. The second one is to return false in the pingBinder function of your IBinder instance.
unbindService(mConnection);