-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: Hilt -> Metro Migration #227
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
base: develop
Are you sure you want to change the base?
Changes from all commits
45c3abc
265ed6b
457d2d9
1f6c226
80231ec
869e8db
d128622
5273273
238d1ac
50da68a
e8af5fa
69a57b1
7083ee8
3704bdc
8f2b542
a579a3f
ea31299
61fe0a9
0970f3e
419ce1a
f538d44
e998355
819c4b5
9b83728
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.ninecraft.booket.di | ||
|
|
||
| import android.app.Activity | ||
| import android.app.Service | ||
| import android.content.Context | ||
| import com.ninecraft.booket.core.di.ApplicationContext | ||
| import com.ninecraft.booket.core.di.DataScope | ||
| import dev.zacsweers.metro.AppScope | ||
| import dev.zacsweers.metro.DependencyGraph | ||
| import dev.zacsweers.metro.Multibinds | ||
| import dev.zacsweers.metro.Provider | ||
| import dev.zacsweers.metro.Provides | ||
| import kotlin.reflect.KClass | ||
|
|
||
| @DependencyGraph( | ||
| scope = AppScope::class, | ||
| additionalScopes = [DataScope::class], | ||
| ) | ||
| interface AppGraph { | ||
|
|
||
| @Multibinds(allowEmpty = true) | ||
| val activityProviders: Map<KClass<out Activity>, Provider<Activity>> | ||
|
|
||
| @Multibinds(allowEmpty = true) | ||
| val serviceProviders: Map<KClass<out Service>, Provider<Service>> | ||
|
|
||
| @DependencyGraph.Factory | ||
| fun interface Factory { | ||
| fun create(@ApplicationContext @Provides context: Context): AppGraph | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package com.ninecraft.booket.di | ||
|
|
||
| import androidx.compose.foundation.background | ||
| import androidx.compose.foundation.text.BasicText | ||
| import androidx.compose.ui.graphics.Color | ||
| import androidx.compose.ui.text.TextStyle | ||
| import com.slack.circuit.foundation.Circuit | ||
| import com.slack.circuit.foundation.LocalCircuit | ||
| import com.slack.circuit.runtime.Navigator | ||
| import com.slack.circuit.runtime.presenter.Presenter | ||
| import com.slack.circuit.runtime.ui.Ui | ||
| import dev.zacsweers.metro.AppScope | ||
| import dev.zacsweers.metro.ContributesTo | ||
| import dev.zacsweers.metro.Multibinds | ||
| import dev.zacsweers.metro.Provides | ||
|
|
||
| @ContributesTo(AppScope::class) | ||
| interface CircuitGraph { | ||
|
|
||
| @Multibinds(allowEmpty = true) | ||
| fun presenterFactories(): Set<Presenter.Factory> | ||
|
|
||
| @Multibinds(allowEmpty = true) | ||
| fun uiFactories(): Set<Ui.Factory> | ||
|
|
||
| @Provides | ||
| fun provideCircuit( | ||
| presenterFactories: Set<Presenter.Factory>, | ||
| uiFactories: Set<Ui.Factory>, | ||
| ): Circuit { | ||
| return Circuit.Builder() | ||
| .addPresenterFactories(presenterFactories) | ||
| .addUiFactories(uiFactories) | ||
| .setAnimatedNavDecoratorFactory(CrossFadeNavDecoratorFactory()) | ||
| .setOnUnavailableContent { screen, modifier -> | ||
| val circuit = LocalCircuit.current | ||
| BasicText( | ||
| text = """ | ||
| Route not available: ${screen.javaClass.name}. | ||
| Presenter: ${circuit?.presenter(screen, Navigator.NoOp)?.javaClass} | ||
| UI: ${circuit?.ui(screen)?.javaClass} | ||
| All presenterFactories: ${circuit?.newBuilder()?.presenterFactories} | ||
| All uiFactories: ${circuit?.newBuilder()?.uiFactories} | ||
| """ | ||
| .trimIndent(), | ||
| modifier = modifier.background(Color.Red), | ||
| style = TextStyle(color = Color.Yellow), | ||
| ) | ||
| } | ||
| .build() | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||||||||||||||||||||||||||||||||||||||
| package com.ninecraft.booket.di | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import android.app.Activity | ||||||||||||||||||||||||||||||||||||||||||
| import android.app.Application | ||||||||||||||||||||||||||||||||||||||||||
| import android.app.Service | ||||||||||||||||||||||||||||||||||||||||||
| import android.content.Intent | ||||||||||||||||||||||||||||||||||||||||||
| import androidx.annotation.Keep | ||||||||||||||||||||||||||||||||||||||||||
| import androidx.core.app.AppComponentFactory | ||||||||||||||||||||||||||||||||||||||||||
| import com.ninecraft.booket.BooketApplication | ||||||||||||||||||||||||||||||||||||||||||
| import dev.zacsweers.metro.Provider | ||||||||||||||||||||||||||||||||||||||||||
| import kotlin.reflect.KClass | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||
| * AppComponentFactory that uses Metro for constructor injection of Activities and Services. | ||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||
| * Requires minSdk 28+. For lower versions, use manual graph access. | ||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||
| @Keep | ||||||||||||||||||||||||||||||||||||||||||
| class MetroAppComponentFactory : AppComponentFactory() { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| private inline fun <reified T : Any> getInstance( | ||||||||||||||||||||||||||||||||||||||||||
| cl: ClassLoader, | ||||||||||||||||||||||||||||||||||||||||||
| className: String, | ||||||||||||||||||||||||||||||||||||||||||
| providers: Map<KClass<out T>, Provider<T>>, | ||||||||||||||||||||||||||||||||||||||||||
| ): T? { | ||||||||||||||||||||||||||||||||||||||||||
| val clazz = Class.forName(className, false, cl).asSubclass(T::class.java) | ||||||||||||||||||||||||||||||||||||||||||
| val modelProvider = providers[clazz.kotlin] ?: return null | ||||||||||||||||||||||||||||||||||||||||||
| return modelProvider() | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| override fun instantiateActivityCompat( | ||||||||||||||||||||||||||||||||||||||||||
| cl: ClassLoader, | ||||||||||||||||||||||||||||||||||||||||||
| className: String, | ||||||||||||||||||||||||||||||||||||||||||
| intent: Intent?, | ||||||||||||||||||||||||||||||||||||||||||
| ): Activity { | ||||||||||||||||||||||||||||||||||||||||||
| return getInstance(cl, className, activityProviders) | ||||||||||||||||||||||||||||||||||||||||||
| ?: super.instantiateActivityCompat(cl, className, intent) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| override fun instantiateServiceCompat( | ||||||||||||||||||||||||||||||||||||||||||
| cl: ClassLoader, | ||||||||||||||||||||||||||||||||||||||||||
| className: String, | ||||||||||||||||||||||||||||||||||||||||||
| intent: Intent?, | ||||||||||||||||||||||||||||||||||||||||||
| ): Service { | ||||||||||||||||||||||||||||||||||||||||||
| return getInstance(cl, className, serviceProviders) | ||||||||||||||||||||||||||||||||||||||||||
| ?: super.instantiateServiceCompat(cl, className, intent) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+40
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lateinit ๋ณ์ ์ ๊ทผ ์ ์ด๊ธฐํ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ค์ diff๋ฅผ ์ ์ฉํ์ธ์: override fun instantiateServiceCompat(
cl: ClassLoader,
className: String,
intent: Intent?,
): Service {
- return getInstance(cl, className, serviceProviders)
+ return if (::serviceProviders.isInitialized) {
+ getInstance(cl, className, serviceProviders)
+ } else {
+ null
+ }
?: super.instantiateServiceCompat(cl, className, intent)
}๐ค Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| override fun instantiateApplicationCompat(cl: ClassLoader, className: String): Application { | ||||||||||||||||||||||||||||||||||||||||||
| val app = super.instantiateApplicationCompat(cl, className) | ||||||||||||||||||||||||||||||||||||||||||
| val appGraph = (app as BooketApplication).appGraph | ||||||||||||||||||||||||||||||||||||||||||
| activityProviders = appGraph.activityProviders | ||||||||||||||||||||||||||||||||||||||||||
| serviceProviders = appGraph.serviceProviders | ||||||||||||||||||||||||||||||||||||||||||
| return app | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+49
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ํ์ ์บ์คํ ๊ณผ thread safety ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
๋ค์ diff๋ฅผ ์ ์ฉํ์ฌ ์์ ์ฑ์ ๊ฐ์ ํ์ธ์: override fun instantiateApplicationCompat(cl: ClassLoader, className: String): Application {
val app = super.instantiateApplicationCompat(cl, className)
- val appGraph = (app as BooketApplication).appGraph
- activityProviders = appGraph.activityProviders
- serviceProviders = appGraph.serviceProviders
+ if (app is BooketApplication) {
+ synchronized(this) {
+ if (!::activityProviders.isInitialized) {
+ val appGraph = app.appGraph
+ activityProviders = appGraph.activityProviders
+ serviceProviders = appGraph.serviceProviders
+ }
+ }
+ }
return app
}๐ Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||
| private lateinit var activityProviders: Map<KClass<out Activity>, Provider<Activity>> | ||||||||||||||||||||||||||||||||||||||||||
| private lateinit var serviceProviders: Map<KClass<out Service>, Provider<Service>> | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ dependencies { | |
| compileOnly(libs.android.gradle.plugin) | ||
| compileOnly(libs.kotlin.gradle.plugin) | ||
| compileOnly(libs.compose.compiler.gradle.plugin) | ||
| compileOnly(libs.ksp.gradle.plugin) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งฉ Analysis chainMetro ๋ฐ KSP ๋ฒ์ ํธํ์ฑ์ ํ์ธํ์ธ์. KSP ํ๋ฌ๊ทธ์ธ ์์กด์ฑ์ด ์ถ๊ฐ๋์์ต๋๋ค. Metro DI ํ๋ ์์ํฌ๋ก์ ๋ง์ด๊ทธ๋ ์ด์ ์ ํ์ํ ๋ณ๊ฒฝ์ฌํญ์ด์ง๋ง, ์ฌ์ฉ ์ค์ธ Metro ๋ฐ KSP ๋ฒ์ ์ด ์๋ก ํธํ๋๋์ง ํ์ธํด์ผ ํฉ๋๋ค. ๋ค์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ์ฌ ๋ฒ์ ์ ๋ณด๋ฅผ ํ์ธํ์ธ์: ๋ํ ์ต์ Metro ๋ฌธ์๋ฅผ ํ์ธํ์ฌ ๊ถ์ฅ KSP ๋ฒ์ ์ ํ์ธํ์ธ์: ๐ Script executed: #!/bin/bash
# Description: Metro์ KSP ๋ฒ์ ํ์ธ
# Metro ๋ฒ์ ํ์ธ
echo "=== Metro ๋ฒ์ ==="
rg -n "metro.*=.*\"" gradle/libs.versions.toml
# KSP ๋ฒ์ ํ์ธ
echo "=== KSP ๋ฒ์ ==="
rg -n "ksp.*=.*\"" gradle/libs.versions.toml
# Metro plugin ์ฌ์ฉ ํ์ธ
echo "=== Metro plugin ์ฌ์ฉ ==="
rg -n "alias\(libs\.plugins\.metro\)" --type kotlinLength of output: 949 ๐ Web query: ๐ก Result: Use KSP 2.2.20-2.0.3. [1][2] Sources: KSP ๋ฒ์ ์ด Metro์ ํธํ๋์ง ์์ต๋๋ค. ํ๋ก์ ํธ๋ KSP 2.3.0์ ์ฌ์ฉ ์ค์ด์ง๋ง, Metro 0.7.7์ KSP 2.2.20-2.0.3์ ๊ถ์ฅํฉ๋๋ค. KSP 2.3.0์ ๊ถ์ฅ ๋ฒ์ ๋ณด๋ค ์ต์ ์ด๋ฏ๋ก Metro์์ ํธํ์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ๐ค Prompt for AI Agents |
||
| implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) | ||
| } | ||
|
|
||
|
|
@@ -20,7 +21,6 @@ gradlePlugin { | |
| "android.library.compose" to "AndroidLibraryComposeConventionPlugin", | ||
| "android.feature" to "AndroidFeatureConventionPlugin", | ||
| "android.firebase" to "AndroidFirebaseConventionPlugin", | ||
| "android.hilt" to "AndroidHiltConventionPlugin", | ||
| "android.retrofit" to "AndroidRetrofitConventionPlugin", | ||
| "jvm.library" to "JvmLibraryConventionPlugin", | ||
| "kotlin.library.serialization" to "KotlinLibrarySerializationConventionPlugin", | ||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lateinit ๋ณ์ ์ ๊ทผ ์ ์ด๊ธฐํ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
activityProviders๋instantiateApplicationCompat์์ ์ด๊ธฐํ๋์ง๋ง, Activity๊ฐ Application๋ณด๋ค ๋จผ์ ์์ฑ๋๋ ๊ฒฝ์ฐUninitializedPropertyAccessException์ด ๋ฐ์ํฉ๋๋ค. ์ด๊ธฐํ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ฑฐ๋ nullable ํ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.๋ค์ diff๋ฅผ ์ ์ฉํ์ฌ ์ด๊ธฐํ ์ฒดํฌ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค:
override fun instantiateActivityCompat( cl: ClassLoader, className: String, intent: Intent?, ): Activity { - return getInstance(cl, className, activityProviders) + return if (::activityProviders.isInitialized) { + getInstance(cl, className, activityProviders) + } else { + null + } ?: super.instantiateActivityCompat(cl, className, intent) }๐ Committable suggestion
๐ค Prompt for AI Agents