ADFA-3169: Auto-generate unique plugin versions at build time#1104
Conversation
📝 WalkthroughRelease Notes: Auto-generate Unique Plugin Versions at Build TimeFeatures
Changes (selected)
|
| Cohort / File(s) | Summary |
|---|---|
Build / Manifest placeholders plugin-api/plugin-builder/src/main/.../PluginBuilder.kt, plugin-api/plugin-builder/src/main/.../PluginBuilderExtension.kt, templates-impl/src/main/.../pluginManifest.kt |
Added pluginVersion extension property; variant-aware onVariants callback computes resolvedVersion (from config or app version + variant + timestamp) and injects pluginVersion manifest placeholder; template emits literal ${pluginVersion}. |
Plugin Manifests apk-viewer-plugin/src/main/AndroidManifest.xml, keystore-generator-plugin/src/main/AndroidManifest.xml, markdown-preview-plugin/src/main/AndroidManifest.xml |
Replaced hardcoded plugin.version meta-data values with ${pluginVersion}; application theme references changed (to plugin-specific themes). |
Plugin loading & native libs plugin-manager/src/main/.../PluginManager.kt, plugin-manager/src/main/.../loaders/PluginLoader.kt, plugin-manager/src/main/.../loaders/PluginResourceContext.kt |
Added native .so extraction, pass nativeLibPath into DexClassLoader, enforce NATIVE_CODE permission to allow native libs, cleanup extracted libs on unload/uninstall, make PluginResourceContext accept pluginId/classloader and switch resource/theme/inflater behavior based on package-id usage. |
Plugin fragment / inflater helpers plugin-api/src/main/.../PluginFragment.kt |
Track per-plugin activity Context/Theme snapshots; expose accessors for current activity theme/context; registerPluginContext gains isLegacy flag and legacy-inflater path retained. |
Permissions & templates plugin-api/src/main/.../IPlugin.kt, templates-impl/src/main/.../PluginTemplateData.kt |
Added PluginPermission.NATIVE_CODE enum constant and mirrored template permission entry. |
Plugin list UI app/src/main/java/com/itsaky/androidide/adapters/PluginListAdapter.kt |
Display logic updated to truncate long dotted version strings to first three segments plus .... |
Keystore plugin UI & resources keystore-generator-plugin/src/main/.../KeystoreGeneratorFragment.kt, .../res/layout/fragment_keystore_generator.xml, .../res/values/*.xml |
Migrated UI to Material components, per-field validation, lifecycle-aware coroutines, localized strings, added many strings, updated styles/colors (Material3 attributes) and night palette; layout and progress indicator refactor. |
Misc build whitespace *.gradle.kts (apk-viewer/keystore/markdown-preview plugins) |
Minor whitespace/formatting changes only. |
Sequence Diagram
sequenceDiagram
participant Dev as Developer
participant Gradle as Gradle/Build System
participant PluginBuilder as PluginBuilder
participant Manifest as AndroidManifest
participant APK as APK Packager
Dev->>Gradle: configure pluginVersion? / run build
Gradle->>PluginBuilder: onVariants(variant)
PluginBuilder->>PluginBuilder: resolveVersion (extension.value or baseVersion + variant + timestamp)
PluginBuilder->>Manifest: set manifestPlaceholder "pluginVersion" = resolvedVersion
PluginBuilder->>APK: package APK with resolved manifest values
sequenceDiagram
participant App as Host App
participant Loader as PluginLoader
participant Manager as PluginManager
participant Context as PluginResourceContext
participant ClassLoader as DexClassLoader
App->>Manager: loadPlugin(apk)
Manager->>Loader: extractNativeLibs(pluginId)
alt native libs found
Loader->>Manager: nativeLibPath
Manager->>Manager: check plugin.permissions for NATIVE_CODE
alt permission present
Manager->>Loader: loadPluginClasses(parentCL, nativeLibPath)
Loader->>ClassLoader: create DexClassLoader(..., nativeLibPath)
Loader->>Context: createPluginContext(pluginId)
Manager->>App: register plugin (resources, classes)
else permission missing
Manager->>Loader: delete nativeLibPath
Manager->>App: fail load with SecurityException
end
else no native libs
Loader->>Manager: null
Loader->>ClassLoader: create DexClassLoader(..., null)
end
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
- ADFA-3260: Fix plugin resource and theme resolution for custom package IDs #1103: Appears to make overlapping changes to plugin resource/theme resolution, PluginResourceContext/PluginLoader/PluginManager APIs, and NATIVE_CODE permission handling.
- ADFA-2212: Implement native Support for Creating Code On the Go Plugins in Code On the Go #744: Related changes around pluginVersion manifest placeholders and PluginBuilder/loader integration for variant/version wiring.
- ADFA-2508: Add PluginBuilder Gradle plugin for .cgp file generation #805: Prior work on PluginBuilder/PluginBuilderExtension; this PR extends that surface by adding pluginVersion and variant resolution.
Suggested reviewers
- jomen-adfa
- jatezzz
- itsaky-adfa
Poem
🐰 I tunneled through manifests and build-time mist,
Replaced the old numbers with placeholders kissed,
Native hops guarded by a permission so bold,
Themes and colors refreshed, new stories told—
Hooray! A plugin parade, shiny, versioned, and swift. 🎉
🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 24.39% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. | |
| Description check | ❓ Inconclusive | No description was provided by the author, making it impossible to assess whether any description content is related to the changeset. | Add a pull request description explaining the motivation, approach, and key changes for auto-generating unique plugin versions at build time. |
✅ Passed checks (1 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title accurately summarizes the primary change: auto-generating unique plugin versions at build time, which is reflected across manifest updates, build logic changes, and version resolution implementation. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
ADFA-3169
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt (2)
13-16: Consider using UTC for timestamp consistency across build environments.
LocalDateTime.now()uses the system's default timezone, which could produce different version strings for the same commit when built on machines in different timezones. Consider usingInstant.now()orLocalDateTime.now(ZoneOffset.UTC)for reproducibility.♻️ Suggested fix for timezone consistency
companion object { - private val TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss") + private val TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss") + .withZone(java.time.ZoneOffset.UTC) private const val DEFAULT_VERSION = "1.0.0" }And update the usage:
-val timestamp = LocalDateTime.now().format(TIMESTAMP_FORMATTER) +val timestamp = java.time.Instant.now().let { TIMESTAMP_FORMATTER.format(it) }Also applies to: 33-33
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt` around lines 13 - 16, The timestamp uses the system default timezone (via LocalDateTime.now()), causing non-reproducible version strings across machines; update the timestamp generation to use UTC: either call LocalDateTime.now(ZoneOffset.UTC) where the timestamp is created or switch to Instant.now() and use a DateTimeFormatter withZone(ZoneOffset.UTC) so TIMESTAMP_FORMATTER produces UTC timestamps consistently (update usages where the timestamp is constructed, e.g., the code referencing TIMESTAMP_FORMATTER around line 33).
53-54: Migrateproject.buildDirtoproject.layout.buildDirectoryfor Gradle 8.3+ compatibility.The
buildDirproperty is deprecated as of Gradle 8.3 and will be removed in Gradle 10.0. Replace withlayout.buildDirectory:Example migration
// Before val apkDir = File(project.buildDir, "outputs/apk/debug") // After val apkDir = project.layout.buildDirectory.dir("outputs/apk/debug").get().asFileThis applies to lines 53–54 (debug task) and 83–84 (release task).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt` around lines 53 - 54, Replace uses of the deprecated project.buildDir in PluginBuilder.kt for both debug and release task sections (the apkDir and outputDir assignments) with the new ProjectLayout API: use project.layout.buildDirectory with dir(...) and then obtain the File via get().asFile; update the apkDir and outputDir initializations in the debug block (symbols apkDir and outputDir) and likewise in the release block to use project.layout.buildDirectory.dir(...).get().asFile instead of File(project.buildDir, ...).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt`:
- Around line 13-16: The timestamp uses the system default timezone (via
LocalDateTime.now()), causing non-reproducible version strings across machines;
update the timestamp generation to use UTC: either call
LocalDateTime.now(ZoneOffset.UTC) where the timestamp is created or switch to
Instant.now() and use a DateTimeFormatter withZone(ZoneOffset.UTC) so
TIMESTAMP_FORMATTER produces UTC timestamps consistently (update usages where
the timestamp is constructed, e.g., the code referencing TIMESTAMP_FORMATTER
around line 33).
- Around line 53-54: Replace uses of the deprecated project.buildDir in
PluginBuilder.kt for both debug and release task sections (the apkDir and
outputDir assignments) with the new ProjectLayout API: use
project.layout.buildDirectory with dir(...) and then obtain the File via
get().asFile; update the apkDir and outputDir initializations in the debug block
(symbols apkDir and outputDir) and likewise in the release block to use
project.layout.buildDirectory.dir(...).get().asFile instead of
File(project.buildDir, ...).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2abdd090-5f9a-4b74-8650-bf777a478877
📒 Files selected for processing (7)
apk-viewer-plugin/src/main/AndroidManifest.xmlapp/src/main/java/com/itsaky/androidide/adapters/PluginListAdapter.ktkeystore-generator-plugin/src/main/AndroidManifest.xmlmarkdown-preview-plugin/src/main/AndroidManifest.xmlplugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.ktplugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilderExtension.kttemplates-impl/src/main/java/com/itsaky/androidide/templates/impl/pluginProject/pluginManifest.kt
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (6)
plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginResourceContext.kt (1)
86-119: Consider cleanup forcachedProviderandcachedLoader.The
cachedProviderandcachedLoaderare stored but there's no explicit cleanup when the plugin is disposed. While this is typically long-lived, consider adding adispose()orclose()method to clean up these resources, especiallycachedProviderwhich wraps file resources.♻️ Optional: Add cleanup method
fun dispose() { cachedProvider?.close() cachedProvider = null cachedLoader = null recreatedAssetManager?.close() recreatedAssetManager = null }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginResourceContext.kt` around lines 86 - 119, Add explicit cleanup for the ResourcesProvider and ResourcesLoader used in ensurePluginResourcesAdded by adding a public dispose/close method on PluginResourceContext that calls cachedProvider?.close() (or appropriate close method), sets cachedProvider = null and cachedLoader = null, and also closes/clears recreatedAssetManager if present; update any plugin teardown path to call this new dispose() so file descriptors and loader references are released when the plugin is disposed (reference symbols: cachedProvider, cachedLoader, ensurePluginResourcesAdded, recreatedAssetManager, dispose).plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt (1)
316-332: Consider narrowing the exception handling for native lib extraction.The current implementation catches a broad
Exception(line 318), but based on project guidelines, prefer catching specific exception types. TheextractNativeLibsmethod can throwIOException,SecurityException, orZipException.That said, the security enforcement logic is well-designed: deleting extracted libs and releasing sidebar slots before returning the failure ensures no partial state.
♻️ Optional: Narrow exception handling
var nativeLibPath: String? = try { pluginLoader.extractNativeLibs(manifest.id)?.absolutePath - } catch (e: Exception) { + } catch (e: IOException) { + logger.warn("Failed to extract native libs for plugin: ${manifest.id}", e) + null + } catch (e: SecurityException) { logger.warn("Failed to extract native libs for plugin: ${manifest.id}", e) null }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt` around lines 316 - 332, Replace the broad catch(Exception) around pluginLoader.extractNativeLibs(manifest.id) with specific catches for the known exceptions (IOException, ZipException, and SecurityException), logging the same warning and setting nativeLibPath to null in each handler; keep the surrounding logic that checks nativeLibPath, deletes the extracted files with File(nativeLibPath).deleteRecursively(), calls SidebarSlotManager.releasePluginSlots(manifest.id) when manifest.sidebarItems > 0, and returns the same Result.failure(SecurityException(...)) if the plugin lacks PluginPermission.NATIVE_CODE.plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginLoader.kt (1)
150-150: Consider iterating through supported ABIs if plugin fallback compatibility is needed.The code uses
Build.SUPPORTED_ABIS[0]which only attempts extraction for the primary ABI. If a plugin APK lacks libraries for the primary ABI but includes a compatible secondary ABI (e.g., primary is arm64-v8a but APK only has armeabi-v7a), extraction returns null. This appears intentional given the current design, and the null return is handled gracefully in PluginManager with appropriate error handling. However, if cross-ABI plugin compatibility becomes important, consider iterating throughBuild.SUPPORTED_ABISto use the first available ABI in the APK.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginLoader.kt` at line 150, Replace the hardcoded single-ABI prefix usage (val libPrefix = "lib/${Build.SUPPORTED_ABIS[0]}/") with logic that iterates Build.SUPPORTED_ABIS and attempts extraction using each ABI in order, returning the first successful extraction; update the code that constructs libPrefix and the extraction routine in PluginLoader (where libPrefix is used) so it tries each ABI (e.g., "lib/{abi}/") until a matching library is found or all ABIs fail.keystore-generator-plugin/src/main/res/layout/fragment_keystore_generator.xml (1)
269-271: Consider usingpaddingBottomon the parent instead of a spacer View.The bottom spacer could be replaced with
android:paddingBottom="16dp"on the rootLinearLayout. This slightly reduces the view hierarchy depth.♻️ Suggested refactor
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> + android:orientation="vertical" + android:paddingBottom="16dp">Then remove the spacer View at the end.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@keystore-generator-plugin/src/main/res/layout/fragment_keystore_generator.xml` around lines 269 - 271, Replace the bottom spacer View with padding on the parent LinearLayout: remove the <View> spacer (the final spacer with android:layout_height="16dp") and add android:paddingBottom="16dp" to the root LinearLayout element in fragment_keystore_generator.xml to reduce view hierarchy depth and preserve the same spacing.keystore-generator-plugin/src/main/kotlin/com/appdevforall/keygen/plugin/fragments/KeystoreGeneratorFragment.kt (2)
452-467: Consider using gradle.properties or environment variables for credentials.The generated signing config writes passwords directly into the build.gradle file. While this matches common Android documentation patterns, it's a security concern if the build file is committed to version control.
A more secure approach would be to generate credentials in
gradle.properties(which is typically gitignored) and reference them:// In gradle.properties (gitignored) KEYSTORE_PASSWORD=... // In build.gradle storePassword = project.findProperty('KEYSTORE_PASSWORD') ?: ''This is a common security best practice but may be outside the scope of this PR.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@keystore-generator-plugin/src/main/kotlin/com/appdevforall/keygen/plugin/fragments/KeystoreGeneratorFragment.kt` around lines 452 - 467, The current generation in KeystoreGeneratorFragment builds a releaseConfig string that inlines storePassword and keyPassword (see releaseConfig, isKotlinDsl and usages of config.keystorePassword/config.keyPassword); change this to avoid embedding credentials in build files by emitting property references instead and writing the actual secrets into gradle.properties or using environment variables: update the generator so it writes KEYSTORE_PASSWORD and KEY_PASSWORD entries (or reads env vars) into the project gradle.properties (or instructs the user to do so) and replace the inlined "${String(config.keystorePassword)}"/'${String(config.keyPassword)}' with project.findProperty(...) or System.getenv(...) references in releaseConfig for both Kotlin and Groovy templates, ensuring no plaintext passwords remain in the generated build.gradle fragment.
489-521: Regex pattern using[^}]*is technically fragile but works for standard signing configs.The pattern will match until the first
}character, which could break if signing configs contained nested braces or comments with}. However, no examples of such structures exist in the codebase—all signing configs follow the standard flat format used in Android development. If robustness is preferred, consider refactoring to a brace-matching approach or adding a comment documenting this assumption.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@keystore-generator-plugin/src/main/kotlin/com/appdevforall/keygen/plugin/fragments/KeystoreGeneratorFragment.kt` around lines 489 - 521, The regexes createPattern, getByNamePattern and groovyPattern use [^}]* which stops at the first '}' and can break with nested braces; update KeystoreGeneratorFragment.kt to either (preferred short-term) add a clear comment beside those patterns documenting the assumption that signing configs are flat (no nested braces or '}' in comments) and why it's acceptable here, or (if you want robustness now) replace the simplistic regex approach with a proper brace-matching parser for the signing block (e.g., scan characters and track brace depth for create("release"), getByName("release") and release { ... } blocks) so nested braces or stray '}' inside strings/comments won't prematurely terminate the match.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/base/PluginFragment.kt`:
- Around line 18-27: The mutable collections pluginContexts, serviceRegistries,
legacyPlugins and activitySnapshots are not thread-safe; replace them with
concurrent collections (e.g., use java.util.concurrent.ConcurrentHashMap-backed
maps for pluginContexts, serviceRegistries and activitySnapshots and a
concurrent key set for legacyPlugins) so accesses from IO/main threads won't
race; keep the ActivitySnapshot data class as-is and swap construction/usages of
these fields to the new concurrent maps/sets (refer to pluginContexts,
serviceRegistries, legacyPlugins, activitySnapshots and ActivitySnapshot to
locate all spots to update).
In
`@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginLoader.kt`:
- Around line 143-179: The current extractNativeLibs(pluginId: String) returns
an existing pluginNativeDir without validating that its contents match the
pluginApk; change this by adding a freshness/completeness check: when
pluginNativeDir.exists() verify (a) a stored marker (e.g. checksum or
lastModified of pluginApk) inside the directory matches the current pluginApk
and/or (b) that the expected .so files listed from ZipFile(pluginApk) exist in
pluginNativeDir with matching sizes or checksums; if the marker mismatches or
files are missing/changed, deleteRecursively the pluginNativeDir and proceed to
re-extract as the existing code does, then update the marker and set
nativeLibDir before returning. Ensure you use the same symbols
(extractNativeLibs, pluginNativeDir, nativeLibDir, pluginApk) so the check
integrates cleanly with the existing flow.
---
Nitpick comments:
In
`@keystore-generator-plugin/src/main/kotlin/com/appdevforall/keygen/plugin/fragments/KeystoreGeneratorFragment.kt`:
- Around line 452-467: The current generation in KeystoreGeneratorFragment
builds a releaseConfig string that inlines storePassword and keyPassword (see
releaseConfig, isKotlinDsl and usages of
config.keystorePassword/config.keyPassword); change this to avoid embedding
credentials in build files by emitting property references instead and writing
the actual secrets into gradle.properties or using environment variables: update
the generator so it writes KEYSTORE_PASSWORD and KEY_PASSWORD entries (or reads
env vars) into the project gradle.properties (or instructs the user to do so)
and replace the inlined
"${String(config.keystorePassword)}"/'${String(config.keyPassword)}' with
project.findProperty(...) or System.getenv(...) references in releaseConfig for
both Kotlin and Groovy templates, ensuring no plaintext passwords remain in the
generated build.gradle fragment.
- Around line 489-521: The regexes createPattern, getByNamePattern and
groovyPattern use [^}]* which stops at the first '}' and can break with nested
braces; update KeystoreGeneratorFragment.kt to either (preferred short-term) add
a clear comment beside those patterns documenting the assumption that signing
configs are flat (no nested braces or '}' in comments) and why it's acceptable
here, or (if you want robustness now) replace the simplistic regex approach with
a proper brace-matching parser for the signing block (e.g., scan characters and
track brace depth for create("release"), getByName("release") and release { ...
} blocks) so nested braces or stray '}' inside strings/comments won't
prematurely terminate the match.
In
`@keystore-generator-plugin/src/main/res/layout/fragment_keystore_generator.xml`:
- Around line 269-271: Replace the bottom spacer View with padding on the parent
LinearLayout: remove the <View> spacer (the final spacer with
android:layout_height="16dp") and add android:paddingBottom="16dp" to the root
LinearLayout element in fragment_keystore_generator.xml to reduce view hierarchy
depth and preserve the same spacing.
In
`@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.kt`:
- Around line 316-332: Replace the broad catch(Exception) around
pluginLoader.extractNativeLibs(manifest.id) with specific catches for the known
exceptions (IOException, ZipException, and SecurityException), logging the same
warning and setting nativeLibPath to null in each handler; keep the surrounding
logic that checks nativeLibPath, deletes the extracted files with
File(nativeLibPath).deleteRecursively(), calls
SidebarSlotManager.releasePluginSlots(manifest.id) when manifest.sidebarItems >
0, and returns the same Result.failure(SecurityException(...)) if the plugin
lacks PluginPermission.NATIVE_CODE.
In
`@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginLoader.kt`:
- Line 150: Replace the hardcoded single-ABI prefix usage (val libPrefix =
"lib/${Build.SUPPORTED_ABIS[0]}/") with logic that iterates Build.SUPPORTED_ABIS
and attempts extraction using each ABI in order, returning the first successful
extraction; update the code that constructs libPrefix and the extraction routine
in PluginLoader (where libPrefix is used) so it tries each ABI (e.g.,
"lib/{abi}/") until a matching library is found or all ABIs fail.
In
`@plugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginResourceContext.kt`:
- Around line 86-119: Add explicit cleanup for the ResourcesProvider and
ResourcesLoader used in ensurePluginResourcesAdded by adding a public
dispose/close method on PluginResourceContext that calls cachedProvider?.close()
(or appropriate close method), sets cachedProvider = null and cachedLoader =
null, and also closes/clears recreatedAssetManager if present; update any plugin
teardown path to call this new dispose() so file descriptors and loader
references are released when the plugin is disposed (reference symbols:
cachedProvider, cachedLoader, ensurePluginResourcesAdded, recreatedAssetManager,
dispose).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 26ccb27c-f043-436e-957f-ef84c27a02b7
📒 Files selected for processing (19)
apk-viewer-plugin/build.gradle.ktsapk-viewer-plugin/src/main/AndroidManifest.xmlkeystore-generator-plugin/build.gradle.ktskeystore-generator-plugin/src/main/AndroidManifest.xmlkeystore-generator-plugin/src/main/kotlin/com/appdevforall/keygen/plugin/fragments/KeystoreGeneratorFragment.ktkeystore-generator-plugin/src/main/res/layout/fragment_keystore_generator.xmlkeystore-generator-plugin/src/main/res/values-night/colors.xmlkeystore-generator-plugin/src/main/res/values/colors.xmlkeystore-generator-plugin/src/main/res/values/strings.xmlkeystore-generator-plugin/src/main/res/values/styles.xmlmarkdown-preview-plugin/build.gradle.ktsmarkdown-preview-plugin/src/main/AndroidManifest.xmlplugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.ktplugin-api/src/main/kotlin/com/itsaky/androidide/plugins/IPlugin.ktplugin-api/src/main/kotlin/com/itsaky/androidide/plugins/base/PluginFragment.ktplugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/core/PluginManager.ktplugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginLoader.ktplugin-manager/src/main/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginResourceContext.kttemplates-impl/src/main/java/com/itsaky/androidide/templates/impl/pluginProject/PluginTemplateData.kt
✅ Files skipped from review due to trivial changes (7)
- apk-viewer-plugin/build.gradle.kts
- markdown-preview-plugin/build.gradle.kts
- keystore-generator-plugin/build.gradle.kts
- templates-impl/src/main/java/com/itsaky/androidide/templates/impl/pluginProject/PluginTemplateData.kt
- keystore-generator-plugin/src/main/res/values-night/colors.xml
- keystore-generator-plugin/src/main/res/values/strings.xml
- keystore-generator-plugin/src/main/res/values/colors.xml
🚧 Files skipped from review as they are similar to previous changes (3)
- apk-viewer-plugin/src/main/AndroidManifest.xml
- keystore-generator-plugin/src/main/AndroidManifest.xml
- plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt
# Conflicts: # apk-viewer-plugin/src/main/AndroidManifest.xml # keystore-generator-plugin/src/main/AndroidManifest.xml # markdown-preview-plugin/src/main/AndroidManifest.xml # plugin-api/plugin-builder/src/main/kotlin/com/itsaky/androidide/plugins/build/PluginBuilder.kt
No description provided.