mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-18 22:20:06 +08:00
Upgrade SDK 35
This commit is contained in:
parent
ea8e4aee60
commit
607afa8ce3
@ -3,7 +3,7 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("kotlin-kapt")
|
||||
id("com.google.devtools.ksp")
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
@ -13,8 +13,8 @@ android {
|
||||
compileOptions {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
}
|
||||
kapt.arguments {
|
||||
arg("room.incremental", true)
|
||||
ksp {
|
||||
arg("room.incremental", "true")
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
}
|
||||
bundle {
|
||||
@ -23,15 +23,19 @@ android {
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
viewBinding = true
|
||||
aidl = true
|
||||
}
|
||||
namespace = "io.nekohasekai.sagernet"
|
||||
packagingOptions {
|
||||
packaging {
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
}
|
||||
androidResources {
|
||||
generateLocaleConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -74,11 +78,11 @@ dependencies {
|
||||
exclude(group = "androidx.appcompat")
|
||||
}
|
||||
|
||||
implementation("androidx.room:room-runtime:2.5.1")
|
||||
kapt("androidx.room:room-compiler:2.5.1")
|
||||
implementation("androidx.room:room-ktx:2.5.1")
|
||||
implementation("androidx.room:room-runtime:2.6.1")
|
||||
ksp("androidx.room:room-compiler:2.6.1")
|
||||
implementation("androidx.room:room-ktx:2.6.1")
|
||||
implementation("com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4")
|
||||
kapt("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4")
|
||||
ksp("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4")
|
||||
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Entity(tableName = "rules")
|
||||
@Parcelize
|
||||
@TypeConverters(StringCollectionConverter::class)
|
||||
data class RuleEntity(
|
||||
@PrimaryKey(autoGenerate = true) var id: Long = 0L,
|
||||
var name: String = "",
|
||||
@ -21,7 +22,7 @@ data class RuleEntity(
|
||||
var source: String = "",
|
||||
var protocol: String = "",
|
||||
var outbound: Long = 0,
|
||||
var packages: List<String> = listOf(),
|
||||
var packages: Set<String> = emptySet(),
|
||||
) : Parcelable {
|
||||
|
||||
fun displayName(): String {
|
||||
|
||||
@ -27,7 +27,7 @@ abstract class SagerDatabase : RoomDatabase() {
|
||||
val instance by lazy {
|
||||
SagerNet.application.getDatabasePath(Key.DB_PROFILE).parentFile?.mkdirs()
|
||||
Room.databaseBuilder(SagerNet.application, SagerDatabase::class.java, Key.DB_PROFILE)
|
||||
.addMigrations(*SagerDatabase_Migrations.build())
|
||||
// .addMigrations(*SagerDatabase_Migrations.build())
|
||||
.allowMainThreadQueries()
|
||||
.enableMultiInstanceInvalidation()
|
||||
.fallbackToDestructiveMigration()
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
package io.nekohasekai.sagernet.database
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
|
||||
class StringCollectionConverter {
|
||||
companion object {
|
||||
const val SPLIT_FLAG = ","
|
||||
|
||||
/*
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun fromList(list: List<String>): String = if (list.isEmpty()) {
|
||||
""
|
||||
} else {
|
||||
list.joinToString(SPLIT_FLAG)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun toList(str: String): List<String> = if (str.isBlank()) {
|
||||
emptyList()
|
||||
} else {
|
||||
str.split(SPLIT_FLAG)
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun fromSet(set: Set<String>): String = if (set.isEmpty()) {
|
||||
""
|
||||
} else {
|
||||
set.joinToString(SPLIT_FLAG)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
@JvmStatic
|
||||
fun toSet(str: String): Set<String> = if (str.isBlank()) {
|
||||
emptySet()
|
||||
} else {
|
||||
str.split(",").toSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,9 +113,6 @@ fun Context.listenForPackageChanges(onetime: Boolean = true, callback: () -> Uni
|
||||
})
|
||||
}
|
||||
|
||||
val PackageInfo.signaturesCompat
|
||||
get() = if (Build.VERSION.SDK_INT >= 28) signingInfo.apkContentsSigners else @Suppress("DEPRECATION") signatures
|
||||
|
||||
/**
|
||||
* Based on: https://stackoverflow.com/a/26348729/2245107
|
||||
*/
|
||||
|
||||
@ -107,7 +107,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
|
||||
PackageCache.awaitLoadSync()
|
||||
for ((_, pkg) in PackageCache.installedPluginPackages) {
|
||||
try {
|
||||
val pluginId = pkg.providers[0].loadString(Plugins.METADATA_KEY_ID)
|
||||
val pluginId = pkg.providers?.get(0)?.loadString(Plugins.METADATA_KEY_ID)
|
||||
if (pluginId.isNullOrBlank() || pluginId.startsWith(Plugins.AUTHORITIES_PREFIX_NEKO_PLUGIN)) continue
|
||||
addItem(MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_nfc_24)
|
||||
|
||||
@ -139,9 +139,9 @@ class AppListActivity : ThemedActivity() {
|
||||
var filteredApps = apps
|
||||
|
||||
suspend fun reload() {
|
||||
apps = getCachedApps().map { (packageName, packageInfo) ->
|
||||
apps = getCachedApps().mapNotNull { (packageName, packageInfo) ->
|
||||
coroutineContext[Job]!!.ensureActive()
|
||||
ProxiedApp(packageManager, packageInfo.applicationInfo, packageName)
|
||||
packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) }
|
||||
}.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() }))
|
||||
}
|
||||
|
||||
@ -200,8 +200,11 @@ class AppListActivity : ThemedActivity() {
|
||||
private fun initProxiedUids(str: String = DataStore.routePackages) {
|
||||
proxiedUids.clear()
|
||||
val apps = getCachedApps()
|
||||
for (line in str.lineSequence()) proxiedUids[(apps[line]
|
||||
?: continue).applicationInfo.uid] = true
|
||||
for (line in str.lineSequence()) {
|
||||
val app = (apps[line] ?: continue)
|
||||
val uid = app.applicationInfo?.uid ?: continue
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun isProxiedApp(app: ProxiedApp) = proxiedUids[app.uid]
|
||||
@ -306,6 +309,7 @@ class AppListActivity : ThemedActivity() {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_clear_selections -> {
|
||||
runOnDefaultDispatcher {
|
||||
proxiedUids.clear()
|
||||
@ -316,6 +320,7 @@ class AppListActivity : ThemedActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R.id.action_export_clipboard -> {
|
||||
val success = SagerNet.trySetPrimaryClip("false\n${DataStore.routePackages}")
|
||||
Snackbar.make(
|
||||
@ -325,6 +330,7 @@ class AppListActivity : ThemedActivity() {
|
||||
).show()
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.action_import_clipboard -> {
|
||||
val proxiedAppString =
|
||||
SagerNet.clipboard.primaryClip?.getItemAt(0)?.text?.toString()
|
||||
@ -344,6 +350,7 @@ class AppListActivity : ThemedActivity() {
|
||||
}
|
||||
Snackbar.make(binding.list, R.string.action_import_err, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
R.id.uninstall_all -> {
|
||||
runOnDefaultDispatcher {
|
||||
proxiedUids.clear()
|
||||
|
||||
@ -103,9 +103,9 @@ class AppManagerActivity : ThemedActivity() {
|
||||
var filteredApps = apps
|
||||
|
||||
suspend fun reload() {
|
||||
apps = cachedApps.map { (packageName, packageInfo) ->
|
||||
apps = cachedApps.mapNotNull { (packageName, packageInfo) ->
|
||||
coroutineContext[Job]!!.ensureActive()
|
||||
ProxiedApp(packageManager, packageInfo.applicationInfo, packageName)
|
||||
packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) }
|
||||
}.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() }))
|
||||
}
|
||||
|
||||
@ -164,8 +164,11 @@ class AppManagerActivity : ThemedActivity() {
|
||||
private fun initProxiedUids(str: String = DataStore.individual) {
|
||||
proxiedUids.clear()
|
||||
val apps = cachedApps
|
||||
for (line in str.lineSequence()) proxiedUids[(apps[line]
|
||||
?: continue).applicationInfo.uid] = true
|
||||
for (line in str.lineSequence()) {
|
||||
val app = (apps[line] ?: continue)
|
||||
val uid = app.applicationInfo?.uid ?: continue
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun isProxiedApp(app: ProxiedApp) = proxiedUids[app.uid]
|
||||
@ -325,14 +328,19 @@ class AppManagerActivity : ThemedActivity() {
|
||||
proxiedUids.clear()
|
||||
for (app in cachedApps) {
|
||||
val needProxy =
|
||||
needProxyAppsList.contains(app.key) || app.value.applicationInfo.uid == 1000
|
||||
needProxyAppsList.contains(app.key) || (app.value.applicationInfo?.uid
|
||||
?: 0) == 1000
|
||||
if (needProxy) {
|
||||
if (!bypass) {
|
||||
proxiedUids[app.value.applicationInfo.uid] = true
|
||||
app.value.applicationInfo?.apply {
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bypass) {
|
||||
proxiedUids[app.value.applicationInfo.uid] = true
|
||||
app.value.applicationInfo?.apply {
|
||||
proxiedUids[uid] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ class RouteSettingsActivity(
|
||||
fun init(packageName: String?) {
|
||||
RuleEntity().apply {
|
||||
if (!packageName.isNullOrBlank()) {
|
||||
packages = listOf(packageName)
|
||||
packages = setOf(packageName)
|
||||
name = app.getString(R.string.route_for, PackageCache.loadLabel(packageName))
|
||||
}
|
||||
}.init()
|
||||
@ -89,7 +89,7 @@ class RouteSettingsActivity(
|
||||
2 -> -2L
|
||||
else -> DataStore.routeOutboundRule
|
||||
}
|
||||
packages = DataStore.routePackages.split("\n").filter { it.isNotBlank() }
|
||||
packages = DataStore.routePackages.split("\n").filter { it.isNotBlank() }.toSet()
|
||||
|
||||
if (DataStore.editingId == 0L) {
|
||||
enabled = true
|
||||
|
||||
@ -22,8 +22,8 @@ object Plugins {
|
||||
const val METADATA_KEY_EXECUTABLE_PATH = "io.nekohasekai.sagernet.plugin.executable_path"
|
||||
|
||||
fun isExeOrPlugin(pkg: PackageInfo): Boolean {
|
||||
if (pkg.providers == null || pkg.providers.isEmpty()) return false
|
||||
val provider = pkg.providers[0] ?: return false
|
||||
if (pkg.providers?.isEmpty() == true) return false
|
||||
val provider = pkg.providers?.get(0) ?: return false
|
||||
val auth = provider.authority ?: return false
|
||||
return auth.startsWith(AUTHORITIES_PREFIX_SEKAI_EXE)
|
||||
|| auth.startsWith(AUTHORITIES_PREFIX_NEKO_EXE)
|
||||
@ -92,8 +92,8 @@ object Plugins {
|
||||
PackageCache.awaitLoadSync()
|
||||
val pkgs = PackageCache.installedPluginPackages
|
||||
.map { it.value }
|
||||
.filter { it.providers[0].loadString(METADATA_KEY_ID) == pluginId }
|
||||
return pkgs.map { it.providers[0] }
|
||||
.filter { it.providers?.get(0)?.loadString(METADATA_KEY_ID) == pluginId }
|
||||
return pkgs.mapNotNull { it.providers?.get(0) }
|
||||
}
|
||||
|
||||
private fun buildUri(id: String, auth: String) = Uri.Builder()
|
||||
|
||||
1
app/src/main/res/resources.properties
Normal file
1
app/src/main/res/resources.properties
Normal file
@ -0,0 +1 @@
|
||||
unqualifiedResLocale=en-US
|
||||
@ -6,3 +6,7 @@ allprojects {
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
|
||||
}
|
||||
|
||||
@ -8,5 +8,5 @@ apply(from = "../repositories.gradle.kts")
|
||||
dependencies {
|
||||
// Gradle Plugins
|
||||
implementation("com.android.tools.build:gradle:8.8.1")
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10")
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21")
|
||||
}
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
import com.android.build.api.dsl.ApplicationExtension
|
||||
import com.android.build.api.dsl.LibraryExtension
|
||||
import com.android.build.api.dsl.Lint
|
||||
import com.android.build.gradle.AbstractAppExtension
|
||||
import com.android.build.gradle.AppExtension
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.build.gradle.internal.api.BaseVariantOutputImpl
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
@ -11,7 +7,9 @@ import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.kotlin.dsl.getByName
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import java.util.Base64
|
||||
import java.util.Locale
|
||||
import java.util.Properties
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
fun sha256Hex(bytes: ByteArray): String {
|
||||
@ -80,7 +78,7 @@ fun Project.requireTargetAbi(): String {
|
||||
var targetAbi = ""
|
||||
if (gradle.startParameter.taskNames.isNotEmpty()) {
|
||||
if (gradle.startParameter.taskNames.size == 1) {
|
||||
val targetTask = gradle.startParameter.taskNames[0].toLowerCase(Locale.ROOT).trim()
|
||||
val targetTask = gradle.startParameter.taskNames[0].lowercase(Locale.ROOT).trim()
|
||||
when {
|
||||
targetTask.contains("arm64") -> targetAbi = "arm64-v8a"
|
||||
targetTask.contains("arm") -> targetAbi = "armeabi-v7a"
|
||||
@ -94,11 +92,11 @@ fun Project.requireTargetAbi(): String {
|
||||
|
||||
fun Project.setupCommon() {
|
||||
android.apply {
|
||||
buildToolsVersion = "30.0.3"
|
||||
compileSdk = 33
|
||||
buildToolsVersion = "35.0.1"
|
||||
compileSdk = 35
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
targetSdk = 33
|
||||
targetSdk = 35
|
||||
}
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
@ -120,7 +118,7 @@ fun Project.setupCommon() {
|
||||
textOutput = project.file("build/lint.txt")
|
||||
htmlOutput = project.file("build/lint.html")
|
||||
}
|
||||
packagingOptions {
|
||||
packaging {
|
||||
resources.excludes.addAll(
|
||||
listOf(
|
||||
"**/*.kotlin_*",
|
||||
@ -137,9 +135,6 @@ fun Project.setupCommon() {
|
||||
)
|
||||
)
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs.useLegacyPackaging = true
|
||||
}
|
||||
(this as? AbstractAppExtension)?.apply {
|
||||
buildTypes {
|
||||
getByName("release") {
|
||||
|
||||
@ -21,6 +21,5 @@ android.enableJetifier=true
|
||||
kotlin.code.style=official
|
||||
# Gradle parallel build
|
||||
org.gradle.parallel=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
|
||||
Loading…
Reference in New Issue
Block a user