85 lines
3.6 KiB
Kotlin
85 lines
3.6 KiB
Kotlin
package org.lsposed.npatch
|
|
|
|
import androidx.core.net.toUri
|
|
import androidx.documentfile.provider.DocumentFile
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.withContext
|
|
import org.lsposed.npatch.config.Configs
|
|
import org.lsposed.npatch.config.MyKeyStore
|
|
import org.lsposed.npatch.share.Constants
|
|
import org.lsposed.npatch.share.PatchConfig
|
|
import org.lsposed.patch.NPatch
|
|
import org.lsposed.patch.util.Logger
|
|
import java.io.File
|
|
import java.io.IOException
|
|
|
|
object Patcher {
|
|
|
|
class Options(
|
|
val newPackageName: String,
|
|
private val injectDex: Boolean,
|
|
private val config: PatchConfig,
|
|
private val apkPaths: List<String>,
|
|
private val embeddedModules: List<String>?
|
|
) {
|
|
fun toStringArray(): Array<String> {
|
|
return buildList {
|
|
add("-o"); add(lspApp.tmpApkDir.absolutePath)
|
|
add("-p"); add(config.newPackage)
|
|
if (config.debuggable) add("-d")
|
|
add("-l"); add(config.sigBypassLevel.toString())
|
|
if (config.useManager) add("--manager")
|
|
if (config.overrideVersionCode) add("-r")
|
|
if (Configs.detailPatchLogs) add("-v")
|
|
embeddedModules?.forEach {
|
|
add("-m"); add(it)
|
|
}
|
|
if (config.injectProvider) add("--provider")
|
|
if(injectDex) add("--injectdex")
|
|
if (config.useMicroG) add("--useMicroG")
|
|
if (!MyKeyStore.useDefault) {
|
|
addAll(arrayOf("-k", MyKeyStore.file.path, Configs.keyStorePassword, Configs.keyStoreAlias, Configs.keyStoreAliasPassword))
|
|
}
|
|
addAll(apkPaths)
|
|
}.toTypedArray()
|
|
}
|
|
}
|
|
|
|
suspend fun patch(logger: Logger, options: Options) {
|
|
withContext(Dispatchers.IO) {
|
|
NPatch(logger, *options.toStringArray()).doCommandLine()
|
|
|
|
val uri = Configs.storageDirectory?.toUri()
|
|
?: throw IOException("Uri is null")
|
|
val root = DocumentFile.fromTreeUri(lspApp, uri)
|
|
?: throw IOException("DocumentFile is null")
|
|
root.listFiles().forEach {
|
|
if (it.name?.endsWith(Constants.PATCH_FILE_SUFFIX) == true) it.delete()
|
|
}
|
|
lspApp.targetApkFiles?.clear()
|
|
val apkFileList = arrayListOf<File>()
|
|
val cacheRoot = lspApp.externalCacheDir ?: lspApp.cacheDir
|
|
lspApp.tmpApkDir.walk()
|
|
.filter { it.isFile && it.name.endsWith(Constants.PATCH_FILE_SUFFIX) }
|
|
.forEach { tempApkFile ->
|
|
val cachedApkFile = File(cacheRoot, tempApkFile.name)
|
|
if (tempApkFile.renameTo(cachedApkFile).not()) {
|
|
tempApkFile.copyTo(cachedApkFile, overwrite = true)
|
|
tempApkFile.delete()
|
|
}
|
|
apkFileList.add(cachedApkFile)
|
|
|
|
val finalFile = root.createFile("application/vnd.android.package-archive", cachedApkFile.name)
|
|
?: throw IOException("無法建立輸出檔案: ${cachedApkFile.name}")
|
|
lspApp.contentResolver.openOutputStream(finalFile.uri)?.use { output ->
|
|
cachedApkFile.inputStream().use { input ->
|
|
input.copyTo(output)
|
|
}
|
|
} ?: throw IOException("Unable to open an output stream: ${finalFile.uri}")
|
|
}
|
|
lspApp.targetApkFiles = apkFileList
|
|
logger.i("Patched files are saved to ${root.uri.lastPathSegment}")
|
|
}
|
|
}
|
|
}
|