Skip to content

Commit bad1a16

Browse files
authored
Chore/#25 add maven publish config (#33)
* fix: remove redundant test configuration blocks from build scripts to streamline setup * chore: update build script for maven publishing and license year * chore: update dependencies and build configuration for compatibility and publishing * docs: update README
1 parent f04a7f0 commit bad1a16

7 files changed

Lines changed: 210 additions & 90 deletions

File tree

README.ko.md

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
# Wisp
22

3-
[![CI](https://github.com/angrypodo/wisp/actions/workflows/ci.yml/badge.svg)](https://github.com/angrypodo/wisp/actions/workflows/ci.yml)
4-
5-
**Wisp**는 Jetpack Compose를 위한 타입 세이프(type-safe), 서버 주도(server-driven) 딥링크 라이브러리입니다. 단일 표준 URI를 기반으로 내비게이션 백스택을 동적으로 구성할 수 있게 하여, 표준 `navigation-compose` 라이브러리의 정적 백스택 한계를 극복합니다.
3+
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
4+
[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21)
5+
[![Build Status](https://github.com/angrypodo/wisp/actions/workflows/ci.yml/badge.svg)](https://github.com/angrypodo/wisp/actions/workflows/ci.yml)
6+
[![Maven Central](https://img.shields.io/maven-central/v/io.github.angrypodo/wisp-runtime)](https://central.sonatype.com/artifact/io.github.angrypodo/wisp-runtime)
67

78
번역: [Read in English](README.md)
89

10+
<br>
11+
12+
<p align="center">
13+
<strong>Wisp</strong>는 Jetpack Compose를 위한 타입 세이프(type-safe), 서버 주도(server-driven) 딥링크 라이브러리입니다.<br>
14+
단일 표준 URI를 기반으로 내비게이션 백스택을 동적으로 구성할 수 있게 하여,<br>
15+
표준 <code>navigation-compose</code> 라이브러리의 정적 백스택 한계를 극복합니다.
16+
</p>
17+
18+
<br>
19+
920
## 🤔 Wisp, 왜 필요한가요?
1021

1122
Jetpack Compose의 표준 딥링크 기능은 미리 정의된 정적 백스택을 만드는 데 주로 사용됩니다. 이 때문에 서버가 실시간으로 동적인 사용자 여정(예: `상품 화면 -> 쿠폰 화면 -> 결제 화면`)을 제어해야 하는 시나리오를 구현하기는 어렵습니다.
@@ -14,17 +25,64 @@ Wisp는 URI의 경로 세그먼트(path segments)로부터 전체 백스택을
1425

1526
## 🏛️ 아키텍처 및 요구사항
1627

17-
- **싱글 액티비티 아키텍처 (Single-Activity Architecture):** Wisp는 **싱글 액티비티 구조** 전용으로 설계되었으며, 여러 Activity 간의 내비게이션은 지원하지 않습니다. 이는 Jetpack Compose에 권장되는 최신 안드로이드 개발 방식과 일치합니다.
18-
- **Jetpack Navigation 및 타입 안정성:** 이 라이브러리는 Jetpack Navigation Compose의 확장 기능이며, **타입 세이프(type-safe) 내비게이션** 패러다임 전용으로 설계되었습니다. `NavController`가 반드시 필요하며, 전통적인 문자열 기반의 라우트는 지원하지 않습니다.
19-
- **멀티 모듈 지원 (Multi-Module Support):** Wisp는 멀티 모듈 프로젝트를 완벽하게 지원합니다. `ServiceLoader` 패턴을 사용하여, 라이브러리가 포함된 모든 모듈로부터 `@Wisp` 라우트 정의를 자동으로 탐지합니다.
28+
- **싱글 액티비티 아키텍처:** Wisp는 **싱글 액티비티 구조(Single-Activity Architecture)**를 위해 설계되었으며, 여러 Activity 간의 내비게이션은 지원하지 않습니다. 이는 Jetpack Compose에 권장되는 최신 안드로이드 개발 방식과 일치합니다.
29+
- **Jetpack Navigation 및 타입 안정성:** 이 라이브러리는 Jetpack Navigation Compose의 **타입 세이프(type-safe) 내비게이션** 패러다임 전용으로 설계되었습니다. `NavController`가 반드시 필요하며, 전통적인 문자열 기반의 라우트는 지원하지 않습니다.
30+
- **멀티 모듈 지원:** Wisp는 멀티 모듈 프로젝트를 완벽하게 지원합니다. `ServiceLoader` 패턴을 사용하여, 라이브러리가 포함된 모든 모듈로부터 `@Wisp` 라우트 정의를 자동으로 탐지합니다.
31+
- **최소 요구사항:**
32+
- **minSdk:** 21 (Android 5.0)
33+
- **Kotlin:** 1.9.0 이상 (KSP 호환 버전)
34+
35+
## 다운로드 (Download)
2036

21-
## 🚀 사용법
37+
[![Maven Central](https://img.shields.io/maven-central/v/io.github.angrypodo/wisp-runtime)](https://central.sonatype.com/artifact/io.github.angrypodo/wisp-runtime)
2238

23-
**참고:** Wisp는 아직 Maven Central에 배포되지 않았습니다. 현재로서는 이 리포지토리를 클론하여 프로젝트에 로컬 모듈로 포함해야 합니다.
39+
### Version Catalog
40+
41+
Version Catalog를 사용 중이라면, `libs.versions.toml` 파일에 다음과 같이 의존성을 추가할 수 있습니다:
42+
43+
```toml
44+
[versions]
45+
#...
46+
wisp = "0.1.0"
47+
48+
[libraries]
49+
#...
50+
wisp-runtime = { module = "io.github.angrypodo:wisp-runtime", version.ref = "wisp" }
51+
wisp-processor = { module = "io.github.angrypodo:wisp-processor", version.ref = "wisp" }
52+
```
53+
54+
### Gradle
55+
56+
프로젝트 수준의 `build.gradle.kts` 파일에 KSP 플러그인을 추가합니다. **반드시 사용하는 Kotlin 버전과 호환되는 KSP 버전을 사용하세요.** ([KSP 릴리즈 확인](https://github.com/google/ksp/releases))
57+
58+
```kotlin
59+
plugins {
60+
id("com.google.devtools.ksp") version "YOUR_KSP_VERSION" apply false
61+
}
62+
```
63+
64+
그리고 **모듈** 수준의 `build.gradle.kts` 파일에 의존성을 추가합니다:
65+
66+
```kotlin
67+
plugins {
68+
id("com.google.devtools.ksp")
69+
}
70+
71+
dependencies {
72+
implementation("io.github.angrypodo:wisp-runtime:0.1.0")
73+
ksp("io.github.angrypodo:wisp-processor:0.1.0")
74+
75+
// Version Catalog를 사용하는 경우
76+
// implementation(libs.wisp.runtime)
77+
// ksp(libs.wisp.processor)
78+
}
79+
```
80+
81+
## 사용법 (Usage)
2482

2583
### 1. 라우트 정의하기
2684

27-
`@Serializable` 어노테이션이 달린 `data class``object``@Wisp` 어노테이션을 추가하여 딥링크 대상을 지정합니다. `@Wisp`에 전달하는 문자열은 딥링크 URI에서 사용될 경로 세그먼트가 됩니다.
85+
`@Serializable` 어노테이션이 달린 `data class``object``@Wisp` 어노테이션을 추가하여 딥링크 대상을 지정합니다.
2886

2987
라우트 클래스의 속성들은 URI의 **쿼리 파라미터**로부터 자동으로 값이 채워집니다. 만약 속성에 **기본값(default value)**이 있다면, 해당 속성은 선택적(optional)인 값이 됩니다.
3088

@@ -34,7 +92,7 @@ import com.angrypodo.wisp.annotations.Wisp
3492
import kotlinx.serialization.Serializable
3593

3694
@Serializable
37-
@Wisp("product") // "product" 경로와 매칭
95+
@Wisp("product") // "product" 경로 세그먼트와 매칭
3896
data class ProductDetail(
3997
val productId: Int, // "?productId=..." 로부터 값을 받음
4098
val showReviews: Boolean = false // 선택적. "?showReviews=..." 값이 없으면 false 사용
@@ -91,23 +149,7 @@ val uri = "app://wisp/product/user?productId=123&userId=99".toUri()
91149
navController.navigateTo(uri)
92150
```
93151

94-
## 🧪 테스트 방법
95-
96-
### 샘플 앱 실행하기
97-
98-
1. 이 리포지토리를 클론하여 Android Studio에서 엽니다.
99-
2. `app` 실행 구성을 선택하고 에뮬레이터나 실제 기기에서 실행합니다.
100-
3. 앱 내의 버튼을 눌러 내비게이션을 테스트합니다.
101-
102-
### ADB로 테스트하기
103-
104-
`adb`를 사용하여 커맨드 라인에서 직접 딥링크를 테스트할 수 있습니다. 이는 외부 소스로부터의 링크 클릭을 시뮬레이션하는 좋은 방법입니다.
105-
106-
```bash
107-
adb shell am start -a android.intent.action.VIEW -d "app://wisp/product/user?productId=123&userId=99"
108-
```
109-
110-
## 고급 사용법
152+
## 고급 사용법 (Advanced Usage)
111153

112154
### 커스텀 URI 파서
113155

@@ -124,9 +166,9 @@ Wisp.initialize(parser = myParser)
124166
- **Kotlinx Serialization:** Wisp는 쿼리 파라미터를 라우트 데이터 클래스로 역직렬화하기 위해 `kotlinx.serialization`에 크게 의존합니다.
125167
- **파라미터 이름:** URI의 쿼리 파라미터 키는 라우트 `data class`의 속성 이름과 정확히 일치해야 합니다.
126168

127-
## 📜 라이선스
169+
# License
128170

129-
```
171+
```xml
130172
Copyright 2025 angrypodo
131173

132174
Licensed under the Apache License, Version 2.0 (the "License");

README.md

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
# Wisp
22

3-
[![CI](https://github.com/angrypodo/wisp/actions/workflows/ci.yml/badge.svg)](https://github.com/angrypodo/wisp/actions/workflows/ci.yml)
4-
5-
**Wisp** is a type-safe, server-driven deep link library for Jetpack Compose. It allows you to dynamically build your navigation backstack from a single, standard URI, overcoming the static backstack limitations of the `navigation-compose` library.
3+
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
4+
[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21)
5+
[![Build Status](https://github.com/angrypodo/wisp/actions/workflows/ci.yml/badge.svg)](https://github.com/angrypodo/wisp/actions/workflows/ci.yml)
6+
[![Maven Central](https://img.shields.io/maven-central/v/io.github.angrypodo/wisp-runtime)](https://central.sonatype.com/artifact/io.github.angrypodo/wisp-runtime)
67

78
translation: [Read in Korean (한국어)](./README.ko.md)
89

10+
<br>
11+
12+
<p align="center">
13+
<strong>Wisp</strong> is a type-safe, server-driven deep link library for Jetpack Compose.<br>
14+
It allows you to dynamically build your navigation backstack from a single, standard URI,<br>
15+
overcoming the static backstack limitations of the <code>navigation-compose</code> library.
16+
</p>
17+
18+
<br>
19+
920
## 🤔 Why Wisp?
1021

1122
Standard deep links in Jetpack Compose often lead to predefined, static backstacks. It's challenging to implement scenarios where a server needs to dictate a dynamic user journey on the fly (e.g., `Product Screen -> Coupon Screen -> Checkout Screen`).
@@ -14,17 +25,64 @@ Wisp automates this process by building the entire backstack from the URI's path
1425

1526
## 🏛️ Architecture & Prerequisites
1627

17-
- **Single-Activity Architecture:** Wisp is designed for a **Single-Activity Architecture** and does not support navigating between different Activities. This aligns with the modern Android development practices recommended for Jetpack Compose.
18-
- **Jetpack Navigation & Type-Safety:** The library is an extension of Jetpack Navigation Compose and is exclusively designed for its **type-safe navigation** paradigm. It requires a `NavController` and does not support traditional string-based routes.
19-
- **Multi-Module Support:** Wisp fully supports multi-module projects. It automatically discovers `@Wisp` route definitions from all modules that include the library, using a `ServiceLoader` pattern.
28+
- **Single-Activity Architecture:** Wisp is designed for a **Single-Activity Architecture** and does not support navigating between different Activities.
29+
- **Jetpack Navigation & Type-Safety:** The library is exclusively designed for the **type-safe navigation** paradigm of Jetpack Navigation Compose. It requires a `NavController` and does not support traditional string-based routes.
30+
- **Multi-Module Support:** Wisp fully supports multi-module projects using a `ServiceLoader` pattern.
31+
- **Minimum Requirements:**
32+
- **minSdk:** 21 (Android 5.0)
33+
- **Kotlin:** 1.9.0 or higher (Compatible with KSP)
34+
35+
## Download
2036

21-
## 🚀 How to Use
37+
[![Maven Central](https://img.shields.io/maven-central/v/io.github.angrypodo/wisp-runtime)](https://central.sonatype.com/artifact/io.github.angrypodo/wisp-runtime)
2238

23-
**Note:** Wisp is not yet published to Maven Central. To use it, you currently need to clone this repository and include the modules in your project locally.
39+
### Version Catalog
40+
41+
If you're using Version Catalog, you can configure the dependency by adding it to your `libs.versions.toml` file as follows:
42+
43+
```toml
44+
[versions]
45+
#...
46+
wisp = "0.1.0"
47+
48+
[libraries]
49+
#...
50+
wisp-runtime = { module = "io.github.angrypodo:wisp-runtime", version.ref = "wisp" }
51+
wisp-processor = { module = "io.github.angrypodo:wisp-processor", version.ref = "wisp" }
52+
```
53+
54+
### Gradle
55+
56+
Add the KSP plugin to your project-level `build.gradle.kts`. **Make sure to use a KSP version that matches your Kotlin version.** (Check [KSP Releases](https://github.com/google/ksp/releases))
57+
58+
```kotlin
59+
plugins {
60+
id("com.google.devtools.ksp") version "YOUR_KSP_VERSION" apply false
61+
}
62+
```
63+
64+
Then, add the dependencies to your **module**'s `build.gradle.kts` file:
65+
66+
```kotlin
67+
plugins {
68+
id("com.google.devtools.ksp")
69+
}
70+
71+
dependencies {
72+
implementation("io.github.angrypodo:wisp-runtime:0.1.0")
73+
ksp("io.github.angrypodo:wisp-processor:0.1.0")
74+
75+
// if you're using Version Catalog
76+
// implementation(libs.wisp.runtime)
77+
// ksp(libs.wisp.processor)
78+
}
79+
```
80+
81+
## Usage
2482

2583
### 1. Define Routes
2684

27-
Designate a deep link destination by adding the `@Wisp` annotation to any `@Serializable` `data class` or `object`. The string passed to `@Wisp` is the path segment that will be used in the deep link URI.
85+
Designate a deep link destination by adding the `@Wisp` annotation to any `@Serializable` `data class` or `object`.
2886

2987
Route properties are automatically populated from the URI's **query parameters**. If a property has a **default value**, it is considered optional.
3088

@@ -43,7 +101,7 @@ data class ProductDetail(
43101

44102
### 2. Configure the Manifest
45103

46-
For deep links to be accessible from outside your app, you must register an `<intent-filter>` in your `AndroidManifest.xml`. Both `scheme` and `host` are required.
104+
Register an `<intent-filter>` in your `AndroidManifest.xml`. Both `scheme` and `host` are required.
47105

48106
```xml
49107
<!-- In AndroidManifest.xml -->
@@ -92,22 +150,6 @@ val uri = "app://wisp/product/user?productId=123&userId=99".toUri()
92150
navController.navigateTo(uri)
93151
```
94152

95-
## 🧪 Testing
96-
97-
### Running the Sample App
98-
99-
1. Clone this repository and open it in Android Studio.
100-
2. Select the `app` run configuration and run it on an emulator or a physical device.
101-
3. Use the buttons in the app to test navigation.
102-
103-
### Testing with ADB
104-
105-
You can test your deep links directly from the command line using `adb`. This is a great way to simulate a link click from an external source.
106-
107-
```bash
108-
adb shell am start -a android.intent.action.VIEW -d "app://wisp/product/user?productId=123&userId=99"
109-
```
110-
111153
## Advanced Usage
112154

113155
### Custom URI Parser
@@ -125,9 +167,9 @@ Wisp.initialize(parser = myParser)
125167
- **Kotlinx Serialization:** Wisp relies heavily on `kotlinx.serialization` to deserialize query parameters into your route data classes.
126168
- **Parameter Naming:** The query parameter keys in the URI must exactly match the property names in your route `data class`.
127169

128-
## 📜 License
170+
# License
129171

130-
```
172+
```xml
131173
Copyright 2025 angrypodo
132174

133175
Licensed under the Apache License, Version 2.0 (the "License");

app/build.gradle.kts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ kotlin {
4343
}
4444
}
4545

46-
tasks.withType<Test> {
47-
useJUnitPlatform()
48-
}
49-
5046
dependencies {
5147
implementation(project(":wisp-runtime"))
5248
ksp(project(":wisp-processor"))

build.gradle.kts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import org.jlleitschuh.gradle.ktlint.KtlintExtension
22

33
plugins {
4+
// Android
45
alias(libs.plugins.android.application) apply false
56
alias(libs.plugins.android.library) apply false
7+
8+
// Kotlin
69
alias(libs.plugins.kotlin.android) apply false
710
alias(libs.plugins.kotlin.jvm) apply false
811
alias(libs.plugins.kotlin.compose) apply false
9-
alias(libs.plugins.ksp) apply false
1012
alias(libs.plugins.kotlin.serialization) apply false
13+
14+
// Tools
15+
alias(libs.plugins.ksp) apply false
1116
alias(libs.plugins.ktlint) apply false
17+
alias(libs.plugins.vanniktech.maven.publish) apply false
1218
}
1319

1420
subprojects {
@@ -21,4 +27,45 @@ subprojects {
2127
verbose.set(true)
2228
outputToConsole.set(true)
2329
}
30+
31+
tasks.withType<Test> {
32+
useJUnitPlatform()
33+
}
34+
35+
if (name != "app") {
36+
apply(plugin = "com.vanniktech.maven.publish")
37+
38+
extensions.configure<com.vanniktech.maven.publish.MavenPublishBaseExtension> {
39+
publishToMavenCentral(com.vanniktech.maven.publish.SonatypeHost.CENTRAL_PORTAL)
40+
signAllPublications()
41+
42+
coordinates("io.github.angrypodo", name, "0.1.0")
43+
44+
pom {
45+
name.set(project.name)
46+
description.set("Wisp library: ${project.name}")
47+
inceptionYear.set("2025")
48+
url.set("https://github.com/angrypodo/wisp")
49+
licenses {
50+
license {
51+
name.set("The Apache License, Version 2.0")
52+
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
53+
distribution.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
54+
}
55+
}
56+
developers {
57+
developer {
58+
id.set("angrypodo")
59+
name.set("MinJae Han")
60+
url.set("https://github.com/angrypodo")
61+
}
62+
}
63+
scm {
64+
url.set("https://github.com/angrypodo/wisp")
65+
connection.set("scm:git:git://github.com/angrypodo/wisp.git")
66+
developerConnection.set("scm:git:ssh://git@github.com/angrypodo/wisp.git")
67+
}
68+
}
69+
}
70+
}
2471
}

0 commit comments

Comments
 (0)