feat: Initial IPTV app with Google DNS and in-app updates
This commit is contained in:
556
README.md
Normal file
556
README.md
Normal file
@@ -0,0 +1,556 @@
|
||||
# IPTV Player
|
||||
|
||||
A modern, feature-rich Android IPTV streaming application built with Jetpack Compose and Media3 ExoPlayer. This app allows users to stream live TV channels from M3U/M3U8 playlists with a beautiful Material Design 3 interface.
|
||||
|
||||
## Features
|
||||
|
||||
### Core Features
|
||||
- **IPTV Streaming**: Stream live TV channels from M3U/M3U8 playlists
|
||||
- **Channel Categories**: Automatic grouping of channels by category (Sports, News, Movies, Kids, etc.)
|
||||
- **Search Functionality**: Real-time search with debouncing for quick channel discovery
|
||||
- **Favorites Management**: Mark channels as favorites for quick access
|
||||
- **Offline Caching**: 24-hour channel cache for offline browsing
|
||||
- **Pull-to-Refresh**: Swipe down to refresh channel list
|
||||
|
||||
### Player Features
|
||||
- **Media3 ExoPlayer**: Modern, extensible media player with HLS/DASH support
|
||||
- **Fullscreen Mode**: Immersive landscape playback with gesture controls
|
||||
- **Audio Focus Management**: Proper audio focus handling with ducking support
|
||||
- **Multiple Audio Tracks**: Support for multi-language audio streams
|
||||
- **Video Quality Selection**: Auto and manual quality selection
|
||||
- **Subtitle Support**: Multi-language subtitle track selection
|
||||
- **Picture-in-Picture**: Background playback support (Android O+)
|
||||
|
||||
### UI/UX Features
|
||||
- **Material Design 3**: Modern, responsive UI with dynamic theming
|
||||
- **Jetpack Compose**: Declarative UI with smooth animations
|
||||
- **Responsive Grid Layout**: Adaptive channel grid (2 columns)
|
||||
- **Category Filter Chips**: Horizontal scrolling category selection
|
||||
- **Loading States**: Skeleton screens and progress indicators
|
||||
- **Error Handling**: User-friendly error messages with retry options
|
||||
|
||||
### TV Support
|
||||
- **Android TV Compatible**: Leanback launcher support
|
||||
- **D-Pad Navigation**: Full remote control support
|
||||
- **TV-Optimized UI**: Large, focusable UI elements
|
||||
|
||||
## Screenshots
|
||||
|
||||
> **Note**: Add your screenshots to the `screenshots/` directory and update the paths below.
|
||||
|
||||
| Channels List | Player | Categories |
|
||||
|--------------|--------|------------|
|
||||
|  |  |  |
|
||||
|
||||
| Search | Favorites | Settings |
|
||||
|--------|-----------|----------|
|
||||
|  |  |  |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before building the project, ensure you have the following installed:
|
||||
|
||||
### Required
|
||||
- **Android Studio Hedgehog (2023.1.1)** or later
|
||||
- **JDK 17** or later
|
||||
- **Android SDK** with the following:
|
||||
- SDK Platform API 34 (Android 14)
|
||||
- Build-Tools 34.0.0
|
||||
- Android SDK Command-line Tools
|
||||
|
||||
### Optional
|
||||
- **Git** for version control
|
||||
- **Android Device** or **Emulator** running Android 7.0 (API 24) or higher
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yourusername/iptv-app.git
|
||||
cd iptv-app
|
||||
```
|
||||
|
||||
### 2. Open in Android Studio
|
||||
|
||||
1. Launch Android Studio
|
||||
2. Select "Open an existing Android Studio project"
|
||||
3. Navigate to the cloned directory and click "OK"
|
||||
4. Wait for Gradle sync to complete
|
||||
|
||||
### 3. Build the Project
|
||||
|
||||
```bash
|
||||
# Build debug APK
|
||||
./gradlew assembleDebug
|
||||
|
||||
# Build release APK (requires signing configuration)
|
||||
./gradlew assembleRelease
|
||||
```
|
||||
|
||||
### 4. Run on Device
|
||||
|
||||
```bash
|
||||
# Connect your Android device or start an emulator
|
||||
# Run the app
|
||||
./gradlew installDebug
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Changing the M3U Playlist URL
|
||||
|
||||
The default M3U URL can be configured in the following locations:
|
||||
|
||||
#### Option 1: Build Configuration (Recommended)
|
||||
|
||||
Edit `app/build.gradle.kts` and add a build config field:
|
||||
|
||||
```kotlin
|
||||
android {
|
||||
defaultConfig {
|
||||
buildConfigField("String", "DEFAULT_M3U_URL", "\"https://your-playlist-url.com/playlist.m3u\"")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then access it in code:
|
||||
```kotlin
|
||||
val m3uUrl = BuildConfig.DEFAULT_M3U_URL
|
||||
```
|
||||
|
||||
#### Option 2: Constants File
|
||||
|
||||
Create or edit `app/src/main/java/com/iptv/app/Constants.kt`:
|
||||
|
||||
```kotlin
|
||||
package com.iptv.app
|
||||
|
||||
object Constants {
|
||||
const val DEFAULT_M3U_URL = "https://your-playlist-url.com/playlist.m3u"
|
||||
|
||||
// Optional: Multiple playlist support
|
||||
val PLAYLISTS = mapOf(
|
||||
"Default" to "https://example.com/playlist1.m3u",
|
||||
"Sports" to "https://example.com/sports.m3u",
|
||||
"News" to "https://example.com/news.m3u"
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Option 3: Settings UI (User-Configurable)
|
||||
|
||||
The app supports runtime playlist URL changes through the Settings screen. Users can:
|
||||
1. Open Settings
|
||||
2. Tap "Playlist URL"
|
||||
3. Enter a new M3U/M3U8 URL
|
||||
4. Tap "Save" to apply changes
|
||||
|
||||
### Supported Playlist Formats
|
||||
|
||||
The app supports standard M3U/M3U8 playlist formats:
|
||||
|
||||
```m3u
|
||||
#EXTM3U
|
||||
|
||||
#EXTINF:-1 tvg-id="channel1" tvg-logo="http://logo.png" group-title="News",CNN
|
||||
http://stream-url.com/cnn.m3u8
|
||||
|
||||
#EXTINF:-1 tvg-id="channel2" tvg-logo="http://logo.png" group-title="Sports",ESPN
|
||||
http://stream-url.com/espn.m3u8
|
||||
```
|
||||
|
||||
**Supported Attributes:**
|
||||
- `tvg-id`: Channel identifier
|
||||
- `tvg-logo`: Channel logo URL
|
||||
- `group-title`: Category/group name
|
||||
- `tvg-language`: Channel language
|
||||
- `tvg-country`: Channel country
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### MVVM Architecture
|
||||
|
||||
The app follows the Model-View-ViewModel (MVVM) architecture pattern:
|
||||
|
||||
```
|
||||
UI Layer (Compose Screens)
|
||||
|
|
||||
v
|
||||
ViewModel Layer (State Management)
|
||||
|
|
||||
v
|
||||
Repository Layer (Data Operations)
|
||||
|
|
||||
v
|
||||
Data Layer (Models, Parsers, Network)
|
||||
```
|
||||
|
||||
### Repository Pattern
|
||||
|
||||
The `ChannelRepository` acts as a single source of truth for channel data:
|
||||
|
||||
- **Data Fetching**: Fetches from network with Retrofit/OkHttp
|
||||
- **Caching**: Local cache with 24-hour expiration
|
||||
- **Favorites**: Persistent storage with SharedPreferences
|
||||
- **Search**: Debounced search with Flow operators
|
||||
- **Filtering**: Category-based filtering
|
||||
|
||||
### Media3 ExoPlayer Integration
|
||||
|
||||
The `PlayerManager` class provides:
|
||||
|
||||
- **Player Lifecycle**: Proper creation and disposal
|
||||
- **Audio Focus**: System audio focus handling
|
||||
- **Track Selection**: Quality and audio track switching
|
||||
- **State Management**: Playback state observation
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
IPTVApp/
|
||||
├── app/
|
||||
│ ├── src/main/java/com/iptv/app/
|
||||
│ │ ├── data/
|
||||
│ │ │ ├── model/
|
||||
│ │ │ │ ├── Channel.kt # Channel data class
|
||||
│ │ │ │ └── Category.kt # Category data class
|
||||
│ │ │ └── repository/
|
||||
│ │ │ └── ChannelRepository.kt # Data repository
|
||||
│ │ ├── ui/
|
||||
│ │ │ ├── components/ # Reusable UI components
|
||||
│ │ │ │ ├── ChannelCard.kt
|
||||
│ │ │ │ ├── CategoryChip.kt
|
||||
│ │ │ │ ├── VideoPlayer.kt
|
||||
│ │ │ │ └── PlayerControls.kt
|
||||
│ │ │ ├── screens/ # Screen composables
|
||||
│ │ │ │ ├── ChannelsScreen.kt
|
||||
│ │ │ │ └── PlayerScreen.kt
|
||||
│ │ │ ├── theme/ # Material 3 theme
|
||||
│ │ │ │ ├── Color.kt
|
||||
│ │ │ │ ├── Type.kt
|
||||
│ │ │ │ └── Theme.kt
|
||||
│ │ │ └── viewmodel/ # ViewModels
|
||||
│ │ │ ├── ChannelsViewModel.kt
|
||||
│ │ │ └── PlayerViewModel.kt
|
||||
│ │ └── utils/
|
||||
│ │ ├── M3UParser.kt # M3U playlist parser
|
||||
│ │ └── PlayerManager.kt # ExoPlayer wrapper
|
||||
│ ├── src/main/res/
|
||||
│ │ ├── values/
|
||||
│ │ │ ├── strings.xml # App strings
|
||||
│ │ │ ├── colors.xml # Color resources
|
||||
│ │ │ └── themes.xml # Theme resources
|
||||
│ │ └── xml/
|
||||
│ │ └── network_security_config.xml
|
||||
│ └── build.gradle.kts # App-level build config
|
||||
├── build.gradle.kts # Project-level build config
|
||||
├── settings.gradle.kts # Project settings
|
||||
└── gradle.properties # Gradle properties
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Core Android
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `core-ktx` | 1.12.0 | Kotlin extensions |
|
||||
| `lifecycle-runtime-ktx` | 2.6.2 | Lifecycle awareness |
|
||||
| `activity-compose` | 1.8.1 | Compose activity |
|
||||
|
||||
### Jetpack Compose
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `compose-bom` | 2023.10.01 | Bill of Materials |
|
||||
| `material3` | - | Material Design 3 |
|
||||
| `material-icons-extended` | - | Extended icons |
|
||||
| `lifecycle-viewmodel-compose` | 2.6.2 | ViewModel integration |
|
||||
| `navigation-compose` | 2.7.5 | Navigation |
|
||||
|
||||
### Media Playback
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `media3-exoplayer` | 1.2.0 | Core player |
|
||||
| `media3-exoplayer-hls` | 1.2.0 | HLS streaming |
|
||||
| `media3-exoplayer-dash` | 1.2.0 | DASH streaming |
|
||||
| `media3-ui` | 1.2.0 | Player UI |
|
||||
| `media3-session` | 1.2.0 | Media session |
|
||||
|
||||
### Networking
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `retrofit` | 2.9.0 | HTTP client |
|
||||
| `okhttp` | 4.12.0 | HTTP engine |
|
||||
| `logging-interceptor` | 4.12.0 | Request logging |
|
||||
|
||||
### Image Loading
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `coil-compose` | 2.5.0 | Image loading |
|
||||
|
||||
### Coroutines
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `kotlinx-coroutines-android` | 1.7.3 | Async operations |
|
||||
|
||||
### JSON Parsing
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `gson` | 2.10.1 | JSON serialization |
|
||||
|
||||
### Testing
|
||||
| Dependency | Version | Purpose |
|
||||
|------------|---------|---------|
|
||||
| `junit` | 4.13.2 | Unit testing |
|
||||
| `espresso-core` | 3.5.1 | UI testing |
|
||||
| `compose-ui-test-junit4` | - | Compose testing |
|
||||
|
||||
## Building the APK
|
||||
|
||||
### Debug APK
|
||||
|
||||
```bash
|
||||
# Build debug APK
|
||||
./gradlew assembleDebug
|
||||
|
||||
# Output location:
|
||||
# app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
### Release APK
|
||||
|
||||
1. **Create a signing keystore** (if not exists):
|
||||
|
||||
```bash
|
||||
keytool -genkey -v -keystore iptv-release.keystore -alias iptv -keyalg RSA -keysize 2048 -validity 10000
|
||||
```
|
||||
|
||||
2. **Configure signing** in `app/build.gradle.kts`:
|
||||
|
||||
```kotlin
|
||||
android {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
storeFile = file("iptv-release.keystore")
|
||||
storePassword = System.getenv("STORE_PASSWORD") ?: "your-password"
|
||||
keyAlias = "iptv"
|
||||
keyPassword = System.getenv("KEY_PASSWORD") ?: "your-password"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Build release APK**:
|
||||
|
||||
```bash
|
||||
# Build release APK
|
||||
./gradlew assembleRelease
|
||||
|
||||
# Output location:
|
||||
# app/build/outputs/apk/release/app-release.apk
|
||||
```
|
||||
|
||||
### App Bundle (Google Play)
|
||||
|
||||
```bash
|
||||
# Build AAB for Google Play
|
||||
./gradlew bundleRelease
|
||||
|
||||
# Output location:
|
||||
# app/build/outputs/bundle/release/app-release.aab
|
||||
```
|
||||
|
||||
## Installing on Android Device
|
||||
|
||||
### Method 1: Android Studio
|
||||
|
||||
1. Connect your Android device via USB
|
||||
2. Enable USB debugging in Developer Options
|
||||
3. Click "Run" (green play button) in Android Studio
|
||||
4. Select your device from the deployment target dialog
|
||||
|
||||
### Method 2: ADB (Android Debug Bridge)
|
||||
|
||||
```bash
|
||||
# Install debug APK
|
||||
adb install app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
# Install release APK
|
||||
adb install app/build/outputs/apk/release/app-release.apk
|
||||
|
||||
# Install with replacement (if already installed)
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
### Method 3: Direct Download
|
||||
|
||||
1. Transfer the APK file to your device
|
||||
2. Open a file manager on your device
|
||||
3. Navigate to the APK file location
|
||||
4. Tap the APK to install
|
||||
5. Allow installation from unknown sources if prompted
|
||||
|
||||
### Method 4: Wireless ADB
|
||||
|
||||
```bash
|
||||
# Connect to device over WiFi
|
||||
adb tcpip 5555
|
||||
adb connect <device-ip-address>:5555
|
||||
|
||||
# Install APK
|
||||
adb install app/build/outputs/apk/debug/app-debug.apk
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build Issues
|
||||
|
||||
#### Gradle Sync Failed
|
||||
```
|
||||
Solution: File -> Invalidate Caches / Restart -> Invalidate and Restart
|
||||
```
|
||||
|
||||
#### Out of Memory Error
|
||||
Add to `gradle.properties`:
|
||||
```properties
|
||||
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=512m
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
```
|
||||
|
||||
#### Kotlin Version Mismatch
|
||||
Ensure Kotlin version matches in `build.gradle.kts`:
|
||||
```kotlin
|
||||
plugins {
|
||||
id("org.jetbrains.kotlin.android") version "1.9.20"
|
||||
}
|
||||
```
|
||||
|
||||
### Runtime Issues
|
||||
|
||||
#### App Crashes on Launch
|
||||
- Check that `INTERNET` permission is in `AndroidManifest.xml`
|
||||
- Verify minimum SDK version (API 24+)
|
||||
- Check for ProGuard obfuscation issues
|
||||
|
||||
#### Channels Not Loading
|
||||
- Verify the M3U URL is accessible
|
||||
- Check network connectivity
|
||||
- Review logcat for parsing errors: `adb logcat | grep M3UParser`
|
||||
|
||||
#### Video Not Playing
|
||||
- Ensure stream URL is valid and accessible
|
||||
- Check if stream format is supported (HLS, DASH, Progressive)
|
||||
- Verify codec support on device
|
||||
- Check logcat for ExoPlayer errors
|
||||
|
||||
#### Audio Issues
|
||||
- Check audio focus is being requested properly
|
||||
- Verify audio track selection in PlayerManager
|
||||
- Test with different audio formats
|
||||
|
||||
### Streaming Issues
|
||||
|
||||
#### Buffering Problems
|
||||
```kotlin
|
||||
// Increase buffer size in PlayerManager
|
||||
val player = ExoPlayer.Builder(context)
|
||||
.setLoadControl(
|
||||
DefaultLoadControl.Builder()
|
||||
.setBufferDurationsMs(
|
||||
5000, // minBufferMs
|
||||
50000, // maxBufferMs
|
||||
1000, // bufferForPlaybackMs
|
||||
5000 // bufferForPlaybackAfterRebufferMs
|
||||
)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
```
|
||||
|
||||
#### SSL/Certificate Errors
|
||||
Update `network_security_config.xml`:
|
||||
```xml
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system"/>
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
</network-security-config>
|
||||
```
|
||||
|
||||
### Development Tips
|
||||
|
||||
#### Enable Debug Logging
|
||||
```kotlin
|
||||
// In PlayerManager
|
||||
exoPlayer.addAnalyticsListener(EventLogger())
|
||||
```
|
||||
|
||||
#### View Compose Layout Bounds
|
||||
Enable in Developer Options:
|
||||
```
|
||||
Settings -> Developer Options -> Show layout bounds
|
||||
```
|
||||
|
||||
#### Profile Performance
|
||||
Use Android Studio Profiler:
|
||||
```
|
||||
View -> Tool Windows -> Profiler
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
```
|
||||
Copyright 2024 IPTV Player
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please follow these steps:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- [ExoPlayer](https://github.com/google/ExoPlayer) - Media player library
|
||||
- [Jetpack Compose](https://developer.android.com/jetpack/compose) - UI toolkit
|
||||
- [Material Design 3](https://m3.material.io/) - Design system
|
||||
- [IPTV Org](https://github.com/iptv-org) - Public IPTV playlists
|
||||
|
||||
## Support
|
||||
|
||||
For issues, questions, or feature requests, please open an issue on GitHub.
|
||||
|
||||
---
|
||||
|
||||
**Disclaimer**: This application is for educational purposes. Users are responsible for complying with local laws and regulations regarding IPTV streaming. The developers do not provide any IPTV content or playlists.
|
||||
Reference in New Issue
Block a user