Skip to content

Android 7 Support#11

Open
WinterWolfVN wants to merge 345 commits into
FireworkSky:mainfrom
WinterWolfVN:main
Open

Android 7 Support#11
WinterWolfVN wants to merge 345 commits into
FireworkSky:mainfrom
WinterWolfVN:main

Conversation

@WinterWolfVN

Copy link
Copy Markdown

No description provided.

@LaoSparrow

Copy link
Copy Markdown
Collaborator

have you tested that?, also you may need to clean up those vietnam comment, translate them into either chinese or english

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR primarily targets adding Android 7.1 (API 25) compatibility across the project by lowering minSdk, enabling desugaring, and removing usages of java.nio.file.Path/kotlin.io.path in favor of java.io.File, plus a few runtime/workflow adjustments to avoid crashes on older devices.

Changes:

  • Lower Android minSdk to 25 and align toolchains/JVM targets to Java 17; enable core library desugaring.
  • Replace Path/kotlin.io.path usage with File throughout patching, extraction, and shared storage code paths.
  • Add Android 7/old-API safety fallbacks (Haze blur opt-out, edge-to-edge guarding, linker namespace bypass gating), and adjust CI workflows.

Reviewed changes

Copilot reviewed 36 out of 37 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
shared/src/commonMain/kotlin/com/app/ralaunch/shared/core/util/HazeUtils.kt Introduces expect modifier helper for conditional Haze usage.
shared/src/androidMain/kotlin/com/app/ralaunch/shared/core/util/HazeUtils.android.kt Android actual implementation: only apply haze on API 31+.
shared/src/commonMain/kotlin/com/app/ralaunch/shared/core/model/domain/GameItem.kt Switches path joining to java.io.File.
shared/src/commonMain/kotlin/com/app/ralaunch/shared/core/data/repository/SettingsRepositoryImpl.kt Migrates settings file IO from kotlin.io.path to File + rename-based persistence.
shared/src/commonMain/kotlin/com/app/ralaunch/shared/core/data/local/CommonGameListStorage.kt Migrates game list storage IO from kotlin.io.path to File.
shared/src/commonMain/kotlin/com/app/ralaunch/shared/core/data/local/CommonControlLayoutStorage.kt Migrates control layout storage IO from kotlin.io.path to File.
shared/src/androidMain/kotlin/com/app/ralaunch/core/platform/runtime/renderer/RendererRegistry.kt Replaces Path.resolve with File for MG dir env var; minor loop cleanup.
shared/build.gradle.kts Lowers toolchain to 17, minSdk to 25, enables desugaring for shared module, adds desugar dependency.
gradle/libs.versions.toml Adds version-catalog entry for desugar JDK libs.
app/src/main/java/com/app/ralaunch/feature/patch/data/PatchManifest.kt Removes Path overloads and Files.* checks; uses File.
app/src/main/java/com/app/ralaunch/feature/patch/data/PatchManagerConfig.kt Migrates patch config keys and IO from Path/Files to File.
app/src/main/java/com/app/ralaunch/feature/patch/data/PatchManager.kt Migrates patch manager storage/discovery/installation from Path/Files to File.
app/src/main/java/com/app/ralaunch/feature/patch/data/Patch.kt Migrates patch model from Path to File.
app/src/main/java/com/app/ralaunch/feature/init/InitializationActivity.kt Guards edge-to-edge / insets behavior for older Android versions; formatting cleanups.
app/src/main/java/com/app/ralaunch/feature/game/legacy/GamePresenter.kt Updates patch manager calls to pass File instead of Path.
app/src/main/java/com/app/ralaunch/core/ui/dialog/PatchManagementDialogCompose.kt Migrates patch import/install flow from Path/Files to File streams.
app/src/main/java/com/app/ralaunch/core/platform/runtime/GameLauncher.kt Replaces kotlin.io.path usage with File for existence checks and directory creation.
app/src/main/java/com/app/ralaunch/core/platform/runtime/AssemblyPatcher.kt Migrates MonoMod install path and asset copy from Path/Files to File.
app/src/main/java/com/app/ralaunch/core/platform/install/extractors/GogShFileExtractor.kt Migrates extractor paths from Path/Files to File.
app/src/main/java/com/app/ralaunch/core/platform/install/extractors/ExtractorCollection.kt Updates extractor interface signatures from Path to File.
app/src/main/java/com/app/ralaunch/core/platform/install/extractors/BasicSevenZipExtractor.kt Migrates extractor implementation to File and adds path traversal checks/prefix filtering.
app/src/main/java/com/app/ralaunch/core/platform/install/GameExtractorUtils.kt Updates extraction utilities to use File-based extractor APIs.
app/src/main/java/com/app/ralaunch/core/platform/android/provider/RaLaunchDocumentsProvider.kt Migrates delete recursion helper usage from Paths.get(...) to File.
app/src/main/java/com/app/ralaunch/core/platform/android/ProcessLauncherService.kt Updates patch lookup call sites to use File(assemblyPath).
app/src/main/java/com/app/ralaunch/core/common/util/TemporaryFileAcquirer.kt Migrates temp file management from Path to File.
app/src/main/java/com/app/ralaunch/core/common/util/FileUtils.kt Replaces NIO-based recursive delete with File-based implementation; adds helpers.
app/src/main/java/com/app/ralaunch/core/common/GameDeletionManager.kt Migrates delete calls to use File rather than Paths.
app/src/main/java/com/app/ralaunch/RaLaunchApp.kt Adds global uncaught exception logger + startup-step logging; minor refactors.
app/src/main/cpp/liblinkernsbypass/android_linker_ns.cpp Disables namespace-bypass logic on API < 28 and falls back to regular dlopen.
app/src/main/cpp/CMakeLists.txt Makes SDL target selection dynamic and adjusts install target list.
app/src/main/AndroidManifest.xml Adds tools:targetApi annotations and uses-sdk overrideLibrary; reorders some attributes.
app/build.gradle Lowers minSdk, enables desugaring, aligns Java/Kotlin targets to 17, adjusts native platform argument.
README_ZH.md Updates requirements badge/text to Android 7.1+.
README.md Updates requirements badge/text to Android 7.1+.
.github/workflows/sync-fork.yml Adds fork sync workflow that prefers local changes on conflict.
.github/workflows/build-apk.yml Simplifies build workflow, pins JDK 17, builds release on push, signs/archives output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/build.gradle Outdated
Comment on lines +68 to +71
dependencies {
coreLibraryDesugaring(libs.desugar.jdk.libs)
implementation 'androidx.multidex:multidex:2.0.1'
}

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dependencies { ... } is nested inside the android { ... } block, which is not valid in the Android Gradle plugin DSL and will fail configuration ("Could not find method dependencies()..."). Move these dependencies to the top-level dependencies { ... } block (and keep coreLibraryDesugaringEnabled in compileOptions).

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +85
// Dùng File thay vì Path
val tempFile = File(settingsFile.parent, "${settingsFile.name}.tmp")
tempFile.writeText(serialized)

