KtProvider

中文文档
Cross-Module Service Provisioning Framework with KMP Support
- Multi-module Project with KMP Support
- Suitable for use in Compose Multiplatform environment.
Setup
Across all modules:
Kotlin Multiplatform projects
Only Jvm or Android projects
plugins {
id("com.google.devtools.ksp")
id("io.github.985892345.KtProvider") version "x.y.z"
}
dependencies {
implementation(ktProvider.manager)
ksp(ktProvider.ksp)
}
Initialization
Kotlin/Jvm: It is recommended to perform initialization in the main function.
fun main() {
XXXKtProviderInitializer.tryInitKtProvider()
}
Android: It is recommended to perform initialization in the Application#onCreate method.
class App : Application() {
override fun onCreate() {
super.onCreate()
XXXKtProviderInitializer.tryInitKtProvider()
}
}
iOS: I'm not proficient in iOS, so this may not be the most optimal approach.
Swift: App#init
@main
struct iOSApp: App {
init() {
XXXKtProviderInitializer.shared.tryInitKtProvider()
}
}
Objective-C: application:didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[XXXKtProviderInitializer.shared tryInitKtProvider];
}
Usage
Add interface
interface ITestService {
fun get(): String
}
Implement interface
@ImplProvider(clazz = ITestService::class, name = "test")
class TestServiceImpl : ITestService {
override fun get(): String {
return "123"
}
}
| Annotation | |
|---|
| ImplProvider | Obtain an instance, which becomes a singleton when the implementation class is an object. |
| KClassProvider | Retrieve the KClass of the implementation class (can be used for Class<out Activity> in Android). |
Use interface
val service = KtProvider.implOrNull(ITestService::class, "test")
println(service.get())
Testing
Add provider-testing to the test source set. The main source set still needs
provider-manager as shown in Setup.
Kotlin Multiplatform projects
kotlin {
sourceSets {
commonTest.dependencies {
implementation(kotlin("test"))
implementation(ktProvider.testing)
}
}
}
JVM or Android projects
dependencies {
testImplementation(ktProvider.testing)
}
Use the initializer generated for the module under test. withKtProviderTest creates an isolated
registry, loads the module and the KtProvider project-module dependencies recorded in its generated
initializer, redirects KtProvider lookups for the block, and restores the production resolver when
the block returns or throws.
import com.g985892345.provider.testing.withKtProviderTest
import kotlin.test.Test
import kotlin.test.assertEquals
private FakeTestService : ITestService {
: String =
}
{
= withKtProviderTest(ModuleKtProviderInitializer) {
overrideImpl<ITestService>(name = ) {
FakeTestService
}
assertEquals(
,
KtProvider.impl(ITestService::, ).(),
)
}
}
Implementation-class routes can be replaced in the same way:
withKtProviderTest(ModuleKtProviderInitializer) {
overrideKClass<ITestService>(name = "test") {
FakeTestService::class
}
}
The generated ModuleKtProviderInitializer is produced by the main KSP task. Running the test task
also runs the required main compilation and KSP generation. If the reference is unresolved immediately
after writing the first test, run Gradle sync or the test task once.
Each withKtProviderTest call owns a fresh registry, so overrides do not mutate production registrations
or leak into later sequential tests. The block is synchronous and resolver scopes must not overlap; do not
run multiple withKtProviderTest blocks concurrently in the same test process.
Implementation principle
- The KtProvider's Gradle plugin automatically resolves the inter-module dependencies and passes this information to KSP to generate an implementation class for KtProviderInitializer.
- KSP scans annotations to generate an implementation class for KtProviderRouter.
Similar to the following code:
object ModuleKtProviderInitializer : KtProviderInitializer() {
override val router: KtProviderRouter = ModuleKtProviderRouter
override val otherModuleKtProvider: List<KtProviderInitializer> = listOf(
Module1KtProviderInitializer,
Module2KtProviderInitializer
)
}
internal object ModuleKtProviderRouter : KtProviderRouter() {
override fun initRouter(delegate: IKtProviderDelegate) {
delegate.addImplProvider(ITestService::class, "abc") { TestServiceImpl }
delegate.addImplProvider(ITestService2::class, "123") { TestServiceImpl2 }
}
}
License
Copyright 2023 985892345
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this except compliance the License.
You may obtain a copy of the License at
http:
Unless applicable law agreed to writing, software
distributed under the License distributed an BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
See the License the specific language governing permissions
limitations under the License.