Browse Source
- Add AAR Duplicate Class Issues section to BUILDING.md with step-by-step solutions - Create dedicated docs/aar-integration-troubleshooting.md with complete troubleshooting guide - Document project reference approach (recommended) vs AAR-only approach - Add verification steps, prevention strategies, and best practices - Update README.md with links to new documentation - Resolve duplicate class issues through proper project reference configuration Fixes AAR integration issues that caused build failures due to plugin being included both as project reference and AAR file simultaneously.master
3 changed files with 446 additions and 0 deletions
@ -0,0 +1,372 @@ |
|||||
|
# AAR Integration Troubleshooting Guide |
||||
|
|
||||
|
**Author**: Matthew Raymer |
||||
|
**Last Updated**: 2025-01-27 |
||||
|
**Version**: 1.0.0 |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
This document provides comprehensive troubleshooting guidance for integrating the DailyNotification plugin AAR into Android applications, specifically addressing the common duplicate class issues that occur during plugin integration. |
||||
|
|
||||
|
## Table of Contents |
||||
|
|
||||
|
- [Common Issues](#common-issues) |
||||
|
- [Root Cause Analysis](#root-cause-analysis) |
||||
|
- [Solution Approaches](#solution-approaches) |
||||
|
- [Step-by-Step Resolution](#step-by-step-resolution) |
||||
|
- [Verification Steps](#verification-steps) |
||||
|
- [Prevention Strategies](#prevention-strategies) |
||||
|
- [Best Practices](#best-practices) |
||||
|
|
||||
|
## Common Issues |
||||
|
|
||||
|
### Duplicate Class Errors |
||||
|
|
||||
|
**Error Message:** |
||||
|
``` |
||||
|
Duplicate class com.timesafari.dailynotification.BootReceiver found in modules: |
||||
|
- plugin-debug.aar -> plugin-debug-runtime (:plugin-debug:) |
||||
|
- plugin-debug.aar -> plugin-debug-runtime (plugin-debug.aar) |
||||
|
``` |
||||
|
|
||||
|
**Symptoms:** |
||||
|
- Build fails with duplicate class errors |
||||
|
- Plugin classes appear twice in dependency tree |
||||
|
- Gradle build process hangs or fails |
||||
|
- AAR integration appears broken |
||||
|
|
||||
|
### Gradle Cache Corruption |
||||
|
|
||||
|
**Error Message:** |
||||
|
``` |
||||
|
Could not read workspace metadata from /home/user/.gradle/caches/8.13/transforms/.../metadata.bin |
||||
|
No matching variant of project :timesafari-daily-notification-plugin was found |
||||
|
``` |
||||
|
|
||||
|
**Symptoms:** |
||||
|
- Gradle sync failures |
||||
|
- Project reference resolution issues |
||||
|
- Inconsistent build behavior |
||||
|
- Cache-related build errors |
||||
|
|
||||
|
## Root Cause Analysis |
||||
|
|
||||
|
### Primary Cause: Dual Inclusion |
||||
|
|
||||
|
The duplicate class issue occurs when the plugin is included **twice** in the build process: |
||||
|
|
||||
|
1. **As Project Reference**: Capacitor's automatic plugin discovery includes the plugin as a project reference |
||||
|
2. **As AAR File**: The AAR file is also included directly in the build dependencies |
||||
|
|
||||
|
### Contributing Factors |
||||
|
|
||||
|
1. **Capacitor Auto-Discovery**: Capacitor automatically discovers plugins via `capacitor.plugins.json` |
||||
|
2. **Symlinked Dependencies**: Node modules may create symlinks that confuse Gradle |
||||
|
3. **Gradle Cache Issues**: Corrupted cache can cause inconsistent behavior |
||||
|
4. **Path Resolution**: Incorrect project paths can cause module resolution failures |
||||
|
|
||||
|
### Technical Details |
||||
|
|
||||
|
**Project Reference Path:** |
||||
|
```gradle |
||||
|
project(':timesafari-daily-notification-plugin').projectDir = new File('../../../android/plugin') |
||||
|
``` |
||||
|
|
||||
|
**AAR File Path:** |
||||
|
```gradle |
||||
|
implementation(name: 'plugin-debug', ext: 'aar') |
||||
|
``` |
||||
|
|
||||
|
**Capacitor Discovery:** |
||||
|
```json |
||||
|
{ |
||||
|
"id": "DailyNotification", |
||||
|
"name": "DailyNotification", |
||||
|
"class": "com.timesafari.dailynotification.DailyNotificationPlugin" |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## Solution Approaches |
||||
|
|
||||
|
### Approach 1: Project Reference (Recommended) |
||||
|
|
||||
|
**Advantages:** |
||||
|
- ✅ No duplicate class issues |
||||
|
- ✅ Better development experience |
||||
|
- ✅ Automatic dependency resolution |
||||
|
- ✅ Easier debugging and testing |
||||
|
|
||||
|
**Disadvantages:** |
||||
|
- ❌ Requires correct project structure |
||||
|
- ❌ More complex initial setup |
||||
|
- ❌ Path-dependent configuration |
||||
|
|
||||
|
### Approach 2: AAR-Only |
||||
|
|
||||
|
**Advantages:** |
||||
|
- ✅ Simpler dependency management |
||||
|
- ✅ Self-contained distribution |
||||
|
- ✅ No project structure dependencies |
||||
|
|
||||
|
**Disadvantages:** |
||||
|
- ❌ Prone to duplicate class issues |
||||
|
- ❌ Requires manual dependency management |
||||
|
- ❌ Harder to debug and test |
||||
|
|
||||
|
## Step-by-Step Resolution |
||||
|
|
||||
|
### Method 1: Project Reference Resolution |
||||
|
|
||||
|
#### Step 1: Clear Gradle Cache |
||||
|
```bash |
||||
|
# Stop Gradle daemon |
||||
|
./gradlew --stop |
||||
|
|
||||
|
# Clear all Gradle caches |
||||
|
rm -rf ~/.gradle |
||||
|
|
||||
|
# Clear project build directories |
||||
|
rm -rf app/build |
||||
|
rm -rf build |
||||
|
``` |
||||
|
|
||||
|
#### Step 2: Configure Project Reference |
||||
|
```gradle |
||||
|
# capacitor.settings.gradle |
||||
|
include ':timesafari-daily-notification-plugin' |
||||
|
project(':timesafari-daily-notification-plugin').projectDir = new File('../../../android/plugin') |
||||
|
``` |
||||
|
|
||||
|
#### Step 3: Add Project Dependency |
||||
|
```gradle |
||||
|
# capacitor.build.gradle |
||||
|
dependencies { |
||||
|
implementation project(':timesafari-daily-notification-plugin') |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### Step 4: Remove AAR Dependency |
||||
|
```gradle |
||||
|
# app/build.gradle |
||||
|
dependencies { |
||||
|
// Comment out or remove AAR dependency |
||||
|
// implementation(name: 'plugin-debug', ext: 'aar') |
||||
|
|
||||
|
// Keep required dependencies |
||||
|
implementation 'androidx.work:work-runtime:2.9.0' |
||||
|
implementation 'androidx.lifecycle:lifecycle-service:2.7.0' |
||||
|
implementation 'com.google.code.gson:gson:2.10.1' |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### Step 5: Verify Plugin Discovery |
||||
|
```json |
||||
|
// assets/capacitor.plugins.json |
||||
|
[ |
||||
|
{ |
||||
|
"id": "DailyNotification", |
||||
|
"name": "DailyNotification", |
||||
|
"class": "com.timesafari.dailynotification.DailyNotificationPlugin" |
||||
|
} |
||||
|
] |
||||
|
``` |
||||
|
|
||||
|
### Method 2: AAR-Only Resolution |
||||
|
|
||||
|
#### Step 1: Remove Project References |
||||
|
```gradle |
||||
|
# capacitor.settings.gradle - Comment out project reference |
||||
|
// include ':timesafari-daily-notification-plugin' |
||||
|
// project(':timesafari-daily-notification-plugin').projectDir = new File('../../../android/plugin') |
||||
|
|
||||
|
# capacitor.build.gradle - Comment out project dependency |
||||
|
// implementation project(':timesafari-daily-notification-plugin') |
||||
|
``` |
||||
|
|
||||
|
#### Step 2: Ensure AAR-Only Dependency |
||||
|
```gradle |
||||
|
# app/build.gradle |
||||
|
dependencies { |
||||
|
implementation(name: 'plugin-debug', ext: 'aar') |
||||
|
implementation 'androidx.work:work-runtime:2.9.0' |
||||
|
implementation 'androidx.lifecycle:lifecycle-service:2.7.0' |
||||
|
implementation 'com.google.code.gson:gson:2.10.1' |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### Step 3: Remove Duplicate Files |
||||
|
```bash |
||||
|
# Remove any duplicate classes.jar files |
||||
|
rm -f libs/classes.jar |
||||
|
rm -f libs/*.jar |
||||
|
|
||||
|
# Clean and rebuild |
||||
|
./gradlew clean build |
||||
|
``` |
||||
|
|
||||
|
## Verification Steps |
||||
|
|
||||
|
### 1. Check Dependency Tree |
||||
|
```bash |
||||
|
# Verify plugin is included only once |
||||
|
./gradlew :app:dependencies | grep timesafari |
||||
|
``` |
||||
|
|
||||
|
**Expected Output:** |
||||
|
``` |
||||
|
+--- project :timesafari-daily-notification-plugin |
||||
|
``` |
||||
|
|
||||
|
**Problematic Output:** |
||||
|
``` |
||||
|
+--- project :timesafari-daily-notification-plugin |
||||
|
+--- plugin-debug.aar |
||||
|
``` |
||||
|
|
||||
|
### 2. Build Verification |
||||
|
```bash |
||||
|
# Clean build should succeed |
||||
|
./gradlew clean assembleDebug |
||||
|
``` |
||||
|
|
||||
|
**Success Indicators:** |
||||
|
- ✅ Build completes without errors |
||||
|
- ✅ No duplicate class warnings |
||||
|
- ✅ APK generated successfully |
||||
|
|
||||
|
### 3. Runtime Verification |
||||
|
```bash |
||||
|
# Install and test |
||||
|
adb install app/build/outputs/apk/debug/app-debug.apk |
||||
|
adb logcat | grep DailyNotification |
||||
|
``` |
||||
|
|
||||
|
**Success Indicators:** |
||||
|
- ✅ App launches without crashes |
||||
|
- ✅ Plugin detected in logs |
||||
|
- ✅ Plugin methods accessible |
||||
|
|
||||
|
## Prevention Strategies |
||||
|
|
||||
|
### 1. Consistent Approach Selection |
||||
|
|
||||
|
**Choose One Approach:** |
||||
|
- **Development**: Use project reference for better debugging |
||||
|
- **Production**: Use AAR for simpler distribution |
||||
|
- **Never Mix**: Don't use both approaches simultaneously |
||||
|
|
||||
|
### 2. Gradle Cache Management |
||||
|
|
||||
|
**Regular Maintenance:** |
||||
|
```bash |
||||
|
# Weekly cache cleanup |
||||
|
./gradlew --stop |
||||
|
rm -rf ~/.gradle/caches |
||||
|
``` |
||||
|
|
||||
|
**Before Major Changes:** |
||||
|
```bash |
||||
|
# Clear cache before switching approaches |
||||
|
rm -rf ~/.gradle |
||||
|
``` |
||||
|
|
||||
|
### 3. Project Structure Validation |
||||
|
|
||||
|
**Verify Paths:** |
||||
|
```bash |
||||
|
# Check project structure |
||||
|
ls -la ../../../android/plugin/ |
||||
|
ls -la libs/ |
||||
|
``` |
||||
|
|
||||
|
**Validate Configuration:** |
||||
|
```bash |
||||
|
# Check Gradle configuration |
||||
|
./gradlew :app:dependencies --configuration debugRuntimeClasspath |
||||
|
``` |
||||
|
|
||||
|
## Best Practices |
||||
|
|
||||
|
### 1. Development Workflow |
||||
|
|
||||
|
**Initial Setup:** |
||||
|
1. Choose integration approach (project reference recommended) |
||||
|
2. Configure all necessary files |
||||
|
3. Clear Gradle cache |
||||
|
4. Build and test |
||||
|
|
||||
|
**Ongoing Development:** |
||||
|
1. Avoid switching approaches mid-development |
||||
|
2. Clear cache when making structural changes |
||||
|
3. Test integration after major updates |
||||
|
|
||||
|
### 2. Configuration Management |
||||
|
|
||||
|
**File Organization:** |
||||
|
- Keep `capacitor.settings.gradle` minimal |
||||
|
- Use `capacitor.build.gradle` for dependencies |
||||
|
- Maintain `capacitor.plugins.json` for discovery |
||||
|
|
||||
|
**Version Consistency:** |
||||
|
- Use consistent Android Gradle Plugin versions |
||||
|
- Align Gradle wrapper versions |
||||
|
- Match dependency versions across modules |
||||
|
|
||||
|
### 3. Testing Strategy |
||||
|
|
||||
|
**Build Testing:** |
||||
|
- Test both debug and release builds |
||||
|
- Verify on multiple Android versions |
||||
|
- Check dependency resolution |
||||
|
|
||||
|
**Runtime Testing:** |
||||
|
- Test plugin functionality |
||||
|
- Verify permission handling |
||||
|
- Check background task execution |
||||
|
|
||||
|
## Troubleshooting Checklist |
||||
|
|
||||
|
### Before Starting |
||||
|
- [ ] Clear Gradle cache (`rm -rf ~/.gradle`) |
||||
|
- [ ] Stop Gradle daemon (`./gradlew --stop`) |
||||
|
- [ ] Verify project structure |
||||
|
- [ ] Check file permissions |
||||
|
|
||||
|
### During Integration |
||||
|
- [ ] Use only one integration approach |
||||
|
- [ ] Verify all configuration files |
||||
|
- [ ] Check dependency tree |
||||
|
- [ ] Test build process |
||||
|
|
||||
|
### After Integration |
||||
|
- [ ] Verify app launches |
||||
|
- [ ] Test plugin functionality |
||||
|
- [ ] Check logs for errors |
||||
|
- [ ] Validate permissions |
||||
|
|
||||
|
### Common Mistakes |
||||
|
- [ ] Mixing project reference and AAR approaches |
||||
|
- [ ] Incorrect project paths |
||||
|
- [ ] Forgetting to clear Gradle cache |
||||
|
- [ ] Missing required dependencies |
||||
|
- [ ] Incorrect plugin discovery configuration |
||||
|
|
||||
|
## Support and Resources |
||||
|
|
||||
|
### Documentation |
||||
|
- [BUILDING.md](../BUILDING.md) - Main build documentation |
||||
|
- [INTEGRATION_GUIDE.md](../INTEGRATION_GUIDE.md) - Integration guide |
||||
|
- [API.md](../API.md) - Plugin API documentation |
||||
|
|
||||
|
### Community |
||||
|
- [GitHub Issues](https://github.com/timesafari/daily-notification-plugin/issues) |
||||
|
- [Capacitor Community](https://github.com/ionic-team/capacitor/discussions) |
||||
|
|
||||
|
### Tools |
||||
|
- `./gradlew :app:dependencies` - Dependency analysis |
||||
|
- `adb logcat | grep DailyNotification` - Runtime debugging |
||||
|
- `./gradlew clean build` - Clean build verification |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**Remember**: The key to successful AAR integration is consistency. Choose one approach, configure it properly, and maintain it throughout development. When in doubt, clear the Gradle cache and start fresh. |
||||
Loading…
Reference in new issue