Bird
Raised Fist0
Android Kotlinmobile~20 mins

Signing configuration in Android Kotlin - Mini App: Build & Ship

Choose your learning style10 modes available
Build: App Signing Setup
This screen helps you configure signing settings for your Android app to prepare it for release.
Target UI
---------------------------------
|       App Signing Setup        |
|-------------------------------|
| Keystore Path: [_____________] |
| Keystore Password: [_________] |
| Key Alias: [_______________]   |
| Key Password: [_____________]  |
|                               |
| [Save Configuration]           |
---------------------------------
Add input fields for keystore path, keystore password, key alias, and key password.
Add a Save Configuration button that validates inputs and shows a confirmation message.
Use secure input for password fields.
Layout should be scrollable if needed and accessible.
Starter Code
Android Kotlin
package com.example.signingconfig

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp

class SigningConfigActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      SigningConfigScreen()
    }
  }
}

@Composable
fun SigningConfigScreen() {
  // TODO: Add input fields and Save button here
}
Task 1
Task 2
Task 3
Task 4
Solution
Android Kotlin
package com.example.signingconfig

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp

class SigningConfigActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      SigningConfigScreen()
    }
  }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SigningConfigScreen() {
  var keystorePath by remember { mutableStateOf("") }
  var keystorePassword by remember { mutableStateOf("") }
  var keyAlias by remember { mutableStateOf("") }
  var keyPassword by remember { mutableStateOf("") }
  var savedMessage by remember { mutableStateOf("") }

  Column(
    modifier = Modifier
      .fillMaxSize()
      .padding(16.dp),
    verticalArrangement = Arrangement.spacedBy(12.dp)
  ) {
    Text(text = "App Signing Setup", style = MaterialTheme.typography.headlineMedium)

    OutlinedTextField(
      value = keystorePath,
      onValueChange = { keystorePath = it },
      label = { Text("Keystore Path") },
      singleLine = true,
      modifier = Modifier.fillMaxWidth()
    )

    OutlinedTextField(
      value = keystorePassword,
      onValueChange = { keystorePassword = it },
      label = { Text("Keystore Password") },
      singleLine = true,
      visualTransformation = PasswordVisualTransformation(),
      keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
      modifier = Modifier.fillMaxWidth()
    )

    OutlinedTextField(
      value = keyAlias,
      onValueChange = { keyAlias = it },
      label = { Text("Key Alias") },
      singleLine = true,
      modifier = Modifier.fillMaxWidth()
    )

    OutlinedTextField(
      value = keyPassword,
      onValueChange = { keyPassword = it },
      label = { Text("Key Password") },
      singleLine = true,
      visualTransformation = PasswordVisualTransformation(),
      keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
      modifier = Modifier.fillMaxWidth()
    )

    Button(
      onClick = {
        if (keystorePath.isBlank() || keystorePassword.isBlank() || keyAlias.isBlank() || keyPassword.isBlank()) {
          savedMessage = "Please fill in all fields."
        } else {
          savedMessage = "Signing configuration saved successfully!"
        }
      },
      modifier = Modifier.fillMaxWidth()
    ) {
      Text("Save Configuration")
    }

    if (savedMessage.isNotEmpty()) {
      Text(text = savedMessage, color = MaterialTheme.colorScheme.primary)
    }
  }
}

This solution uses Jetpack Compose to build a simple form for signing configuration.

We use OutlinedTextField for each input. Password fields use PasswordVisualTransformation to hide input characters.

The Save button checks if any field is empty and shows a message accordingly.

The layout uses a vertical Column with spacing and padding for a clean look.

Final Result
Completed Screen
---------------------------------
|       App Signing Setup        |
|-------------------------------|
| Keystore Path: [my/path/keystore.jks] |
| Keystore Password: [••••••••] |
| Key Alias: [mykey]             |
| Key Password: [••••••••]       |
|                               |
| [Save Configuration]           |
|                               |
| Signing configuration saved   |
| successfully!                 |
---------------------------------
User types keystore path and passwords into fields.
Passwords show dots instead of characters.
Tapping Save Configuration validates inputs.
If any field is empty, shows 'Please fill in all fields.' message.
If all fields filled, shows 'Signing configuration saved successfully!' message.
Stretch Goal
Add a file picker button next to the Keystore Path field to select the keystore file from device storage.
💡 Hint
Use Android's Storage Access Framework with an Intent to pick a file and update the keystore path state.

Practice

(1/5)
1.

What is the main purpose of a signing configuration in Android app development?

easy
A. To prove the app's identity and allow publishing
B. To increase app performance
C. To change the app's user interface
D. To add new features automatically

Solution

  1. Step 1: Understand signing configuration role

    Signing configuration is used to prove the app's identity to Google Play and users.
  2. Step 2: Identify its necessity for publishing

    Without signing, apps cannot be published or updated on app stores.
  3. Final Answer:

    To prove the app's identity and allow publishing -> Option A
  4. Quick Check:

    Signing config = app identity proof [OK]
Hint: Signing config proves app identity for publishing [OK]
Common Mistakes:
  • Thinking signing improves app speed
  • Confusing signing with UI changes
  • Assuming signing adds features automatically
2.

Which of the following is the correct syntax to define a signing configuration in build.gradle?

signingConfigs {
    release {
        keyAlias 'myKey'
        keyPassword 'myPass'
        storeFile file('mykeystore.jks')
        storePassword 'storePass'
    }
}
easy
A. signingConfigs { release { keyAlias = 'myKey' keyPassword = 'myPass' storeFile = file('mykeystore.jks') storePassword = 'storePass' } }
B. signingConfigs { release { keyAlias 'myKey' keyPassword 'myPass' storeFile file('mykeystore.jks') storePassword 'storePass' } }
C. signingConfigs release { keyAlias = 'myKey' keyPassword = 'myPass' storeFile = file('mykeystore.jks') storePassword = 'storePass' }
D. signingConfigs { release { keyAlias: 'myKey' keyPassword: 'myPass' storeFile: file('mykeystore.jks') storePassword: 'storePass' } }

Solution

  1. Step 1: Check Gradle Groovy DSL syntax for properties

    In Gradle Groovy DSL (build.gradle), properties are assigned without '=' but by space, e.g., keyAlias 'myKey'.
  2. Step 2: Verify correct block structure

    The signingConfigs block must wrap the release block with properties assigned without '='.
  3. Final Answer:

    signingConfigs { release { keyAlias 'myKey' keyPassword 'myPass' storeFile file('mykeystore.jks') storePassword 'storePass' } } -> Option B
  4. Quick Check:

    Groovy DSL uses space for property assignment [OK]
Hint: Use space (no '=') for property assignment in Groovy Gradle blocks [OK]
Common Mistakes:
  • Using '=' in Groovy DSL instead of space
  • Using ':' instead of '=' or space
  • Not wrapping properties inside release block
3.

Given this build.gradle snippet, what signing configuration will be used when building the release version?

android {
  signingConfigs {
    debug {
      keyAlias = 'debugKey'
    }
    release {
      keyAlias = 'releaseKey'
    }
  }
  buildTypes {
    release {
      signingConfig signingConfigs.release
    }
    debug {
      signingConfig signingConfigs.debug
    }
  }
}
medium
A. releaseKey
B. Both debugKey and releaseKey
C. No signing configuration used
D. debugKey

Solution

  1. Step 1: Identify signingConfig for release buildType

    The release buildType uses signingConfigs.release as its signingConfig.
  2. Step 2: Check keyAlias in release signingConfig

    The release signingConfig has keyAlias set to 'releaseKey'.
  3. Final Answer:

    releaseKey -> Option A
  4. Quick Check:

    release build uses release signingConfig [OK]
Hint: Release build uses signingConfigs.release [OK]
Common Mistakes:
  • Confusing debug and release signingConfigs
  • Assuming no signingConfig is set
  • Thinking both keys are used simultaneously
4.

What is the error in this signing configuration snippet?

signingConfigs {
  release {
    keyAlias = 'myKey'
    keyPassword = 'pass'
    storeFile = 'mykeystore.jks'
    storePassword = 'storePass'
  }
}
medium
A. storePassword is missing
B. keyAlias must be a number
C. storeFile should use file() function
D. keyPassword cannot be set

Solution

  1. Step 1: Check storeFile assignment

    storeFile must be assigned a File object using file('filename'), not a plain string.
  2. Step 2: Confirm other properties are correct

    keyAlias, keyPassword, and storePassword are correctly assigned strings.
  3. Final Answer:

    storeFile should use file() function -> Option C
  4. Quick Check:

    storeFile = file('path') required [OK]
Hint: Use file() for storeFile path in signingConfigs [OK]
Common Mistakes:
  • Assigning storeFile directly as string
  • Confusing keyAlias type
  • Omitting storePassword
5.

You want to create a signing configuration that uses different keystores for debug and release builds. How should you configure build.gradle to achieve this?

android {
  signingConfigs {
    debug {
      keyAlias = 'debugKey'
      keyPassword = 'debugPass'
      storeFile = file('debug.keystore')
      storePassword = 'debugStorePass'
    }
    release {
      keyAlias = 'releaseKey'
      keyPassword = 'releasePass'
      storeFile = file('release.keystore')
      storePassword = 'releaseStorePass'
    }
  }
  buildTypes {
    debug {
      signingConfig signingConfigs.debug
    }
    release {
      signingConfig signingConfigs.release
    }
  }
}

What will happen if you build the debug version?

hard
A. Build will fail due to missing signingConfig
B. The app will be signed with the release keystore
C. The app will not be signed
D. The app will be signed with the debug keystore

Solution

  1. Step 1: Check signingConfig assigned to debug buildType

    The debug buildType uses signingConfigs.debug as its signingConfig.
  2. Step 2: Identify keystore used for debug build

    SigningConfigs.debug uses 'debug.keystore' with its own keys and passwords.
  3. Final Answer:

    The app will be signed with the debug keystore -> Option D
  4. Quick Check:

    Debug build uses debug signingConfig [OK]
Hint: Debug build uses debug keystore signingConfig [OK]
Common Mistakes:
  • Assuming debug uses release keystore
  • Thinking build fails without explicit signingConfig
  • Believing app is unsigned by default
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard