Conversation
📝 Walkthrough
WalkthroughAdds NDK support across installers, environment, templates, and UI: NDK tar constant and directory, installer extraction/logging for NDK, Gradle NDK build generators, an NDK module/template (activity, native sources, CMake), UI strings/tag, and updated SDK asset sizes. Changes
Sequence Diagram(s)sequenceDiagram
participant BaseInstaller as BaseAssetsInstaller
participant Logger
participant FS as FileSystem
participant Shell as ProcessBuilder
BaseInstaller->>Logger: debug "starting NDK installation"
BaseInstaller->>FS: check archiveFile exists (Environment.NDK_TAR_XZ)
FS-->>BaseInstaller: exists / not exists
alt archive exists
BaseInstaller->>Shell: spawn bash -c "tar -xJf <archive> -C <output> --no-same-owner"
Shell->>FS: extract files into NDK_DIR
FS-->>Shell: extraction result
Shell-->>BaseInstaller: exit code & output
BaseInstaller->>Logger: log extraction duration & result
BaseInstaller->>FS: attempt delete archive
FS-->>BaseInstaller: deletion success/failure
BaseInstaller->>Logger: log cleanup status
else archive missing
BaseInstaller->>Logger: debug "NDK archive missing"
end
sequenceDiagram
participant TemplateProvider
participant NdkBuilder as NdkModuleTemplateBuilder
participant RecipeExec as RecipeExecutor
participant Writer as SourceWriter
participant FS as FileSystem
TemplateProvider->>NdkBuilder: request ndkActivityProject()
NdkBuilder->>RecipeExec: execute recipe
RecipeExec->>NdkBuilder: call buildGradle() (KTS/Groovy)
NdkBuilder->>Writer: write C++ source (native-lib.cpp)
Writer-->>FS: create src/main/cpp/native-lib.cpp
NdkBuilder->>Writer: write CMakeLists.txt
Writer-->>FS: create CMakeLists.txt
NdkBuilder->>RecipeExec: write activity sources/layout/resources
RecipeExec-->>FS: files created
NdkBuilder-->>TemplateProvider: return ProjectTemplate
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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 |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Fix all issues with AI agents
In `@app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt`:
- Around line 48-51: The process.waitFor() call in BaseAssetsInstaller can block
indefinitely; change it to use process.waitFor(timeout, TimeUnit.SECONDS) with a
reasonable timeout (e.g., 60s), handle the boolean timedOut result by calling
process.destroy() and if necessary process.destroyForcibly(), capture/handle
InterruptedException, and set exitCode/result appropriately; also ensure you
drain both process.inputStream and process.errorStream (or read them
asynchronously) to avoid stream blocking when the process is running.
In
`@templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt`:
- Around line 604-609: The Groovy build script unconditionally appends
composeConfigGroovy() causing compose config to be present in non-compose
modules; update the template in buildGradle.kt to call composeConfigGroovy()
only when isComposeModule is true (mirror the conditional logic used for the
buildFeatures block), i.e., guard the composeConfigGroovy() invocation using the
isComposeModule flag so that compose-specific configuration is emitted only for
compose modules.
- Around line 494-499: The file unconditionally injects composeConfigKts()
causing Compose options to be added for non-Compose NDK modules; update the
template to call composeConfigKts() only when isComposeModule is true (mirror
the conditional used in buildGradleSrcKts). Locate the buildFeatures block and
the composeConfigKts() invocation and wrap or conditionally render
composeConfigKts() based on the isComposeModule flag so compose-specific
settings (kotlinCompilerExtensionVersion, packaging rules, dependency
resolution) are only added for modules where isComposeModule is true.
- Around line 460-462: The ndk block currently emits invalid Kotlin DSL by
writing abiFilters += "arm64-v8a","x86_64"; change the generation so abiFilters
is given a Kotlin list: produce abiFilters +=
listOf(${abiFilters.joinToString(",") { "\"$it\"" }}) (or use
abiFilters.addAll(listOf(...))) so the emitted code uses listOf(...) instead of
a comma-separated string list; update the template in buildGradle.kt around the
ndk { abiFilters ... } section accordingly.
In
`@templates-api/src/main/java/com/itsaky/androidide/templates/base/ndkExtensions.kt`:
- Around line 50-67: The current RecipeExecutor.buildGradle() passes empty
strings/lists for ndkVersion, abiFilters, and cppFlags which produces invalid
Gradle snippets; update buildGradle() to forward nullable values (ndkVersion,
abiFilters, cppFlags) without coercing to ""/emptyList or else compute
conditional content so ndkBuildGradleSrcKts and ndkBuildGradleSrcGroovy can omit
their NDK blocks when values are null/empty; specifically, stop using ndkVersion
?: "", abiFilters ?: emptyList(), cppFlags ?: "" and either call
ndkBuildGradleSrcKts/ndkBuildGradleSrcGroovy with nullable params or prebuild
the NDK-specific strings only when values are present, then call
save(gradleContent, buildGradleFile()).
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkActivityTemplate.kt`:
- Around line 29-31: Update the NDK ABI filters in ndkActivityTemplate.kt so
emulators are supported: in the block defining ndkVersion, abiFilters, and
cppFlags (symbols: ndkVersion, abiFilters, cppFlags) add "x86_64" to the
abiFilters list (e.g., listOf("arm64-v8a", "x86_64")) while keeping the existing
ndkVersion and cppFlags values unchanged.
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkSources.kt`:
- Around line 17-30: The Kotlin template uses Java syntax; update MainActivity
to valid Kotlin by removing the `public` modifier, keep _binding:
ActivityMainBinding? and the binding getter as-is, replace the Java static block
with a companion object containing an init that calls
System.loadLibrary("native-lib"), and convert the native declaration to Kotlin
external syntax by replacing `public native String stringFromJNI();` with an
external function declaration like `external fun stringFromJNI(): String`;
ensure these changes reference MainActivity, _binding, binding, companion
object/init, System.loadLibrary, and stringFromJNI.
🧹 Nitpick comments (8)
common/src/main/java/com/itsaky/androidide/utils/Environment.java (1)
115-116: Consider makingNDK_TAR_XZfinal for consistency.Other string constants in this class (like
PROJECTS_FOLDER,DEFAULT_ROOT, etc.) are declared aspublic static final. For consistency and to prevent accidental reassignment,NDK_TAR_XZshould also befinal.Suggested fix
- public static String NDK_TAR_XZ = "ndk-cmake.tar.xz"; + public static final String NDK_TAR_XZ = "ndk-cmake.tar.xz";app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt (2)
21-24: Consider handling the return value ofinstallNdk.The return value is currently ignored. While NDK installation may be optional, logging the outcome would help with troubleshooting if users expect NDK features to work.
Suggested fix
- installNdk( + val ndkInstalled = installNdk( File(Environment.ANDROID_HOME, Environment.NDK_TAR_XZ), Environment.ANDROID_HOME ) + logger.debug("NDK installation result: {}", if (ndkInstalled) "success" else "skipped or failed")
54-72: Confusing return semantics when deletion fails after successful extraction.The function returns
falseif the archive was extracted successfully but couldn't be deleted (lines 62-64) or wasn't found (line 67). This conflates extraction success with cleanup success. Consider returningtruefor successful extraction regardless of cleanup, or separating the concerns.Suggested fix
return if (exitCode == 0) { logger.debug("Extraction of ${archiveFile.absolutePath} successful took ${elapsed}ms : $result") - if (archiveFile.exists()) { - val deleted = archiveFile.delete() - if (deleted) { - logger.debug("${archiveFile.absolutePath} deleted successfully.") - } else { - logger.debug("Failed to delete ${archiveFile.absolutePath}.") - } - deleted - } else { - logger.debug("Archive file not found for deletion.") - false + // Attempt cleanup but don't fail extraction success + if (archiveFile.exists() && !archiveFile.delete()) { + logger.warn("Failed to delete ${archiveFile.absolutePath} after extraction") } + true } else { logger.error("Extraction failed with code $exitCode: $result") false }app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt (1)
179-181: Use threshold comparison instead of floating-point equality.Comparing
percent == 100.0with exact equality can be unreliable due to floating-point precision. While this specific calculation may work, a threshold comparison is safer and more robust.Suggested fix
val snapshot = - if (percent == 100.0) { + if (percent >= 99.99) { "Post install processing in progress...." } else {templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt (1)
396-507: Consider extracting common template logic to reduce duplication.Both NDK build functions share ~90% of their logic with the existing
buildGradleSrcKtsandbuildGradleSrcGroovyfunctions. The only additions are the NDK-specific blocks (ndk { abiFilters },externalNativeBuild,ndkVersion). Consider refactoring to compose these templates from smaller, reusable pieces to improve maintainability.Also applies to: 509-615
templates-api/src/main/java/com/itsaky/androidide/templates/base/ndkExtensions.kt (2)
28-37: Unusedwriterparameter inwriteCpp.The
writer: SourceWriterparameter is never used in this function. This appears to be dead code that should be removed.♻️ Proposed fix
- inline fun writeCpp( - writer: SourceWriter, - fileName: String, - crossinline cppSrcProvider: () -> String - ) { + inline fun writeCpp( + fileName: String, + crossinline cppSrcProvider: () -> String + ) { val src = cppSrcProvider() if (src.isNotBlank() && fileName.isNotBlank()) { executor.save(src, srcNativeFilePath(SrcSet.Main, fileName)) } }
39-48: Remove unusedwriterparameter fromwriteCMakeListandwriteCpp.Both functions have an unused
writer: SourceWriterparameter that should be removed. This also affects the callers in ndkActivityTemplate.kt which will need to be updated to remove thethisargument being passed.♻️ Proposed changes
Function signatures:
inline fun writeCpp( - writer: SourceWriter, fileName: String, crossinline cppSrcProvider: () -> String ) inline fun writeCMakeList( - writer: SourceWriter, fileName: String, crossinline cmakeSrcProvider: () -> String )Callers in ndkActivityTemplate.kt:
-writeCpp(this, fileName = "native-lib.cpp") { ndkCpp() } +writeCpp(fileName = "native-lib.cpp") { ndkCpp() } -writeCMakeList(this, fileName = "CMakeLists.txt") { ndkCMakeLists() } +writeCMakeList(fileName = "CMakeLists.txt") { ndkCMakeLists() }templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkSources.kt (1)
41-43: Kotlin style: Use property assignment syntax instead ofsetText.Kotlin's Android extensions and view binding support property syntax for setters.
♻️ Proposed fix
// Call JNI method and display result - binding.textView.setText(stringFromJNI()); + binding.textView.text = stringFromJNI() }
app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt
Outdated
Show resolved
Hide resolved
templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt
Show resolved
Hide resolved
templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt
Show resolved
Hide resolved
templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt
Show resolved
Hide resolved
templates-api/src/main/java/com/itsaky/androidide/templates/base/ndkExtensions.kt
Show resolved
Hide resolved
...s-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkActivityTemplate.kt
Show resolved
Hide resolved
templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkSources.kt
Outdated
Show resolved
Hide resolved
| ) | ||
| } | ||
|
|
||
| private fun installNdk(archiveFile: File, outputDir: File): Boolean { |
There was a problem hiding this comment.
@jomen-adfa I have a question about this process: does it run on the main thread or is it called from a coroutine? Since it processes files.
There was a problem hiding this comment.
@jatezzz It's called from assetsinstallationhelper after the doinstalls are done, either for debug or release. This needs to be done in postInstall since it needs both android-sdk and bootstrap packages to be already extracted for tar and xz to run without potential issues for the moment so we can release and get feedback. This would be a bit temporary since in the near future we could be putting the ndk package in a plugin and additionally if we do decide to adapt tar.xz packaging then we'd do the extraction in our code using apache commons packages and not delegated to tar and xz utilities in termux.
| private val cppFlags: String? = null | ||
| ) : AndroidModuleTemplateBuilder() { | ||
|
|
||
| fun srcNativeFilePath(srcSet: SrcSet, fileName: String): File { |
There was a problem hiding this comment.
@jomen-adfa Could you move the handling of coroutines to a lower level to avoid errors in the high-level caller?
There was a problem hiding this comment.
For all methods in this file, including the I/O dispatcher or the most appropriate one in each case.
eabfdcf to
8e7411b
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt`:
- Around line 178-191: The snapshot logic currently uses percent >= 99.99 to
show the "Post install processing..." message; instead, change it to check that
all entries are finished by inspecting entryStatusMap (e.g.
entryStatusMap.values.all { it == STATUS_FINISHED }) so the per-entry status
list is only hidden when every entry is STATUS_FINISHED; update the condition
around the snapshot variable (and any related branches that produce the "Post
install processing in progress...." text) to use this all-finished check rather
than the percent threshold so approximate/zero expectedSize won’t prematurely
hide entry statuses.
In `@app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt`:
- Around line 49-56: The current code reads process.inputStream with
process.inputStream.bufferedReader().use { it.readText() } before calling
process.waitFor, which can block indefinitely; instead start draining both
stdout and stderr concurrently (e.g., spawn threads or use Executors to read
process.inputStream and process.errorStream into strings or StringBuilders)
immediately after processBuilder.start(), then call process.waitFor(2,
TimeUnit.MINUTES) and set exitCode based on the completed flag (and call
process.destroyForcibly() on timeout); finally collect the drained output into
result and include stderr if needed. Ensure you keep references to the started
threads/futures so you can await their completion (or cancel) after waitFor, and
update variables result and exitCode accordingly.
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkActivityTemplate.kt`:
- Around line 28-31: The ndkActivity template currently hardcodes ndkVersion =
"29.0.14206865" in the call to defaultAppModuleWithNdk; change it to use
BuildConfig.NDK_VERSION instead (i.e., set ndkVersion = BuildConfig.NDK_VERSION)
so the template aligns with the canonical NDK version; update any necessary
imports or references so BuildConfig is accessible from ndkActivityTemplate.kt
and verify the ndkVersion parameter of defaultAppModuleWithNdk receives
BuildConfig.NDK_VERSION.
♻️ Duplicate comments (1)
templates-api/src/main/java/com/itsaky/androidide/templates/base/ndkExtensions.kt (1)
50-64: Avoid empty NDK defaults in generated Gradle (still present).At Line 54–63, nulls are coerced into empty strings/lists, which can emit invalid NDK config (e.g.,
ndkVersion = "", emptyabiFilters). This mirrors the earlier review feedback; consider requiring non-null values or omitting the NDK blocks when values are missing.
| val snapshot = | ||
| buildString { | ||
| entryStatusMap.forEach { (entry, status) -> | ||
| appendLine("$entry ${if (status == STATUS_FINISHED) "✓" else ""}") | ||
| if (percent >= 99.99) { | ||
| "Post install processing in progress...." | ||
| } else { | ||
| buildString { | ||
| entryStatusMap.forEach { (entry, status) -> | ||
| appendLine("$entry ${if (status == STATUS_FINISHED) "✓" else ""}") | ||
| } | ||
| appendLine("--------------------") | ||
| appendLine("Progress: ${formatPercent(percent)}") | ||
| appendLine("Installed: ${formatBytes(installedSize)} / ${formatBytes(totalSize)}") | ||
| appendLine("Remaining storage: ${formatBytes(freeStorage)}") | ||
| } | ||
| appendLine("--------------------") | ||
| appendLine("Progress: ${formatPercent(percent)}") | ||
| appendLine("Installed: ${formatBytes(installedSize)} / ${formatBytes(totalSize)}") | ||
| appendLine("Remaining storage: ${formatBytes(freeStorage)}") | ||
| } |
There was a problem hiding this comment.
Gate the “post install” message on completion, not percent.
If any expectedSize is approximate/zero, percent can reach 99.99 before all entries are finished, which hides the per‑entry status prematurely. Consider switching the condition to “all entries finished” for a more accurate status.
🔧 Suggested adjustment
- val snapshot =
- if (percent >= 99.99) {
+ val allFinished =
+ entryStatusMap.size == expectedEntries.size &&
+ entryStatusMap.values.all { it == STATUS_FINISHED }
+
+ val snapshot =
+ if (allFinished) {
"Post install processing in progress...."
} else {
buildString {
entryStatusMap.forEach { (entry, status) ->
appendLine("$entry ${if (status == STATUS_FINISHED) "✓" else ""}")
}
appendLine("--------------------")
appendLine("Progress: ${formatPercent(percent)}")
appendLine("Installed: ${formatBytes(installedSize)} / ${formatBytes(totalSize)}")
appendLine("Remaining storage: ${formatBytes(freeStorage)}")
}
}🤖 Prompt for AI Agents
In `@app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt`
around lines 178 - 191, The snapshot logic currently uses percent >= 99.99 to
show the "Post install processing..." message; instead, change it to check that
all entries are finished by inspecting entryStatusMap (e.g.
entryStatusMap.values.all { it == STATUS_FINISHED }) so the per-entry status
list is only hidden when every entry is STATUS_FINISHED; update the condition
around the snapshot variable (and any related branches that produce the "Post
install processing in progress...." text) to use this all-finished check rather
than the percent threshold so approximate/zero expectedSize won’t prematurely
hide entry statuses.
| val process = processBuilder.start() | ||
|
|
||
| result = process.inputStream.bufferedReader().use { it.readText() } | ||
| val completed = process.waitFor(2, TimeUnit.MINUTES) | ||
| exitCode = if (completed) process.exitValue() else { | ||
| process.destroyForcibly() | ||
| -1 | ||
| } |
There was a problem hiding this comment.
Timeout is ineffective because output is read before waitFor.
readText() blocks until the process exits, so a hung tar extraction can still block indefinitely (and can deadlock if output buffers fill). Drain output concurrently, then apply the timeout.
🔧 Suggested fix (drain output concurrently)
import java.util.concurrent.TimeUnit
+import kotlin.concurrent.thread
...
val process = processBuilder.start()
- result = process.inputStream.bufferedReader().use { it.readText() }
- val completed = process.waitFor(2, TimeUnit.MINUTES)
- exitCode = if (completed) process.exitValue() else {
- process.destroyForcibly()
- -1
- }
+ val output = StringBuilder()
+ val reader = thread(start = true, name = "ndk-extract-output") {
+ process.inputStream.bufferedReader().useLines { lines ->
+ lines.forEach { output.appendLine(it) }
+ }
+ }
+
+ val completed = process.waitFor(2, TimeUnit.MINUTES)
+ if (!completed) {
+ process.destroyForcibly()
+ }
+ reader.join()
+ result = output.toString()
+ exitCode = if (completed) process.exitValue() else -1📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| val process = processBuilder.start() | |
| result = process.inputStream.bufferedReader().use { it.readText() } | |
| val completed = process.waitFor(2, TimeUnit.MINUTES) | |
| exitCode = if (completed) process.exitValue() else { | |
| process.destroyForcibly() | |
| -1 | |
| } | |
| import java.util.concurrent.TimeUnit | |
| import kotlin.concurrent.thread | |
| val process = processBuilder.start() | |
| val output = StringBuilder() | |
| val reader = thread(start = true, name = "ndk-extract-output") { | |
| process.inputStream.bufferedReader().useLines { lines -> | |
| lines.forEach { output.appendLine(it) } | |
| } | |
| } | |
| val completed = process.waitFor(2, TimeUnit.MINUTES) | |
| if (!completed) { | |
| process.destroyForcibly() | |
| } | |
| reader.join() | |
| result = output.toString() | |
| exitCode = if (completed) process.exitValue() else -1 |
🤖 Prompt for AI Agents
In `@app/src/main/java/com/itsaky/androidide/assets/BaseAssetsInstaller.kt` around
lines 49 - 56, The current code reads process.inputStream with
process.inputStream.bufferedReader().use { it.readText() } before calling
process.waitFor, which can block indefinitely; instead start draining both
stdout and stderr concurrently (e.g., spawn threads or use Executors to read
process.inputStream and process.errorStream into strings or StringBuilders)
immediately after processBuilder.start(), then call process.waitFor(2,
TimeUnit.MINUTES) and set exitCode based on the completed flag (and call
process.destroyForcibly() on timeout); finally collect the drained output into
result and include stderr if needed. Ensure you keep references to the started
threads/futures so you can await their completion (or cancel) after waitFor, and
update variables result and exitCode accordingly.
| defaultAppModuleWithNdk( | ||
| ndkVersion = "29.0.14206865", | ||
| abiFilters = listOf("arm64-v8a"), | ||
| cppFlags = "-std=c++17" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find the Environment.java file
fd -type f -name "Environment.java"Repository: appdevforall/CodeOnTheGo
Length of output: 238
🏁 Script executed:
# Search for NDK version related constants and patterns
rg -n "NDK_(TAR|VERSION|DIR|REVISION|BUILD)" --type javaRepository: appdevforall/CodeOnTheGo
Length of output: 409
🏁 Script executed:
# Check the actual template file for context
fd -type f -name "ndkActivityTemplate.kt"Repository: appdevforall/CodeOnTheGo
Length of output: 238
🏁 Script executed:
# Search for ndkVersion usages across the entire codebase
rg -n "ndkVersion\s*=" --type kotlin --type javaRepository: appdevforall/CodeOnTheGo
Length of output: 833
🏁 Script executed:
# Find BuildConfig to understand NDK_VERSION
fd -type f -name "BuildConfig.kt" -o -name "BuildConfig.java"Repository: appdevforall/CodeOnTheGo
Length of output: 238
🏁 Script executed:
# Check the content of buildGradle.kt to understand the ndkVersion parameter
cat -n templates-api/src/main/java/com/itsaky/androidide/templates/base/modules/android/buildGradle.kt | sed -n '465,480p'Repository: appdevforall/CodeOnTheGo
Length of output: 497
🏁 Script executed:
# View the full ndkActivityTemplate.kt file to understand context
cat -n templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkActivityTemplate.ktRepository: appdevforall/CodeOnTheGo
Length of output: 2630
🏁 Script executed:
# Find BuildConfig files
fd -name "BuildConfig*"Repository: appdevforall/CodeOnTheGo
Length of output: 298
🏁 Script executed:
# Search for NDK_VERSION in BuildConfig files
rg -n "NDK_VERSION" --type kotlinRepository: appdevforall/CodeOnTheGo
Length of output: 820
🏁 Script executed:
# Check if there's version info in gradle files or properties
fd -name "gradle.properties" -o -name "build.gradle.kts" | head -5Repository: appdevforall/CodeOnTheGo
Length of output: 298
🏁 Script executed:
# Look at the actual gradle.properties or main build file for NDK version
rg -n "29\.0\.14206865"Repository: appdevforall/CodeOnTheGo
Length of output: 213
🏁 Script executed:
# Check the defaultAppModuleWithNdk function signature
rg -A 10 "fun defaultAppModuleWithNdk" --type kotlinRepository: appdevforall/CodeOnTheGo
Length of output: 50
🏁 Script executed:
# Look at BuildConfig.kt to understand the full context
cat -n composite-builds/build-logic/common/src/main/java/com/itsaky/androidide/build/config/BuildConfig.ktRepository: appdevforall/CodeOnTheGo
Length of output: 1908
🏁 Script executed:
# Find the defaultAppModuleWithNdk function definition
rg -B 5 -A 15 "fun defaultAppModuleWithNdk"Repository: appdevforall/CodeOnTheGo
Length of output: 50
🏁 Script executed:
# Check what file this function is in
fd -name "*.kt" | xargs rg -l "defaultAppModuleWithNdk"Repository: appdevforall/CodeOnTheGo
Length of output: 498
🏁 Script executed:
# Read the ndkExtensions.kt file to see the function definition
cat templates-api/src/main/java/com/itsaky/androidide/templates/base/ndkExtensions.ktRepository: appdevforall/CodeOnTheGo
Length of output: 3405
Use BuildConfig.NDK_VERSION instead of hardcoding the NDK version.
Line 29 hardcodes ndkVersion = "29.0.14206865", but the canonical version defined in BuildConfig.NDK_VERSION is "28.1.13356709". This mismatch is inconsistent with other modules (termux-app, libjdwp, shizuku-manager) which correctly reference BuildConfig.NDK_VERSION. Update the template to derive the version from the build configuration to keep the template aligned with the packaged NDK and prevent Gradle sync failures.
🤖 Prompt for AI Agents
In
`@templates-impl/src/main/java/com/itsaky/androidide/templates/impl/ndkActivity/ndkActivityTemplate.kt`
around lines 28 - 31, The ndkActivity template currently hardcodes ndkVersion =
"29.0.14206865" in the call to defaultAppModuleWithNdk; change it to use
BuildConfig.NDK_VERSION instead (i.e., set ndkVersion = BuildConfig.NDK_VERSION)
so the template aligns with the canonical NDK version; update any necessary
imports or references so BuildConfig is accessible from ndkActivityTemplate.kt
and verify the ndkVersion parameter of defaultAppModuleWithNdk receives
BuildConfig.NDK_VERSION.
Adding NDK support