Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions .github/workflows/build_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout DeepLinkDispatch
uses: actions/checkout@v6
- name: Set up JDK 22
uses: actions/setup-java@v5
uses: actions/checkout@v7
- name: Set up JDK 25
uses: actions/setup-java@v6
with:
distribution: 'corretto'
java-version: '22'
java-version: '25'
- name: Set up Android SDK
uses: android-actions/setup-android@v4.0.4
- name: Install Android SDK
run: sdkmanager 'platforms;android-37.2' 'build-tools;37.0.0'
- name: Build/Test DeepLinkDispatch
run: ./gradlew assemble check javadoc lintKotlin
run: ./gradlew assemble assembleAndroidTest check javadoc lintKotlin
24 changes: 11 additions & 13 deletions .github/workflows/deploy_snapshot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout DeepLinkDispatch
uses: actions/checkout@v6
- name: Set up JDK 22
uses: actions/setup-java@v5
uses: actions/checkout@v7
- name: Set up JDK 25
uses: actions/setup-java@v6
with:
distribution: 'corretto'
java-version: '22'
- name: Update gradle.properties
uses: DamianReeves/write-file-action@master
with:
path: gradle.properties
write-mode: append
contents: |
mavenCentralUsername=${{ secrets.NEXUS_USER }}
mavenCentralPassword=${{ secrets.NEXUS_PASSWORD }}

java-version: '25'
- name: Set up Android SDK
uses: android-actions/setup-android@v4.0.4
- name: Install Android SDK
run: sdkmanager 'platforms;android-37.2' 'build-tools;37.0.0'
- name: Deploy new snapshot of DeepLinkDispatch
shell: bash
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.NEXUS_USER }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.NEXUS_PASSWORD }}
run: ./gradlew -PenforceSnapshotVersion=true publishAllPublicationsToMavenCentral
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -836,3 +836,17 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

## Building from source

Use JDK 25 (LTS) and install Android SDK Platform 37.2 and Build Tools 37.0.0.
The Gradle wrapper supplies Gradle; build and test dependency versions are centralized in
[`dependencies.gradle`](dependencies.gradle).

```shell
./gradlew assemble assembleAndroidTest check javadoc lintKotlin
```

