Praktyczny, krok-po-kroku przewodnik prowadzący Cię przez cały cykl produkcji aplikacji — od pierwszego pomysłu aż po publikację w Google Play.
Ten przewodnik opisuje konkretne czynności, które musisz wykonać, żeby ukończyć projekt semestralny z Laboratorium PAM i uzyskać zaliczenie. Każdy krok zawiera listę zadań, wskazówki oraz wymagania, które będą oceniane. Czytaj i realizuj zadania w podanej kolejności.
Zanim napiszesz pierwszą linię kodu, musisz wiedzieć: co budujesz, dla kogo i w jakiej technologii. Poniższe decyzje podejmij razem z zespołem.
SRS (Software Requirements Specification) to podstawowy dokument każdego projektu programistycznego. Opisuje co system ma robić, nie jak. W projekcie PAM zastępują go User Stories z kryteriami akceptacji.
Struktura dokumentu SRS / User Stories:
Jako [rola] chcę [funkcja] aby [korzyść].US-07: Jako zalogowany użytkownik chcę dodać nowe zadanie do listy,
aby móc śledzić swoje obowiązki.
Kryteria akceptacji:
✓ Formularz zawiera pole: tytuł (wymagane), opis, termin, priorytet
✓ Po zapisaniu zadanie pojawia się natychmiast na liście
✓ Walidacja: tytuł nie może być pusty (komunikat błędu)
✓ Zadanie jest persystowane lokalnie (działa offline)
Repozytorium GitHub to centralne miejsce pracy całego zespołu. Prawidłowa konfiguracja od początku uchroni Was przed konfliktami i problemami z historią commitów.
main:
Settings → Branches → Add rule. Zaznacz
"Require a pull request before merging" i
"Require status checks to pass before merging".
main ← tylko stabilny, przetestowany kod develop ← integracja zmian od wszystkich developerów feature/xxx ← nowa funkcja (np. feature/login-screen) fix/xxx ← poprawka błędu release/x.y ← przygotowanie wydania
main — wymagany PR i review przed merge.
Zanim napiszesz kod, musisz zainstalować i skonfigurować odpowiednie narzędzia. Ten krok wykonuje każdy developer w zespole na swoim komputerze.
| Platforma | IDE | SDK / narzędzia | Wymagania sprzętowe |
|---|---|---|---|
| Android (Kotlin) | Android Studio Hedgehog+ | JDK 17, Android SDK 34+, Emulator | 8 GB RAM (16 GB zalecane), 8 GB dysk |
| Flutter | VS Code / Android Studio | Flutter SDK 3.x, Dart, Android SDK | 8 GB RAM, 10 GB dysk |
| Backend (Node.js) | VS Code / IntelliJ | Node.js 20+, npm/yarn, Docker | 4 GB RAM |
git config --global user.name "Imię Nazwisko"
git clone https://github.com/TEAM/REPO.git
git checkout -b develop i wypchnij ją na GitHub:
git push -u origin develop
Prototyp w Figma pozwala "przetestować" UI bez pisania kodu. Oszczędza to czas — poprawki layoutu w Figmie zajmują minuty, a w kodzie — godziny.
Architektura MVVM (Model-View-ViewModel) to standard w aplikacjach Android. Rozdziela logikę biznesową od interfejsu użytkownika — kod jest testowalny i łatwy w utrzymaniu.
pl.prz.pam.taskmaster),
minSdk: 26, targetSdk: 34.
com.example.app/ ├── data/ │ ├── local/ ← Room DAO, Database, entities │ ├── remote/ ← Retrofit API, DTOs │ └── repository/ ← implementacje repozytoriów ├── domain/ │ ├── model/ ← modele domenowe │ └── usecase/ ← logika biznesowa ├── ui/ │ ├── screens/ ← Composables dla każdego ekranu │ │ ├── home/ │ │ ├── detail/ │ │ └── settings/ │ ├── components/ ← reużywalne komponenty UI │ ├── navigation/ ← NavGraph │ └── theme/ ← kolory, typografia, kształty └── di/ ← Hilt / Koin modules
build.gradle.kts:
Hilt (DI), Navigation Compose, Room,
Retrofit, Coil (obrazy), ViewModel Compose.
feature/project-setup
i otwórz Pull Request do develop.
@HiltViewModel
class TaskViewModel @Inject constructor(
private val taskRepository: TaskRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(TaskUiState())
val uiState: StateFlow<TaskUiState> = _uiState.asStateFlow()
fun loadTasks() {
viewModelScope.launch {
taskRepository.getTasks().collect { tasks ->
_uiState.update { it.copy(tasks = tasks, isLoading = false) }
}
}
}
}
Zanim zaczniesz pisać kod, przygotuj fundamenty dla zespołu.
main.feat:, fix:, refactor:..github/pull_request_template.md z opisem zmian i screenshotami UI.Nawigacja to "szkielet" aplikacji łączący wszystkie ekrany. W Jetpack Compose używamy Navigation Compose — deklaratywnego systemu opartego o NavController.
AppNavGraph — composable z NavHost
i wszystkimi composable { } destinacjami.
@Composable
fun AppNavGraph(navController: NavHostController) {
NavHost(navController, startDestination = Screen.Home.route) {
composable(Screen.Home.route) {
HomeScreen(onNavigateToDetail = { id ->
navController.navigate(Screen.Detail.createRoute(id))
})
}
composable(
Screen.Detail.route,
arguments = listOf(navArgument("id") { type = NavType.LongType })
) { backStackEntry ->
val id = backStackEntry.arguments?.getLong("id") ?: return@composable
DetailScreen(itemId = id, onBack = { navController.popBackStack() })
}
}
}
Room to ORM (Object-Relational Mapper) dla SQLite na Androidzie. Umożliwia przechowywanie danych lokalnie — aplikacja działa offline i jest szybsza.
room-runtime, room-ktx
i room-compiler do build.gradle.kts.
@Entity dla każdej tabeli (np. TaskEntity).
@Dao z metodami
@Insert, @Update, @Delete, @Query.
@Database rozszerzającą RoomDatabase.
Użyj Room.databaseBuilder() w module Hilt.
Repository łączącą Room z resztą aplikacji
(ViewModel nie powinien znać Room bezpośrednio).
@Entity(tableName = "tasks")
data class TaskEntity(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val description: String,
val isDone: Boolean = false,
val createdAt: Long = System.currentTimeMillis()
)
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks ORDER BY createdAt DESC")
fun getAllTasks(): Flow<List<TaskEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTask(task: TaskEntity): Long
@Delete
suspend fun deleteTask(task: TaskEntity)
}
Backend zapewnia serwer, bazę danych i API, z którym komunikuje się aplikacja mobilna. Możesz zbudować własny backend (Node.js, Spring Boot, Django) lub skorzystać z gotowej usługi (Firebase, Supabase).
| Opcja backendu | Zalety | Wady |
|---|---|---|
| Firebase (Google) | Szybki start, brak konfiguracji serwera, auth gotowy | Uzależnienie od usługi, ograniczone darmowe limity |
| Node.js + Express | Pełna kontrola, łatwy do nauki | Trzeba skonfigurować hosting |
| Supabase | Open-source Firebase, PostgreSQL, REST auto-generated | Nowa platforma, mniejsza dokumentacja |
EncryptedSharedPreferences lub Keystore,
nigdy w zwykłych SharedPreferences.
To wyróżnik aplikacji mobilnej, funkcje dostępne tylko na smartfonie. Musisz zaimplementować co najmniej 2 natywne funkcje.
Wymagane (min. 2 z listy):
Obowiązkowe kroki:
AndroidManifest.xml.
Kiedy kolega/koleżanka wysyła Ci Pull Request, nie klikaj od razu "Approve". Sprawdź te 4 punkty:
strings.xml? Nigdy nie wpisujemy tekstu "na sztywno" w kodzie Kotlin/Compose.ViewModel, a UI tylko wyświetla dane?MaterialTheme.colorScheme), czy są wpisane jako Color(0xFF...)?Dobre Review pomaga budować lepszy produkt i lepszą atmosferę w zespole.
for moglibyśmy użyć funkcji .filter { ... }. Kod byłby bardziej czytelny i zgodny z naszym stylem Kotlina. Co o tym sądzisz?"
Możesz używać skrótów, aby przyspieszyć komunikację:
Testy zapewniają, że kod działa poprawnie i że przyszłe zmiany niczego nie psują. Wymagane są testy jednostkowe frontendu (≥60% pokrycia logiki) oraz testy integracyjne API (min. 5 scenariuszy).
test/
(testy jednostkowe JVM). Użyj JUnit4 + MockK/Mockito do mockowania zależności.
Testuj ViewModele, UseCases, Repozytoria.
./gradlew test w terminalu.
@ExperimentalCoroutinesApi
class TaskViewModelTest {
@get:Rule val mainCoroutineRule = MainCoroutineRule()
private val mockRepository: TaskRepository = mockk()
private lateinit var viewModel: TaskViewModel
@Before
fun setup() {
every { mockRepository.getTasks() } returns flowOf(listOf(fakeTask))
viewModel = TaskViewModel(mockRepository)
}
@Test
fun `loadTasks emits tasks in uiState`() = runTest {
viewModel.loadTasks()
val state = viewModel.uiState.first()
assertEquals(1, state.tasks.size)
assertEquals("Test Task", state.tasks[0].title)
}
}
CI/CD (Continuous Integration / Continuous Delivery) automatycznie uruchamia build i testy przy każdym Pull Requeście. Dzięki temu błędy są wykrywane natychmiast.
.github/workflows/android-ci.yml
develop lub main
uruchamiał: build projektu i testy jednostkowe.
README.md.
name: Android CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew assembleDebug --no-daemon
- name: Run unit tests
run: ./gradlew test --no-daemon
main.
Po każdym sukcesie w Actions znajdziesz gotowy plik APK do pobrania.
W profesjonalnych zespołach nikt nie wysyła APK "mailem". Dzięki GitHub Actions:
main jest poprawny.Każda aplikacja Android musi być podpisana cyfrowo przed dystrybucją. Google Play wymaga formatu AAB (Android App Bundle). Keystore to Twój "podpis deweloperski" — przechowuj go bezpiecznie i nigdy nie wrzucaj do repozytorium!
.jks w bezpiecznym miejscu poza repozytorium.
build.gradle.kts
(hasła z zmiennych środowiskowych lub local.properties).
versionCode i versionName w build.gradle.kts
(np. versionCode 1, versionName "1.0.0").
.jks i hasła dodaj do .gitignore.
Jeśli stracisz keystore, nie będziesz mógł aktualizować aplikacji w Google Play!
Trzymaj kopię zapasową w bezpiecznym miejscu (np. zaszyfrowany plik w chmurze).
.gitignore).
Dobra dokumentacja to znak profesjonalnego projektu. Jest oceniana i wymagana do publikacji w Google Play. Nie zostawiaj jej na ostatnią chwilę.
CHANGELOG.md): lista zmian w każdej wersji.
Format: keepachangelog.com.
Publikacja w Google Play to finał projektu. Wymaga jednorazowej opłaty rejestracyjnej (25 USD) i weryfikacji konta. Możesz opublikować na kanale testowym (Internal Testing) — nie wymaga pełnego przeglądu Google.
Ostatni krok — zaprezentowanie gotowej aplikacji prowadzącemu. Prezentacja powinna pokazać zarówno produkt (demo aplikacji), jak i proces (GitHub, CI/CD).
Jeśli ukończyłeś wszystkie 18 kroków, Twoja aplikacja jest gotowa do zaliczenia. Projekt semestralny PAM to realne doświadczenie produkcji oprogramowania mobilnego — umiejętności, które będą cenne w Twojej karierze.
"Zmień to, to jest źle napisane. Nie używamy tu pętli for."