Upgrade SDK 35

This commit is contained in:
armv9 2025-02-23 18:11:55 +09:00
parent ea8e4aee60
commit 607afa8ce3
15 changed files with 106 additions and 46 deletions

View File

@ -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")
}

View File

@ -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 {

View File

@ -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()

View File

@ -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()
}
}
}

View File

@ -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
*/

View File

@ -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)

View File

@ -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()

View File

@ -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
}
}
}
}

View File

@ -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

View File

@ -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()

View File

@ -0,0 +1 @@
unqualifiedResLocale=en-US

View File

@ -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
}

View File

@ -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")
}

View File

@ -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") {

View File

@ -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