Create An Android Mobile App Using Kotlin That Consumes An API From A Drupal Instance
Drupal is a content management system(CMS) written using PHP and is used to build websites and web applications. Popular websites that use Drupal include: Nokia, Prime Minister Of Australia and Tesla. Below are the steps one can use to extend Drupal to the Android client. The assumption is that the Drupal instance has been installed and is running.
Drupal
- Install and enable the JSON:API module on the Drupal instance
- Run the endpoints using Postman to simulate how the requests will be made by the Android client.
Drupal URL structure
In the JSON:API, each resource has a globally unique type property. For example:
- node–article for articles
- user–user for users
- node–pages for pages
When running the Postman requests, represent the URL as follows. Replace the BASE_URL with your domain or IP Address.
- https://BASE_URL/jsonapi/node/article get articles
- https://BASE_URL/jsonapi/node/page get pages
Kotlin Android Client
The Android App makes HTTP requests to the Drupal instance. Below are the steps used when building the App.
1. Open Android Studio and create a project
2. Add the necessary dependencies
dependencies {
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.room:room-common:2.6.1")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
implementation("androidx.hilt:hilt-work:1.2.0")
implementation("androidx.work:work-runtime-ktx:2.9.0")
kapt("androidx.hilt:hilt-compiler:1.2.0")
implementation("com.google.dagger:hilt-android:$hilt")
kapt("com.google.dagger:hilt-compiler:$hilt")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3")
implementation("com.squareup.retrofit2:retrofit:$retrofit")
implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
implementation ("com.squareup.okhttp3:okhttp:4.9.3")
implementation("de.hdodenhof:circleimageview:3.1.0")
implementation("androidx.activity:activity-ktx:1.9.0")
}
3. Add the Data Classes corresponding to the JSON structure of your Drupal API responses.
data class ArticleResponse(
@field:Json(name = "data") val data: List<Data> = listOf()
)
data class Data(
@field:Json(name = "id") val id: String? = "",
@field:Json(name = "attributes") val attributes: Attributes = Attributes()
)
data class Attributes(
@field:Json(name = "title") val title: String? = "",
@field:Json(name = "created") val created: String? = "",
@field:Json(name = "path") val path: Path = Path(),
@field:Json(name = "body") val body: Body = Body()
)
data class Path(
@field:Json(name = "alias") val alias: String? = "",
@field:Json(name = "pid") val pid: Int? = 0
)
data class Body(
@field:Json(name = "value") val value: String? = ""
)
4. In this case, we made use of the Retrofit library to make HTTP requests to the JSON API.
@Singleton
@Provides
fun provideRetrofit(): Retrofit{
val okHttpClient = OkHttpClient().newBuilder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
return Retrofit.Builder()
.baseUrl(Common.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create())
.client(okHttpClient)
.build();
}
5. Set the API endpoints
interface ArticleApi: Common {
@GET("node/article")
suspend fun getArticles(): ArticleResponse;
}
6. Ensure you have the requisite permissions
/* AndroidManifest.xml file */
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
/* Kotlin Activity class */
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var articleRepository: ArticleRepository;
lateinit var mainActivityMvc: MainActivityMvc;
lateinit var networkTools: NetworkTools;
val mainActivityViewModel: MainActivityViewModel by viewModels<MainActivityViewModel>();
companion object {
lateinit var appCompatActivity: AppCompatActivity;
}
init {
appCompatActivity = this;
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mainActivityMvc =
MainActivityMvc(LayoutInflater.from(this), null, this, articleRepository, mainActivityViewModel);
setContentView(mainActivityMvc.getRootView_())
networkTools = NetworkTools(this);
mainActivityMvc.setListerners();
appCompatActivity = this;
mainActivityMvc.sendAPIRequest();
mainActivityViewModel.observe(this, this, mainActivityMvc, mainActivityViewModel);
requestMultiplePermissionLauncher.launch(
arrayOf(
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE
)
)
}
override fun onResume() {
super.onResume()
if (networkTools.checkConnectivity()) {
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK) {
val homeIntent = Intent(Intent.ACTION_MAIN)
homeIntent.addCategory(Intent.CATEGORY_HOME)
homeIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(homeIntent)
return true
}
return super.onKeyDown(keyCode, event)
}
private val requestMultiplePermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { result ->
}
}
The above codebase is also available on Github
Symatech Labs is a Software Development company based in Nairobi, Kenya that specializes in Software Development, Mobile App Development, Web Application Development, Integrations, USSD and Consultancy.