355 líneas
13 KiB
Markdown
355 líneas
13 KiB
Markdown
# AleJabber — XMPP/Jabber Client for Android
|
|
|
|
[](.)
|
|
[](.)
|
|
[](LICENSE)
|
|
[](https://kotlinlang.org)
|
|
[](https://developer.android.com/jetpack/compose)
|
|
|
|
A modern, feature-rich XMPP/Jabber messaging client for Android built with **Jetpack Compose** and **Material Design 3**. AleJabber supports multiple accounts, end-to-end encryption (OTR, OMEMO, OpenPGP), multimedia file transfers via `http_upload`, in-app audio recording, group chat rooms, and full accessibility support.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Features](#features)
|
|
2. [Screenshots](#screenshots)
|
|
3. [Architecture](#architecture)
|
|
4. [Project Structure](#project-structure)
|
|
5. [Getting Started](#getting-started)
|
|
6. [Configuration](#configuration)
|
|
7. [Encryption](#encryption)
|
|
8. [Multimedia & Audio](#multimedia--audio)
|
|
9. [Internationalization](#internationalization)
|
|
10. [Accessibility](#accessibility)
|
|
11. [Dependencies](#dependencies)
|
|
12. [Contributing](#contributing)
|
|
13. [License](#license)
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
| Feature | Description |
|
|
|---------|-------------|
|
|
| 🔐 **OTR Encryption** | Off-the-Record messaging with perfect forward secrecy |
|
|
| 🔒 **OMEMO Encryption** | XEP-0384 multi-device end-to-end encryption (recommended) |
|
|
| 🗝️ **OpenPGP** | Asymmetric PGP encryption via XEP-0373/0374 |
|
|
| 👥 **Multi-Account** | Manage multiple XMPP accounts from different servers |
|
|
| 💬 **Group Rooms (MUC)** | Join and manage Multi-User Chat rooms (XEP-0045) |
|
|
| 📎 **File Transfer** | Upload images, audio, and files via XEP-0363 `http_upload` |
|
|
| 🎙️ **Audio Messages** | Record and send voice messages directly from the app |
|
|
| 🔔 **Smart Notifications** | Per-account notification channels with vibration/sound control |
|
|
| 🌐 **Multilingual** | English 🇬🇧, Spanish 🇪🇸, Chinese 🇨🇳 |
|
|
| ♿ **Accessible** | Full TalkBack support with content descriptions and semantic roles |
|
|
| 🎨 **Material You** | Dynamic theming with Light/Dark/System modes |
|
|
| 🔄 **Auto-Reconnect** | Automatic reconnection with random increasing delay policy |
|
|
| 💾 **Offline Storage** | Room database caches messages for offline reading |
|
|
|
|
---
|
|
|
|
## Screenshots
|
|
|
|
> _Screenshots to be added after first device deployment._
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
AleJabber follows **Clean Architecture** with an **MVVM** presentation layer:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────┐
|
|
│ Presentation Layer │
|
|
│ Compose Screens ←→ ViewModels ←→ UI State │
|
|
├─────────────────────────────────────────────────────┤
|
|
│ Domain Layer │
|
|
│ Models · Use Cases · Repository Interfaces │
|
|
├─────────────────────────────────────────────────────┤
|
|
│ Data Layer │
|
|
│ Room DB · Smack XMPP · DataStore · OkHttp │
|
|
└─────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Key Patterns
|
|
|
|
- **Dependency Injection**: Hilt (Dagger-based)
|
|
- **Reactive Streams**: Kotlin `Flow` + `StateFlow` + `SharedFlow`
|
|
- **Navigation**: Jetpack Navigation Compose with type-safe routes
|
|
- **Background Work**: `XmppForegroundService` keeps connections alive
|
|
- **Persistence**: Room with KSP-generated DAOs
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
app/src/main/java/com/manalejandro/alejabber/
|
|
├── AleJabberApp.kt # Application class with Hilt initialization
|
|
├── MainActivity.kt # Single-Activity entry point
|
|
│
|
|
├── data/
|
|
│ ├── local/
|
|
│ │ ├── AppDatabase.kt # Room database definition
|
|
│ │ ├── dao/ # Data Access Objects (AccountDao, MessageDao, ContactDao, RoomDao)
|
|
│ │ └── entity/ # Room entities (AccountEntity, MessageEntity, etc.)
|
|
│ ├── remote/
|
|
│ │ └── XmppConnectionManager.kt # Smack connection lifecycle manager
|
|
│ └── repository/
|
|
│ ├── AccountRepository.kt
|
|
│ ├── ContactRepository.kt
|
|
│ ├── MessageRepository.kt
|
|
│ └── RoomRepository.kt
|
|
│
|
|
├── domain/
|
|
│ └── model/ # Pure Kotlin domain models
|
|
│ ├── Account.kt # XMPP account model
|
|
│ ├── Contact.kt # Roster contact
|
|
│ ├── Message.kt # Chat message with encryption + media metadata
|
|
│ ├── Room.kt # MUC room
|
|
│ └── Enums.kt # EncryptionType, MessageStatus, PresenceStatus, etc.
|
|
│
|
|
├── di/
|
|
│ └── AppModule.kt # Hilt module: DB, OkHttp, DataStore, XmppManager
|
|
│
|
|
├── media/
|
|
│ ├── AudioRecorder.kt # MediaRecorder wrapper with StateFlow
|
|
│ └── HttpUploadManager.kt # XEP-0363 file upload via OkHttp
|
|
│
|
|
├── service/
|
|
│ ├── XmppForegroundService.kt # Foreground service keeping XMPP alive
|
|
│ └── BootReceiver.kt # BroadcastReceiver to restart on boot
|
|
│
|
|
└── ui/
|
|
├── theme/
|
|
│ ├── Color.kt # Brand colors + bubble colors
|
|
│ ├── Theme.kt # Material3 dynamic theme with AppTheme enum
|
|
│ └── Type.kt # Typography scale
|
|
├── navigation/
|
|
│ ├── Screen.kt # Sealed class route definitions
|
|
│ └── AleJabberNavGraph.kt # NavHost with all destinations
|
|
├── components/
|
|
│ ├── AvatarWithStatus.kt # Avatar + presence dot component
|
|
│ └── EncryptionBadge.kt # Encryption type indicator badge
|
|
├── accounts/
|
|
│ ├── AccountsScreen.kt # Account list with connect/disconnect
|
|
│ ├── AccountsViewModel.kt
|
|
│ └── AddEditAccountScreen.kt # Add/edit XMPP account form
|
|
├── contacts/
|
|
│ ├── ContactsScreen.kt # Roster list with search + presence
|
|
│ └── ContactsViewModel.kt
|
|
├── rooms/
|
|
│ ├── RoomsScreen.kt # MUC rooms list
|
|
│ └── RoomsViewModel.kt
|
|
├── chat/
|
|
│ ├── ChatScreen.kt # Full chat UI with bubbles, media, recording
|
|
│ └── ChatViewModel.kt
|
|
└── settings/
|
|
├── SettingsScreen.kt # App preferences
|
|
└── SettingsViewModel.kt
|
|
```
|
|
|
|
---
|
|
|
|
## Getting Started
|
|
|
|
### Prerequisites
|
|
|
|
- Android Studio Hedgehog (2023.1.1) or later
|
|
- JDK 11+
|
|
- Android SDK 36
|
|
- A running XMPP server (e.g., [ejabberd](https://www.ejabberd.im/), [Prosody](https://prosody.im/), [Openfire](https://www.igniterealtime.org/projects/openfire/))
|
|
|
|
### Build
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone https://github.com/manalejandro/AleJabber.git
|
|
cd AleJabber
|
|
|
|
# Build debug APK
|
|
./gradlew assembleDebug
|
|
|
|
# Install on connected device
|
|
./gradlew installDebug
|
|
|
|
# Run unit tests
|
|
./gradlew test
|
|
|
|
# Run instrumented tests
|
|
./gradlew connectedAndroidTest
|
|
```
|
|
|
|
The debug APK will be at:
|
|
```
|
|
app/build/outputs/apk/debug/app-debug.apk
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
### Adding an XMPP Account
|
|
|
|
1. Open the app → tap **Accounts** tab
|
|
2. Press the **+** FAB
|
|
3. Fill in:
|
|
- **JID** — your full Jabber ID, e.g. `user@jabber.org`
|
|
- **Password** — your account password
|
|
- **Server** _(optional)_ — override DNS-resolved hostname
|
|
- **Port** _(default: 5222)_ — custom port if needed
|
|
- **TLS** — toggle to require TLS (recommended)
|
|
- **Resource** _(default: AleJabber)_ — client resource identifier
|
|
|
|
### Gradle Properties
|
|
|
|
`gradle.properties` contains build-time flags:
|
|
|
|
| Property | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `android.disallowKotlinSourceSets` | `false` | Required for KSP + AGP 9.x compatibility |
|
|
| `org.gradle.jvmargs` | `-Xmx2048m` | Gradle daemon heap size |
|
|
| `android.useAndroidX` | `true` | AndroidX migration flag |
|
|
|
|
---
|
|
|
|
## Encryption
|
|
|
|
AleJabber supports three levels of end-to-end encryption, selectable per conversation:
|
|
|
|
### OMEMO (Recommended — XEP-0384)
|
|
- Multi-device, forward-secrecy encryption based on the Signal Protocol
|
|
- Works even when the recipient is offline
|
|
- Select **OMEMO** in the encryption picker (🔒 icon in chat toolbar)
|
|
|
|
### OTR (Off-the-Record — XEP-0364)
|
|
- Classic two-party encryption with perfect forward secrecy
|
|
- Requires both parties to be online simultaneously
|
|
- Best for high-privacy one-on-one conversations
|
|
|
|
### OpenPGP (XEP-0373/0374)
|
|
- Asymmetric RSA/ECC encryption using PGP key pairs
|
|
- Works offline; keys must be exchanged in advance
|
|
- Uses Bouncy Castle (`bcpg-jdk18on`, `bcprov-jdk18on`)
|
|
|
|
### None (Plain Text)
|
|
- Messages are sent unencrypted over the TLS-secured XMPP stream
|
|
- Only use on trusted, private servers
|
|
|
|
---
|
|
|
|
## Multimedia & Audio
|
|
|
|
### File Upload (XEP-0363 `http_upload`)
|
|
1. Tap the 📎 attach button in the chat input
|
|
2. Select any file from the device storage
|
|
3. AleJabber requests an upload slot from the XMPP server
|
|
4. The file is PUT to the provided URL via OkHttp
|
|
5. The download URL is sent as a message body
|
|
6. Images are auto-rendered inline in the chat bubble
|
|
|
|
### Audio Messages
|
|
1. In the chat input, press and hold the 🎙️ microphone button
|
|
2. Speak your message — a recording timer appears
|
|
3. Release to **send**, or tap **✕** to cancel
|
|
4. Audio is recorded with `MediaRecorder` (AAC/MP4 format)
|
|
5. The recording is uploaded via `http_upload` automatically
|
|
|
|
> **Note:** Microphone permission (`RECORD_AUDIO`) is requested on first use.
|
|
|
|
---
|
|
|
|
## Internationalization
|
|
|
|
AleJabber ships with three locale bundles:
|
|
|
|
| Locale | File |
|
|
|--------|------|
|
|
| English (default) | `app/src/main/res/values/strings.xml` |
|
|
| Spanish | `app/src/main/res/values-es/strings.xml` |
|
|
| Chinese (Simplified) | `app/src/main/res/values-zh/strings.xml` |
|
|
|
|
To add a new language:
|
|
1. Create `app/src/main/res/values-<locale>/strings.xml`
|
|
2. Copy all keys from the default `strings.xml`
|
|
3. Translate each string value
|
|
|
|
---
|
|
|
|
## Accessibility
|
|
|
|
AleJabber is designed to be fully usable with Android's TalkBack screen reader:
|
|
|
|
- All interactive elements have `contentDescription` labels
|
|
- Message status icons (sent, delivered, read) announce their state
|
|
- Recording timer is announced to screen readers
|
|
- Encryption badge announces the current encryption type
|
|
- Avatar components announce contact name and presence status
|
|
- The app passes the [Accessibility Scanner](https://support.google.com/accessibility/android/answer/6376559) basic checks
|
|
|
|
---
|
|
|
|
## Dependencies
|
|
|
|
| Library | Version | Purpose |
|
|
|---------|---------|---------|
|
|
| Jetpack Compose BOM | 2024.09.00 | UI framework |
|
|
| Material3 | (via BOM) | Design system |
|
|
| Hilt | 2.59.2 | Dependency injection |
|
|
| Room | 2.7.0 | Local database |
|
|
| Navigation Compose | 2.9.0 | In-app navigation |
|
|
| Smack (XMPP) | 4.4.8 | XMPP protocol implementation |
|
|
| OkHttp | 4.12.0 | HTTP file uploads |
|
|
| Coil | 2.7.0 | Image loading |
|
|
| DataStore | 1.1.1 | Settings persistence |
|
|
| Accompanist Permissions | 0.36.0 | Runtime permission handling |
|
|
| Bouncy Castle | 1.78.1 | OpenPGP crypto |
|
|
| Coroutines | 1.9.0 | Async/reactive programming |
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Please follow these steps:
|
|
|
|
1. Fork the repository
|
|
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
3. Commit your changes: `git commit -m "feat: add my feature"`
|
|
4. Push to the branch: `git push origin feature/my-feature`
|
|
5. Open a Pull Request
|
|
|
|
### Code Style
|
|
- Follow [Kotlin coding conventions](https://kotlinlang.org/docs/coding-conventions.html)
|
|
- Use `ktlint` for formatting: `./gradlew ktlintCheck`
|
|
- Write KDoc comments for all public functions and classes
|
|
- Add unit tests for ViewModels and Repository classes
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
```
|
|
MIT License
|
|
|
|
Copyright (c) 2026 Manuel Alejandro
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
```
|
|
|