If you would like to log into remote servers and authenticate against remote FHIR APIs, you will need Keycloak credentials. For this, add the following properties to local.properties:
OAUTH_BASE_URL=https://keycloak-stage.smartregister.org/auth/realms/FHIR_Android/
OAUTH_CIENT_ID=fhir-core-client
OAUTH_CLIENT_SECRET=xxxxxx
OAUTH_SCOPE=openid
FHIR_BASE_URL=https://fhir.labs.smartregister.org/fhir/
In order for the assembleRelease and/or bundleRelease Gradle task to work e.g. to generate a signed release version of you APK (or AAB), you need to generate a keystore.
To generate your own release keystore you can use the keytool utility (installed as part of the java runtime) by running the the command:
keytool -genkey -v -keystore fhircore.keystore.jks -alias <my_alias_name> -keyalg RSA -keysize 4096 -validity 1000
Place the Keystore file in your user(home) directory i.e. /Users/username/fhircore.keystore.jks or ~/fhircore.keystore.jks
You then need to create the following System variables and set the corresponding values KEYSTORE_ALIAS, KEYSTORE_PASSWORD, KEY_PASSWORD
Note: The values used in generating the keystore will be the values assigned to the system properties above. Also note, if your platform doesn't prompt you for a second password when generating the Keystore (e.g. of type PKCS12) then the KEYSTORE_PASSWORD and KEY_PASSWORD values will be the same.
You can also choose to store the above credentials in a file named keystore.properties
KEYSTORE_PASSWORD=xxxxxx
KEYSTORE_ALIAS=xxxxxx
KEY_PASSWORD=xxxxxx
Note When using this approach to store credentials please remember to add a keystore.properties entry to the .gitignore file to prevent versioning on git
- For more on the
keytoolutility see: Java Key and Certificate Management Tool - For more on signing your application see: Signing your Android app
FHIR Core is based on MVVM Android application architecture. It follows the recommended Repository Pattern in the architecture. The diagram below shows the different layers of the application structure and how they interact with each other. At the core is Android FHIR SDK which provides Data Access API, Search API, Sync API, Smart Guidelines API and Data Capture API. Refer to FHIR Core Docs for more information.
The project currently consists of two application modules (anc and eir) and one shared Android library module (engine) . The engine module contains shared code for both anc and eir applications, including: code for authenticating users, shared UI code, application and view configuration contracts, domain models and shared utility functions. The engine module project structure and implementation details are discussed intensively on the module's README.MD file.
Both anc and eir Android application modules have their packages grouped based on features. engine module on the other hand uses a hybrid approach, combining both layered and feature based package structure.
At a higher level every module is at least organized into three main packages, namely:
datauiutil
Conventionally, classes are further organized into more cohesive directories within the main packages mentioned above. This should allow for minimal updates in the code base when code is refactored by moving directories.
This package is used to hold classes/object or any implementations used to interact with local database via the FhirEngine implementation provided via the Android FHIR SDK. This package will mostly hold the Repository and Model classes for the application modules. The data package for engine module is further sub-divided into two sub-packages that is local and remote. local directory holds the implementation for accessing the Sqlite database. remote directory contains implementation for making http requests to HAPI FHIR server backend.
This package mostly contains Android Activity, Fragment, ViewModel View classes or any custom implementations that involve data presentation. The views should conventionally be grouped based on their purposed, e.g. is a family package that has both register and details packages for showing a list of all families and individual family details respectively.
This package is used to hold any internally shared utility methods usually implemented as Kotlin extensions with a few exceptions where Kotlin object is used to implement singleton classes.
The engine module provides code that is shared across the supported applications. Every implementation in the engine module that is not common should be implemented as abstract base classes and overridden in the application modules. An example is the BaseLoginActivity (Most abstract classes in engine module conventionally starts with the word Base) that is extended in both application modules to provide specific configurations for login.
Utility methods are conventionally implemented as Kotlin extensions. Others are implemented as singletons using Kotlin object
FHIR Core supports application configurations through contracts. These contracts MUST be implemented by Android Application and any user interface related classes like Activity, Fragment and Android View classes. This allows for passing application level configurations synced from the server or configurations that dictate how data is presented to the user, i.e. which parts of the screen to show or hide, which screens to show, which UI elements to disable etc.
Application level configuration is provided through ConfigurableApplication contract. ConfigurableApplication exposes the following properties that need to be implemented.
| Property | Description |
|---|---|
applicationConfiguration |
Used to set Application level configuration. Typically a Kotlin data class |
authenticationService |
A singleton instance of AuthenticationService used for handling user authorization and authentication using Android AccountManager API |
fhirEngine |
Provides an instance of FhirEngine from Android FHIR SDK |
secureSharedPreference |
Sets a singleton of SecureSharedPreference used to access encrypted shared preference data |
resourceSyncParams |
Provides resource sync parameters needed for syncing data to and from FHIR server |
syncBroadcaster |
Sets a singleton instance of SyncBroadcaster that is used to react to FHIR server sync states. Any view can register to this broadcaster to receive sync states |
workerContextProvider |
Loads SimpleWorkerContext required for StructureMap-based extraction |
ConfigurableApplication also exposes a configureApplication method that accepts an instance of ApplicationConfiguration used to configure the application. This method should be called on the onCreate method of the Application class.
FHIR Core view configurations are provided through two contracts ConfigurableComposableView and ConfigurableView. ConfigurableComposableView is used to configure Android views created using Jetpack Compose. View configurations are used to show or hide views, change view content, change view background etc. Each of the two contracts exposes configureViews method that accepts view Configuration as an argument. This method should be called when the Activity or Fragment is created. It is also recommended to update the view configurations via a ViewModel so they can be observed whenever the configurations are changed.
- Code Documentation - Access FHIR Core code documentation
- Developer Guidelines - Get started with FHIR Core
- FHIR Core Docs - Read FHIR Core Documentation
- Android App Architecture Guide - Learn more about Android App Architecture
- Jetpack Compose - Learn more about Jetpack Compose

