|
| 1 | +# V2er Android App - GitHub Copilot Instructions |
| 2 | + |
| 3 | +**ALWAYS follow these instructions first and fallback to additional search and context gathering only if the information here is incomplete or found to be in error.** |
| 4 | + |
| 5 | +## Working Effectively |
| 6 | + |
| 7 | +The V2er Android app is a beautiful V2EX client built using MVP architecture with Dagger 2 dependency injection, RxJava, and Retrofit. The app parses HTML responses from V2EX rather than using a JSON API. |
| 8 | + |
| 9 | +### Essential Setup Commands |
| 10 | +Run these commands in sequence to set up the development environment: |
| 11 | + |
| 12 | +```bash |
| 13 | +# Verify Java 17 is installed (required) |
| 14 | +java -version # Should show Java 17 |
| 15 | + |
| 16 | +# Grant execute permissions to gradlew |
| 17 | +chmod +x gradlew |
| 18 | + |
| 19 | +# Clean and prepare the project |
| 20 | +./gradlew clean --stacktrace |
| 21 | +``` |
| 22 | + |
| 23 | +### Build Commands - **NEVER CANCEL BUILDS** |
| 24 | + |
| 25 | +**CRITICAL: All build commands can take 5-15 minutes. NEVER CANCEL. Set timeouts to 60+ minutes minimum.** |
| 26 | + |
| 27 | +```bash |
| 28 | +# Build debug APK - NEVER CANCEL: Takes 5-10 minutes. Set timeout to 60+ minutes. |
| 29 | +./gradlew assembleDebug --stacktrace |
| 30 | + |
| 31 | +# Build release APK (requires signing configuration) - NEVER CANCEL: Takes 10-15 minutes. Set timeout to 60+ minutes. |
| 32 | +./gradlew assembleRelease --stacktrace |
| 33 | + |
| 34 | +# Clean and rebuild - NEVER CANCEL: Takes 8-12 minutes. Set timeout to 60+ minutes. |
| 35 | +./gradlew clean assembleDebug --stacktrace |
| 36 | + |
| 37 | +# Build App Bundle (AAB) for Play Store - NEVER CANCEL: Takes 10-15 minutes. Set timeout to 60+ minutes. |
| 38 | +./gradlew bundleRelease --stacktrace |
| 39 | +``` |
| 40 | + |
| 41 | +### Testing Commands - **NEVER CANCEL TESTS** |
| 42 | + |
| 43 | +**CRITICAL: Test commands can take 5-20 minutes. NEVER CANCEL. Set timeouts to 30+ minutes minimum.** |
| 44 | + |
| 45 | +```bash |
| 46 | +# Run unit tests - NEVER CANCEL: Takes 3-8 minutes. Set timeout to 30+ minutes. |
| 47 | +./gradlew test --stacktrace |
| 48 | + |
| 49 | +# Run specific variant tests - NEVER CANCEL: Takes 2-5 minutes each. Set timeout to 30+ minutes. |
| 50 | +./gradlew testDebugUnitTest --stacktrace |
| 51 | +./gradlew testReleaseUnitTest --stacktrace |
| 52 | + |
| 53 | +# Run instrumented tests (requires connected device/emulator) - NEVER CANCEL: Takes 10-20 minutes. Set timeout to 45+ minutes. |
| 54 | +./gradlew connectedAndroidTest --stacktrace |
| 55 | +``` |
| 56 | + |
| 57 | +### Linting and Code Quality |
| 58 | + |
| 59 | +```bash |
| 60 | +# Run Android lint checks - Takes 1-3 minutes. Lint is configured with abortOnError false, so errors won't fail builds. |
| 61 | +./gradlew lint --stacktrace |
| 62 | + |
| 63 | +# Note: Lint errors will not fail the build but should be reviewed and fixed when possible. |
| 64 | +``` |
| 65 | + |
| 66 | +### Installation Commands |
| 67 | + |
| 68 | +```bash |
| 69 | +# Install debug build on connected device - Takes 1-2 minutes. |
| 70 | +./gradlew installDebug --stacktrace |
| 71 | + |
| 72 | +# Install release build on connected device - Takes 1-2 minutes. |
| 73 | +./gradlew installRelease --stacktrace |
| 74 | +``` |
| 75 | + |
| 76 | +## Network Connectivity Issues |
| 77 | + |
| 78 | +**IMPORTANT**: If you encounter network connectivity issues with repositories (e.g., "dl.google.com: No address associated with hostname"), document this limitation in your work. The build will fail due to network restrictions in some environments. This is a known limitation and should be noted as "Build commands fail due to network connectivity restrictions in the current environment." |
| 79 | + |
| 80 | +## Validation and Testing Scenarios |
| 81 | + |
| 82 | +After making any changes, ALWAYS run through these validation steps: |
| 83 | + |
| 84 | +### 1. Code Quality Validation |
| 85 | +```bash |
| 86 | +# Always run lint before committing - errors won't fail build but should be reviewed |
| 87 | +./gradlew lint --stacktrace |
| 88 | + |
| 89 | +# Check for compilation errors |
| 90 | +./gradlew compileDebugJava --stacktrace |
| 91 | +``` |
| 92 | + |
| 93 | +### 2. Unit Test Validation - **NEVER CANCEL: Set timeout to 30+ minutes** |
| 94 | +```bash |
| 95 | +# Run all unit tests |
| 96 | +./gradlew test --stacktrace |
| 97 | + |
| 98 | +# Check specific test classes if making focused changes |
| 99 | +./gradlew test --tests="me.ghui.v2er.util.UriUtilsTest" --stacktrace |
| 100 | +``` |
| 101 | + |
| 102 | +### 3. Manual Testing Scenarios |
| 103 | +When making UI or functional changes, manually test these core scenarios: |
| 104 | + |
| 105 | +**Core User Flows to Test:** |
| 106 | +1. **App Launch**: Open the app and verify it loads without crashes |
| 107 | +2. **Topic Browsing**: Navigate through topic lists and verify content loads |
| 108 | +3. **Deep Linking**: Test V2EX URL handling: |
| 109 | + - `https://v2ex.com/t/*` - Topic pages |
| 110 | + - `https://v2ex.com/member/*` - User profiles |
| 111 | + - `https://v2ex.com/go/*` - Node pages |
| 112 | +4. **Theme Switching**: Test both day and night themes |
| 113 | +5. **Image Loading**: Verify images load correctly using Glide |
| 114 | +6. **Network Handling**: Test with poor network conditions |
| 115 | + |
| 116 | +**UI Testing Requirements:** |
| 117 | +- Test on both day and night themes |
| 118 | +- Verify RecyclerView scrolling performance |
| 119 | +- Check custom UI components in `app/src/main/java/me/ghui/v2er/widget/` |
| 120 | +- Ensure proper MVP pattern implementation |
| 121 | + |
| 122 | +## Architecture and Navigation |
| 123 | + |
| 124 | +### Project Structure |
| 125 | +``` |
| 126 | +app/src/main/java/me/ghui/v2er/ |
| 127 | +├── module/ # Feature modules (MVP pattern) |
| 128 | +│ ├── base/ # Base classes for activities/presenters |
| 129 | +│ ├── login/ # Login feature |
| 130 | +│ ├── topic/ # Topic viewing/creation |
| 131 | +│ └── user/ # User profile features |
| 132 | +├── injector/ # Dagger 2 dependency injection |
| 133 | +│ ├── component/ # Dagger components |
| 134 | +│ └── module/ # Dagger modules |
| 135 | +├── network/ # Networking layer |
| 136 | +│ ├── bean/ # Data models (HTML parsing) |
| 137 | +│ └── *.java # Retrofit services |
| 138 | +├── adapter/ # RecyclerView adapters |
| 139 | +├── widget/ # Custom UI components |
| 140 | +└── util/ # Utility classes |
| 141 | +``` |
| 142 | + |
| 143 | +### Key Files and Locations |
| 144 | + |
| 145 | +**Configuration Files:** |
| 146 | +- `config.gradle` - Version management and build configuration |
| 147 | +- `gradle.properties` - Gradle settings including JVM args for Java 17+ |
| 148 | +- `app/build.gradle` - Main Android build configuration |
| 149 | +- `sentry.properties` - Crash reporting configuration |
| 150 | +- `app/flurry.config` - Analytics configuration |
| 151 | + |
| 152 | +**Important Source Directories:** |
| 153 | +- `app/src/main/java/me/ghui/v2er/module/` - All feature modules following MVP pattern |
| 154 | +- `app/src/main/java/me/ghui/v2er/network/bean/` - Data models that parse V2EX HTML |
| 155 | +- `app/src/main/java/me/ghui/v2er/widget/` - Custom UI components and behaviors |
| 156 | +- `app/src/test/java/` - Unit tests (small test suite) |
| 157 | +- `app/src/androidTest/java/` - Instrumented tests |
| 158 | + |
| 159 | +**MVP Pattern Implementation:** |
| 160 | +Each feature module contains: |
| 161 | +- `Contract.java` - Interface defining View and Presenter contracts |
| 162 | +- `*Activity.java` or `*Fragment.java` - View implementation |
| 163 | +- `*Presenter.java` - Business logic implementation |
| 164 | + |
| 165 | +### Development Guidelines |
| 166 | + |
| 167 | +**Always follow these patterns when making changes:** |
| 168 | + |
| 169 | +1. **MVP Architecture**: Use existing MVP patterns for new features |
| 170 | +2. **Dependency Injection**: Use Dagger 2 for all dependencies |
| 171 | +3. **HTML Parsing**: Use Fruit library annotations for V2EX data parsing |
| 172 | +4. **Async Operations**: Use RxJava 2 for all async operations |
| 173 | +5. **Image Loading**: Use Glide 4 for all image loading operations |
| 174 | +6. **Navigation**: Use Navigator class for activity transitions |
| 175 | + |
| 176 | +**Before committing changes:** |
| 177 | +```bash |
| 178 | +# Always run these validation steps |
| 179 | +./gradlew lint --stacktrace |
| 180 | +./gradlew test --stacktrace |
| 181 | +# Manually test day and night themes |
| 182 | +# Test relevant deep linking scenarios |
| 183 | +``` |
| 184 | + |
| 185 | +## CI/CD Integration |
| 186 | + |
| 187 | +The project uses GitHub Actions for CI/CD: |
| 188 | + |
| 189 | +**Workflows:** |
| 190 | +- `.github/workflows/ci.yml` - Runs tests, lint, and builds on PR/push |
| 191 | +- `.github/workflows/release.yml` - Creates signed releases |
| 192 | +- Uses JDK 17 and caches Gradle dependencies |
| 193 | + |
| 194 | +**Expected CI Timings:** |
| 195 | +- Unit tests: 5-10 minutes |
| 196 | +- Lint checks: 2-5 minutes |
| 197 | +- Debug build: 8-15 minutes |
| 198 | +- Release build: 10-20 minutes |
| 199 | + |
| 200 | +## Signing Configuration |
| 201 | + |
| 202 | +**For Debug Builds:** |
| 203 | +Use default debug keystore - no additional configuration needed. |
| 204 | + |
| 205 | +**For Release Builds:** |
| 206 | +Requires environment variables (see `SIGNING.md` for details): |
| 207 | +- `KEYSTORE_PASSWORD` - Keystore password |
| 208 | +- `KEY_PASSWORD` - Key password |
| 209 | +- `KEY_ALIAS` - Key alias (defaults to "ghui") |
| 210 | + |
| 211 | +**Security Note**: Never commit keystore files. The `.gitignore` excludes all `.jks` and `.keystore` files. |
| 212 | + |
| 213 | +## Troubleshooting |
| 214 | + |
| 215 | +### Common Issues and Solutions |
| 216 | + |
| 217 | +1. **Build fails with "dl.google.com: No address associated with hostname"** |
| 218 | + - This indicates network connectivity restrictions |
| 219 | + - Document as a known limitation in your work |
| 220 | + - The CI/CD environment has proper connectivity |
| 221 | + |
| 222 | +2. **Java compatibility issues** |
| 223 | + - Ensure Java 17 is being used |
| 224 | + - The `gradle.properties` file contains required JVM args for Java 17+ |
| 225 | + |
| 226 | +3. **Dagger compilation errors** |
| 227 | + - Clean and rebuild: `./gradlew clean assembleDebug` |
| 228 | + - Check that all `@Inject` and `@Provides` annotations are correct |
| 229 | + |
| 230 | +4. **RxJava threading issues** |
| 231 | + - Ensure proper use of `.observeOn(AndroidSchedulers.mainThread())` |
| 232 | + - Use RxLifecycle for automatic subscription management |
| 233 | + |
| 234 | +5. **HTML parsing failures** |
| 235 | + - Check Fruit annotations in `network/bean/` classes |
| 236 | + - V2EX may have changed their HTML structure |
| 237 | + |
| 238 | +### Performance Considerations |
| 239 | + |
| 240 | +- **Large RecyclerViews**: Use `SpeedyLinearLayoutManager` for improved scrolling |
| 241 | +- **Image Loading**: Glide is configured with OkHttp integration for better performance |
| 242 | +- **Memory**: Proguard and resource shrinking are enabled for release builds |
| 243 | + |
| 244 | +## Key Technologies and Versions |
| 245 | + |
| 246 | +- **Language**: Java 8 (source/target compatibility) |
| 247 | +- **Build System**: Gradle 8.13 with Android Gradle Plugin |
| 248 | +- **Minimum SDK**: API 27 (Android 8.1) |
| 249 | +- **Target SDK**: API 36 |
| 250 | +- **Compile SDK**: API 36 |
| 251 | + |
| 252 | +**Core Dependencies:** |
| 253 | +- **DI**: Dagger 2.57 |
| 254 | +- **Networking**: Retrofit 3.0.0 + OkHttp 5.1.0 + RxJava 2.2.21 |
| 255 | +- **View Binding**: ButterKnife 10.2.3 |
| 256 | +- **Image Loading**: Glide 4.16.0 |
| 257 | +- **HTML Parsing**: Fruit 1.0.4 (custom library) |
| 258 | +- **Event Bus**: EventBus 3.3.1 |
| 259 | + |
| 260 | +## Distribution |
| 261 | + |
| 262 | +- **Google Play Store**: https://play.google.com/store/apps/details?id=me.ghui.v2er |
| 263 | +- **CoolApk**: https://www.coolapk.com/apk/me.ghui.v2er |
| 264 | + |
| 265 | +The app is distributed under GPL license. See `LICENSE` file for details. |
0 commit comments