Update access control page

Fix bug
This commit is contained in:
chen08209
2024-08-05 19:25:35 +08:00
parent bee2f8aa4f
commit 38221bcd10
50 changed files with 1393 additions and 645 deletions

View File

@@ -102,6 +102,9 @@ flutter {
dependencies {
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'com.google.code.gson:gson:2.10'
implementation("com.android.tools.smali:smali-dexlib2:3.0.7") {
exclude group: "com.google.guava", module: "guava"
}
}

View File

@@ -1,7 +1,10 @@
package com.follow.clash.models
import java.util.Date
data class Package(
val packageName: String,
val label: String,
val isSystem:Boolean
val isSystem: Boolean,
val firstInstallTime: Long,
)

View File

@@ -6,11 +6,13 @@ import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.ComponentInfo
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.os.Build
import android.widget.Toast
import androidx.core.content.ContextCompat.getSystemService
import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile
import androidx.core.content.FileProvider
import androidx.core.content.getSystemService
import com.follow.clash.GlobalState
@@ -32,6 +34,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.net.InetSocketAddress
import java.util.zip.ZipFile
class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware {
@@ -49,6 +52,62 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
private var connectivity: ConnectivityManager? = null
private val iconMap = mutableMapOf<String, String?>()
private val packages = mutableListOf<Package>()
private val skipPrefixList = listOf(
"com.google",
"com.android.chrome",
"com.android.vending",
"com.microsoft",
"com.apple",
"com.zhiliaoapp.musically", // Banned by China
)
private val chinaAppPrefixList = listOf(
"com.tencent",
"com.alibaba",
"com.umeng",
"com.qihoo",
"com.ali",
"com.alipay",
"com.amap",
"com.sina",
"com.weibo",
"com.vivo",
"com.xiaomi",
"com.huawei",
"com.taobao",
"com.secneo",
"s.h.e.l.l",
"com.stub",
"com.kiwisec",
"com.secshell",
"com.wrapper",
"cn.securitystack",
"com.mogosec",
"com.secoen",
"com.netease",
"com.mx",
"com.qq.e",
"com.baidu",
"com.bytedance",
"com.bugly",
"com.miui",
"com.oppo",
"com.coloros",
"com.iqoo",
"com.meizu",
"com.gionee",
"cn.nubia",
"com.oplus",
"andes.oplus",
"com.unionpay",
"cn.wps"
)
private val chinaAppRegex by lazy {
("(" + chinaAppPrefixList.joinToString("|").replace(".", "\\.") + ").*").toRegex()
}
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
scope = CoroutineScope(Dispatchers.Default)
@@ -88,7 +147,13 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
"getPackages" -> {
scope.launch {
result.success(getPackages())
result.success(getPackagesToJson())
}
}
"getChinaPackageNames" -> {
scope.launch {
result.success(getChinaPackageNames())
}
}
@@ -248,26 +313,106 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
return iconMap[packageName]
}
private suspend fun getPackages(): String {
return withContext(Dispatchers.Default) {
val packageManager = context?.packageManager
val packages: List<Package>? =
packageManager?.getInstalledPackages(PackageManager.GET_META_DATA)?.filter {
it.packageName != context?.packageName
|| it.requestedPermissions?.contains(Manifest.permission.INTERNET) == true
|| it.packageName == "android"
private fun getPackages(): List<Package> {
val packageManager = context?.packageManager
if (packages.isNotEmpty()) return packages;
packageManager?.getInstalledPackages(PackageManager.GET_META_DATA)?.filter {
it.packageName != context?.packageName
|| it.requestedPermissions?.contains(Manifest.permission.INTERNET) == true
|| it.packageName == "android"
}?.map {
Package(
packageName = it.packageName,
label = it.applicationInfo.loadLabel(packageManager).toString(),
isSystem = (it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 1
)
}
}?.map {
Package(
packageName = it.packageName,
label = it.applicationInfo.loadLabel(packageManager).toString(),
isSystem = (it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 1,
firstInstallTime = it.firstInstallTime
)
}?.let { packages.addAll(it) }
return packages;
}
private suspend fun getPackagesToJson(): String {
return withContext(Dispatchers.Default) {
Gson().toJson(getPackages())
}
}
private suspend fun getChinaPackageNames(): String {
return withContext(Dispatchers.Default) {
val packages: List<String> =
getPackages().map { it.packageName }.filter { isChinaPackage(it) }
Gson().toJson(packages)
}
}
private fun isChinaPackage(packageName: String): Boolean {
val packageManager = context?.packageManager ?: return false
skipPrefixList.forEach {
if (packageName == it || packageName.startsWith("$it.")) return false
}
val packageManagerFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
} else {
@Suppress("DEPRECATION")
PackageManager.GET_UNINSTALLED_PACKAGES or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
}
if (packageName.matches(chinaAppRegex)) {
return true
}
try {
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(
packageName,
PackageManager.PackageInfoFlags.of(packageManagerFlags.toLong())
)
} else {
@Suppress("DEPRECATION") packageManager.getPackageInfo(
packageName, packageManagerFlags
)
}
mutableListOf<ComponentInfo>().apply {
packageInfo.services?.let { addAll(it) }
packageInfo.activities?.let { addAll(it) }
packageInfo.receivers?.let { addAll(it) }
packageInfo.providers?.let { addAll(it) }
}.forEach {
if (it.name.matches(chinaAppRegex)) return true
}
ZipFile(File(packageInfo.applicationInfo.publicSourceDir)).use {
for (packageEntry in it.entries()) {
if (packageEntry.name.startsWith("firebase-")) return false
}
for (packageEntry in it.entries()) {
if (!(packageEntry.name.startsWith("classes") && packageEntry.name.endsWith(
".dex"
))
) {
continue
}
if (packageEntry.size > 15000000) {
return true
}
val input = it.getInputStream(packageEntry).buffered()
val dexFile = try {
DexBackedDexFile.fromInputStream(null, input)
} catch (e: Exception) {
return false
}
for (clazz in dexFile.classes) {
val clazzName =
clazz.type.substring(1, clazz.type.length - 1).replace("/", ".")
.replace("$", ".")
if (clazzName.matches(chinaAppRegex)) return true
}
}
}
} catch (_: Exception) {
return false
}
return false
}
fun requestGc() {
channel.invokeMethod("gc", null)
}