Android modules use AGP's built-in Kotlin support. The kapt sample uses
`com.android.legacy-kapt`; KSP samples continue to use `com.google.devtools.ksp`.
The compile SDK is independent of the existing minimum and target SDK levels.
16 changes: 11 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ buildscript {
dependencies {
classpath deps.androidPlugin
classpath deps.kotlinGradlePlugin
classpath "org.jetbrains.kotlin:kotlin-sam-with-receiver:$versions.kotlinVersion"
classpath "com.android.legacy-kapt:com.android.legacy-kapt.gradle.plugin:$androidConfig.agpVersion"
classpath deps.gradleMavenPublishPlugin
classpath deps.benchmarkGradlePlugin
// Dokka is needed on classpath for vanniktech publish plugin
Expand All @@ -34,20 +36,24 @@ allprojects {
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
compilerOptions {
allWarningsAsErrors = true
}
}

// Apply consistent JVM toolchain and target to all subprojects
subprojects {
plugins.withId('checkstyle') {
checkstyle.toolVersion = rootProject.ext.versions.checkstyleVersion
}
afterEvaluate {
def toolchainVersion = rootProject.ext.jvmToolchainVersion
def targetVersion = rootProject.ext.jvmTargetVersion
// Gradle/AGP plugins run on Java 17+; library bytecode remains Java 11.
def targetVersion = plugins.hasPlugin('java-gradle-plugin') ? 17 : rootProject.ext.jvmTargetVersion

// For Kotlin projects (both pure JVM and Android)
if (plugins.hasPlugin('org.jetbrains.kotlin.jvm') || plugins.hasPlugin('kotlin') ||
plugins.hasPlugin('kotlin-android') || plugins.hasPlugin('org.jetbrains.kotlin.android')) {
plugins.hasPlugin('com.android.library') || plugins.hasPlugin('com.android.application')) {
kotlin {
jvmToolchain(toolchainVersion)
}
Expand All @@ -58,7 +64,7 @@ subprojects {
}
}
// For Java-only projects (without Kotlin)
else if (plugins.hasPlugin('java') && !plugins.hasPlugin('kotlin-dsl')) {
else if (plugins.hasPlugin('java')) {
java {
toolchain {
languageVersion = JavaLanguageVersion.of(toolchainVersion)
Expand All @@ -77,7 +83,7 @@ subprojects {
}

// For pure Java projects
if (plugins.hasPlugin('java') && !plugins.hasPlugin('kotlin-dsl')) {
if (plugins.hasPlugin('java')) {
java {
sourceCompatibility = JavaVersion.toVersion(targetVersion)
targetCompatibility = JavaVersion.toVersion(targetVersion)
Expand Down
9 changes: 7 additions & 2 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
`kotlin-dsl`
id("org.jetbrains.kotlin.jvm")
id("org.jetbrains.kotlin.plugin.sam.with.receiver")
`java-gradle-plugin`
}

Expand All @@ -11,14 +12,18 @@ apply(from = "../dependencies.gradle")

val deps: Map<String, Any> by project
val jvmToolchainVersion: Int by extra
val jvmTargetVersion: Int by extra
val jvmTargetVersion = 17 // Gradle and AGP require Java 17 or newer.

repositories {
google()
mavenCentral()
gradlePluginPortal()
}

samWithReceiver {
annotation("org.gradle.api.HasImplicitReceiver")
}

java {
toolchain.languageVersion.set(JavaLanguageVersion.of(jvmToolchainVersion))
sourceCompatibility = JavaVersion.toVersion(jvmTargetVersion)
Expand Down
13 changes: 13 additions & 0 deletions buildSrc/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pluginManagement {
apply(from = "../dependencies.gradle")
@Suppress("UNCHECKED_CAST")
val versions = extra["versions"] as Map<String, String>
repositories {
gradlePluginPortal()
mavenCentral()
}
plugins {
id("org.jetbrains.kotlin.jvm") version versions.getValue("kotlinVersion")
id("org.jetbrains.kotlin.plugin.sam.with.receiver") version versions.getValue("kotlinVersion")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,21 +272,35 @@ sealed class DeepLinkEntry(
*/
override fun compareTo(other: DeepLinkEntry): Int {
return when {
/**
/*
* Specific conditions added for fully concrete links.
* Concrete link will always return -1 for firstNonConcreteIndex,
* so the general comparison logic will not work.
*/
this.firstNonConcreteIndex < 0 && this.firstNonConcreteIndex != other.firstNonConcreteIndex -> -1
other.firstNonConcreteIndex < 0 && other.firstNonConcreteIndex != this.firstNonConcreteIndex -> 1
this.firstNonConcreteIndex < other.firstNonConcreteIndex -> 1
this.firstNonConcreteIndex < 0 && this.firstNonConcreteIndex != other.firstNonConcreteIndex -> {
-1
}

other.firstNonConcreteIndex < 0 && other.firstNonConcreteIndex != this.firstNonConcreteIndex -> {
1
}

this.firstNonConcreteIndex < other.firstNonConcreteIndex -> {
1
}

this.firstNonConcreteIndex == other.firstNonConcreteIndex -> {
when {
// Both are fully concrete
this.firstNonConcreteIndex == -1 -> 0
this.firstNonConcreteIndex == -1 -> {
0
}

// Compare by total number of non-concrete elements (fewer is more concrete)
this.totalNonConcreteElements != other.totalNonConcreteElements ->
this.totalNonConcreteElements != other.totalNonConcreteElements -> {
this.totalNonConcreteElements.compareTo(other.totalNonConcreteElements)
}

// Same number of non-concrete elements, compare types and positions pairwise
else -> {
val thisElements = this.nonConcreteElementIndicesAndTypes
Expand Down Expand Up @@ -327,7 +341,10 @@ sealed class DeepLinkEntry(
}
}
}
else -> -1

else -> {
-1
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ class NodeMetadata(
validateIfConfigurablePathSegment(this) -> {
MetadataMasks.CONFIGURABLE_PATH_SEGMENT_MASK
}

validateIfComponentParam(this) -> {
MetadataMasks.COMPONENT_PARAM_MASK
}

else -> {
0
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,27 +228,32 @@ data class Root(

private fun uriMatch(deepLinkEntry: DeepLinkEntry) =
when (deepLinkEntry) {
is DeepLinkEntry.ActivityDeeplinkEntry ->
is DeepLinkEntry.ActivityDeeplinkEntry -> {
UriMatch(
MatchType.Activity,
deepLinkEntry.uriTemplate,
deepLinkEntry.className,
null,
)
is DeepLinkEntry.MethodDeeplinkEntry ->
}

is DeepLinkEntry.MethodDeeplinkEntry -> {
UriMatch(
MatchType.Method,
deepLinkEntry.uriTemplate,
deepLinkEntry.className,
deepLinkEntry.method,
)
is DeepLinkEntry.HandlerDeepLinkEntry ->
}

is DeepLinkEntry.HandlerDeepLinkEntry -> {
UriMatch(
MatchType.Handler,
deepLinkEntry.uriTemplate,
deepLinkEntry.className,
null,
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ import java.io.InputStream
private fun Char.modifiedUtf8ByteSize(): Int {
val codePoint = this.code
return when {
codePoint == 0 -> 2 // Null character is encoded as 2 bytes in Modified UTF-8
codePoint == 0 -> 2

// Null character is encoded as 2 bytes in Modified UTF-8
codePoint <= 0x7F -> 1

codePoint <= 0x7FF -> 2

else -> 3
}
}
Expand Down
15 changes: 12 additions & 3 deletions deeplinkdispatch-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@ apply(from = "$rootDir/publishing.gradle")

val deps: Map<String, Any> by project
val jvmToolchainVersion: Int by rootProject.extra
val jvmTargetVersion: Int by rootProject.extra
val jvmTargetVersion = 17 // Matches the minimum JVM required by Gradle and AGP.
val androidConfig: Map<String, Any> by project

repositories {
google()
mavenCentral()
gradlePluginPortal()
maven(url = "https://oss.sonatype.org/service/local/repositories/snapshots/content/")
maven(url = "https://central.sonatype.com/repository/maven-snapshots/")
}

plugins {
`kotlin-dsl`
id("org.jetbrains.kotlin.jvm")
id("org.jetbrains.kotlin.plugin.sam.with.receiver")
`java-gradle-plugin`
}

samWithReceiver {
annotation("org.gradle.api.HasImplicitReceiver")
}

// JVM toolchain and target - uses central versions from dependencies.gradle
java {
toolchain {
Expand Down Expand Up @@ -55,6 +61,9 @@ dependencies {

tasks.test {
useJUnit()
systemProperty("test.compileSdk", androidConfig.getValue("compileSdkVersion").toString())
systemProperty("test.compileSdkMinor", androidConfig.getValue("compileSdkMinorVersion").toString())
systemProperty("test.buildTools", androidConfig.getValue("buildToolsVersion").toString())
testLogging {
events("passed", "skipped", "failed")
showStandardStreams = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault

/**
* Task that relocates the KSP-generated assets from the resources directory to a safe location.
Expand All @@ -22,6 +23,7 @@ import org.gradle.api.tasks.TaskAction
* This is a separate task (rather than a doLast on KSP) because doLast doesn't run when
* KSP is restored FROM-CACHE. This task will always run after KSP, even if KSP was cached.
*/
@DisableCachingByDefault(because = "Relocation deletes KSP inputs, which must also happen after a cache restore")
abstract class RelocateDeepLinkAssetsTask : DefaultTask() {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault

/**
* Task that relocates the KSP-generated manifest from the resources directory to a safe location.
Expand All @@ -24,6 +25,7 @@ import org.gradle.api.tasks.TaskAction
* source file, and when KSP is restored from cache, it recreates the file but Gradle's
* up-to-date check only compares content, not file existence.
*/
@DisableCachingByDefault(because = "Relocation deletes KSP inputs, which must also happen after a cache restore")
abstract class RelocateDeepLinkManifestTask : DefaultTask() {

@get:InputFiles
Expand Down
Loading
Loading