Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android component 모듈 추가 및 빌드 구성 수정 #2

Merged
merged 6 commits into from
Aug 23, 2024
Merged
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
26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,30 @@

안드로이드에서 공통적으로 사용될 모듈 저장소

##### 초기화
- 최초로 프로젝트를 다운받은 후 `./init_lint_settings.sh` 를 실행해주세요. commit changes 에 대한 lint를 자동적으로 수행합니다.
**Authors** : raine@lemoncloud.io

## Module

| module | description |
|---------------------------------------------|---------------------------|
| lemon-core-ui:architecture | mvi 기반 architecture 인터페이스 |
| lemon-core-android:component(Not implement) | android component 관련 유틸리티 |

| module | description |
|------------------------------|---------------------------|
| lemon-core-ui:architecture | mvi 기반 architecture 인터페이스 |
| lemon-core-android:component | android component 유틸리티 |

### UI-Architecture
안드로이드 UI 구조를 효과적으로 빌딩하기 위한 아키텍처 라이브러리. MVI 기반의 아키텍처로 State Event Effect를 제어하여 사용자와 UI간의 상태 및 이벤트 흐름과 사이에 발생하는 이펙트를 효과적으로 처리할 수 있습니다.

안드로이드 UI 구조를 효과적으로 빌딩하기 위한 아키텍처 라이브러리. MVI 기반의 아키텍처로 State Event Effect를 제어하여 사용자와 UI간의 상태 및 이벤트 흐름과 사이에 발생하는 이펙트를 효과적으로
처리할 수 있습니다.

### Android-Component

안드로이드 컴포넌트 제어 라이브러리 안드로이드 컴포넌트 초기화, 설정 및 컴포넌트간의 통신과 같은 작업을 수행합니다.

## 초기화

최초로 프로젝트를 다운받은 후 `./init_lint_settings.sh` 를 실행해주세요. commit changes 에 대한 lint를 자동적으로 수행합니다.

## AAR 배포

Lemon Android Core Module에서 사용되는 라이브러리를 배포해야 할 상황이 존재할 경우 루트 디렉터리에 존재하는 `assemble_aar.sh` 스크립트 파일을 실행하면 됩니다.
이때 생성되는 AAR들은 난독화가 적용되어 있습니다. 배포되는 aar들의 난독화 여부와 flavor 구성들을 수정하고 싶을 경우, `build-system` 모듈의 `Config` 를 확인하세요.

13 changes: 13 additions & 0 deletions assemble_aar.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

chmod +x "./gradlew"

# ktlint 검사
./gradlew ktlintCheck

# AAR 배포
./gradlew assembleRelease

# 모든 모듈의 AAR 을 수집하여 ./build/outputs 에 배치
./gradlew assembleAAR

File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ dependencyResolutionManagement {
}


rootProject.name = "buildSystem"
rootProject.name = "build-system"


Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.lemon.android.buildSystem

import io.lemon.android.buildSystem.extensions.type.FlavorType
import io.lemon.android.buildSystem.extensions.type.ResourceType
import org.gradle.api.JavaVersion
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.time.ZonedDateTime
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.lemon.android.buildSystem.plugin

import com.android.build.api.dsl.ApplicationExtension
import io.lemon.android.buildSystem.Config
import io.lemon.android.buildSystem.Config.COMPILE_SDK
import io.lemon.android.buildSystem.Config.MIN_SDK
import io.lemon.android.buildSystem.Config.TARGET_SDK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class AndroidFeaturePlugin : Plugin<Project> {
add("implementation", versionCatalog.findLibrary("androidx-appcompat").get())
add("implementation", versionCatalog.findLibrary("androidx-core-ktx").get())
add("implementation", versionCatalog.findLibrary("androidx-core-splashscreen").get())
add("implementation", versionCatalog.findLibrary("androidx-lifecycle-service").get())
add("implementation", versionCatalog.findLibrary("androidx-lifecycle-viewmodel-ktx").get())
add("implementation", versionCatalog.findLibrary("androidx-lifecycle-runtime-ktx").get())
add("implementation", versionCatalog.findLibrary("androidx-navigation-runtime-ktx").get())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.lemon.android.buildSystem.plugin

import com.android.build.gradle.LibraryExtension
import io.lemon.android.buildSystem.Config
import io.lemon.android.buildSystem.Config.BuildType.DEBUG
import io.lemon.android.buildSystem.Config.BuildType.RELEASE
import io.lemon.android.buildSystem.Config.COMPILE_SDK
Expand Down Expand Up @@ -36,11 +35,11 @@ class AndroidLibraryPlugin : Plugin<Project> {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
"proguard-rules.pro",
)
}
}
}
}
}
}
}
11 changes: 11 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,14 @@ allprojects {
)
}
}

tasks.register<Copy>("assembleAAR") {
from(
project.provider {
subprojects.flatMap { subproject ->
subproject.layout.buildDirectory.dir("outputs/aar").get().asFile.listFiles()?.toList() ?: emptyList()
}
}
)
into(rootProject.layout.buildDirectory.dir("outputs/aar"))
}
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ androidx-test-core = { group = "androidx.test", name = "core", version.ref = "an
androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "androidxTestRules" }
androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTestRunner" }
androidx-test-ext = { group = "androidx.test.ext", name = "junit", version.ref = "androidxTestExt" }
androidx-lifecycle-service = { group = "androidx.lifecycle", name = "lifecycle-service", version.ref = "androidxLifecycle" }
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "androidxLifecycle" }
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" }
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" }
Expand Down
1 change: 1 addition & 0 deletions lemon-core-android/component/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
18 changes: 18 additions & 0 deletions lemon-core-android/component/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Android-Component
android component 유틸리티

### Intent
`Intent` 설정을 빌드하는 모듈입니다. `IntentBuilder`를 사용하여 Intent를 구성할 수 있으며, 이는 `Component` 의 `Launcher`와 연동하여 사용할 수 있습니다.
또한 특수한 목적으로 사용되는 `Intent`를 빠르게 구성하는 확장 람다 함수가 존재합니다. (예를 들어, URL에 대한 사이트를 빠르게 불러오는 `getUrlIntent`, Application 설정으로 빠르게 이동하는 `getSettingIntent`)
`Intent`를 컴포넌트 목적에 따른 `PendingIntent`로 변환하는 함수는 `PendingIntent` Object 내에 존재합니다.

### Launcher
`Android Component` 설정을 빠르게 구성하는 모듈입니다.
`Launcher` 생성 시 `Intent` 가 구성되며, 컴포넌트를 수행할 수 있는 함수가 존재합니다. 내부 `Intent` 정보는 `IntentBuilder`를 사용하여 수정할 수 있습니다. 이를 통해 extra,data 그리고 특수한 flag등을 설정할 수 있습니다.







9 changes: 9 additions & 0 deletions lemon-core-android/component/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
alias(libs.plugins.lemon.android.library)
alias(libs.plugins.lemon.android.feature)
alias(libs.plugins.lemon.android.kotlin)
}

android {
namespace = "io.lemon.android.core.android.component"
}
Empty file.
21 changes: 21 additions & 0 deletions lemon-core-android/component/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
4 changes: 4 additions & 0 deletions lemon-core-android/component/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.remon.android.core.android.component.intent

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Parcelable
import android.provider.Settings
import java.io.Serializable

/**
* [Intent]
*
* Intent 유틸리티
*
* @author raine@lemoncloud.io
*/
object Intent {

/**
* [intentBuilder]
*
* 인텐트 빌더를 생성합니다.
*
* context를 포함하지 않는 인텐트의 경우 해당 메서드를 사용합니다.
*
* @see IntentBuilder
*/
fun intentBuilder(): IntentBuilder = IntentBuilder()

/**
* [intentBuilder]
*
* 인텐트 빌더를 생성합니다.
*
* intent 타겟을 포함할 경우 헤당 메서드를 사용합니다.
*
* @see IntentBuilder
*/
fun intentBuilder(context: Context, `class`: Class<*>): IntentBuilder = IntentBuilder(context, `class`)

/**
* [getParcelableExtraExt]
*
* intent extra에 포함되어 있는 parcelable 객체를 가져올 때 사용합니다.
*/
fun <T : Parcelable> Intent.getParcelableExtraExt(key: String, `class`: Class<T>): T? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
getParcelableExtra(key, `class`)
else getParcelableExtra(key)
}

/**
* [getSerializableExtraExt]
*
* intent extra에 포함되어 있는 serializable 객체를 가져올 때 사용합니다.
*/
@Suppress("UNCHECKED_CAST")
fun <T : Serializable> Intent.getSerializableExtraExt(key: String, `class`: Class<T>): T? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
this.getSerializableExtra(key, `class`)
} else {
this.getSerializableExtra(key) as T?
}
}

/**
* [getUrlIntent]
*
* url 주소를 포함한 intent를 생성합니다.
*
* `startActivity()`와 연계하여 사용합니다.
*/
val getUrlIntent: (String) -> Intent =
{ url -> intentBuilder().setAction(Intent.ACTION_VIEW).setData(Uri.parse(url)).build() }

/**
* [getSettingsIntent]
*
* 애플리케이션의 설정으로 이동하는 intent를 생성합니다.
*
* `startActivity()`와 연계하여 사용합니다.
*/
val getSettingsIntent: (Context) -> Intent = { context ->
intentBuilder().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
Uri.parse("package:${context.packageName}")
).build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package io.remon.android.core.android.component.intent

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Parcelable
import androidx.core.os.bundleOf
import java.io.Serializable

/**
* [IntentBuilder]
*
* intent 생성을 도와주는 Builder 클래스
*
* @author raine@lemoncloud.io
*/
open class IntentBuilder() {

private var intent: Intent = Intent()

constructor(context: Context, `class`: Class<*>) : this() {
intent = Intent(context, `class`)
}

/**
* [putExtras]
*
* intent 에 담아서 보낼 데이터인, extra를 정의합니다.
*/
open fun <T : Parcelable> putExtra(extra: T, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

open fun <T : Serializable> putExtra(extra: T, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

open fun <T : Parcelable> putExtra(extra: ArrayList<T>, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

open fun putExtra(extra: String, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

open fun putExtra(extra: Long, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

open fun putExtra(extra: Int, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

open fun putExtra(extra: Float, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

open fun putExtra(extra: Boolean, key: String = DEFAULT_KEY) = apply {
intent.putExtra(key, extra)
}

/**
* [putExtras]
*
* 번들 단위로 데이터 추가
*/
open fun putExtras(vararg pairs: Pair<String, Any?>) = apply {
intent.putExtras(bundleOf(*pairs))
}

/**
* [setAction]
*
* action 추가
*/
open fun setAction(action: String) = apply {
intent.setAction(action)
}

/**
* [setAction]
*
* uri 형태 데이터 추가
*/
open fun setData(uri: Uri) = apply {
intent.setData(uri)
}

/**
* [setFlags]
*
* 플래그 설정
*/
open fun setFlags(flag: Int) = apply {
intent.setFlags(flag)
}

/**
* [addFlags]
*
* 플래그 추가
*/
open fun addFlags(flag: Int) = apply {
intent.addFlags(flag)
}

/**
* [build]
*
* IntentBuilder를 통해 조합한 intent 객체를 반환합니다.
*/
open fun build(): Intent = intent

companion object {
const val DEFAULT_KEY = "KEY"
}
}
Loading