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
keytool
utility 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:
data
ui
util
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