9.4 KiB
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
- Root Cause Analysis
- Solution Approaches
- Step-by-Step Resolution
- Verification Steps
- Prevention Strategies
- 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:
- As Project Reference: Capacitor's automatic plugin discovery includes the plugin as a project reference
- As AAR File: The AAR file is also included directly in the build dependencies
Contributing Factors
- Capacitor Auto-Discovery: Capacitor automatically discovers plugins via
capacitor.plugins.json - Symlinked Dependencies: Node modules may create symlinks that confuse Gradle
- Gradle Cache Issues: Corrupted cache can cause inconsistent behavior
- Path Resolution: Incorrect project paths can cause module resolution failures
Technical Details
Project Reference Path:
project(':timesafari-daily-notification-plugin').projectDir = new File('../../../android/plugin')
AAR File Path:
implementation(name: 'plugin-debug', ext: 'aar')
Capacitor Discovery:
{
"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
# 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
# capacitor.settings.gradle
include ':timesafari-daily-notification-plugin'
project(':timesafari-daily-notification-plugin').projectDir = new File('../../../android/plugin')
Step 3: Add Project Dependency
# capacitor.build.gradle
dependencies {
implementation project(':timesafari-daily-notification-plugin')
}
Step 4: Remove AAR Dependency
# 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
// assets/capacitor.plugins.json
[
{
"id": "DailyNotification",
"name": "DailyNotification",
"class": "com.timesafari.dailynotification.DailyNotificationPlugin"
}
]
Method 2: AAR-Only Resolution
Step 1: Remove Project References
# 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
# 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
# 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
# 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
# Clean build should succeed
./gradlew clean assembleDebug
Success Indicators:
- ✅ Build completes without errors
- ✅ No duplicate class warnings
- ✅ APK generated successfully
3. Runtime Verification
# 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:
# Weekly cache cleanup
./gradlew --stop
rm -rf ~/.gradle/caches
Before Major Changes:
# Clear cache before switching approaches
rm -rf ~/.gradle
3. Project Structure Validation
Verify Paths:
# Check project structure
ls -la ../../../android/plugin/
ls -la libs/
Validate Configuration:
# Check Gradle configuration
./gradlew :app:dependencies --configuration debugRuntimeClasspath
Best Practices
1. Development Workflow
Initial Setup:
- Choose integration approach (project reference recommended)
- Configure all necessary files
- Clear Gradle cache
- Build and test
Ongoing Development:
- Avoid switching approaches mid-development
- Clear cache when making structural changes
- Test integration after major updates
2. Configuration Management
File Organization:
- Keep
capacitor.settings.gradleminimal - Use
capacitor.build.gradlefor dependencies - Maintain
capacitor.plugins.jsonfor 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 - Main build documentation
- INTEGRATION_GUIDE.md - Integration guide
- API.md - Plugin API documentation
Community
Tools
./gradlew :app:dependencies- Dependency analysisadb 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.