Skip to content

Commit 0aac02d

Browse files
authored
Merge pull request #150 from solrudev/develop
0.18.5
2 parents a0ddb04 + 0c1fa9d commit 0aac02d

19 files changed

Lines changed: 224 additions & 53 deletions

File tree

.github/ci-gradle.properties

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ org.gradle.parallel=true
55
org.gradle.configuration-cache=true
66
org.gradle.configuration-cache.parallel=true
77
org.gradle.configureondemand=true
8+
# org.gradle.unsafe.isolated-projects=true
89
android.useAndroidX=true
910
kotlin.code.style=official
1011
android.r8.maxWorkers=2
11-
android.lint.useK2Uast=true
12+
android.lint.useK2Uast=true
13+
ksp.project.isolation.enabled=true

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828

2929
- name: Validate binary compatibility
3030
run: |
31-
./gradlew apiCheck || { exit_code=$?; printf "*** This PR changes Ackpine's public API. If this is intentional, run './gradlew apiDump' and commit the new API dumps. ***"; exit $exit_code; }
31+
./gradlew :checkAckpineAbi || { exit_code=$?; printf "*** This PR changes Ackpine's public ABI. If this is intentional, run './gradlew :updateAckpineAbi' and commit the new ABI dumps. ***"; exit $exit_code; }
3232
3333
- name: Build
3434
run: |

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Ackpine depends on Jetpack libraries, so it's also necessary to add the `google(
3737