// Atomic move
if (!tempFile.renameTo(settingsFile)) {
// Nếu renameTo thất bại (khác partition), dùng copy + delete
settingsFile.writeText(serialized)
tempFile.delete()
}

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renameTo() is not a reliable atomic replacement across Android filesystems/SAF providers, and the fallback path writes directly to the final settings file (risking partial/corrupted writes if the process is killed mid-write). Use an actual atomic file pattern (e.g., AndroidX/Android AtomicFile, or a temp + fsync + replace strategy) and handle failures explicitly.

Copilot uses AI. Check for mistakes.
Comment on lines +163 to +166
// Tinh toan target file va chong path traversal
val targetFile = File(destinationFile, relativeFilePath).canonicalFile
if (!targetFile.path.startsWith(destinationFile.canonicalPath)) {
throw SevenZipException("Path traversal detected: $targetFile")

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path traversal guard is too weak: targetFile.path.startsWith(destinationFile.canonicalPath) can be bypassed by paths like ${dest}../... (handled by canonicalization) but also by sibling prefixes (e.g., /dest_evil/... startsWith /dest). Compare against destCanonical + File.separator (or use Path-based startsWith) to ensure the extracted file is truly inside the destination directory.

Copilot uses AI. Check for mistakes.
val prefix = sourceExtractionPrefix.path
val relativeFilePath = if (prefix.isEmpty() || prefix == ".") {
filePath
} else if (filePath.startsWith(prefix)) {

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prefix filtering uses a plain startsWith(prefix) check. This can incorrectly match entries like data/noarch/gameX/... when the prefix is data/noarch/game, causing unintended files to be extracted. Ensure the match is on a path segment boundary (e.g., require filePath == prefix or filePath.startsWith(prefix + "/")) before stripping the prefix.

Suggested change
} else if (filePath.startsWith(prefix)) {
} else if (filePath == prefix || filePath.startsWith("$prefix/") || filePath.startsWith("$prefix\\")) {

Copilot uses AI. Check for mistakes.
Comment on lines 35 to 40
fun getEnabledPatchIds(gameAsmFile: File): ArrayList<String> { // CHANGED: Path to File
return enabledPatches.getOrDefault(
gameAsmPath.toAbsolutePath().normalize().toString(),
// CHANGED: toAbsolutePath().normalize().toString() to canonicalFile.absolutePath
gameAsmFile.canonicalFile.absolutePath,
arrayListOf()
)

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canonicalFile can throw an IOException. Using it directly here means patch enable/disable checks can crash the app if the path cannot be canonicalized (e.g., permission issues, broken symlinks). Wrap canonicalization in runCatching { ... } with a safe fallback (like absoluteFile) and make sure the same normalization strategy is used consistently across reads/writes.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to 12
fun getEntryAssemblyAbsolutePath(): File {
return File(patchDir, manifest.entryAssemblyFile).canonicalFile
}

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getEntryAssemblyAbsolutePath() uses canonicalFile, which can throw IOException at call sites (e.g., when constructing DOTNET_STARTUP_HOOKS). A failure here would crash the launch flow; consider catching canonicalization errors and falling back to absoluteFile (or returning a Result).

Copilot uses AI. Check for mistakes.
Comment thread app/build.gradle Outdated
// 本地 JAR/AAR 依赖
// --- THAY ĐỔI 4: Thêm thư viện Desugaring ---
// Điều này bắt buộc để chạy các API Java hiện đại trên Android 7
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2'

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coreLibraryDesugaring is declared twice and with different versions (version-catalog at libs.desugar.jdk.libs vs hardcoded 2.1.2). This can lead to confusing resolution and makes version bumps error-prone. Prefer a single declaration using the version catalog (e.g., coreLibraryDesugaring(libs.desugar.jdk.libs)) in the top-level dependencies block.

Suggested change
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2'
coreLibraryDesugaring(libs.desugar.jdk.libs)

Copilot uses AI. Check for mistakes.
Comment thread shared/build.gradle.kts Outdated
Comment on lines +96 to 103
if (!settingsFile.exists()) return
val backupFile = File(
settingsFile.parent,
"${settingsFile.name}.corrupt.${System.currentTimeMillis()}"
)
settingsFilePathFull.moveTo(backupPathFull, overwrite = true)
// Dùng renameTo thay vì moveTo
settingsFile.renameTo(backupFile)
}

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

backupCorruptedFile() calls settingsFile.renameTo(backupFile) but ignores the boolean result. If the rename fails, the corrupted file remains in place and the app will keep failing to parse it on the next startup. Check the return value and consider falling back to copy+delete (or at least delete the corrupted file if it cannot be backed up).

Copilot uses AI. Check for mistakes.
Comment on lines 181 to 192
@Throws(IOException::class)
private fun getDefaultPatchStorageDirectories(customStoragePath: String?): Path {
private fun getDefaultPatchStorageDirectories(customStoragePath: String?): File {
val context: Context = KoinJavaComponent.get(Context::class.java)
val baseDir = customStoragePath ?: if (IS_DEFAULT_PATCH_STORAGE_DIR_EXTERNAL) {
Objects.requireNonNull(context.getExternalFilesDir(null))?.absolutePath
context.getExternalFilesDir(null)?.absolutePath
?: context.filesDir.absolutePath
} else {
context.filesDir.absolutePath
}
return Paths.get(baseDir, PATCH_STORAGE_DIR).normalize()
// Thay Paths.get().normalize() bang File()
return File(baseDir, PATCH_STORAGE_DIR).canonicalFile
}

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getDefaultPatchStorageDirectories() returns File(...).canonicalFile, which can throw IOException and crash during PatchManager initialization. Prefer a non-throwing normalization (absoluteFile) or catch IOException and fall back to the non-canonical path (while still normalizing separators) to avoid startup crashes.

Copilot uses AI. Check for mistakes.
@LaoSparrow

Copy link
Copy Markdown
Collaborator

bro you have 328 commits😭

@WinterWolfVN

Copy link
Copy Markdown
Author

Yeah

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants