add manifest patching using axml
This commit is contained in:
parent
739196fa52
commit
e479d082c1
8 changed files with 182 additions and 28 deletions
38
.editorconfig
Normal file
38
.editorconfig
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Android Studio: Settings > Editor > Code Style > Enable EditorConfig support
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
max_line_length = 150
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_size = 4
|
||||
# these are Intellij specific so they will only work in Android Studio / IDEA
|
||||
ij_continuation_indent_size = 4
|
||||
|
||||
[*.java]
|
||||
ij_java_names_count_to_use_import_on_demand = 3
|
||||
ij_java_class_count_to_use_import_on_demand = 3
|
||||
ij_java_blank_lines_around_method_in_interface = 0
|
||||
ij_java_doc_do_not_wrap_if_one_line = true
|
||||
ij_java_keep_first_column_comment = false
|
||||
ij_java_keep_simple_blocks_in_one_line = true
|
||||
ij_java_keep_simple_classes_in_one_line = true
|
||||
ij_java_keep_simple_lambdas_in_one_line = true
|
||||
ij_java_keep_simple_methods_in_one_line = true
|
||||
ij_java_line_comment_add_space = true
|
||||
ij_java_line_comment_at_first_column = false
|
||||
ij_java_spaces_within_array_initializer_braces = true
|
||||
|
||||
[*.kt]
|
||||
ij_kotlin_name_count_to_use_star_import = 3
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 3
|
||||
ij_kotlin_keep_first_column_comment = false
|
||||
ij_kotlin_line_comment_add_space = true
|
||||
ij_kotlin_line_comment_at_first_column = false
|
||||
|
||||
[*.{xml,yml}]
|
||||
indent_size = 2
|
||||
|
|
@ -89,9 +89,10 @@ dependencies {
|
|||
implementation("com.google.code.gson:gson:2.8.9")
|
||||
implementation("io.coil-kt:coil-compose:1.4.0")
|
||||
implementation("org.bouncycastle:bcpkix-jdk15on:1.65")
|
||||
implementation("de.upb.cs.swt:axml:2.1.1") // 2.1.2 is broken btw
|
||||
|
||||
// ktor
|
||||
implementation("io.ktor:ktor-client-core:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-android:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-gson:$ktorVersion")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,21 +49,6 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
|
|||
}
|
||||
}
|
||||
|
||||
val useDebuggableManifest = Prefs.debuggable.get()
|
||||
val manifest =
|
||||
File(
|
||||
context.externalCacheDir,
|
||||
if (useDebuggableManifest) "AndroidManifest-debuggable.xml" else "AndroidManifest.xml"
|
||||
).also { file ->
|
||||
if (file.exists()) return@also
|
||||
|
||||
log += "Downloading patched manifest...\n"
|
||||
|
||||
DownloadUtils.downloadManifest(context, useDebuggableManifest)
|
||||
|
||||
log += "Done\n"
|
||||
}
|
||||
|
||||
val injector = File(context.externalCacheDir, "Injector.dex").also { file ->
|
||||
if (file.exists()) return@also
|
||||
|
||||
|
|
@ -84,13 +69,17 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
|
|||
log += "Repacking APK\n"
|
||||
|
||||
var patched = false
|
||||
var manifestBytes: ByteArray?
|
||||
|
||||
with(Zip(outputApk.absolutePath, 6, 'r')) {
|
||||
repeat(totalEntries) { index ->
|
||||
for (index in 0 until totalEntries) {
|
||||
openEntryByIndex(index)
|
||||
val name = entryName
|
||||
if (name == "classes5.dex") patched = true
|
||||
closeEntry()
|
||||
if (name == "classes5.dex") {
|
||||
patched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
val cacheDir = context.cacheDir.absolutePath
|
||||
|
|
@ -101,6 +90,10 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
|
|||
closeEntry()
|
||||
}
|
||||
|
||||
openEntry("AndroidManifest.xml")
|
||||
manifestBytes = readEntry()
|
||||
closeEntry()
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
|
|
@ -136,15 +129,19 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
|
|||
|
||||
writeEntry("classes5.dex", assetManager.open("pine/classes.dex"))
|
||||
|
||||
openEntry("AndroidManifest.xml")
|
||||
compressFile(manifest.absolutePath)
|
||||
closeEntry()
|
||||
|
||||
writeEntry("lib/arm64-v8a/libpine.so", assetManager.open("pine/arm64-v8a/libpine.so"))
|
||||
writeEntry("lib/armeabi-v7a/libpine.so", assetManager.open("pine/armeabi-v7a/libpine.so"))
|
||||
|
||||
writeEntry("classes6.dex", assetManager.open("kotlin/classes.dex"))
|
||||
|
||||
manifestBytes?.let { bytes ->
|
||||
log += "Patching manifest\n"
|
||||
val newManifestBytes = patchManifest(bytes)
|
||||
openEntry("AndroidManifest.xml")
|
||||
writeEntry(newManifestBytes, newManifestBytes.size.toLong())
|
||||
closeEntry()
|
||||
}
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
|
|
@ -210,4 +207,4 @@ fun InstallerScreen(navigator: DestinationsNavigator, apk: File?) {
|
|||
// progress = 0.5f
|
||||
// )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,4 +12,8 @@ val httpClient = HttpClient(Android) {
|
|||
}
|
||||
val aliucordDir = File(Environment.getExternalStorageDirectory(), "Aliucord")
|
||||
val pluginsDir = File(aliucordDir, "plugins")
|
||||
val gson = Gson()
|
||||
val gson = Gson()
|
||||
|
||||
const val MANAGE_EXTERNAL_STORAGE = "android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"
|
||||
const val REQUEST_LEGACY_STORAGE = "requestLegacyExternalStorage"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Juby210
|
||||
* Licensed under the Open Software License version 3.0
|
||||
*/
|
||||
|
||||
package com.aliucord.manager.utils
|
||||
|
||||
import com.aliucord.manager.preferences.Prefs
|
||||
import pxb.android.axml.AxmlReader
|
||||
import pxb.android.axml.AxmlVisitor
|
||||
import pxb.android.axml.AxmlWriter
|
||||
import pxb.android.axml.NodeVisitor
|
||||
|
||||
fun patchManifest(manifestBytes: ByteArray): ByteArray {
|
||||
val packageName = "com.aliucord"
|
||||
val debuggable = Prefs.debuggable.get()
|
||||
|
||||
val reader = AxmlReader(manifestBytes)
|
||||
val writer = AxmlWriter()
|
||||
reader.accept(object : AxmlVisitor(writer) {
|
||||
override fun child(ns: String?, name: String?) =
|
||||
object : ReplaceAttrsVisitor(super.child(ns, name), mapOf("package" to packageName)) {
|
||||
private var addManagePerm = true
|
||||
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
super.attr(ns, name, resourceId, type, value)
|
||||
if (value == MANAGE_EXTERNAL_STORAGE) addManagePerm = false
|
||||
}
|
||||
|
||||
override fun child(ns: String?, name: String): NodeVisitor {
|
||||
val nv = super.child(ns, name)
|
||||
return when (name) {
|
||||
"uses-sdk" -> ReplaceAttrsVisitor(nv, mapOf("targetSdkVersion" to 29))
|
||||
"permission" -> ReplaceAttrsVisitor(nv, mapOf("name" to "$packageName.permission.CONNECT"))
|
||||
"application" -> object : ReplaceAttrsVisitor(nv, mapOf(REQUEST_LEGACY_STORAGE to 1, "label" to "Aliucord", "debuggable" to debuggable)) {
|
||||
private var addLegacyStorage = true
|
||||
private var addDebuggable = debuggable
|
||||
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
super.attr(ns, name, resourceId, type, value)
|
||||
if (name == REQUEST_LEGACY_STORAGE) addLegacyStorage = false
|
||||
}
|
||||
|
||||
override fun child(ns: String?, name: String): NodeVisitor {
|
||||
val visitor = super.child(ns, name)
|
||||
return when (name) {
|
||||
"activity" -> ReplaceAttrsVisitor(visitor, mapOf("label" to "Aliucord"))
|
||||
"service" -> object : NodeVisitor(visitor) {
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
super.attr(ns, name, resourceId, type,
|
||||
if (value is String && value.endsWith("CONNECT")) "$packageName.permission.CONNECT" else value)
|
||||
}
|
||||
}
|
||||
"provider" -> object : NodeVisitor(visitor) {
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
super.attr(ns, name, resourceId, type,
|
||||
if (name == "authorities") (value as String).replace("com.discord", packageName) else value)
|
||||
}
|
||||
}
|
||||
"meta-data" -> object : NodeVisitor(visitor) {
|
||||
private var crashlytics = false
|
||||
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
if (name == "name" && value == "firebase_crashlytics_collection_enabled") crashlytics = true
|
||||
super.attr(ns, name, resourceId, type,
|
||||
if (name == "value" && crashlytics) 0 else value)
|
||||
}
|
||||
}
|
||||
else -> visitor
|
||||
}
|
||||
}
|
||||
|
||||
override fun end() {
|
||||
if (addLegacyStorage)
|
||||
super.attr(ANDROID_NAMESPACE, REQUEST_LEGACY_STORAGE, -1, TYPE_INT_BOOLEAN, 1)
|
||||
if (addDebuggable)
|
||||
super.attr(ANDROID_NAMESPACE, "debuggable", -1, TYPE_INT_BOOLEAN, 1)
|
||||
super.end()
|
||||
}
|
||||
}
|
||||
else -> nv
|
||||
}
|
||||
}
|
||||
|
||||
override fun end() {
|
||||
if (addManagePerm) super.child(null, "uses-permission").attr(
|
||||
ANDROID_NAMESPACE, "name", -1, TYPE_STRING, MANAGE_EXTERNAL_STORAGE
|
||||
)
|
||||
super.end()
|
||||
}
|
||||
}
|
||||
})
|
||||
return writer.toByteArray()
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Juby210
|
||||
* Licensed under the Open Software License version 3.0
|
||||
*/
|
||||
|
||||
package com.aliucord.manager.utils
|
||||
|
||||
import pxb.android.axml.NodeVisitor
|
||||
|
||||
open class ReplaceAttrsVisitor(
|
||||
nv: NodeVisitor,
|
||||
private val attrs: Map<String, Any>
|
||||
) : NodeVisitor(nv) {
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
val replace = attrs.containsKey(name)
|
||||
val newValue = attrs[name]
|
||||
super.attr(ns, name, resourceId, if (newValue is String) TYPE_STRING else type, if (replace) newValue else value)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,8 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:7.1.2")
|
||||
// please do not update to 7.1+, it breaks compatibility with arctic fox android studio
|
||||
classpath("com.android.tools.build:gradle:7.0.4")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
@ -29,4 +30,4 @@ allprojects {
|
|||
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,6 +1,6 @@
|
|||
#Tue Jan 25 18:24:43 EST 2022
|
||||
#Sat Mar 12 19:39:38 CET 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue