mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 12:05:30 +00:00
Fix build script
This commit is contained in:
parent
ca31412c05
commit
307cf87215
@ -1,3 +1,7 @@
|
|||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.file.DirectoryProperty
|
||||||
|
import org.gradle.api.file.RegularFileProperty
|
||||||
|
import org.gradle.api.tasks.*
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -72,23 +76,41 @@ fun genKeyData(keysDir: File, outSrc: File) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun genStubManifest(srcDir: File, outDir: File): String {
|
@CacheableTask
|
||||||
fun String.ind(level: Int) = replaceIndentByMargin(" ".repeat(level))
|
abstract class ManifestUpdater: DefaultTask() {
|
||||||
|
@get:InputFile
|
||||||
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
abstract val mergedManifest: RegularFileProperty
|
||||||
|
|
||||||
val cmpList = mutableListOf<String>()
|
@get:InputFiles
|
||||||
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
abstract val factoryClassDir: DirectoryProperty
|
||||||
|
|
||||||
cmpList.add(
|
@get:InputFiles
|
||||||
"""
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
abstract val appClassDir: DirectoryProperty
|
||||||
|
|
||||||
|
@get:OutputFile
|
||||||
|
abstract val outputManifest: RegularFileProperty
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun taskAction() {
|
||||||
|
fun String.ind(level: Int) = replaceIndentByMargin(" ".repeat(level))
|
||||||
|
|
||||||
|
val cmpList = mutableListOf<String>()
|
||||||
|
|
||||||
|
cmpList.add(
|
||||||
|
"""
|
||||||
|<provider
|
|<provider
|
||||||
| android:name="x.COMPONENT_PLACEHOLDER_0"
|
| android:name="x.COMPONENT_PLACEHOLDER_0"
|
||||||
| android:authorities="${'$'}{applicationId}.provider"
|
| android:authorities="${'$'}{applicationId}.provider"
|
||||||
| android:directBootAware="true"
|
| android:directBootAware="true"
|
||||||
| android:exported="false"
|
| android:exported="false"
|
||||||
| android:grantUriPermissions="true" />""".ind(2)
|
| android:grantUriPermissions="true" />""".ind(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
cmpList.add(
|
cmpList.add(
|
||||||
"""
|
"""
|
||||||
|<receiver
|
|<receiver
|
||||||
| android:name="x.COMPONENT_PLACEHOLDER_1"
|
| android:name="x.COMPONENT_PLACEHOLDER_1"
|
||||||
| android:exported="false">
|
| android:exported="false">
|
||||||
@ -104,10 +126,10 @@ fun genStubManifest(srcDir: File, outDir: File): String {
|
|||||||
| <data android:scheme="package" />
|
| <data android:scheme="package" />
|
||||||
| </intent-filter>
|
| </intent-filter>
|
||||||
|</receiver>""".ind(2)
|
|</receiver>""".ind(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
cmpList.add(
|
cmpList.add(
|
||||||
"""
|
"""
|
||||||
|<activity
|
|<activity
|
||||||
| android:name="x.COMPONENT_PLACEHOLDER_2"
|
| android:name="x.COMPONENT_PLACEHOLDER_2"
|
||||||
| android:exported="true">
|
| android:exported="true">
|
||||||
@ -116,37 +138,55 @@ fun genStubManifest(srcDir: File, outDir: File): String {
|
|||||||
| <category android:name="android.intent.category.LAUNCHER" />
|
| <category android:name="android.intent.category.LAUNCHER" />
|
||||||
| </intent-filter>
|
| </intent-filter>
|
||||||
|</activity>""".ind(2)
|
|</activity>""".ind(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
cmpList.add(
|
cmpList.add(
|
||||||
"""
|
"""
|
||||||
|<activity
|
|<activity
|
||||||
| android:name="x.COMPONENT_PLACEHOLDER_3"
|
| android:name="x.COMPONENT_PLACEHOLDER_3"
|
||||||
| android:directBootAware="true"
|
| android:directBootAware="true"
|
||||||
| android:exported="false"
|
| android:exported="false"
|
||||||
| android:taskAffinity=""
|
| android:taskAffinity="">
|
||||||
| tools:ignore="AppLinkUrlError">
|
|
||||||
| <intent-filter>
|
| <intent-filter>
|
||||||
| <action android:name="android.intent.action.VIEW"/>
|
| <action android:name="android.intent.action.VIEW"/>
|
||||||
| <category android:name="android.intent.category.DEFAULT"/>
|
| <category android:name="android.intent.category.DEFAULT"/>
|
||||||
| </intent-filter>
|
| </intent-filter>
|
||||||
|</activity>""".ind(2)
|
|</activity>""".ind(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
cmpList.add(
|
cmpList.add(
|
||||||
"""
|
"""
|
||||||
|<service
|
|<service
|
||||||
| android:name="x.COMPONENT_PLACEHOLDER_4"
|
| android:name="x.COMPONENT_PLACEHOLDER_4"
|
||||||
| android:exported="false" />""".ind(2)
|
| android:exported="false" />""".ind(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
cmpList.add(
|
cmpList.add(
|
||||||
"""
|
"""
|
||||||
|<service
|
|<service
|
||||||
| android:name="x.COMPONENT_PLACEHOLDER_5"
|
| android:name="x.COMPONENT_PLACEHOLDER_5"
|
||||||
| android:exported="false"
|
| android:exported="false"
|
||||||
| android:permission="android.permission.BIND_JOB_SERVICE" />""".ind(2)
|
| android:permission="android.permission.BIND_JOB_SERVICE" />""".ind(2)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Shuffle the order of the components
|
||||||
|
cmpList.shuffle(RANDOM)
|
||||||
|
val (factoryPkg, factoryClass) = factoryClassDir.asFileTree.first().let {
|
||||||
|
it.parentFile.name to it.name.removeSuffix(".java")
|
||||||
|
}
|
||||||
|
val (appPkg, appClass) = appClassDir.asFileTree.first().let {
|
||||||
|
it.parentFile.name to it.name.removeSuffix(".java")
|
||||||
|
}
|
||||||
|
var manifest = mergedManifest.asFile.get().readText()
|
||||||
|
manifest = manifest.replace("<application", """<application android:appComponentFactory="$factoryPkg.$factoryClass" android:name="$appPkg.$appClass"""")
|
||||||
|
manifest = manifest.replace("</application", "${cmpList.joinToString("\n\n")}\n</application")
|
||||||
|
outputManifest.get().asFile.writeText(manifest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun genStubClass(factoryOutDir: File, appOutDir: File) {
|
||||||
|
fun String.ind(level: Int) = replaceIndentByMargin(" ".repeat(level))
|
||||||
|
|
||||||
val classNameGenerator = sequence {
|
val classNameGenerator = sequence {
|
||||||
fun notJavaKeyword(name: String) = when (name) {
|
fun notJavaKeyword(name: String) = when (name) {
|
||||||
@ -176,7 +216,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
|
|||||||
}
|
}
|
||||||
}.distinct().iterator()
|
}.distinct().iterator()
|
||||||
|
|
||||||
fun genClass(type: String): String {
|
fun genClass(type: String, outDir: File) {
|
||||||
val clzName = classNameGenerator.next()
|
val clzName = classNameGenerator.next()
|
||||||
val (pkg, name) = clzName.split('.')
|
val (pkg, name) = clzName.split('.')
|
||||||
val pkgDir = File(outDir, pkg)
|
val pkgDir = File(outDir, pkg)
|
||||||
@ -185,18 +225,10 @@ fun genStubManifest(srcDir: File, outDir: File): String {
|
|||||||
it.println("package $pkg;")
|
it.println("package $pkg;")
|
||||||
it.println("public class $name extends com.topjohnwu.magisk.$type {}")
|
it.println("public class $name extends com.topjohnwu.magisk.$type {}")
|
||||||
}
|
}
|
||||||
return clzName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate 2 non redirect-able classes
|
genClass("DelegateComponentFactory", factoryOutDir)
|
||||||
val factory = genClass("DelegateComponentFactory")
|
genClass("DelegateApplication", appOutDir)
|
||||||
val app = genClass("DelegateApplication")
|
|
||||||
|
|
||||||
// Shuffle the order of the components
|
|
||||||
cmpList.shuffle(RANDOM)
|
|
||||||
|
|
||||||
val xml = File(srcDir, "AndroidManifest.xml").readText()
|
|
||||||
return xml.format(factory, app, cmpList.joinToString("\n\n"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun genEncryptedResources(res: InputStream, outDir: File) {
|
fun genEncryptedResources(res: InputStream, outDir: File) {
|
||||||
|
@ -1,26 +1,29 @@
|
|||||||
|
import com.android.build.api.artifact.ArtifactTransformationRequest
|
||||||
|
import com.android.build.api.artifact.SingleArtifact
|
||||||
|
import com.android.build.api.dsl.ApkSigningConfig
|
||||||
|
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||||
import com.android.build.gradle.BaseExtension
|
import com.android.build.gradle.BaseExtension
|
||||||
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
|
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
|
||||||
import com.android.builder.internal.packaging.IncrementalPackager
|
import com.android.builder.internal.packaging.IncrementalPackager
|
||||||
import com.android.builder.model.SigningConfig
|
|
||||||
import com.android.tools.build.apkzlib.sign.SigningExtension
|
import com.android.tools.build.apkzlib.sign.SigningExtension
|
||||||
import com.android.tools.build.apkzlib.sign.SigningOptions
|
import com.android.tools.build.apkzlib.sign.SigningOptions
|
||||||
import com.android.tools.build.apkzlib.zfile.ZFiles
|
import com.android.tools.build.apkzlib.zfile.ZFiles
|
||||||
import com.android.tools.build.apkzlib.zip.ZFileOptions
|
import com.android.tools.build.apkzlib.zip.ZFileOptions
|
||||||
import org.apache.tools.ant.filters.FixCrLfFilter
|
import org.apache.tools.ant.filters.FixCrLfFilter
|
||||||
import org.gradle.api.Action
|
import org.gradle.api.Action
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.JavaVersion
|
import org.gradle.api.JavaVersion
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.file.DirectoryProperty
|
||||||
import org.gradle.api.plugins.ExtensionAware
|
import org.gradle.api.plugins.ExtensionAware
|
||||||
import org.gradle.api.tasks.Delete
|
import org.gradle.api.provider.Property
|
||||||
import org.gradle.api.tasks.StopExecutionException
|
import org.gradle.api.tasks.*
|
||||||
import org.gradle.api.tasks.Sync
|
|
||||||
import org.gradle.kotlin.dsl.*
|
import org.gradle.kotlin.dsl.*
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
|
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintStream
|
|
||||||
import java.security.KeyStore
|
import java.security.KeyStore
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -46,6 +49,9 @@ private fun BaseExtension.kotlin(configure: Action<KotlinAndroidProjectExtension
|
|||||||
private val Project.android: BaseAppModuleExtension
|
private val Project.android: BaseAppModuleExtension
|
||||||
get() = extensions["android"] as BaseAppModuleExtension
|
get() = extensions["android"] as BaseAppModuleExtension
|
||||||
|
|
||||||
|
private val Project.androidComponents
|
||||||
|
get() = extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
|
||||||
|
|
||||||
fun Project.setupCommon() {
|
fun Project.setupCommon() {
|
||||||
androidBase {
|
androidBase {
|
||||||
compileSdkVersion(33)
|
compileSdkVersion(33)
|
||||||
@ -72,7 +78,7 @@ fun Project.setupCommon() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SigningConfig.getPrivateKey(): KeyStore.PrivateKeyEntry {
|
private fun ApkSigningConfig.getPrivateKey(): KeyStore.PrivateKeyEntry {
|
||||||
val keyStore = KeyStore.getInstance(storeType ?: KeyStore.getDefaultType())
|
val keyStore = KeyStore.getInstance(storeType ?: KeyStore.getDefaultType())
|
||||||
storeFile!!.inputStream().use {
|
storeFile!!.inputStream().use {
|
||||||
keyStore.load(it, storePassword!!.toCharArray())
|
keyStore.load(it, storePassword!!.toCharArray())
|
||||||
@ -82,7 +88,7 @@ private fun SigningConfig.getPrivateKey(): KeyStore.PrivateKeyEntry {
|
|||||||
return entry as KeyStore.PrivateKeyEntry
|
return entry as KeyStore.PrivateKeyEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addComment(apkPath: File, signConfig: SigningConfig, minSdk: Int, eocdComment: String) {
|
private fun addComment(inFile: File, outFile: File, signConfig: ApkSigningConfig, minSdk: Int, eocdComment: String) {
|
||||||
val privateKey = signConfig.getPrivateKey()
|
val privateKey = signConfig.getPrivateKey()
|
||||||
val signingOptions = SigningOptions.builder()
|
val signingOptions = SigningOptions.builder()
|
||||||
.setMinSdkVersion(minSdk)
|
.setMinSdkVersion(minSdk)
|
||||||
@ -96,7 +102,9 @@ private fun addComment(apkPath: File, signConfig: SigningConfig, minSdk: Int, eo
|
|||||||
noTimestamps = true
|
noTimestamps = true
|
||||||
autoSortFiles = true
|
autoSortFiles = true
|
||||||
}
|
}
|
||||||
ZFiles.apk(apkPath, options).use {
|
outFile.parentFile.mkdirs()
|
||||||
|
inFile.copyTo(outFile, overwrite = true)
|
||||||
|
ZFiles.apk(outFile, options).use {
|
||||||
SigningExtension(signingOptions).register(it)
|
SigningExtension(signingOptions).register(it)
|
||||||
it.eocdComment = eocdComment.toByteArray()
|
it.eocdComment = eocdComment.toByteArray()
|
||||||
it.get(IncrementalPackager.APP_METADATA_ENTRY_PATH)?.delete()
|
it.get(IncrementalPackager.APP_METADATA_ENTRY_PATH)?.delete()
|
||||||
@ -104,6 +112,31 @@ private fun addComment(apkPath: File, signConfig: SigningConfig, minSdk: Int, eo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
addComment(inFile, outFile, signingConfig.get(), 0, comment.get())
|
||||||
|
outFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Project.setupAppCommon() {
|
private fun Project.setupAppCommon() {
|
||||||
setupCommon()
|
setupCommon()
|
||||||
|
|
||||||
@ -146,15 +179,22 @@ private fun Project.setupAppCommon() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
android.applicationVariants.all {
|
androidComponents.onVariants { variant ->
|
||||||
val projectName = project.name.lowercase()
|
val commentTask = tasks.register(
|
||||||
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
"comment${variant.name.replaceFirstChar { it.uppercase() }}",
|
||||||
tasks.getByPath(":$projectName:package$variantCapped").doLast {
|
AddCommentTask::class.java
|
||||||
val apk = outputs.files.asFileTree.filter { it.name.endsWith(".apk") }.singleFile
|
)
|
||||||
val comment = "version=${Config.version}\n" +
|
val transformationRequest = variant.artifacts.use(commentTask)
|
||||||
|
.wiredWithDirectories(AddCommentTask::apkFolder, AddCommentTask::outFolder)
|
||||||
|
.toTransformMany(SingleArtifact.APK)
|
||||||
|
val signingConfig = android.buildTypes.getByName(variant.buildType!!).signingConfig
|
||||||
|
commentTask.configure {
|
||||||
|
this.transformationRequest.set(transformationRequest)
|
||||||
|
this.signingConfig.set(signingConfig)
|
||||||
|
this.comment.set("version=${Config.version}\n" +
|
||||||
"versionCode=${Config.versionCode}\n" +
|
"versionCode=${Config.versionCode}\n" +
|
||||||
"stubVersion=${Config.stubVersion}\n"
|
"stubVersion=${Config.stubVersion}\n")
|
||||||
addComment(apk, signingConfig, android.defaultConfig.minSdk!!, comment)
|
this.outFolder.set(File(buildDir, "outputs/apk/${variant.name}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,33 +305,45 @@ fun Project.setupApp() {
|
|||||||
fun Project.setupStub() {
|
fun Project.setupStub() {
|
||||||
setupAppCommon()
|
setupAppCommon()
|
||||||
|
|
||||||
|
|
||||||
|
androidComponents.onVariants { variant ->
|
||||||
|
val manifestUpdater =
|
||||||
|
project.tasks.register(
|
||||||
|
"${variant.name}ManifestProducer",
|
||||||
|
ManifestUpdater::class.java
|
||||||
|
) {
|
||||||
|
dependsOn("generate${variant.name.replaceFirstChar { it.uppercase() }}ObfuscatedClass")
|
||||||
|
appClassDir.set(File(buildDir, "generated/source/app/${variant.name}"))
|
||||||
|
factoryClassDir.set(File(buildDir, "generated/source/factory/${variant.name}"))
|
||||||
|
}
|
||||||
|
variant.artifacts.use(manifestUpdater)
|
||||||
|
.wiredWithFiles(
|
||||||
|
ManifestUpdater::mergedManifest,
|
||||||
|
ManifestUpdater::outputManifest)
|
||||||
|
.toTransform(SingleArtifact.MERGED_MANIFEST)
|
||||||
|
}
|
||||||
|
|
||||||
android.applicationVariants.all {
|
android.applicationVariants.all {
|
||||||
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
val variantCapped = name.replaceFirstChar { it.uppercase() }
|
||||||
val variantLowered = name.lowercase()
|
val variantLowered = name.lowercase()
|
||||||
val manifest = file("src/${variantLowered}/AndroidManifest.xml")
|
val outFactoryClassDir = File(buildDir, "generated/source/factory/${variantLowered}")
|
||||||
val outManifestDir = File(buildDir, "generated/source/manifest/${variantLowered}")
|
val outAppClassDir = File(buildDir, "generated/source/app/${variantLowered}")
|
||||||
val outResDir = File(buildDir, "generated/source/res/${variantLowered}")
|
val outResDir = File(buildDir, "generated/source/res/${variantLowered}")
|
||||||
val templateDir = file("template")
|
|
||||||
val aapt = File(android.sdkDirectory, "build-tools/${android.buildToolsVersion}/aapt2")
|
val aapt = File(android.sdkDirectory, "build-tools/${android.buildToolsVersion}/aapt2")
|
||||||
val apk = File(buildDir, "intermediates/processed_res/" +
|
val apk = File(buildDir, "intermediates/processed_res/" +
|
||||||
"${variantLowered}/out/resources-${variantLowered}.ap_")
|
"${variantLowered}/out/resources-${variantLowered}.ap_")
|
||||||
val apkTmp = File("${apk}.tmp")
|
val apkTmp = File("${apk}.tmp")
|
||||||
|
|
||||||
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedManifest") {
|
val genManifestTask = tasks.register("generate${variantCapped}ObfuscatedClass") {
|
||||||
inputs.property("seed", RAND_SEED)
|
inputs.property("seed", RAND_SEED)
|
||||||
inputs.dir(templateDir)
|
outputs.dirs(outFactoryClassDir, outAppClassDir)
|
||||||
outputs.dir(outManifestDir)
|
|
||||||
outputs.file(manifest)
|
|
||||||
doLast {
|
doLast {
|
||||||
val xml = genStubManifest(templateDir, outManifestDir)
|
outFactoryClassDir.mkdirs()
|
||||||
manifest.parentFile.mkdirs()
|
outAppClassDir.mkdirs()
|
||||||
PrintStream(manifest).use {
|
genStubClass(outFactoryClassDir, outAppClassDir)
|
||||||
it.print(xml)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
preBuildProvider.configure { dependsOn(genManifestTask) }
|
registerJavaGeneratingTask(genManifestTask, outFactoryClassDir, outAppClassDir)
|
||||||
registerJavaGeneratingTask(genManifestTask, outManifestDir)
|
|
||||||
|
|
||||||
val processResourcesTask = tasks.getByPath(":stub:process${variantCapped}Resources")
|
val processResourcesTask = tasks.getByPath(":stub:process${variantCapped}Resources")
|
||||||
processResourcesTask.doLast {
|
processResourcesTask.doLast {
|
||||||
|
@ -1 +1,14 @@
|
|||||||
<manifest/>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||||
|
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon,UnusedAttribute">
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
|
||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
|
||||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:appComponentFactory="%s"
|
|
||||||
android:name="%s"
|
|
||||||
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon,UnusedAttribute">
|
|
||||||
|
|
||||||
%s
|
|
||||||
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
Loading…
Reference in New Issue
Block a user