3838
```toml
3939
[versions]
40-
ackpine = "0.18.4"
40+
ackpine = "0.18.5"
4141

4242
[libraries]
4343
ackpine-core = { module = "ru.solrudev.ackpine:ackpine-core", version.ref = "ackpine" }
@@ -78,7 +78,7 @@ ackpine = [
7878

7979
```kotlin
8080
dependencies {
81-
val ackpineVersion = "0.18.4"
81+
val ackpineVersion = "0.18.5"
8282
implementation("ru.solrudev.ackpine:ackpine-core:$ackpineVersion")
8383

8484
// optional - Kotlin extensions and Coroutines support

ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/PackageInstallerImpl.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ internal class PackageInstallerImpl internal constructor(
259259
ackpineServiceProviders,
260260
InstallSessionFactoryImpl(
261261
applicationContext,
262+
@SuppressLint("NewApi")
262263
PackageInstallerWrapper.default(applicationContext),
263264
ackpineServiceProviders,
264265
database.lastUpdateTimestampDao(),

ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/installer/session/IntentBasedInstallSession.kt

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616

1717
package ru.solrudev.ackpine.impl.installer.session
1818

19+
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
1920
import android.content.Context
21+
import android.content.pm.PackageManager.PERMISSION_DENIED
2022
import android.net.Uri
2123
import android.os.Build
2224
import android.os.Environment
2325
import android.os.Handler
2426
import androidx.annotation.RestrictTo
27+
import androidx.core.content.ContextCompat
2528
import androidx.core.content.FileProvider
2629
import androidx.core.net.toUri
2730
import ru.solrudev.ackpine.AckpineFileProvider
@@ -78,19 +81,9 @@ internal class IntentBasedInstallSession internal constructor(
7881
) {
7982

8083
private val apkFile by lazy(LazyThreadSafetyMode.NONE) {
81-
File(context.externalDir, "ackpine/sessions/$id/0.apk")
84+
File(getRootApkDir(), "ackpine/sessions/$id/0.apk")
8285
}
8386

84-
private val Context.externalDir: File
85-
get() {
86-
val externalFilesDir = getExternalFilesDir(null)
87-
return if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED && externalFilesDir != null) {
88-
externalFilesDir
89-
} else {
90-
filesDir
91-
}
92-
}
93-
9487
override fun prepare() {
9588
createApkCopy()
9689
val apkPackageName = context.packageManager
@@ -134,6 +127,23 @@ internal class IntentBasedInstallSession internal constructor(
134127
return true
135128
}
136129

130+
private fun getRootApkDir(): File {
131+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
132+
return context.filesDir
133+
}
134+
val externalFilesDir = context.getExternalFilesDir(null)
135+
if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED && externalFilesDir != null) {
136+
return externalFilesDir
137+
}
138+
val cause = if (ContextCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED) {
139+
" WRITE_EXTERNAL_STORAGE permission denied."
140+
} else {
141+
""
142+
}
143+
completeExceptionally(IllegalStateException("External storage is not available.$cause"))
144+
return File("")
145+
}
146+
137147
private fun getApkUri(): Uri {
138148
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
139149
return apkFile.toUri()

ackpine-core/src/main/kotlin/ru/solrudev/ackpine/impl/uninstaller/session/IntentBasedUninstallSession.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import ru.solrudev.ackpine.impl.helpers.concurrent.BinarySemaphore
2626
import ru.solrudev.ackpine.impl.helpers.launchConfirmation
2727
import ru.solrudev.ackpine.impl.session.AbstractSession
2828
import ru.solrudev.ackpine.impl.uninstaller.UninstallStatusReceiver
29-
import ru.solrudev.ackpine.impl.uninstaller.activity.UninstallActivity
29+
import ru.solrudev.ackpine.impl.uninstaller.activity.IntentBasedUninstallActivity
3030
import ru.solrudev.ackpine.session.Session
3131
import ru.solrudev.ackpine.session.parameters.Confirmation
3232
import ru.solrudev.ackpine.session.parameters.NotificationData
@@ -64,7 +64,7 @@ internal class IntentBasedUninstallSession internal constructor(
6464
}
6565

6666
override fun launchConfirmation() {
67-
context.launchConfirmation<UninstallActivity>(
67+
context.launchConfirmation<IntentBasedUninstallActivity>(
6868
confirmation, notificationData,
6969
sessionId = id,
7070
notificationId,

build-logic/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,5 @@ dependencies {
6969
implementation(libs.plugin.kotlin)
7070
implementation(libs.plugin.gradleMavenPublish)
7171
implementation(libs.plugin.dokka)
72-
implementation(libs.plugin.bcv)
7372
implementation(kotlinx.serialization.json)
7473
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (C) 2025 Ilya Fomichev
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package ru.solrudev.ackpine.gradle
18+
19+
import org.gradle.api.Named
20+
import org.gradle.api.attributes.Attribute
21+
22+
internal interface AbiValidationAttribute : Named {
23+
companion object {
24+
val ABI_VALIDATION_UPDATE_ATTRIBUTE = Attribute.of(
25+
"ru.solrudev.ackpine.gradle.abi-validation.update",
26+
AbiValidationAttribute::class.java
27+
)
28+
val ABI_VALIDATION_CHECK_ATTRIBUTE = Attribute.of(
29+
"ru.solrudev.ackpine.gradle.abi-validation.check",
30+
AbiValidationAttribute::class.java
31+
)
32+
}
33+
}

build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/AckpineLibraryBasePlugin.kt

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import com.android.build.api.artifact.SingleArtifact
2020
import com.android.build.api.dsl.LibraryExtension
2121
import com.android.build.api.variant.LibraryAndroidComponentsExtension
2222
import com.android.build.gradle.LibraryPlugin
23-
import kotlinx.validation.ApiValidationExtension
2423
import org.gradle.api.JavaVersion
2524
import org.gradle.api.Plugin
2625
import org.gradle.api.Project
@@ -32,11 +31,14 @@ import org.gradle.kotlin.dsl.configure
3231
import org.gradle.kotlin.dsl.findByType
3332
import org.gradle.kotlin.dsl.named
3433
import org.gradle.kotlin.dsl.the
34+
import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension
35+
import ru.solrudev.ackpine.gradle.AbiValidationAttribute.Companion.ABI_VALIDATION_CHECK_ATTRIBUTE
36+
import ru.solrudev.ackpine.gradle.AbiValidationAttribute.Companion.ABI_VALIDATION_UPDATE_ATTRIBUTE
37+
import ru.solrudev.ackpine.gradle.helpers.abiValidation
3538
import ru.solrudev.ackpine.gradle.helpers.addOutgoingArtifact
3639
import ru.solrudev.ackpine.gradle.helpers.libraryElements
3740
import ru.solrudev.ackpine.gradle.helpers.withReleaseBuildType
3841
import ru.solrudev.ackpine.gradle.versioning.ackpineVersion
39-
import java.util.Optional
4042

4143
public class AckpineLibraryBasePlugin : Plugin<Project> {
4244

@@ -48,17 +50,16 @@ public class AckpineLibraryBasePlugin : Plugin<Project> {
4850
}
4951
configureJava()
5052
val libraryExtension = the<LibraryExtension>()
51-
val apiValidationExtension = extensions.findByType<ApiValidationExtension>()?.apply {
52-
nonPublicMarkers += "androidx.annotation.RestrictTo"
53-
}
53+
val abiValidationExtension = lazy { extensions.findByType<KotlinBaseExtension>()?.abiValidation }
5454
extensions.create(
5555
"ackpine",
5656
AckpineLibraryExtension::class.java,
5757
libraryExtension,
58-
Optional.ofNullable(apiValidationExtension)
58+
abiValidationExtension
5959
)
6060
configureAndroid()
6161
registerConsumableLibraryConfiguration()
62+
registerAbiValidationConfigurations()
6263
}
6364

6465
private fun Project.configureJava() = extensions.configure<JavaPluginExtension> {
@@ -97,8 +98,25 @@ public class AckpineLibraryBasePlugin : Plugin<Project> {
9798
}
9899
}
99100

101+
private fun Project.registerAbiValidationConfigurations() {
102+
configurations.consumable(ABI_UPDATE_CONFIGURATION) {
103+
attributes {
104+
attribute(ABI_VALIDATION_UPDATE_ATTRIBUTE, objects.named(ABI_UPDATE))
105+
}
106+
}
107+
configurations.consumable(ABI_CHECK_CONFIGURATION) {
108+
attributes {
109+
attribute(ABI_VALIDATION_CHECK_ATTRIBUTE, objects.named(ABI_CHECK))
110+
}
111+
}
112+
}
113+
100114
internal companion object {
101115
internal const val LIBRARY_ELEMENTS = "aar"
102116
internal const val PLUGIN_ID = "ru.solrudev.ackpine.library.base"
117+
internal const val ABI_UPDATE_CONFIGURATION = "abiValidationUpdateElements"
118+
internal const val ABI_CHECK_CONFIGURATION = "abiValidationCheckElements"
119+
internal const val ABI_UPDATE = "update"
120+
internal const val ABI_CHECK = "check"
103121
}
104122
}

build-logic/src/main/kotlin/ru/solrudev/ackpine/gradle/AckpineLibraryExtension.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717
package ru.solrudev.ackpine.gradle
1818

1919
import com.android.build.api.dsl.LibraryExtension
20-
import kotlinx.validation.ApiValidationExtension
2120
import org.gradle.api.model.ObjectFactory
2221
import org.gradle.api.plugins.ExtensionAware
2322
import org.gradle.api.provider.Provider
2423
import org.gradle.kotlin.dsl.assign
2524
import org.gradle.kotlin.dsl.setProperty
26-
import java.util.Optional
25+
import org.jetbrains.kotlin.gradle.dsl.abi.AbiValidationExtension
26+
import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
2727
import javax.inject.Inject
28-
import kotlin.jvm.optionals.getOrNull
2928

3029
private val PACKAGE_NAME_REGEX = Regex("^[a-z.]+$")
3130

@@ -34,7 +33,7 @@ private val PACKAGE_NAME_REGEX = Regex("^[a-z.]+$")
3433
*/
3534
public abstract class AckpineLibraryExtension @Inject constructor(
3635
libraryExtension: LibraryExtension,
37-
private val apiValidationExtension: Optional<ApiValidationExtension>,
36+
private val abiValidationExtension: Lazy<AbiValidationExtension?>,
3837
objectFactory: ObjectFactory
3938
) : AckpineCommonExtension(libraryExtension, Constants.PACKAGE_NAME), ExtensionAware {
4039

@@ -49,11 +48,14 @@ public abstract class AckpineLibraryExtension @Inject constructor(
4948
/**
5049
* Adds [packageNames] to ignored packages. They will not appear in resulting public API dumps and documentation.
5150
*/
51+
@OptIn(ExperimentalAbiValidation::class)
5252
public fun internalPackages(vararg packageNames: String) {
5353
for (packageName in packageNames) {
5454
require(packageName.matches(PACKAGE_NAME_REGEX)) { "Illegal package name: $packageName" }
5555
}
5656
_internalPackages = packageNames.toSet()
57-
apiValidationExtension.getOrNull()?.ignoredPackages += packageNames
57+
abiValidationExtension.value?.run {
58+
filters.excluded.byNames.addAll(packageNames.map { "$it.**" })
59+
}
5860
}
5961
}

0 commit comments

Comments
 (0)