1
mirror of https://github.com/topjohnwu/Magisk synced 2025-10-28 05:40:52 +01:00

Compare commits

..

44 Commits

Author SHA1 Message Date
topjohnwu
e81de7ec36 Release Magisk v30.0
[skip ci]
2025-07-01 10:14:43 -07:00
topjohnwu
c78da1ce24 Update v30.0 changelog 2025-07-01 10:00:38 -07:00
Wang Han
7b2d40987c Refactor magisk bins injection logic
Magisk binary mounting logic is not very clear now. In this commit, it
is rewritten in a more robust way. Now it has following cases in mind:
1) Device has a su binary, magisk need to overlay it
2) Choose the PATH with least files to reduce bind mount
3) Filter path which is not suitable
2025-07-01 02:16:16 -07:00
Wang Han
3a37e8c9c5 Don't clone attributes for magisk symlinks
This avoids use existing attributes for su, which will obviously break
magisk functions.
2025-07-01 02:16:16 -07:00
igor
58b405bce1 Update portuguese/english translation 2025-07-01 01:32:36 -07:00
Wang Han
810174ef73 Ignore set_context() error if magisktmp is /sbin
recreate_sbin() will bind mount original files in /sbin to tmpfs /sbin,
so we have no choice but just log here to let the loop continue.
2025-06-30 17:39:54 -07:00
topjohnwu
690a5ac033 Update to ONDK r28.5 2025-06-30 12:15:43 -07:00
topjohnwu
89aad31f7e Update gradle dependencies 2025-06-26 09:35:18 -07:00
topjohnwu
7124db98e3 Stop involving JSON in release script 2025-06-20 00:59:38 -07:00
topjohnwu
0860e859f7 Stop updating README for each release 2025-06-20 00:32:11 -07:00
topjohnwu
04008949b8 Deprecate canary channel 2025-06-20 00:22:17 -07:00
Wang Han
39f2940bd1 Skip symlink in restore_tmpcon()
If magisktmp is /sbin, there may exist files which is symlink to files in
root dir. As root is RO, setcontext will fail and break iterating loop.
2025-06-16 11:09:33 -07:00
topjohnwu
1460317ebd Cleanup C++ headers 2025-06-16 02:25:38 -07:00
topjohnwu
12340c9bd5 Update gradle version 2025-06-16 02:17:29 -07:00
topjohnwu
c4590fe2ba Reorganize buildSrc 2025-06-10 16:51:31 -07:00
topjohnwu
b36066bbcd Run clippy fix 2025-06-10 16:34:38 -07:00
topjohnwu
65d1c5827c Update dependencies 2025-06-10 16:33:06 -07:00
AshiVered
1d675c8b2e Update strings.xml
Improve Hebrew translations
2025-06-06 17:08:51 -07:00
Wang Han
0b494ed7df Avoid throwing error if chmod a symlink
It is possible that we want to clone attributes of a regular file to a
symlink. In this case, we don't need to error out if chmod fails. Just
skip it.
2025-06-06 17:08:34 -07:00
topjohnwu
48d9fc24eb Update release.sh 2025-06-05 11:00:27 -07:00
topjohnwu
83426f7f36 Update check update logic 2025-06-04 12:50:19 -07:00
Wang Han
0e86d4dbcb Fix file pointer leak on error path 2025-06-03 00:34:52 -07:00
Wang Han
5e050d7456 Check binary existence before injecting zygisk bins 2025-06-03 00:33:40 -07:00
topjohnwu
898580bf90 Update dependencies 2025-06-02 19:51:12 -07:00
topjohnwu
86621a4c46 Fix gradle cache 2025-05-30 11:11:53 -07:00
topjohnwu
a834e72b71 Use sccache for clippy 2025-05-30 11:11:45 -07:00
topjohnwu
d8cf42af16 Reduce unstable feature usage 2025-05-30 11:11:36 -07:00
topjohnwu
8c79d66b7b Update ONDK r28.4 2025-05-30 01:53:26 -07:00
Wang Han
fada8b148a Ensure manager can always bypass su access policy
This fixes https://github.com/topjohnwu/Magisk/issues/9050.
2025-05-21 16:14:46 -07:00
topjohnwu
dc0acea47c Remove C++ I/O streams 2025-05-20 03:26:00 -07:00
topjohnwu
78d1200608 Migrate all compression code to Rust 2025-05-20 03:26:00 -07:00
topjohnwu
527bbc0368 Migrate module mounting to Rust 2025-05-20 03:24:43 -07:00
topjohnwu
4c89c7e2b3 Directly use MagiskJson 2025-05-19 10:40:58 -07:00
topjohnwu
adbea7e313 Improve update check code 2025-05-19 10:23:15 -07:00
vvb2060
76962f965e app: use github api to check updates 2025-05-19 10:23:15 -07:00
topjohnwu
a4b8c5e46b Update app dependencies 2025-05-18 22:24:44 -07:00
The Ali Dev
83c707439c Add Urdu Translation 2025-05-18 22:21:05 -07:00
Radoš Milićev
25dd6121f4 Add author for Serbian translations to .xml files 2025-05-18 21:54:24 -07:00
Radoš Milićev
67f35ad027 Add Serbian latin (values-b+sr+Latn) 2025-05-18 21:54:24 -07:00
topjohnwu
0c4b8afbc5 Simplify JNI hooking code 2025-05-17 02:05:21 -07:00
topjohnwu
34b30d7ce1 Promite Magisk v29.0 to stable 2025-05-16 12:17:53 -07:00
topjohnwu
2215088973 Remove unused files in native directory 2025-05-15 13:48:12 -07:00
topjohnwu
8b7fb6cdde Improve scripts 2025-05-15 02:56:36 -07:00
topjohnwu
94c7dbedf2 Fix signing config
[skip ci]
2025-05-14 15:14:34 -07:00
121 changed files with 4157 additions and 3421 deletions

View File

@@ -70,7 +70,7 @@ runs:
.gradle/caches
.gradle/wrapper
!.gradle/caches/build-cache-*
key: gradle-cache-${{ hashFiles('gradle/**') }}
key: gradle-cache-${{ hashFiles('app/gradle/**') }}
restore-keys: gradle-cache-
- name: Restore Gradle dependencies

View File

@@ -110,7 +110,7 @@ jobs:
timeout-minutes: 10
env:
AVD_TEST_LOG: 1
run: scripts/avd_test.sh ${{ matrix.version }} ${{ matrix.type }}
run: scripts/avd.sh test ${{ matrix.version }} ${{ matrix.type }}
- name: Upload logs on error
if: ${{ failure() }}
@@ -152,7 +152,7 @@ jobs:
env:
FORCE_32_BIT: 1
AVD_TEST_LOG: 1
run: scripts/avd_test.sh ${{ matrix.version }}
run: scripts/avd.sh test ${{ matrix.version }}
- name: Upload logs on error
if: ${{ failure() }}

3
.gitmodules vendored
View File

@@ -10,9 +10,6 @@
[submodule "libcxx"]
path = native/src/external/libcxx
url = https://github.com/topjohnwu/libcxx.git
[submodule "zopfli"]
path = native/src/external/zopfli
url = https://github.com/google/zopfli.git
[submodule "cxx-rs"]
path = native/src/external/cxx-rs
url = https://github.com/topjohnwu/cxx.git

View File

@@ -16,13 +16,7 @@ Some highlight features:
## Downloads
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
Click the icon below to download Magisk apk.
[![](https://img.shields.io/badge/Magisk-v28.1-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v28.1)
[![](https://img.shields.io/badge/Magisk%20Beta-v29.0-blue)](https://github.com/topjohnwu/Magisk/releases/tag/v29.0)
[![](https://img.shields.io/badge/Magisk-Canary-red)](https://github.com/topjohnwu/Magisk/releases/tag/canary-29001)
[Github](https://github.com/topjohnwu/Magisk/releases) is the only source where you can get official Magisk information and downloads.
## Useful Links

View File

@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.dialog
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.R
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.download.DownloadEngine
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.view.MagiskDialog
@@ -11,15 +10,10 @@ import java.io.File
class ManagerInstallDialog : MarkDownDialog() {
private val svc get() = ServiceLocator.networkService
override suspend fun getMarkdownText(): String {
val text = svc.fetchString(Info.remote.magisk.note)
val text = Info.update.note
// Cache the changelog
AppContext.cacheDir.listFiles { _, name -> name.endsWith(".md") }.orEmpty().forEach {
it.delete()
}
File(AppContext.cacheDir, "${Info.remote.magisk.versionCode}.md").writeText(text)
File(AppContext.cacheDir, "${Info.update.versionCode}.md").writeText(text)
return text
}

View File

@@ -91,16 +91,15 @@ class HomeViewModel(
override suspend fun doLoadWork() {
appState = State.LOADING
Info.getRemote(svc)?.apply {
Info.fetchUpdate(svc)?.apply {
appState = when {
BuildConfig.APP_VERSION_CODE < magisk.versionCode -> State.OUTDATED
BuildConfig.APP_VERSION_CODE < versionCode -> State.OUTDATED
else -> State.UP_TO_DATE
}
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
managerRemoteVersion =
("${magisk.version} (${magisk.versionCode})" +
if (isDebug) " (D)" else "").asText()
("$version (${versionCode})" + if (isDebug) " (D)" else "").asText()
} ?: run {
appState = State.INVALID
managerRemoteVersion = CoreR.string.not_available.asText()

View File

@@ -14,9 +14,8 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.core.AppContext
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.base.ContentResultCallback
import com.topjohnwu.magisk.core.ktx.toast
@@ -70,17 +69,16 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
init {
viewModelScope.launch(Dispatchers.IO) {
try {
val file = File(AppContext.cacheDir, "${BuildConfig.APP_VERSION_CODE}.md")
val text = when {
file.exists() -> file.readText()
Const.Url.CHANGELOG_URL.isEmpty() -> ""
val noteFile = File(AppContext.cacheDir, "${APP_VERSION_CODE}.md")
val noteText = when {
noteFile.exists() -> noteFile.readText()
else -> {
val str = svc.fetchString(Const.Url.CHANGELOG_URL)
file.writeText(str)
str
val note = svc.fetchUpdate(APP_VERSION_CODE).note
noteFile.writeText(note)
note
}
}
val spanned = markwon.toMarkdown(text)
val spanned = markwon.toMarkdown(noteText)
withContext(Dispatchers.Main) {
notes = spanned
}
@@ -100,13 +98,15 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
}
override fun onSaveState(state: Bundle) {
state.putParcelable(INSTALL_STATE_KEY, InstallState(
methodId,
step,
Config.keepVerity,
Config.keepEnc,
Config.recovery
))
state.putParcelable(
INSTALL_STATE_KEY, InstallState(
methodId,
step,
Config.keepVerity,
Config.keepEnc,
Config.recovery
)
)
}
override fun onRestoreState(state: Bundle) {
@@ -124,6 +124,7 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
override fun onActivityLaunch() {
AppContext.toast(CoreR.string.patch_file_msg, Toast.LENGTH_LONG)
}
override fun onActivityResult(result: Uri) {
uri.value = result
}

View File

@@ -147,19 +147,11 @@ object UpdateChannel : BaseSettingsItem.Selector() {
get() = Config.updateChannel
set(value) {
Config.updateChannel = value
Info.remote = Info.EMPTY_REMOTE
Info.resetUpdate()
}
override val title = CoreR.string.settings_update_channel_title.asText()
override val entryRes = CoreR.array.update_channel
override fun entries(res: Resources): Array<String> {
return super.entries(res).let {
if (!Const.APP_IS_CANARY && !BuildConfig.DEBUG)
it.copyOfRange(0, Config.Value.CANARY_CHANNEL)
else it
}
}
}
object UpdateChannelUrl : BaseSettingsItem.Input() {
@@ -169,7 +161,7 @@ object UpdateChannelUrl : BaseSettingsItem.Input() {
get() = Config.customChannelUrl
set(value) {
Config.customChannelUrl = value
Info.remote = Info.EMPTY_REMOTE
Info.resetUpdate()
notifyPropertyChanged(BR.description)
}

View File

@@ -30,5 +30,6 @@ dependencies {
implementation(libs.ksp.plugin)
implementation(libs.navigation.safe.args.plugin)
implementation(libs.lsparanoid.plugin)
implementation(libs.moshi.plugin)
implementation(libs.jgit)
}

View File

@@ -0,0 +1,77 @@
import com.android.build.api.artifact.ArtifactTransformationRequest
import com.android.build.api.dsl.ApkSigningConfig
import com.android.builder.internal.packaging.IncrementalPackager
import com.android.tools.build.apkzlib.sign.SigningExtension
import com.android.tools.build.apkzlib.sign.SigningOptions
import com.android.tools.build.apkzlib.zfile.ZFiles
import com.android.tools.build.apkzlib.zip.ZFileOptions
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import java.io.File
import java.security.KeyStore
import java.security.cert.X509Certificate
import java.util.jar.JarFile
abstract class AddCommentTask: DefaultTask() {
@get:Input
abstract val comment: Property<String>
@get:Input
abstract val signingConfig: Property<ApkSigningConfig>
@get:InputFiles
abstract val apkFolder: DirectoryProperty
@get:OutputDirectory
abstract val outFolder: DirectoryProperty
@get:Internal
abstract val transformationRequest: Property<ArtifactTransformationRequest<AddCommentTask>>
@TaskAction
fun taskAction() = transformationRequest.get().submit(this) { artifact ->
val inFile = File(artifact.outputFile)
val outFile = outFolder.file(inFile.name).get().asFile
val privateKey = signingConfig.get().getPrivateKey()
val signingOptions = SigningOptions.builder()
.setMinSdkVersion(0)
.setV1SigningEnabled(true)
.setV2SigningEnabled(true)
.setKey(privateKey.privateKey)
.setCertificates(privateKey.certificate as X509Certificate)
.setValidation(SigningOptions.Validation.ASSUME_INVALID)
.build()
val options = ZFileOptions().apply {
noTimestamps = true
autoSortFiles = true
}
outFile.parentFile?.mkdirs()
inFile.copyTo(outFile, overwrite = true)
ZFiles.apk(outFile, options).use {
SigningExtension(signingOptions).register(it)
it.eocdComment = comment.get().toByteArray()
it.get(IncrementalPackager.APP_METADATA_ENTRY_PATH)?.delete()
it.get(IncrementalPackager.VERSION_CONTROL_INFO_ENTRY_PATH)?.delete()
it.get(JarFile.MANIFEST_NAME)?.delete()
}
outFile
}
private fun ApkSigningConfig.getPrivateKey(): KeyStore.PrivateKeyEntry {
val keyStore = KeyStore.getInstance(storeType ?: KeyStore.getDefaultType())
storeFile!!.inputStream().use {
keyStore.load(it, storePassword!!.toCharArray())
}
val keyPwdArray = keyPassword!!.toCharArray()
val entry = keyStore.getEntry(keyAlias!!, KeyStore.PasswordProtection(keyPwdArray))
return entry as KeyStore.PrivateKeyEntry
}
}

View File

@@ -5,6 +5,12 @@ import org.gradle.api.Project
import org.gradle.kotlin.dsl.provideDelegate
import java.io.File
import java.util.Properties
import java.util.Random
// Set non-zero value here to fix the random seed for reproducible builds
// CI builds are always reproducible
val RAND_SEED = if (System.getenv("CI") != null) 42 else 0
lateinit var RANDOM: Random
private val props = Properties()
private var commitHash = ""
@@ -28,7 +34,11 @@ object Config {
}
}
val Project.baseDir: File get() = rootProject.file("..")
fun Project.rootFile(path: String): File {
val file = File(path)
return if (file.isAbsolute) file
else File(rootProject.file(".."), path)
}
class MagiskPlugin : Plugin<Project> {
override fun apply(project: Project) = project.applyPlugin()
@@ -38,11 +48,11 @@ class MagiskPlugin : Plugin<Project> {
props.clear()
rootProject.file("gradle.properties").inputStream().use { props.load(it) }
val configPath: String? by this
val config = configPath?.let { File(it) } ?: File(baseDir, "config.prop")
val config = rootFile(configPath ?: "config.prop")
if (config.exists())
config.inputStream().use { props.load(it) }
val repo = FileRepository(File(baseDir, ".git"))
val repo = FileRepository(rootFile(".git"))
val refId = repo.refDatabase.exactRef("HEAD").objectId
commitHash = repo.newObjectReader().abbreviate(refId, 8).name()
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,11 @@
import com.android.build.api.artifact.SingleArtifact
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
@@ -10,22 +13,25 @@ import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.named
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.security.SecureRandom
import java.util.Random
import java.util.zip.Deflater
import java.util.zip.DeflaterOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
import javax.crypto.Cipher
import javax.crypto.CipherOutputStream
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import kotlin.random.asKotlinRandom
// Set non-zero value here to fix the random seed for reproducible builds
// CI builds are always reproducible
val RAND_SEED = if (System.getenv("CI") != null) 42 else 0
private lateinit var RANDOM: Random
private val kRANDOM get() = RANDOM.asKotlinRandom()
private val c1 = mutableListOf<String>()
@@ -72,7 +78,7 @@ private fun PrintStream.byteField(name: String, bytes: ByteArray) {
}
@CacheableTask
abstract class ManifestUpdater: DefaultTask() {
private abstract class ManifestUpdater: DefaultTask() {
@get:Input
abstract val applicationId: Property<String>
@@ -182,9 +188,7 @@ abstract class ManifestUpdater: DefaultTask() {
}
fun genStubClasses(factoryOutDir: File, appOutDir: File) {
fun String.ind(level: Int) = replaceIndentByMargin(" ".repeat(level))
private fun genStubClasses(factoryOutDir: File, appOutDir: File) {
val classNameGenerator = sequence {
fun notJavaKeyword(name: String) = when (name) {
"do", "if", "for", "int", "new", "try" -> false
@@ -228,7 +232,7 @@ fun genStubClasses(factoryOutDir: File, appOutDir: File) {
genClass("StubApplication", appOutDir)
}
fun genEncryptedResources(res: ByteArray, outDir: File) {
private fun genEncryptedResources(res: ByteArray, outDir: File) {
val mainPkgDir = File(outDir, "com/topjohnwu/magisk")
mainPkgDir.mkdirs()
@@ -259,3 +263,86 @@ fun genEncryptedResources(res: ByteArray, outDir: File) {
it.println("}")
}
}
fun Project.setupStubApk() {
setupAppCommon()
androidComponents.onVariants { variant ->
val variantName = variant.name
val variantCapped = variantName.replaceFirstChar { it.uppercase() }
val manifestUpdater =
project.tasks.register("${variantName}ManifestProducer", ManifestUpdater::class.java) {
dependsOn("generate${variantCapped}ObfuscatedClass")
applicationId = variant.applicationId
appClassDir.set(layout.buildDirectory.dir("generated/source/app/$variantName"))
factoryClassDir.set(layout.buildDirectory.dir("generated/source/factory/$variantName"))
}
variant.artifacts.use(manifestUpdater)
.wiredWithFiles(
ManifestUpdater::mergedManifest,
ManifestUpdater::outputManifest)
.toTransform(SingleArtifact.MERGED_MANIFEST)
}
androidApp.applicationVariants.all {
val variantCapped = name.replaceFirstChar { it.uppercase() }
val variantLowered = name.lowercase()
val outFactoryClassDir = layout.buildDirectory.file("generated/source/factory/${variantLowered}").get().asFile
val outAppClassDir = layout.buildDirectory.file("generated/source/app/${variantLowered}").get().asFile
val outResDir = layout.buildDirectory.dir("generated/source/res/${variantLowered}").get().asFile
val aapt = File(androidApp.sdkDirectory, "build-tools/${androidApp.buildToolsVersion}/aapt2")
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
"${variantLowered}/process${variantCapped}Resources/linked-resources-binary-format-${variantLowered}.ap_").get().asFile
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
inputs.property("seed", RAND_SEED)
outputs.dirs(outFactoryClassDir, outAppClassDir)
doLast {
outFactoryClassDir.mkdirs()
outAppClassDir.mkdirs()
genStubClasses(outFactoryClassDir, outAppClassDir)
}
}
registerJavaGeneratingTask(genManifestTask, outFactoryClassDir, outAppClassDir)
val processResourcesTask = tasks.named("process${variantCapped}Resources") {
outputs.dir(outResDir)
doLast {
val apkTmp = File("${apk}.tmp")
exec {
commandLine(aapt, "optimize", "-o", apkTmp, "--collapse-resource-names", apk)
}
val bos = ByteArrayOutputStream()
ZipFile(apkTmp).use { src ->
ZipOutputStream(apk.outputStream()).use {
it.setLevel(Deflater.BEST_COMPRESSION)
it.putNextEntry(ZipEntry("AndroidManifest.xml"))
src.getInputStream(src.getEntry("AndroidManifest.xml")).transferTo(it)
it.closeEntry()
}
DeflaterOutputStream(bos, Deflater(Deflater.BEST_COMPRESSION)).use {
src.getInputStream(src.getEntry("resources.arsc")).transferTo(it)
}
}
apkTmp.delete()
genEncryptedResources(bos.toByteArray(), outResDir)
}
}
registerJavaGeneratingTask(processResourcesTask, outResDir)
}
// Override optimizeReleaseResources task
val apk = layout.buildDirectory.file("intermediates/linked_resources_binary_format/" +
"release/processReleaseResources/linked-resources-binary-format-release.ap_").get().asFile
val optRes = layout.buildDirectory.file("intermediates/optimized_processed_res/" +
"release/optimizeReleaseResources/resources-release-optimize.ap_").get().asFile
afterEvaluate {
tasks.named("optimizeReleaseResources") {
doLast { apk.copyTo(optRes, true) }
}
}
tasks.named<Delete>("clean") {
delete.addAll(listOf("src/debug/AndroidManifest.xml", "src/release/AndroidManifest.xml"))
}
}

5
app/core/.gitignore vendored
View File

@@ -1,4 +1,3 @@
/build
src/*/assets
src/*/jniLibs
src/*/resources
src/debug
src/release

View File

@@ -2,6 +2,7 @@ plugins {
id("com.android.library")
kotlin("android")
kotlin("plugin.parcelize")
id("dev.zacsweers.moshix")
id("com.google.devtools.ksp")
}
@@ -48,9 +49,6 @@ dependencies {
implementation(libs.okhttp.logging)
implementation(libs.okhttp.dnsoverhttps)
implementation(libs.moshi)
ksp(libs.moshi.codegen)
implementation(libs.room.runtime)
implementation(libs.room.ktx)
ksp(libs.room.compiler)

View File

@@ -33,7 +33,7 @@ object Config : PreferenceConfig, DBConfig {
const val SU_REAUTH = "su_reauth"
const val SU_TAPJACK = "su_tapjack"
const val CHECK_UPDATES = "check_update"
const val UPDATE_CHANNEL = "update_channel"
const val RELEASE_CHANNEL = "release_channel"
const val CUSTOM_CHANNEL = "custom_channel"
const val LOCALE = "locale"
const val DARK_THEME = "dark_theme_extended"
@@ -48,7 +48,7 @@ object Config : PreferenceConfig, DBConfig {
SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK)
}
object Value {
object OldValue {
// Update channels
const val DEFAULT_CHANNEL = -1
const val STABLE_CHANNEL = 0
@@ -56,6 +56,15 @@ object Config : PreferenceConfig, DBConfig {
const val CUSTOM_CHANNEL = 2
const val CANARY_CHANNEL = 3
const val DEBUG_CHANNEL = 4
}
object Value {
// Update channels
const val DEFAULT_CHANNEL = -1
const val STABLE_CHANNEL = 0
const val BETA_CHANNEL = 1
const val DEBUG_CHANNEL = 2
const val CUSTOM_CHANNEL = 3
// root access mode
const val ROOT_ACCESS_DISABLED = 0
@@ -86,14 +95,6 @@ object Config : PreferenceConfig, DBConfig {
val TIMEOUT_LIST = longArrayOf(0, -1, 10, 20, 30, 60)
}
private val defaultChannel =
if (BuildConfig.DEBUG)
Value.DEBUG_CHANNEL
else if (Const.APP_IS_CANARY)
Value.CANARY_CHANNEL
else
Value.DEFAULT_CHANNEL
@JvmField var keepVerity = false
@JvmField var keepEnc = false
@JvmField var recovery = false
@@ -109,7 +110,7 @@ object Config : PreferenceConfig, DBConfig {
private var checkUpdatePrefs by preference(Key.CHECK_UPDATES, true)
private var localePrefs by preference(Key.LOCALE, "")
var doh by preference(Key.DOH, false)
var updateChannel by preferenceStrInt(Key.UPDATE_CHANNEL, defaultChannel)
var updateChannel by preference(Key.RELEASE_CHANNEL, Value.DEFAULT_CHANNEL)
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
var downloadDir by preference(Key.DOWNLOAD_DIR, "")
var randName by preference(Key.RAND_NAME, true)
@@ -148,6 +149,7 @@ object Config : PreferenceConfig, DBConfig {
var suTapjack by preference(Key.SU_TAPJACK, true)
private const val SU_FINGERPRINT = "su_fingerprint"
private const val UPDATE_CHANNEL = "update_channel"
fun toBundle(): Bundle {
val map = prefs.all - Key.NO_MIGRATION
@@ -183,17 +185,23 @@ object Config : PreferenceConfig, DBConfig {
}
prefs.edit {
// Settings migration
// Migrate su_fingerprint
if (prefs.getBoolean(SU_FINGERPRINT, false))
suBiometric = true
remove(SU_FINGERPRINT)
prefs.getString(Key.UPDATE_CHANNEL, null).also {
if (it == null ||
it.toInt() > Value.DEBUG_CHANNEL ||
it.toInt() < Value.DEFAULT_CHANNEL) {
putString(Key.UPDATE_CHANNEL, defaultChannel.toString())
// Migrate update_channel
prefs.getString(UPDATE_CHANNEL, null)?.let {
val channel = when (it.toInt()) {
OldValue.STABLE_CHANNEL -> Value.STABLE_CHANNEL
OldValue.CANARY_CHANNEL, OldValue.BETA_CHANNEL -> Value.BETA_CHANNEL
OldValue.DEBUG_CHANNEL -> Value.DEBUG_CHANNEL
OldValue.CUSTOM_CHANNEL -> Value.CUSTOM_CHANNEL
else -> Value.DEFAULT_CHANNEL
}
putInt(Key.RELEASE_CHANNEL, channel)
}
remove(UPDATE_CHANNEL)
}
}
}

View File

@@ -2,6 +2,7 @@ package com.topjohnwu.magisk.core
import android.os.Build
import android.os.Process
import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE
@Suppress("DEPRECATION")
object Const {
@@ -20,18 +21,14 @@ object Const {
// Misc
val USER_ID = Process.myUid() / 100000
val APP_IS_CANARY get() = Version.isCanary(BuildConfig.APP_VERSION_CODE)
object Version {
const val MIN_VERSION = "v22.0"
const val MIN_VERCODE = 22000
fun atLeast_24_0() = Info.env.versionCode >= 24000 || isCanary()
fun atLeast_25_0() = Info.env.versionCode >= 25000 || isCanary()
fun atLeast_28_0() = Info.env.versionCode >= 28000 || isCanary()
fun isCanary() = isCanary(Info.env.versionCode)
fun isCanary(ver: Int) = ver > 0 && ver % 100 != 0
fun atLeast_24_0() = Info.env.versionCode >= 24000
fun atLeast_25_0() = Info.env.versionCode >= 25000
fun atLeast_28_0() = Info.env.versionCode >= 28000
}
object ID {
@@ -43,13 +40,9 @@ object Const {
const val PATREON_URL = "https://www.patreon.com/topjohnwu"
const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk"
val CHANGELOG_URL = if (APP_IS_CANARY) Info.remote.magisk.note
else "https://topjohnwu.github.io/Magisk/releases/${BuildConfig.APP_VERSION_CODE}.md"
const val GITHUB_RAW_URL = "https://raw.githubusercontent.com/"
const val GITHUB_API_URL = "https://api.github.com/"
const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk-files/"
const val JS_DELIVR_URL = "https://cdn.jsdelivr.net/gh/"
const val INVALID_URL = "https://example.com/"
}
object Key {

View File

@@ -19,12 +19,18 @@ object Info {
var stub: StubApk.Data? = null
val EMPTY_REMOTE = UpdateInfo()
var remote = EMPTY_REMOTE
suspend fun getRemote(svc: NetworkService): UpdateInfo? {
return if (remote === EMPTY_REMOTE) {
svc.fetchUpdate()?.apply { remote = this }
} else remote
private val EMPTY_UPDATE = UpdateInfo()
var update = EMPTY_UPDATE
private set
suspend fun fetchUpdate(svc: NetworkService): UpdateInfo? {
return if (update === EMPTY_UPDATE) {
svc.fetchUpdate()?.apply { update = this }
} else update
}
fun resetUpdate() {
update = EMPTY_UPDATE
}
var isRooted = false

View File

@@ -75,9 +75,8 @@ class JobService : BaseJobService() {
private fun checkUpdate(params: JobParameters): Boolean {
GlobalScope.launch(Dispatchers.IO) {
ServiceLocator.networkService.fetchUpdate()?.let {
Info.remote = it
if (Info.env.isActive && BuildConfig.APP_VERSION_CODE < it.magisk.versionCode)
Info.fetchUpdate(ServiceLocator.networkService)?.let {
if (Info.env.isActive && BuildConfig.APP_VERSION_CODE < it.versionCode)
Notifications.updateAvailable()
jobFinished(params, false)
}

View File

@@ -1,45 +0,0 @@
package com.topjohnwu.magisk.core.data
import com.topjohnwu.magisk.core.model.BranchInfo
import com.topjohnwu.magisk.core.model.ModuleJson
import com.topjohnwu.magisk.core.model.UpdateInfo
import okhttp3.ResponseBody
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Path
import retrofit2.http.Streaming
import retrofit2.http.Url
private const val BRANCH = "branch"
private const val REPO = "repo"
private const val FILE = "file"
interface GithubPageServices {
@GET
suspend fun fetchUpdateJSON(@Url file: String): UpdateInfo
}
interface RawServices {
@GET
@Streaming
suspend fun fetchFile(@Url url: String): ResponseBody
@GET
suspend fun fetchString(@Url url: String): String
@GET
suspend fun fetchModuleJson(@Url url: String): ModuleJson
}
interface GithubApiServices {
@GET("repos/{$REPO}/branches/{$BRANCH}")
@Headers("Accept: application/vnd.github.v3+json")
suspend fun fetchBranch(
@Path(REPO, encoded = true) repo: String,
@Path(BRANCH) branch: String
): BranchInfo
}

View File

@@ -0,0 +1,48 @@
package com.topjohnwu.magisk.core.data
import com.topjohnwu.magisk.core.model.ModuleJson
import com.topjohnwu.magisk.core.model.Release
import com.topjohnwu.magisk.core.model.UpdateJson
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.Path
import retrofit2.http.Query
import retrofit2.http.Streaming
import retrofit2.http.Url
interface RawUrl {
@GET
@Streaming
suspend fun fetchFile(@Url url: String): ResponseBody
@GET
suspend fun fetchString(@Url url: String): String
@GET
suspend fun fetchModuleJson(@Url url: String): ModuleJson
@GET
suspend fun fetchUpdateJson(@Url url: String): UpdateJson
}
interface GithubApiServices {
@GET("/repos/{owner}/{repo}/releases")
@Headers("Accept: application/vnd.github+json")
suspend fun fetchReleases(
@Path("owner") owner: String = "topjohnwu",
@Path("repo") repo: String = "Magisk",
@Query("per_page") per: Int = 10,
@Query("page") page: Int = 1,
): Response<MutableList<Release>>
@GET("/repos/{owner}/{repo}/releases/latest")
@Headers("Accept: application/vnd.github+json")
suspend fun fetchLatestRelease(
@Path("owner") owner: String = "topjohnwu",
@Path("repo") repo: String = "Magisk",
): Release
}

View File

@@ -5,6 +5,7 @@ import com.squareup.moshi.Moshi
import com.topjohnwu.magisk.ProviderInstaller
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.model.DateTimeAdapter
import com.topjohnwu.magisk.core.utils.LocaleSetting
import okhttp3.Cache
import okhttp3.ConnectionSpec
@@ -77,7 +78,7 @@ fun createOkHttpClient(context: Context): OkHttpClient {
}
fun createMoshiConverterFactory(): MoshiConverterFactory {
val moshi = Moshi.Builder().build()
val moshi = Moshi.Builder().add(DateTimeAdapter()).build()
return MoshiConverterFactory.create(moshi)
}

View File

@@ -35,8 +35,8 @@ object ServiceLocator {
val markwon by lazy { createMarkwon(AppContext) }
val networkService by lazy {
NetworkService(
createApiService(retrofit, Const.Url.GITHUB_PAGE_URL),
createApiService(retrofit, Const.Url.GITHUB_RAW_URL),
createApiService(retrofit, Const.Url.INVALID_URL),
createApiService(retrofit, Const.Url.GITHUB_API_URL),
)
}
}

View File

@@ -8,7 +8,7 @@ import android.net.Uri
import android.os.Parcelable
import androidx.core.net.toUri
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.MagiskJson
import com.topjohnwu.magisk.core.model.UpdateInfo
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.view.Notifications
@@ -38,7 +38,7 @@ abstract class Subject : Parcelable {
@Parcelize
class App(
private val json: MagiskJson = Info.remote.magisk,
private val json: UpdateInfo = Info.update,
override val notifyId: Int = Notifications.nextId()
) : Subject() {
override val title: String get() = "Magisk-${json.version}(${json.versionCode})"

View File

@@ -1,17 +1,23 @@
package com.topjohnwu.magisk.core.model
import android.os.Parcelable
import com.squareup.moshi.FromJson
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.squareup.moshi.JsonQualifier
import com.squareup.moshi.ToJson
import kotlinx.parcelize.Parcelize
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME
@JsonClass(generateAdapter = true)
data class UpdateInfo(
val magisk: MagiskJson = MagiskJson(),
class UpdateJson(
val magisk: UpdateInfo = UpdateInfo(),
)
@Parcelize
@JsonClass(generateAdapter = true)
data class MagiskJson(
data class UpdateInfo(
val version: String = "",
val versionCode: Int = -1,
val link: String = "",
@@ -27,11 +33,37 @@ data class ModuleJson(
)
@JsonClass(generateAdapter = true)
data class CommitInfo(
val sha: String
data class ReleaseAssets(
val name: String,
@Json(name = "browser_download_url") val url: String,
)
class DateTimeAdapter {
@ToJson
fun toJson(date: LocalDateTime): String {
return date.toString()
}
@FromJson
fun fromJson(date: String): LocalDateTime {
return LocalDateTime.parse(date, ISO_OFFSET_DATE_TIME)
}
}
@JsonClass(generateAdapter = true)
data class BranchInfo(
val commit: CommitInfo
)
data class Release(
@Json(name = "tag_name") val tag: String,
val name: String,
val prerelease: Boolean,
val assets: List<ReleaseAssets>,
val body: String,
@Json(name = "created_at") val createdTime: LocalDateTime,
) {
val versionCode: Int get() {
return if (tag[0] == 'v') {
(tag.drop(1).toFloat() * 1000).toInt()
} else {
tag.drop(7).toInt()
}
}
}

View File

@@ -1,46 +1,112 @@
package com.topjohnwu.magisk.core.repository
import com.topjohnwu.magisk.core.BuildConfig
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Config.Value.BETA_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.CANARY_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.CUSTOM_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.DEBUG_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.DEFAULT_CHANNEL
import com.topjohnwu.magisk.core.Config.Value.STABLE_CHANNEL
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.data.GithubPageServices
import com.topjohnwu.magisk.core.data.RawServices
import com.topjohnwu.magisk.core.data.GithubApiServices
import com.topjohnwu.magisk.core.data.RawUrl
import com.topjohnwu.magisk.core.model.Release
import com.topjohnwu.magisk.core.model.ReleaseAssets
import com.topjohnwu.magisk.core.model.UpdateInfo
import retrofit2.HttpException
import timber.log.Timber
import java.io.IOException
import java.time.format.DateTimeFormatter
class NetworkService(
private val pages: GithubPageServices,
private val raw: RawServices
private val raw: RawUrl,
private val api: GithubApiServices,
) {
suspend fun fetchUpdate() = safe {
var info = when (Config.updateChannel) {
DEFAULT_CHANNEL, STABLE_CHANNEL -> fetchStableUpdate()
DEFAULT_CHANNEL -> if (BuildConfig.DEBUG) fetchDebugUpdate() else fetchStableUpdate()
STABLE_CHANNEL -> fetchStableUpdate()
BETA_CHANNEL -> fetchBetaUpdate()
CANARY_CHANNEL -> fetchCanaryUpdate()
DEBUG_CHANNEL -> fetchDebugUpdate()
CUSTOM_CHANNEL -> fetchCustomUpdate(Config.customChannelUrl)
else -> throw IllegalArgumentException()
}
if (info.magisk.versionCode < Info.env.versionCode &&
Config.updateChannel == DEFAULT_CHANNEL) {
if (info.versionCode < Info.env.versionCode &&
Config.updateChannel == DEFAULT_CHANNEL &&
!BuildConfig.DEBUG
) {
Config.updateChannel = BETA_CHANNEL
info = fetchBetaUpdate()
}
info
}
// UpdateInfo
private suspend fun fetchStableUpdate() = pages.fetchUpdateJSON("stable.json")
private suspend fun fetchBetaUpdate() = pages.fetchUpdateJSON("beta.json")
private suspend fun fetchCanaryUpdate() = pages.fetchUpdateJSON("canary.json")
private suspend fun fetchDebugUpdate() = pages.fetchUpdateJSON("debug.json")
private suspend fun fetchCustomUpdate(url: String) = pages.fetchUpdateJSON(url)
suspend fun fetchUpdate(version: Int) = findRelease { it.versionCode == version }.asInfo()
// Keep going through all release pages until we find a match
private suspend inline fun findRelease(predicate: (Release) -> Boolean): Release? {
var page = 1
while (true) {
val response = api.fetchReleases(page = page)
val releases = response.body() ?: throw HttpException(response)
// Remove all non Magisk releases
releases.removeAll { it.tag[0] != 'v' && !it.tag.startsWith("canary") }
// Make sure it's sorted correctly
releases.sortByDescending { it.createdTime }
releases.find(predicate)?.let { return it }
if (response.headers()["link"]?.contains("rel=\"next\"", ignoreCase = true) == true) {
page += 1
} else {
return null
}
}
}
private inline fun Release?.asInfo(
selector: (ReleaseAssets) -> Boolean = {
// Default selector picks the non-debug APK
it.name.run { endsWith(".apk") && !contains("debug") }
}): UpdateInfo {
return if (this == null) UpdateInfo()
else if (tag[0] == 'v') asPublicInfo(selector)
else asCanaryInfo(selector)
}
private inline fun Release.asPublicInfo(selector: (ReleaseAssets) -> Boolean): UpdateInfo {
val version = tag.drop(1)
val date = createdTime.format(DateTimeFormatter.ofPattern("yyyy.M.d"))
return UpdateInfo(
version = version,
versionCode = versionCode,
link = assets.find(selector)!!.url,
note = "## $date $name\n\n$body"
)
}
private inline fun Release.asCanaryInfo(selector: (ReleaseAssets) -> Boolean): UpdateInfo {
return UpdateInfo(
version = name.substring(8, 16),
versionCode = versionCode,
link = assets.find(selector)!!.url,
note = "## $name\n\n$body"
)
}
// Version number: debug == beta >= stable
// Find the latest non-prerelease
private suspend fun fetchStableUpdate() = api.fetchLatestRelease().asInfo()
// Find the latest release, regardless whether it's prerelease
private suspend fun fetchBetaUpdate() = findRelease { true }.asInfo()
private suspend fun fetchDebugUpdate() =
findRelease { true }.asInfo { it.name == "app-debug.apk" }
private suspend fun fetchCustomUpdate(url: String): UpdateInfo {
val info = raw.fetchUpdateJson(url).magisk
return info.let { it.copy(note = raw.fetchString(it.note)) }
}
private inline fun <T> safe(factory: () -> T): T? {
return try {

View File

@@ -62,7 +62,7 @@ class NetworkObserver(context: Context) {
}
private fun postValue(b: Boolean) {
Info.remote = Info.EMPTY_REMOTE
Info.resetUpdate()
Info.isConnected.postValue(b)
}

View File

@@ -0,0 +1,252 @@
<resources>
<!--Author: Radoš Milićev (https://github.com/rammba)-->
<!--Sections-->
<string name="modules">Moduli</string>
<string name="superuser">Super-korisnik</string>
<string name="logs">Logovi</string>
<string name="settings">Podešavanja</string>
<string name="install">Instalacija</string>
<string name="section_home">Početno</string>
<string name="section_theme">Teme</string>
<string name="denylist">Lista zabrana</string>
<!--Home-->
<string name="no_connection">Nedostupna konekcija</string>
<string name="app_changelog">Promene u aplikaciji</string>
<string name="loading">Učitavanje…</string>
<string name="update">Ažuriranje</string>
<string name="not_available">N/A</string>
<string name="hide">Sakrij</string>
<string name="home_package">Paket</string>
<string name="home_app_title">Apl.</string>
<string name="home_notice_content">Preuzmite Magisk SAMO sa zvanične GitHub stranice. Fajlovi iz nepoznatih izvora mogu biti maliciozni!</string>
<string name="home_support_title">Podržite nas</string>
<string name="home_follow_title">Zapratite nas</string>
<string name="home_item_source">Izvor</string>
<string name="home_support_content">Magisk jeste i uvek će biti besplatan i open source. Možete pokazati da vam je stalo svojom donacijom.</string>
<string name="home_installed_version">Instalirano</string>
<string name="home_latest_version">Najnovije</string>
<string name="invalid_update_channel">Nevalidan kanal ažuriranja</string>
<string name="uninstall_magisk_title">Deinstaliraj Magisk</string>
<string name="uninstall_magisk_msg">Svi moduli će biti onemogućeni/uklonjeni!\nKoren će biti uklonjen!\nSvako neenkriptovano interno skladište će upotrebom Magisk-a biti ponovo enkriptovano!</string>
<!--Install-->
<string name="keep_force_encryption">Zadrži forsiranu enkripciju</string>
<string name="keep_dm_verity">Zadrži AVB 2.0/dm-verity</string>
<string name="recovery_mode">Režim oporavka</string>
<string name="install_options_title">Opcije</string>
<string name="install_method_title">Metod</string>
<string name="install_next">Naredno</string>
<string name="install_start">Počnimo</string>
<string name="manager_download_install">Pritisni da preuzmeš i instaliraš</string>
<string name="direct_install">Direktna instalacija (Preporučeno)</string>
<string name="install_inactive_slot">Instalacija na neaktivan slot (Nakon OTA)</string>
<string name="install_inactive_slot_msg">Vaš uređaj će biti FORSIRAN da se pokrene na trenutno neaktivnom slotu nakon ponovnog pokretanja!\nKoristite opciju samo kad se OTA završi.\nNastavi?</string>
<string name="setup_title">Dodatne postavke</string>
<string name="select_patch_file">Izaberite fajl</string>
<string name="patch_file_msg">Izaberite sliku (*.img) ili ODIN tarfile (*.tar) ili payload.bin (*.bin)</string>
<string name="reboot_delay_toast">Ponovo pokretanje za 5 sekundi…</string>
<string name="flash_screen_title">Instalacija</string>
<!--Superuser-->
<string name="su_request_title">Super-korisnički zahtev</string>
<string name="touch_filtered_warning">Magisk ne može da verifikuje vaš odgovor, jer aplikacija prikriva super-korisnički zahtev</string>
<string name="deny">Zabrani</string>
<string name="prompt">Zahtev</string>
<string name="grant">Dozvoli</string>
<string name="su_warning">Pruža potpun pristup vašem uređaju.\nZabranite ako niste sigurni!</string>
<string name="forever">Zauvek</string>
<string name="once">Jednom</string>
<string name="tenmin">10 min</string>
<string name="twentymin">20 min</string>
<string name="thirtymin">30 min</string>
<string name="sixtymin">60 min</string>
<string name="su_allow_toast">%1$s je dobio prava na super-korisnika</string>
<string name="su_deny_toast">%1$s nije dobio prava na super-korisnika</string>
<string name="su_snack_grant">Super-korisnička prava od %1$s su pružena</string>
<string name="su_snack_deny">Super-korisnička prava od %1$s su odbijena</string>
<string name="su_snack_notif_on">Notifikacije od %1$s su omogućene</string>
<string name="su_snack_notif_off">Notifikacije od %1$s su onemogućene</string>
<string name="su_snack_log_on">Logovanje za %1$s je omogućeno</string>
<string name="su_snack_log_off">Logovanje za %1$s je onemogućeno</string>
<string name="su_revoke_title">Opozovi?</string>
<string name="su_revoke_msg">Potvrdi da opozoveš prava na super-korisnika od %1$s?</string>
<string name="toast">Toast</string>
<string name="none">Ništa</string>
<string name="superuser_toggle_notification">Notifikacije</string>
<string name="superuser_toggle_revoke">Opozovi</string>
<string name="superuser_policy_none">Nijedna aplikacija nije tražila permisije za super-korisnika još uvek.</string>
<!--Logs-->
<string name="log_data_none">Nemate logova, pokušajte koristiti korenske aplikacije više</string>
<string name="log_data_magisk_none">Magisk logovi su prazni, to je čudno</string>
<string name="menuSaveLog">Sačuvaj log</string>
<string name="menuClearLog">Ukloni log</string>
<string name="logs_cleared">Log uspešno uklonjen</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">Ciljani UID: %1$d</string>
<string name="target_pid">Mount ns cinjani PID: %s</string>
<string name="selinux_context">SELinux kontekst: %s</string>
<string name="supp_group">Dopunska grupa: %s</string>
<!--SafetyNet-->
<!--MagiskHide-->
<string name="show_system_app">Prikaži sistemske apl.</string>
<string name="show_os_app">Prikaži apl. OS-a</string>
<string name="hide_filter_hint">Filtriraj po imenu</string>
<string name="hide_search">Pretraga</string>
<!--Module-->
<string name="no_info_provided">(Bez informacija)</string>
<string name="reboot_userspace">Lako ponovo pokretanje</string>
<string name="reboot_recovery">Ponovo pokreni za oporavak</string>
<string name="reboot_bootloader">Ponovo pokreni za bootloader</string>
<string name="reboot_download">Ponovo pokreni za preuzimanje</string>
<string name="reboot_edl">Ponovo pokreni za EDL</string>
<string name="reboot_safe_mode">Siguran mod</string>
<string name="module_version_author">%1$s od %2$s</string>
<string name="module_state_remove">Ukloni</string>
<string name="module_action">Akcija</string>
<string name="module_state_restore">Povrati</string>
<string name="module_action_install_external">Instaliraj iz skladišta</string>
<string name="update_available">Ažuriranje dostupno</string>
<string name="suspend_text_riru">Modul je suspendovan jer je %1$s omogućeno</string>
<string name="suspend_text_zygisk">Modul je suspendovan jer %1$s nije omogućeno</string>
<string name="zygisk_module_unloaded">Zygisk modul nije učitan zbog nekompatibilnosti</string>
<string name="module_empty">Nijedan modul nije instaliran</string>
<string name="confirm_install">Instaliraj modul %1$s?</string>
<string name="confirm_install_title">Potvrda instalacije</string>
<!--Settings-->
<string name="settings_dark_mode_title">Tema</string>
<string name="settings_dark_mode_message">Izaberite temu koja vam najviše odgovara!</string>
<string name="settings_dark_mode_light">Uvek svetlo</string>
<string name="settings_dark_mode_system">Prati sistem</string>
<string name="settings_dark_mode_dark">Uvek tamno</string>
<string name="settings_download_path_title">Putanja za preuzimanje</string>
<string name="settings_download_path_message">Fajlovi će biti sačuvani na %1$s</string>
<string name="settings_hide_app_title">Sakrij Magisk apl.</string>
<string name="settings_hide_app_summary">Instaliraj proxy aplikaciju sa nasumičnim ID-jem paketa i prilagođenom labelom</string>
<string name="settings_restore_app_title">Povrati Magisk apl.</string>
<string name="settings_restore_app_summary">Otkrij apl. i povrati originalni APK</string>
<string name="language">Jezik</string>
<string name="system_default">(Podrazumevano sistemski)</string>
<string name="settings_check_update_title">Proveri ažuriranja</string>
<string name="settings_check_update_summary">Periodično proveri ažuriranja u pozadini</string>
<string name="settings_update_channel_title">Kanal ažuriranja</string>
<string name="settings_update_stable">Stabilno</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Prilagođeno</string>
<string name="settings_update_custom_msg">Unesi prilagođeni URL kanala</string>
<string name="settings_zygisk_summary">Pokreni delove Magisk-a u zygote daemon-u</string>
<string name="settings_denylist_title">Sprovedi listu zabrana</string>
<string name="settings_denylist_summary">Procesi na listi zabrana će povratiti sve Magisk izmene</string>
<string name="settings_denylist_config_title">Konfiguriši listu zabrana</string>
<string name="settings_denylist_config_summary">Izaberi procese koji će biti na listi zabrana</string>
<string name="settings_hosts_title">Bezsistemski domaćini (hosts)</string>
<string name="settings_hosts_summary">Podrška bezsistemskih domaćina za aplikacije blokiranja reklama</string>
<string name="settings_hosts_toast">Modul bezsistemskih domaćina dodat</string>
<string name="settings_app_name_hint">Novo ime</string>
<string name="settings_app_name_helper">Apl. će biti spakovana pod ovim imenom</string>
<string name="settings_app_name_error">Nevalidan format</string>
<string name="settings_su_app_adb">Aplikacije i ADB</string>
<string name="settings_su_app">Samo aplikacije</string>
<string name="settings_su_adb">Samo ADB</string>
<string name="settings_su_disable">Onemogućeno</string>
<string name="settings_su_request_10">10 sekundi</string>
<string name="settings_su_request_15">15 sekundi</string>
<string name="settings_su_request_20">20 sekundi</string>
<string name="settings_su_request_30">30 sekundi</string>
<string name="settings_su_request_45">45 sekundi</string>
<string name="settings_su_request_60">60 sekundi</string>
<string name="superuser_access">Pristup super-korisnika</string>
<string name="auto_response">Automatski odgovor</string>
<string name="request_timeout">Istek zahteva</string>
<string name="superuser_notification">Notifikacije super-korisnika</string>
<string name="settings_su_reauth_title">Ponovo odobri nakon ažuriranja</string>
<string name="settings_su_reauth_summary">Ponovo traži permisije super-korisnika nakon ažuriranja aplikacija</string>
<string name="settings_su_tapjack_title">Zaštita od tapjacking-a</string>
<string name="settings_su_tapjack_summary">Prompt dijalog super-korisnika neće reagovati dok je prikriven drugim prozorom ili overlay-em</string>
<string name="settings_su_auth_title">Autentifikacija korisnika</string>
<string name="settings_su_auth_summary">Traži autentifikaciju korisnika tokom zahteva super-korisnika</string>
<string name="settings_su_auth_insecure">Nijedan metod autentifikacije nije podešen na uređaju</string>
<string name="settings_customization">Prilagođavanje</string>
<string name="setting_add_shortcut_summary">Dodaj lepu prečicu na početni ekran u slučaju da se ime i ikonica ne prepoznaju lako nakon skrivanja aplikacije</string>
<string name="settings_doh_title">DNS preko HTTPS-a</string>
<string name="settings_doh_description">Zaobilazno rešenje DNS trovanja u nekim nacijama</string>
<string name="settings_random_name_title">Nasumično ime na izlazu</string>
<string name="settings_random_name_description">Nasumično ime izlaznog fajla slika i tar fajlova radi sprečavanja detekcije</string>
<string name="multiuser_mode">Višekorisnički režim</string>
<string name="settings_owner_only">Samo vlasnik uređaja</string>
<string name="settings_owner_manage">Određeno od strane vlasnika</string>
<string name="settings_user_independent">Nezavisno od korisnika</string>
<string name="owner_only_summary">Samo vlasnik ima pristup korenu</string>
<string name="owner_manage_summary">Samo vlasnik može da pristupa korenu i da prima zahteve za njega</string>
<string name="user_independent_summary">Svaki korisnik ima svoja pravila korena</string>
<string name="mount_namespace_mode">Mount režim namespace-a</string>
<string name="settings_ns_global">Globalni namespace</string>
<string name="settings_ns_requester">Nasleđeni namespace</string>
<string name="settings_ns_isolate">Izolovani namespace</string>
<string name="global_summary">Sve korenske sesije koriste globalni mount namespace</string>
<string name="requester_summary">Korenske sesije će naslediti namespace od podnosioca zahteva</string>
<string name="isolate_summary">Svaka korenska sesija će imati svoj izolovani namespace</string>
<!--Notifications-->
<string name="update_channel">Ažuriranja Magisk-a</string>
<string name="progress_channel">Notifikacije o progresu</string>
<string name="updated_channel">Ažuriranje završeno</string>
<string name="download_complete">Preuzimanje završeno</string>
<string name="download_file_error">Greška pri preuzimanju fajla</string>
<string name="magisk_update_title">Ažuriranje Magisk-a dostupno!</string>
<string name="updated_title">Magisk je ažuriran</string>
<string name="updated_text">Klikni da otvoriš aplikaciju</string>
<!--Toasts, Dialogs-->
<string name="yes">Da</string>
<string name="no">Ne</string>
<string name="repo_install_title">Instaliraj %1$s %2$s(%3$d)</string>
<string name="download">Preuzmi</string>
<string name="reboot">Ponovo pokreni</string>
<string name="close">Zatvori</string>
<string name="release_notes">Release notes</string>
<string name="flashing">Flešovanje…</string>
<string name="running">Pokretanje…</string>
<string name="done">Završeno!</string>
<string name="done_action">Pokretanje akcije %1$s završeno</string>
<string name="failure">Neuspešno!</string>
<string name="hide_app_title">Skrivanje Magisk aplikacije…</string>
<string name="open_link_failed_toast">Nije pronađena aplikacija za otvaranje linka</string>
<string name="complete_uninstall">Kompletna deinstalacija</string>
<string name="restore_img">Povrati slike</string>
<string name="restore_img_msg">Povratak…</string>
<string name="restore_done">Povratak uspešan!</string>
<string name="restore_fail">Fabrički bekap ne postoji!</string>
<string name="setup_fail">Neuspešna postavka</string>
<string name="env_fix_title">Potrebno dodatno podešavanje</string>
<string name="env_fix_msg">Vaš uređaj zahteva dodatno podešavanje da bi Magisk radio kako treba. Da li želite nastaviti i pokrenuti ponovo?</string>
<string name="env_full_fix_msg">Vaš uređaj zahteva ponovno flešovanje da bi Magisk radio kako treba. Reinstalirajte Magisk kroz aplikaciju, režim oporavka ne može dobiti tačne informacije o uređaju.</string>
<string name="setup_msg">Pokretanje podešavanja okruženja…</string>
<string name="unsupport_magisk_title">Nepodržana verzija Magisk-a</string>
<string name="unsupport_magisk_msg">Ova verzija aplikacije ne podržava Magisk verzije manje od %1$s.\n\nAplikacija će se ponašati kao da Magisk nije instaliran, molimo ažurirajte Magisk što pre.</string>
<string name="unsupport_general_title">Nenormalno stanje</string>
<string name="unsupport_system_app_msg">Pokretanje aplikacije kao sistemske nije podržano. Molimo postavite aplikaciju da bude korisnička.</string>
<string name="unsupport_other_su_msg">Detektovan \"su\" binary koji nije Magisk-ov. Molimo uklonite konkurentno korensko rešenje i/ili reinstalirajte Magisk.</string>
<string name="unsupport_external_storage_msg">Magisk je instaliran na eksterno skladište. Molimo pomerite apl. u interno skladište.</string>
<string name="unsupport_nonroot_stub_msg">Skrivena Magisk aplikacija ne može nastaviti sa radom jer je koren izgubljen. Molimo povratite originalni APK.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Dozvolite permisiju za skladište da biste omogućili ovu funkcionalnost</string>
<string name="post_notifications_denied">Dozvolite permisiju za notifikacije da biste omogućili ovu funkcionalnost</string>
<string name="install_unknown_denied">Dozvolite "instaliranje nepoznatih aplikacija" da biste omogućili ovu funkcionalnost</string>
<string name="add_shortcut_title">Dodaj prečicu na početni ekran</string>
<string name="add_shortcut_msg">Nakon skrivanja aplikacije, njeno ime i ikonicu ćete teško prepoznati. Želite li dodati lepu prečicu na početni ekran?</string>
<string name="app_not_found">Nije pronađena aplikacija za ovu akciju</string>
<string name="reboot_apply_change">Ponovo pokreni da primeniš izmene</string>
<string name="restore_app_confirmation">Ovo će vratiti skrivenu aplikaciju na originalnu. Da li stvarno to želite?</string>
</resources>

View File

@@ -3,7 +3,7 @@
<!--Sections-->
<string name="modules">מודולים</string>
<string name="superuser">משתמש על</string>
<string name="logs">יומני רישום</string>
<string name="logs">Log</string>
<string name="settings">הגדרות</string>
<string name="install">התקנה</string>
<string name="section_home">בית</string>
@@ -12,10 +12,10 @@
<!--Home-->
<string name="no_connection">אין חיבור זמין</string>
<string name="app_changelog">יומן שינויים</string>
<string name="app_changelog">רשימת שינויים</string>
<string name="loading">טוען…</string>
<string name="update">עדכון</string>
<string name="not_available">ל</string>
<string name="not_available">לא זמין</string>
<string name="hide">הסתרה</string>
<string name="home_package">חבילה</string>
<string name="home_app_title">יישום</string>
@@ -23,28 +23,28 @@
<string name="home_support_title">תמיכה בנו</string>
<string name="home_follow_title">עקבו אחרינו</string>
<string name="home_item_source">מקור</string>
<string name="home_support_content">Magisk היה ותמיד יהיה בעל קוד מקור פתוח. עם זאת באפשרותך להראות לנו שאכפת לך על ידי שליחת תרומה קטנה.</string>
<string name="home_support_content">Magisk היה ותמיד יהיה בקוד פתוח. עם זאת באפשרותך להראות לנו שאכפת לך על ידי שליחת תרומה קטנה.</string>
<string name="home_installed_version">מותקנת</string>
<string name="home_latest_version">אחרונה</string>
<string name="invalid_update_channel">ערוץ עדכון לא חוקי</string>
<string name="uninstall_magisk_title">הסרת Magisk</string>
<string name="uninstall_magisk_msg">כל המודולים יושבתו/יוסרו!\nגישת שורש תושבת!\nהנתונים שלך עשויים להיות מוצפנים אם לא הוצפנו כבר!</string>
<string name="uninstall_magisk_msg">כל המודולים יושבתו/יוסרו!\nגישת Root תושבת!\nהנתונים שלך עשויים להיות מוצפנים אם לא הוצפנו כבר!</string>
<!--Install-->
<string name="keep_force_encryption">שמירה על הצפנה בכח</string>
<string name="keep_dm_verity">שמירה על AVB 2.0/dm-verity</string>
<string name="recovery_mode">מצב שחזור</string>
<string name="recovery_mode">מצב Recovery</string>
<string name="install_options_title">אפשרויות</string>
<string name="install_method_title">שיטה</string>
<string name="install_next">הבא</string>
<string name="install_start">צא לדרך</string>
<string name="manager_download_install">לחיצה להורדה והתקנה</string>
<string name="direct_install">התקנה ישירה (מומלץ)</string>
<string name="install_inactive_slot">התקנה לחריץ לא פעיל (לאחר OTA)</string>
<string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לחריץ הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string>
<string name="install_inactive_slot">התקנה לסלוט לא פעיל (לאחר OTA)</string>
<string name="install_inactive_slot_msg">ההתקן שלך ייאלץ אתחול לסלוט הלא פעיל הנוכחי שלך לאחר הפעלה מחדש!\nיש להשתמש באפשרות זו רק לאחר ביצוע OTA בלבד.\nלהמשיך?</string>
<string name="setup_title">התקנה נוספת</string>
<string name="select_patch_file">בחירה והתקנת קובץ</string>
<string name="patch_file_msg">בחירת תמונה גולמית (*.img) או ODIN tarfile (*.tar) או payload.bin (*.bin)</string>
<string name="patch_file_msg">בחירת קובץ גולמי (*.img) או ODIN tarfile (*.tar) או payload.bin (*.bin)</string>
<string name="reboot_delay_toast">מאתחל בעוד 5 שניות…</string>
<string name="flash_screen_title">התקנה</string>
@@ -67,22 +67,22 @@
<string name="su_snack_deny">הרשאות משתמש על עבור %1$s נשללו</string>
<string name="su_snack_notif_on">התראות של %1$s מופעלות</string>
<string name="su_snack_notif_off">התראות של %1$s מושבתות</string>
<string name="su_snack_log_on">יומני רישום עבור %1$s פועלות</string>
<string name="su_snack_log_off">יומני רישום עבור %1$s מושבתות</string>
<string name="su_snack_log_on">Log עבור %1$s מופעל</string>
<string name="su_snack_log_off">Log עבור %1$s מושבת</string>
<string name="su_revoke_title">להסיר?</string>
<string name="su_revoke_msg">נא לאשר שלילת הרשאות עבור %1$s?</string>
<string name="toast">הרמת כוסית</string>
<string name="toast">התראה</string>
<string name="none">ללא</string>
<string name="superuser_toggle_notification">התראות</string>
<string name="superuser_toggle_revoke">הסרה</string>
<string name="superuser_policy_none">טרם נתבקשו הרשאות משתמש על על ידי יישומים</string>
<!--Logs-->
<string name="log_data_none">הינך ללא יומן, יש לנסות להשתמש יותר ביישומי השורש שלך</string>
<string name="log_data_magisk_none">יומני רישום Magisk ריקים, זה מוזר</string>
<string name="menuSaveLog">שמירת יומן רישום</string>
<string name="menuClearLog">ניקוי יומן רישום כעת</string>
<string name="logs_cleared">יומני רישום נוקו בהצלחה</string>
<string name="log_data_none">אין Log, יש לנסות להשתמש יותר ביישומי הRoot שלך</string>
<string name="log_data_magisk_none">Log Magisk ריק, זה מוזר</string>
<string name="menuSaveLog">שמירת Log</string>
<string name="menuClearLog">ניקוי Log כעת</string>
<string name="logs_cleared">Log נוקה בהצלחה</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">יעד UID: %1$d</string>
<string name="target_pid">מציב ns יעד PID: %s</string>
@@ -100,15 +100,15 @@
<!--Module-->
<string name="no_info_provided">(לא סופק מידע)</string>
<string name="reboot_userspace">אתחול רך</string>
<string name="reboot_recovery">אתחול למצב שחזור</string>
<string name="reboot_bootloader">אתחול לטוען האתחול</string>
<string name="reboot_recovery">אתחול למצב Recovery</string>
<string name="reboot_bootloader">אתחול לBootloader</string>
<string name="reboot_download">אתחול למצב הורדה</string>
<string name="reboot_edl">אתחול למצב EDL</string>
<string name="reboot_safe_mode">מצב בטוח</string>
<string name="module_version_author">%1$s מאת %2$s</string>
<string name="module_state_remove">הסרה</string>
<string name="module_action">פעולה</string>
<string name="module_state_restore">שחזור</string>
<string name="module_state_restore">שיחזור</string>
<string name="module_action_install_external">התקנה מהאחסון</string>
<string name="update_available">עדכונים זמינים</string>
<string name="suspend_text_riru">מודול מושעה כי %1$s מופעל</string>
@@ -129,7 +129,7 @@
<string name="settings_hide_app_title">הסתרת היישום Magisk</string>
<string name="settings_hide_app_summary">התקנת יישום מתווך עם מזהה חבילה אקראי ותווית שם מותאמת אישית</string>
<string name="settings_restore_app_title">שיחזור היישום Magisk</string>
<string name="settings_restore_app_summary">ביטול הסתרת היישום ושחזור אל ה-APK המקורי</string>
<string name="settings_restore_app_summary">ביטול הסתרת היישום ושיחזור אל ה-APK המקורי</string>
<string name="language">שפה</string>
<string name="system_default">(ברירת מחדל מערכת)</string>
<string name="settings_check_update_title">בדיקת עדכונים</string>
@@ -144,9 +144,9 @@
<string name="settings_denylist_summary">כל השינויים של Magisk יוחזרו לתהליכים ברשימת הדחייה</string>
<string name="settings_denylist_config_title">הגדרת רשימת הדחייה</string>
<string name="settings_denylist_config_summary">בחירת התהליכים שייכללו ברשימת הדחייה</string>
<string name="settings_hosts_title">מארחים חסרי מערכת</string>
<string name="settings_hosts_summary">מארחים חסרי מערכת תומכים ביישומים חוסמי פרסומות</string>
<string name="settings_hosts_toast">הוספת מודול מארחים חסרי מערכת</string>
<string name="settings_hosts_title">hosts חסרי מערכת</string>
<string name="settings_hosts_summary">hosts חסרי מערכת תומכים ביישומים חוסמי פרסומות</string>
<string name="settings_hosts_toast">הוספת מודול hosts חסרי מערכת</string>
<string name="settings_app_name_hint">שם חדש</string>
<string name="settings_app_name_helper">היישום יארז מחדש בשם זה</string>
<string name="settings_app_name_error">פורמט לא חוקי</string>
@@ -181,16 +181,16 @@
<string name="settings_owner_only">בעל ההתקן בלבד</string>
<string name="settings_owner_manage">אחראי ניהול ההתקן</string>
<string name="settings_user_independent">משתמש עצמאי</string>
<string name="owner_only_summary">לבעלים בלבד ישנה גישת שורש</string>
<string name="owner_manage_summary">הבעלים בלבד יכול לנהל גישת שורש ולקבל הנחיות לבקשה</string>
<string name="user_independent_summary">לכל משתמש יש כללי שורש נפרדים משלו</string>
<string name="owner_only_summary">לבעלים בלבד ישנה גישת Root</string>
<string name="owner_manage_summary">הבעלים בלבד יכול לנהל גישת Root ולקבל הנחיות לבקשה</string>
<string name="user_independent_summary">לכל משתמש יש כללי Root נפרדים משלו</string>
<string name="mount_namespace_mode">מצב הצבת מרחב שם</string>
<string name="settings_ns_global">מרחב שם גלובלי</string>
<string name="settings_ns_requester">מרחב שם מורש</string>
<string name="settings_ns_isolate">מרחב שם מבודד</string>
<string name="global_summary">כלל חיבורי השורש משתמשים במרחב שם הגלובלי</string>
<string name="requester_summary">חיבורי השורש יירשו את מרחב השם של המבקש</string>
<string name="isolate_summary">לכל חיבור שורש יהיה מרחב שם מבודד</string>
<string name="global_summary">כלל חיבורי הRoot משתמשים במרחב שם הגלובלי</string>
<string name="requester_summary">חיבורי הRoot יירשו את מרחב השם של המבקש</string>
<string name="isolate_summary">לכל חיבור Root יהיה מרחב שם מבודד</string>
<!--Notifications-->
<string name="update_channel">עדכוני Magisk</string>
@@ -225,7 +225,7 @@
<string name="setup_fail">ההתקנה כשלה</string>
<string name="env_fix_title">דורש התקנה נוספת</string>
<string name="env_fix_msg">ההתקן שלך זקוק להתקנה נוספת כדי ש-Magisk יפעל כראוי. האם ברצונך להמשיך ולהפעיל מחדש?</string>
<string name="env_full_fix_msg">ההתקן שלך זקוק לצריבה מחדש של Magisk כדי לעבוד כראוי. נא להתקין מחדש את Magisk בתוך היישום, מצב השחזור אינו יכול לקבל מידע נכון על ההתקן.</string>
<string name="env_full_fix_msg">ההתקן שלך זקוק לצריבה מחדש של Magisk כדי לעבוד כראוי. נא להתקין מחדש את Magisk בתוך היישום, מצב הRecovery אינו יכול לקבל מידע נכון על ההתקן.</string>
<string name="setup_msg">הגדרת סביבת ריצה…</string>
<string name="unsupport_magisk_title">גרסת Magisk אינה נתמכת</string>
<string name="unsupport_magisk_msg">גרסה זו של היישום אינה תומכת ביישום Magisk הנמוך מ- %1$s.\n\nהיישום יתנהג כאילו Magisk אינו מותקן,יש לשדרג את Magisk במהירות האפשריות.</string>
@@ -233,7 +233,7 @@
<string name="unsupport_system_app_msg">הפעלת יישום זה כיישום מערכת אינה נתמך. נא להשיב את היישום כיישום משתמש.</string>
<string name="unsupport_other_su_msg">התגלתה פקודת \"su\" שאינה שייכת ליישום Magisk נא להסיר את הפקודה שאינה נתמכת.</string>
<string name="unsupport_external_storage_msg">Magisk מותקן באחסון החיצוני. נא להעביר את היישום לאחסון הפנימי.</string>
<string name="unsupport_nonroot_stub_msg">היישום אינו יכול להמשיך לעבוד במצב הנסתר מכיוון שגישת השורש אבדה. נא לשחזר אותו חזרה ל-APK המקורי.</string>
<string name="unsupport_nonroot_stub_msg">היישום אינו יכול להמשיך לעבוד במצב הנסתר מכיוון שגישת הRoot אבדה. נא לשחזר אותו חזרה ל-APK המקורי.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">הענת הרשאת אחסון להפעלת פונקציה זו</string>
<string name="post_notifications_denied">הענקת הרשאה להתראות כדי להפעיל פונקציה זו</string>

View File

@@ -54,7 +54,7 @@
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Permite acesso total ao seu aparelho.\nNão permita se você não tiver certeza do que está fazendo!</string>
<string name="su_warning">Permite acesso total ao seu dispositivo.\nNão permita se você não tiver certeza do que está fazendo!</string>
<string name="forever">Sempre</string>
<string name="once">Uma vez</string>
<string name="tenmin">10 mins</string>
@@ -63,19 +63,19 @@
<string name="sixtymin">60 mins</string>
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram concedidos</string>
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
<string name="su_revoke_msg">Confirme para revogar os acessos de SuperUsuário de %1$s</string>
<string name="toast">Notificação (Pop-up)</string>
<string name="none">Nenhum</string>
<string name="superuser_toggle_notification">Notificações</string>
<string name="superuser_toggle_revoke">Revogar</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
<!--Logs-->
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
@@ -135,6 +135,7 @@
<string name="settings_update_channel_title">Canal de atualização</string>
<string name="settings_update_stable">Estável</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_debug">Debug</string>
<string name="settings_update_custom">Personalizado</string>
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
@@ -235,7 +236,7 @@
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a opção \"Instalar apps de fontes desconhecidas\" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>

View File

@@ -3,7 +3,7 @@
<!--Sections-->
<string name="modules">Módulos</string>
<string name="superuser">SuperUsuário</string>
<string name="logs">Registros</string>
<string name="logs">Registos</string>
<string name="settings">Configurações</string>
<string name="install">Instalar</string>
<string name="section_home">Início</string>
@@ -11,50 +11,50 @@
<string name="denylist">Lista de negação</string>
<!--Home-->
<string name="no_connection">Nenhuma conexão disponível</string>
<string name="app_changelog">Registro de alterações</string>
<string name="loading">Carregando…</string>
<string name="no_connection">Nenhuma ligação disponível</string>
<string name="app_changelog">Registo de alterações</string>
<string name="loading">A carregar…</string>
<string name="update">Atualizar</string>
<string name="not_available">Não disponível</string>
<string name="hide">Ocultar</string>
<string name="home_package">Pacote</string>
<string name="home_app_title">App</string>
<string name="home_notice_content">Baixe o Magisk SOMENTE pela página oficial do GitHub. Arquivos de fontes desconhecidas podem ser maliciosos!</string>
<string name="home_notice_content">Descarregue o Magisk APENAS na página oficial do GitHub. Os ficheiros de fontes desconhecidas podem ser maliciosos!</string>
<string name="home_support_title">Apoie-nos</string>
<string name="home_follow_title">Siga-nos</string>
<string name="home_item_source">Fonte</string>
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode nos ajudar enviando uma pequena doação.</string>
<string name="home_support_content">Magisk sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode ajudar-nos enviando uma pequena doação.</string>
<string name="home_installed_version">Instalado</string>
<string name="home_latest_version">Recente</string>
<string name="invalid_update_channel">Canal de atualização inválido</string>
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nSeus dados não criptografados devido ao uso do Magisk, serão re-criptografados!</string>
<string name="uninstall_magisk_msg">Todos os módulos serão desativados/removidos!\nO root será removido!\nOs seus dados não encriptados devido à utilização do Magisk, serão re-encriptados!</string>
<!--Install-->
<string name="keep_force_encryption">Manter criptografia forçada</string>
<string name="keep_force_encryption">Manter encriptação forçada</string>
<string name="keep_dm_verity">Manter AVB 2.0/dm-verity</string>
<string name="recovery_mode">Modo Recovery</string>
<string name="install_options_title">Opções</string>
<string name="install_method_title">Método</string>
<string name="install_next">Próximo</string>
<string name="install_start">Vamos lá</string>
<string name="manager_download_install">Toque para baixar e instalar</string>
<string name="manager_download_install">Toque para descarregar e instalar</string>
<string name="direct_install">Instalação direta (recomendada)</string>
<string name="install_inactive_slot">Instalar no slot inativo (após o OTA)</string>
<string name="install_inactive_slot_msg">Seu dispositivo será FORÇADO a inicializar no slot inativo atual após uma reinicialização!\nSó use esta opção após a conclusão do OTA.\nDeseja continuar?</string>
<string name="install_inactive_slot_msg">O seu dispositivo será FORÇADO a inicializar no slot inativo atual após um reinício!\nSó use esta opção após a conclusão do OTA.\nDeseja continuar?</string>
<string name="setup_title">Configuração adicional</string>
<string name="select_patch_file">Selecione e corrija um arquivo</string>
<string name="patch_file_msg">Selecione um arquivo imagem (*.img) ou um arquivo tar (*.tar) ou um arquivo payload.bin (*.bin)</string>
<string name="reboot_delay_toast">Reiniciando em 5 segundos…</string>
<string name="select_patch_file">Selecione e corrija um ficheiro</string>
<string name="patch_file_msg">Selecione um ficheiro de imagem (*.img) ou um ficheiro tar (*.tar) ou um ficheiro payload.bin (*.bin)</string>
<string name="reboot_delay_toast">A reiniciar em 5 segundos…</string>
<string name="flash_screen_title">Instalação</string>
<!--Superuser-->
<string name="su_request_title">Solicitação de SuperUsuário</string>
<string name="touch_filtered_warning">Como um app está ocultando uma solicitação de SuperUsuário, o Magisk não pode verificar sua resposta.</string>
<string name="touch_filtered_warning">Como um app está a ocultar um pedido de SuperUsuário, o Magisk não consegue verificar a sua resposta.</string>
<string name="deny">Negar</string>
<string name="prompt">Perguntar</string>
<string name="grant">Permitir</string>
<string name="su_warning">Permite acesso total ao seu aparelho.\nNão permita se você não tiver certeza do que está fazendo!</string>
<string name="su_warning">Permite o acesso total ao seu dispositivo.\nNão o permita se não tiver a certeza do que está a fazer!</string>
<string name="forever">Sempre</string>
<string name="once">Uma vez</string>
<string name="tenmin">10 mins</string>
@@ -63,26 +63,26 @@
<string name="sixtymin">60 mins</string>
<string name="su_allow_toast">%1$s foi permitido o acesso de SuperUsuário</string>
<string name="su_deny_toast">%1$s foi negado o acesso de SuperUsuário</string>
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram concedidos</string>
<string name="su_snack_grant">Os acessos de SuperUsuário de %1$s foram permitidos</string>
<string name="su_snack_deny">Os acessos de SuperUsuário de %1$s foram negados</string>
<string name="su_snack_notif_on">As notificações de %1$s foram ativadas</string>
<string name="su_snack_notif_off">As notificações de %1$s foram desativadas</string>
<string name="su_snack_log_on">Os registros de %1$s foram ativados</string>
<string name="su_snack_log_off">Os registros de %1$s foram desativados</string>
<string name="su_snack_log_on">Os registos de %1$s foram ativados</string>
<string name="su_snack_log_off">Os registos de %1$s foram desativados</string>
<string name="su_revoke_title">Revogar?</string>
<string name="su_revoke_msg">Confirmar a remoção do acesso de SuperUsuário de %1$s?</string>
<string name="su_revoke_msg">Confirme para revogar os acessos de SuperUsuário de %1$s</string>
<string name="toast">Notificação (Pop-up)</string>
<string name="none">Nenhum</string>
<string name="superuser_toggle_notification">Notificações</string>
<string name="superuser_toggle_revoke">Revogar</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda</string>
<string name="superuser_policy_none">Nenhum app solicitou permissão de SuperUsuário ainda.</string>
<!--Logs-->
<string name="log_data_none">Não há registros. Tente usar mais seus apps root.</string>
<string name="log_data_magisk_none">Os registros do Magisk estão vazios, isso é estranho.</string>
<string name="menuSaveLog">Salvar registros</string>
<string name="menuClearLog">Limpar registros agora</string>
<string name="logs_cleared">Registros limpo com sucesso</string>
<string name="log_data_none">Não há registos. Tente utilizar mais seus apps root.</string>
<string name="log_data_magisk_none">Os registos do Magisk estão vazios, isto é estranho.</string>
<string name="menuSaveLog">Salvar registos</string>
<string name="menuClearLog">Limpar registos agora</string>
<string name="logs_cleared">Registos limpo com sucesso</string>
<string name="pid">PID: %1$d</string>
<string name="target_uid">Alvo UID: %1$d</string>
<string name="target_pid">Alvo PID: %s</string>
@@ -118,12 +118,12 @@
<!--Settings-->
<string name="settings_dark_mode_title">Modo do tema</string>
<string name="settings_dark_mode_message">Selecione o modo mais adequado para você!</string>
<string name="settings_dark_mode_message">Selecione o modo mais adequado para si!</string>
<string name="settings_dark_mode_light">Sempre claro</string>
<string name="settings_dark_mode_system">Seguir sistema</string>
<string name="settings_dark_mode_dark">Sempre escuro</string>
<string name="settings_download_path_title">Caminho para baixar</string>
<string name="settings_download_path_message">Os arquivos serão salvos em %1$s</string>
<string name="settings_download_path_title">Caminho para descarregar</string>
<string name="settings_download_path_message">Os ficheiros serão salvos em %1$s</string>
<string name="settings_hide_app_title">Ocultar app do Magisk</string>
<string name="settings_hide_app_summary">Instala o app oculto com ID aleatório e nome personalizado</string>
<string name="settings_restore_app_title">Restaurar app do Magisk</string>
@@ -135,8 +135,9 @@
<string name="settings_update_channel_title">Canal de atualização</string>
<string name="settings_update_stable">Estável</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_debug">Debug</string>
<string name="settings_update_custom">Personalizado</string>
<string name="settings_update_custom_msg">Insira um URL de canal personalizado</string>
<string name="settings_update_custom_msg">Introduza um URL de canal personalizado</string>
<string name="settings_zygisk_summary">Executa partes do Magisk no Zygote</string>
<string name="settings_denylist_title">Aplicar lista de negação</string>
<string name="settings_denylist_summary">Os processos na lista de negação terão todas as modificações do Magisk revertidas</string>
@@ -167,35 +168,35 @@
<string name="settings_su_tapjack_title">Proteção contra atividades sobrepostas</string>
<string name="settings_su_tapjack_summary">A caixa de diálogo do SuperUsuário não responderá à entrada enquanto estiver oculta por qualquer outra janela ou sobreposição</string>
<string name="settings_su_auth_title">Autenticação de usuário</string>
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante solicitações de SuperUsuário</string>
<string name="settings_su_auth_summary">Solicite autenticação de usuário durante pedidos de SuperUsuário</string>
<string name="settings_su_auth_insecure">Nenhum método de autenticação está configurado no dispositivo</string>
<string name="settings_customization">Personalizações</string>
<string name="setting_add_shortcut_summary">Adicione um atalho na tela inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
<string name="setting_add_shortcut_summary">Adicione um atalho no ecrã inicial, caso o nome e o ícone sejam difíceis de reconhecer logo após ocultar o app.</string>
<string name="settings_doh_title">DNS sobre HTTPS</string>
<string name="settings_doh_description">Solução alternativa para envenenamento de DNS em alguns países</string>
<string name="settings_random_name_title">Randomizar nome de saída</string>
<string name="settings_random_name_description">Randomize o nome do arquivo de saída de imagens corrigidas e arquivos tar (*.tar) para evitar a detecção</string>
<string name="settings_random_name_description">Randomize o nome do ficheiro de saída de imagens corrigidas e ficheiros tar (*.tar) para evitar a deteção</string>
<string name="multiuser_mode">Modo multiusuário</string>
<string name="settings_owner_only">Somente proprietário do dispositivo</string>
<string name="settings_owner_manage">Gerenciado pelo proprietário do dispositivo</string>
<string name="settings_owner_manage">Gerido pelo proprietário do dispositivo</string>
<string name="settings_user_independent">Independente do usuário</string>
<string name="owner_only_summary">Somente o proprietário tem acesso root</string>
<string name="owner_manage_summary">Somente o proprietário pode gerenciar o acesso root e receber pedidos de solicitação</string>
<string name="owner_manage_summary">Somente o proprietário pode gerir o acesso root e receber pedidos de solicitação</string>
<string name="user_independent_summary">Cada usuário tem suas próprias regras de root separadas</string>
<string name="mount_namespace_mode">Montar namespace</string>
<string name="settings_ns_global">Global</string>
<string name="settings_ns_requester">Herdado</string>
<string name="settings_ns_isolate">Individual</string>
<string name="global_summary">Todas as sessões root usam o namespace de montagem global</string>
<string name="requester_summary">As sessões root herdarão o namespace do solicitante</string>
<string name="isolate_summary">Cada sessão root terá seu próprio namespace individual</string>
<string name="global_summary">Todas as sessões root utilizam o namespace de montagem global</string>
<string name="requester_summary">As sessões root herdarão o namespace do requerente</string>
<string name="isolate_summary">Cada sessão root terá o seu próprio namespace individual</string>
<!--Notifications-->
<string name="update_channel">Atualizações do Magisk</string>
<string name="progress_channel">Notificações de progresso</string>
<string name="updated_channel">Atualização concluída</string>
<string name="download_complete">Download concluído</string>
<string name="download_file_error">Erro ao baixar arquivo</string>
<string name="download_file_error">Erro ao descarregar ficheiro</string>
<string name="magisk_update_title">Atualização do Magisk disponível!</string>
<string name="updated_title">Magisk atualizado</string>
<string name="updated_text">Toque para abrir o app</string>
@@ -209,37 +210,37 @@
<string name="close">Fechar</string>
<string name="release_notes">Notas da atualização</string>
<string name="flashing">Flashando…</string>
<string name="running">Executando…</string>
<string name="running">A executar…</string>
<string name="done">Concluído!</string>
<string name="done_action">Ação de execução de %1$s concluída</string>
<string name="failure">Falhou!</string>
<string name="hide_app_title">Ocultando o app do Magisk…</string>
<string name="hide_app_title">A ocultar o app do Magisk…</string>
<string name="open_link_failed_toast">Nenhum app encontrado para abrir o link</string>
<string name="complete_uninstall">Desinstalação completa</string>
<string name="restore_img">Restaurar imagens</string>
<string name="restore_img_msg">Restaurando…</string>
<string name="restore_img_msg">A restaurar…</string>
<string name="restore_done">Restauração concluída!</string>
<string name="restore_fail">O backup original não existe!</string>
<string name="setup_fail">Falha na instalação</string>
<string name="env_fix_title">Configuração adicional exigida</string>
<string name="env_fix_msg">Seu dispositivo exige uma configuração adicional para o Magisk funcionar corretamente. Deseja continuar e reiniciar?</string>
<string name="env_full_fix_msg">Seu dispositivo precisa refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não pode obter as devidas informações do dispositivo.</string>
<string name="setup_msg">Executando a configuração do ambiente…</string>
<string name="env_full_fix_msg">O seu dispositivo precisa de refazer o flash do Magisk para funcionar corretamente. Por favor, reinstale o Magisk no app, o modo Recovery não consegue obter as devidas informações do dispositivo.</string>
<string name="setup_msg">A executar a configuração do ambiente…</string>
<string name="unsupport_magisk_title">Versão do Magisk não suportada</string>
<string name="unsupport_magisk_msg">Esta versão do app não suporta a versão do Magisk inferior a %1$s.\n\nO app irá se comportar como se nenhum Magisk estivesse sido instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_magisk_msg">Esta versão do app não suporta versões do Magisk inferiores a %1$s.\n\nO app irá comportar-se como se nenhum Magisk estivesse instalado. Por favor, atualize o Magisk assim que possível.</string>
<string name="unsupport_general_title">Estado anormal</string>
<string name="unsupport_system_app_msg">Não há suporte para executar este app como um app do sistema. Por favor, reverta o app para um app de usuário.</string>
<string name="unsupport_other_su_msg">Não foi possível detectar o binário \"su\" do Magisk. Por favor, remova qualquer outro root concorrente e/ou reinstale o Magisk.</string>
<string name="unsupport_external_storage_msg">O app do Magisk está instalado no armazenamento externo. Por favor, mova o app para o armazenamento interno.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar funcionando porque o root foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_nonroot_stub_msg">O app oculto do Magisk não pode continuar a funcionar porque o root foi perdido. Por favor, restaure o APK original.</string>
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
<string name="external_rw_permission_denied">Conceda permissão de armazenamento para ativar esta funcionalidade</string>
<string name="post_notifications_denied">Conceda permissão às notificações para ativar esta funcionalidade</string>
<string name="install_unknown_denied">Permita a opção "Instalar apps de fontes desconhecidas" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar atalho à tela inicial</string>
<string name="add_shortcut_msg">Após ocultar o app do Magisk, seu nome e ícone ficarão difíceis de reconhecer. Deseja adicionar um atalho na tela inicial?</string>
<string name="install_unknown_denied">Permita a opção \"Instalar apps de fontes desconhecidas\" para ativar esta funcionalidade</string>
<string name="add_shortcut_title">Adicionar atalho ao ecrã inicial</string>
<string name="add_shortcut_msg">Após ocultar o app do Magisk, o seu nome e ícone serão difíceis de reconhecer. Deseja adicionar um atalho no ecrã inicial?</string>
<string name="app_not_found">Nenhum app encontrado para realizar esta ação</string>
<string name="reboot_apply_change">Reinicie para aplicar as mudanças</string>
<string name="reboot_apply_change">Reinicie para aplicar as alterações</string>
<string name="restore_app_confirmation">Isso irá restaurar o app oculto do Magisk de volta para o app original. Deseja realmente fazer isso?</string>
</resources>

View File

@@ -1,4 +1,5 @@
<resources>
<!--Author: Radoš Milićev (https://github.com/rammba)-->
<!--Sections-->
<string name="modules">Модули</string>

Some files were not shown because too many files have changed in this diff Show More