Skip to content

Integrate backend with a new Android app in Android Studio #53

@garotm

Description

@garotm

Integrate backend with a new Android app in Android Studio

1. Create a New Android Project:

  • Open Android Studio: Launch Android Studio.
  • Start a New Project: Click "Start a new Android Studio project."
  • Choose "Empty Compose Activity": Select this template for a project using Jetpack Compose.
  • Click "Next".
  • Configure Your Project:
    • Name: Choose a name for your app (e.g., "RunOn").
    • Package name: Use com.flexrpl.runon (to match your backend and previous discussions).
    • Save location: Choose where you want to save your project.
    • Language: Select "Kotlin."
    • Minimum SDK: Choose an appropriate minimum SDK (API level).
  • Click "Finish."

2. New Project Structure:

com.flexrpl.runon/
  ├── data/
  │   ├── api/          # Retrofit interfaces
  │   ├── models/       # Data classes
  │   └── repository/   # Repository pattern
  ├── di/               # Dependency injection
  ├── ui/
  │   ├── components/   # Reusable UI components
  │   ├── screens/      # Main screens
  │   └── theme/        # App theme
  └── utils/            # Utility classes

3. Add Dependencies:

  • Open your app-level build.gradle file (usually app/build.gradle or build.gradle.kts for newer projects).
  • Add the following dependencies inside the dependencies block:
implementation("com.google.android.gms:play-services-auth:21.0.0") // Google Sign-In
implementation("com.squareup.retrofit2:retrofit:2.9.0") // Retrofit
implementation("com.squareup.retrofit2:converter-gson:2.9.0") // Gson Converter for Retrofit (or use another converter like Moshi)
implementation("com.google.code.gson:gson:2.10.1") // Gson for JSON parsing (if not using a different library)
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") // Optional: For logging network requests
// You might need the Google API Client for handling dates/times if your backend doesn't return them in a readily usable format:
implementation("com.google.api-client:google-api-client-android:2.3.0")
implementation("com.google.apis:google-api-services-calendar:v3-rev20231027-2.0.0")
  • Sync Project with Gradle Files: Click the "Sync Now" button in the bar that appears at the top of Android Studio after you modify the build.gradle file.

4. Implement Google Sign-In:

  • Follow the Official Guide: Refer to the official Google Sign-In for Android documentation for detailed instructions: https://developers.google.com/identity/sign-in/android/sign-in [invalid URL removed]
  • Create GoogleSignInClient: In your main activity (or a dedicated authentication class), create a GoogleSignInClient object:
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignInOptions

// ...

lateinit var googleSignInClient: GoogleSignInClient

// ... in onCreate() or a similar initialization method ...

val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
    .requestIdToken(getString(R.string.server_client_id)) // Get the Web Client ID from strings.xml
    .requestEmail()
    .build()

googleSignInClient = GoogleSignIn.getClient(this, gso)
  • Add Web Client ID to strings.xml:
    • Open res/values/strings.xml.

    • Add a new string resource for your web client ID:

      ```xml
      <string name="server_client_id">YOUR_WEB_CLIENT_ID</string>
      ```
      
      Replace `YOUR_WEB_CLIENT_ID` with the actual **Web Client ID** from your Google Cloud Console (under Credentials).
      
  • Handle Sign-In Button: Add a sign-in button to your UI and trigger the sign-in flow when it's clicked.
  • Get ID Token: After successful sign-in, get the ID token from the GoogleSignInAccount object:
val account = GoogleSignIn.getSignedInAccountFromIntent(data).getResult(ApiException::class.java)
val idToken = account?.idToken
  • Send ID Token to Backend: Send the idToken to your backend for verification (you'll do this in the Retrofit network calls later).

5. Create Data Models:

  • Create Kotlin data classes to represent the JSON objects you'll be sending to and receiving from your backend. For example:
data class SearchQuery(val query: String)

data class SearchResult(
    val title: String,
    val snippet: String,
    val link: String,
    val extractedDateTime: String? = null // Optional
)

data class CalendarEvent(
    val query: String? = null,
    val searchResult: SearchResult? = null,
    val startTime: String, // Example format: "2023-12-29T10:00:00"
    val endTime: String   // Example format: "2023-12-29T11:00:00"
)

6. Create a Service Interface (Retrofit):

  • Define a Kotlin interface to represent your backend API endpoints using Retrofit annotations:
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.POST

interface RunOnApiService {
    @POST("/search")
    suspend fun search(
        @Header("Authorization") idToken: String, // Pass ID token in header
        @Body query: SearchQuery
    ): List<SearchResult>

    @POST("/calendar/event")
    suspend fun createCalendarEvent(
        @Header("Authorization") idToken: String, // Pass ID token in header
        @Body event: CalendarEvent
    ): Response<Unit> // Or a custom response object indicating success/failure
}

7. Implement Network Calls (Retrofit):

  • Create a Retrofit instance:
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

// ...

val logging = HttpLoggingInterceptor().apply {
    level = HttpLoggingInterceptor.Level.BODY // Log request and response bodies (for debugging)
}

val client = OkHttpClient.Builder()
    .addInterceptor(logging)
    .build()

val retrofit = Retrofit.Builder()
    .baseUrl("YOUR_BACKEND_URL") // Replace with your backend URL (local or deployed)
    .client(client)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val apiService = retrofit.create(RunOnApiService::class.java)
  • Make network calls using the apiService instance and the functions you defined in the interface. For example:
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

// ...

// Example of making a search request:
runBlocking { // Or use viewModelScope.launch if you're inside a ViewModel
    launch {
        try {
            val idToken = "Bearer $idToken"
            val results = apiService.search(idToken, SearchQuery("running events near me"))
            // Process the search results and update the UI
        } catch (e: Exception) {
            // Handle error
        }
    }
}

8. Connect UI to Backend:

  • Design UI: Create the UI elements in your Compose activity (search bar, buttons, result display, etc.).
  • Trigger Network Calls: When the user performs an action (e.g., clicks a search button), trigger the corresponding network call to your backend using the apiService and the idToken.
  • Handle Responses: Update your UI based on the responses you receive from the backend. Display search results, show loading indicators, and handle errors appropriately.

Important Considerations:

  • Backend URL:
    • For local development, you'll likely use a localhost URL with ngrok (as we discussed before).
    • When you deploy your backend, you'll need to update the baseUrl in your Retrofit setup.
  • Error Handling: Implement proper error handling in your network calls and UI to provide a good user experience.
  • Threading: Make sure to perform network calls on a background thread (using coroutines, as shown in the example) to avoid blocking the main thread and causing UI freezes.
  • Security:
    • Always send the ID token in the Authorization header as a Bearer token (e.g., Authorization: Bearer <idToken>).
    • Do not hardcode your Web Client ID directly in your code. Use strings.xml to store it securely.

This comprehensive guide should provide you with a solid foundation for integrating your backend with your Android app.

Remember to replace placeholder values like YOUR_WEB_CLIENT_ID and YOUR_BACKEND_URL with your actual values.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

Status

Backlog

Relationships

None yet

Development

No branches or pull requests

Issue actions