Home - softtiny/Counting_sheep GitHub Wiki
Welcome to the Counting_sheep wiki! I'm glad to hear that you’ve successfully integrated com.github.javiersantos:AppUpdater:2.7 to check your app’s version and provide a link to download updates! To help you keep track of the journey and lessons learned, below are detailed notes summarizing the history of issues, solutions, and key takeaways. These notes are structured to serve as a reference for future development, ensuring you avoid similar pitfalls and maintain a smooth workflow. Notes: History of Integrating AppUpdater in Your Android Project Project Context
Project Details:
Android app using Jetpack Compose (libs.androidx.activity.compose).
Package name: proxy.kunkka.tts.
Gradle version: 8.2.11, using Kotlin DSL (build.gradle.kts).
Dependencies managed via version catalog (libs.versions.toml).
Goal: Add com.github.javiersantos:AppUpdater:2.7 to check for app updates and provide a download link.
AppUpdater Usage:
Library: com.github.javiersantos:AppUpdater:2.7.
Purpose: Check for newer app versions and display a dialog with a link to download updates (e.g., via Play Store or custom URL).
Likely implemented in a Compose-based activity, requiring a themed context for AlertDialog.
Timeline of Issues and Resolutions
Initial Issue: Duplicate Classes Error
Error: Execution failed for task ':app:checkReleaseDuplicateClasses'.
Caused by duplicate class android.support.v4.app.INotificationSideChannel in androidx.core:core:1.12.0 and com.android.support:support-compat:27.1.1.
Cause: AppUpdater:2.7 depends on the deprecated Android Support Library (com.android.support), conflicting with your AndroidX-based project (androidx.core:core).
Solution:
Excluded Support Library from AppUpdater in build.gradle.kts:
kotlin
implementation("com.github.javiersantos:AppUpdater:2.7") {
exclude(group = "com.android.support")
}
Enabled Jetifier in gradle.properties to rewrite Support Library references to AndroidX:
properties
android.useAndroidX=true
android.enableJetifier=true
Takeaway: Always check for library compatibility with AndroidX. Exclude conflicting dependencies and use Jetifier for legacy libraries.
Second Issue: ClassNotFoundException
Error: java.lang.ClassNotFoundException: Didn't find class "android.support.v7.app.AlertDialog$Builder".
Cause: AppUpdater tried to use android.support.v7.app.AlertDialog.Builder, but your project only had AndroidX (androidx.appcompat). Jetifier didn’t fully resolve the dependency.
Solution:
Explicitly added androidx.appcompat:appcompat to ensure androidx.appcompat.app.AlertDialog.Builder was available:
kotlin
implementation(libs.androidx.appcompat)
Confirmed exclusion of com.android.support to prevent conflicts.
Takeaway: Ensure all required AndroidX dependencies (e.g., appcompat) are included when using libraries that indirectly rely on them.
Third Issue: Theme.AppCompat Requirement
Error: You need to use a Theme.AppCompat theme (or descendant) with this activity.
Cause: AppUpdater’s AlertDialog required an activity theme based on Theme.AppCompat, but your original theme was android:Theme.Material.Light.NoActionBar (platform theme, not AppCompat-compatible).
Solution:
Updated res/values/themes.xml to use Theme.MaterialComponents.Light.NoActionBar:
xml
<style name="Theme.TTSGo" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
</style>
Added com.google.android.material:material dependency to provide Theme.MaterialComponents and attributes:
kotlin
implementation(libs.material)
Verified theme application in AndroidManifest.xml:
xml
<application android:theme="@style/Theme.TTSGo">
Takeaway: Activities using AppCompat components (e.g., AlertDialog) must use Theme.AppCompat or descendants like Theme.MaterialComponents. Platform themes (android:Theme.*) are incompatible.
Fourth Issue: Test Failure with Theme
Error: Test using InstrumentationRegistry.getInstrumentation().targetContext failed, requiring a Theme.AppCompat theme.
Specific code block:
kotlin
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
val themedContext = appContext.createConfigurationContext(appContext.resources.configuration)
themedContext.theme.applyStyle(R.style.Theme_Material_Light, true)
Cause:
R.style.Theme_Material_Light didn’t exist in themes.xml.
Test environment didn’t inherit the app’s theme (Theme.TTSGo) automatically.
Solution:
Updated test to use R.style.Theme_TTSGo:
kotlin
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
val themedContext = appContext.createConfigurationContext(appContext.resources.configuration)
themedContext.theme.applyStyle(R.style.Theme_TTSGo, true)
val appUpdater = AppUpdater(themedContext)
Added test dependencies for robustness:
kotlin
androidTestImplementation(libs.androidx.test.junit)
androidTestImplementation(libs.androidx.test.core)
Takeaway: Tests accessing targetContext for AppCompat components need a themed context. Use the app’s theme (Theme.TTSGo) and avoid non-existent styles. Mock UI components (e.g., AppUpdater’s dialog) to prevent test failures in headless environments.
Fifth Issue: Resource Linking Failure
Error: Execution failed for task ':app:processDebugResources'.
resource style/Theme.MaterialComponents.Light.NoActionBar not found.
Missing attributes: colorPrimaryVariant, colorOnPrimary, etc.
Cause: themes.xml referenced Theme.MaterialComponents.Light.NoActionBar, but com.google.android.material:material wasn’t initially included, causing resource linking to fail.
Solution:
Added Material Components dependency:
kotlin
implementation(libs.material)
toml
[versions]
material = "1.12.0"
[libraries]
material = { module = "com.google.android.material:material", version.ref = "material" }
Defined missing attributes in themes.xml (see Step 3 above).
Created res/values/colors.xml:
xml
<resources>
<color name="purple_500">#6200EE</color>
<color name="purple_700">#3700B3</color>
<color name="teal_200">#03DAC5</color>
<color name="teal_700">#018786</color>
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
</resources>
Takeaway: Themes like Theme.MaterialComponents require the com.google.android.material:material library. Always define required theme attributes (e.g., colorPrimaryVariant) to avoid resource errors.
Final Working Setup
Dependencies (build.gradle.kts):
kotlin
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation("com.github.javiersantos:AppUpdater:2.7") {
exclude(group = "com.android.support")
}
androidTestImplementation(libs.androidx.test.junit)
androidTestImplementation(libs.androidx.test.core)
}
Version Catalog (libs.versions.toml):
toml
[versions]
androidx-core-ktx = "1.13.1"
androidx-appcompat = "1.7.0"
material = "1.12.0"
androidx-lifecycle-runtime-ktx = "2.8.6"
androidx-activity-compose = "1.9.3"
androidx-test-junit = "1.2.1"
androidx-test-core = "1.6.1"
[libraries]
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core-ktx" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
material = { module = "com.google.android.material:material", version.ref = "material" }
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle-runtime-ktx" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" }
androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-junit" }
androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test-core" }
Theme (res/values/themes.xml):
xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.TTSGo" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
</style>
</resources>
Colors (res/values/colors.xml):
xml
<resources>
<color name="purple_500">#6200EE</color>
<color name="purple_700">#3700B3</color>
<color name="teal_200">#03DAC5</color>
<color name="teal_700">#018786</color>
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
</resources>
Manifest (AndroidManifest.xml):
xml
<application
android:theme="@style/Theme.TTSGo">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Test:
kotlin
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.github.javiersantos.appupdater.AppUpdater
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class AppUpdaterTest {
@Test
fun testAppUpdaterInitialization() {
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
val themedContext = appContext.createConfigurationContext(appContext.resources.configuration)
themedContext.theme.applyStyle(R.style.Theme_TTSGo, true)
val appUpdater = AppUpdater(themedContext)
// Assertions or mocked behavior
}
}
AppUpdater Usage (assumed):
Likely in MainActivity or a composable, e.g.:
kotlin
val appUpdater = AppUpdater(context).setUpdateFrom(UpdateFrom.GOOGLE_PLAY)
appUpdater.showAppUpdatedDialog()
Configured to check the app version and open a link (e.g., Play Store) for updates.
Key Takeaways
Library Compatibility:
Older libraries like AppUpdater:2.7 (last updated 2018) often depend on deprecated Android Support Library, causing conflicts in AndroidX projects.
Always exclude legacy dependencies (com.android.support) and enable Jetifier.
Theme Requirements:
AppCompat components (e.g., AlertDialog) require Theme.AppCompat or descendants (Theme.MaterialComponents).
Platform themes (android:Theme.*) are incompatible with AndroidX libraries.
Define all required theme attributes (e.g., colorPrimaryVariant) to avoid resource linking errors.
Testing Challenges:
Instrumentation tests using targetContext need a themed context for AppCompat components.
Avoid UI operations (e.g., showing dialogs) in tests; use mocking (e.g., MockK) for reliability.
Ensure test dependencies (androidx.test.core, etc.) are up-to-date.
Dependency Management:
Use version catalogs (libs.versions.toml) to keep dependencies consistent.
Include required libraries (e.g., com.google.android.material:material for Theme.MaterialComponents).
Compose Integration:
Compose apps rely on androidx.compose.material3 for UI theming, but activities still need XML themes for AppCompat compatibility.
Theme.MaterialComponents bridges View-based dependencies (like AppUpdater) with Compose.
Future-Proofing:
AppUpdater:2.7 is outdated and caused multiple issues (duplicate classes, theme errors, test failures).
Consider replacing it with Google’s In-App Updates API (com.google.android.play:app-update-ktx:2.1.0) for:
Modern integration with Compose.
No AppCompat theme requirements.
Better testability and maintenance.
Example dependency:
kotlin
implementation(libs.google.play.app.update.ktx)
Example usage:
kotlin
@Composable
fun AppUpdateChecker() {
val appUpdateManager = AppUpdateManagerFactory.create(LocalContext.current)
// Check for updates
}
Recommendations for Future Maintenance
Monitor AppUpdater:
Check [AppUpdater’s GitHub](https://github.com/javiersantos/AppUpdater) for updates or forks supporting AndroidX natively.
If no updates, plan to migrate to In-App Updates to avoid future compatibility issues.
Simplify Theme:
If fully transitioning to Compose (no View-based UI), consider minimizing com.google.android.material:material usage by using Theme.AppCompat.Light.NoActionBar or a custom theme after replacing AppUpdater.
Enhance Tests:
Add MockK for robust testing:
kotlin
android androidTestImplementation(libs.mockk.android)
Mock AppUpdater methods to avoid UI issues:
kotlin
val appUpdater = mockk<AppUpdater>()
every { appUpdater.showAppUpdatedDialog() } returns appUpdater
Regular Dependency Updates:
Periodically check [Maven Central](https://mvnrepository.com/) for updates to androidx.*, com.google.android.material:material, and other libraries.
Update libs.versions.toml to keep versions current.
Documentation:
Maintain a project changelog or README to track dependency changes and issue resolutions.
Document test cases for AppUpdater to ensure consistent behavior.
Current Status
Achievement: You’ve successfully integrated AppUpdater:2.7 to check app versions and open download links.
Build: App builds without errors after resolving duplicate classes, missing classes, theme issues, and resource linking failures.
Tests: Instrumentation tests work with a themed context using Theme.TTSGo.
Next Steps: Consider migrating to In-App Updates for a more robust solution, especially given your Compose-based app.
These notes should serve as a comprehensive reference for your AppUpdater integration. Keep them in your project’s documentation or a dedicated file (e.g., NOTES.md) to guide future maintenance or debugging. If you decide to explore In-App Updates or need help with further optimizations, let me know, and I’ll provide tailored guidance! Congratulations on getting it working! 🚀