App mòbil
Triar la tecnologia i muntar una arquitectura que aguanti tres sprints
Cap tecnologia és obligatòria. El que compta és que la decisió estigui justificada i que el codi sigui net, provat i fàcil de canviar quan el backend o el servei de l'altre equip canviïn.
Les opcions
Android
Kotlin + Jetpack Compose, l'opció oficial. Java o Kotlin amb Views és el món antic: el trobareu en codi heretat.
iOS
Swift + SwiftUI. UIKit és l'opció antiga. Cal un Mac per compilar i per publicar.
Flutter
Dart i un sol codi per a Android, iOS, web i escriptori. Molts paquets a pub.dev i bona integració amb Firebase o Supabase.
React Native
JavaScript o TypeScript amb React. Ionic i Cordova són alternatives més basades en web.
Kotlin Multiplatform
La lògica en Kotlin compartida entre Android i iOS. Amb Compose Multiplatform també compartiu la UI.
Preguntes clau
- Què sap ja l'equip?
- Necessiteu iOS i teniu Mac?
- Hi ha llibreries per al que voleu (mapes, login social, xat)?
- Ho justifiqueu a la memòria?
El mateix model en tres llenguatges
data class Station(val id: Int, val name: String, val freeBikes: Int)
// null safety: si no hi ha estació, un text per defecte
fun label(s: Station?) = s?.name ?: "Desconeguda"
class Station {
final int id;
final String name;
final int freeBikes;
const Station({required this.id, required this.name, required this.freeBikes});
}
String label(Station? s) => s?.name ?? 'Desconeguda';
struct Station: Codable {
let id: Int
let name: String
let freeBikes: Int
}
func label(_ s: Station?) -> String { s?.name ?? "Desconeguda" }
Dues arquitectures que separen la UI de la lògica
La regla és la mateixa: la vista no parla mai directament amb l'API. Així podeu provar la lògica sense pantalles i canviar la font de dades (mock o real) sense tocar la UI.
MVVM (Android, iOS)
El binder és l'enllaç reactiu: StateFlow, LiveData, Combine. La vista observa l'estat i es redibuixa sola (patró Observer).
BLoC (Flutter)
Els events entren (un toc, l'obertura de la pantalla), el BLoC els processa i emet states que la UI pinta.
class StationsViewModel(private val source: StationsDataSource) : ViewModel() {
private val _stations = MutableStateFlow<List<Station>>(emptyList())
val stations: StateFlow<List<Station>> = _stations
init {
viewModelScope.launch { _stations.value = source.getStations().sortedBy { it.name } }
}
}
@Composable
fun StationsScreen(vm: StationsViewModel = koinViewModel()) {
val stations by vm.stations.collectAsStateWithLifecycle()
LazyColumn {
items(stations) { StationRow(it) }
}
}
class StationsBloc {
StationsBloc(this.source);
final StationsDataSource source;
final stations = ValueNotifier<List<Station>>([]);
Future<void> load() async {
final list = await source.getStations();
stations.value = [...list]..sort((a, b) => a.name.compareTo(b.name));
}
}
class StationsPage extends StatelessWidget {
const StationsPage({super.key});
@override
Widget build(BuildContext context) {
final bloc = locator<StationsBloc>();
return ValueListenableBuilder(
valueListenable: bloc.stations,
builder: (context, stations, _) => ListView(
children: [for (final s in stations) StationTile(station: s)],
),
);
}
}
Per a projectes més grans, el paquet flutter_bloc fa explícits els events i els states. Per començar, un ValueNotifier ja separa la lògica de la UI.
Linters: codi a punt per ensenyar
Un linter analitza el codi sense executar-lo i troba errors i problemes d'estil. L'objectiu és un codi net, com un document que algú altre haurà de llegir. Compta per a la gestió de la qualitat.
- Kotlin: ktlint (estil) i detekt (problemes de codi).
- Swift: SwiftLint.
- Dart:
flutter analyzeamb el paquetflutter_lints, idart format. - JavaScript o TypeScript: ESLint i Prettier.
- Tot plegat: SonarQube o SonarCloud per seguir-ho al llarg del curs.
Un test que el mock fa possible
test('ordena les estacions per nom', () async {
final bloc = StationsBloc(FakeStationsDataSource());
await bloc.load();
final names = bloc.stations.value.map((s) => s.name).toList();
expect(names, [...names]..sort());
});
Sense xarxa i en mil·lisegons. Genereu la font de dades falsa al generador i afegiu la cobertura a la memòria (flutter test --coverage, Kover o JaCoCo a Kotlin).
Integració contínua amb GitHub Actions
Cada pull request passa el linter, els tests i el build abans de fusionar-se. És la gestió de configuracions que s'avalua. Deseu el fitxer a .github/workflows/ci.yml. Alternatives: GitLab CI, Jenkins, Codemagic o Azure DevOps.
name: Android CI
on:
pull_request:
push:
branches: [develop, main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Lint, tests i build
run: |
chmod +x gradlew
./gradlew lint testDebugUnitTest assembleDebug
# amb els plugins de ktlint i detekt: ./gradlew ktlintCheck detekt
name: Flutter CI
on:
pull_request:
push:
branches: [develop, main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- run: flutter pub get
- run: dart format --output=none --set-exit-if-changed .
- run: flutter analyze
- run: flutter test --coverage
- run: flutter build apk --debug
Fer arribar l'app a professors i stakeholders
Firebase App Distribution
Envieu cada versió per correu a qui la vulgueu provar, Android i iOS. La manera més còmoda per a PES.
TestFlight
Per a iOS. Cal el programa de desenvolupadors d'Apple.
Google Play i App Store
La pista de proves interna de Google Play és una bona primera passa. També hi ha botigues alternatives com F-Droid.
Per a l'entrega final, la informació de la release ha d'explicar pas a pas com executar l'app. Un APK a GitHub Releases més un enllaç de distribució ho posa molt fàcil. Vegeu el Fag-5 →
Assistents d'IA: sí, però amb ulls
Gemini, Copilot, Claude i similars ajuden a planificar i dissenyar (esborranys d'arquitectura), a generar codi repetitiu, a depurar (explicar errors, refactoritzar) i a automatitzar fluxos amb agents.
- Reviseu, proveu i valideu sempre el codi generat. Si no l'enteneu, no el fusioneu.
- Si els feu servir per a tasques d'enginyeria, expliqueu el procés a la memòria: és un dels aspectes metodològics avaluats.
Exemples i recursos
Dues implementacions de la mateixa app d'estacions de Bicing, mostrades en directe a la sessió de desenvolupament mòbil del curs. Fixeu-vos com separen UI, lògica i dades.
BicingAround
Android: Kotlin, Jetpack Compose i MVVM.
bicing-around-flutter
Flutter: Dart i arquitectura BLoC.
Kotlin i Android
- Kotlin Koans
- Android Basics with Compose
- ViewModel (MVVM)
- Retrofit, per a les peticions REST
- The Clean Architecture
Flutter i Dart
- Documentació de Flutter i el cookbook
- Dart i DartPad, per provar codi al navegador
- Comparativa d'arquitectures de Flutter