{"id":13428892,"url":"https://github.com/corbella83/PopKorn","last_synced_at":"2025-03-16T02:30:44.729Z","repository":{"id":39222125,"uuid":"221466107","full_name":"corbella83/PopKorn","owner":"corbella83","description":"DI can be simple. Forget about modules and components. Just use it!","archived":false,"fork":false,"pushed_at":"2023-07-04T07:45:48.000Z","size":447,"stargazers_count":155,"open_issues_count":7,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-27T06:39:22.257Z","etag":null,"topics":["android","dependency-injection","injection","java","kotlin","kotlin-dependency-injection","kotlin-library","kotlin-multiplatform","multiplatform"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/corbella83.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-13T13:30:39.000Z","updated_at":"2024-06-21T09:04:10.000Z","dependencies_parsed_at":"2024-10-27T06:38:15.094Z","dependency_job_id":"e8056fe2-f034-4076-b262-d90a9e973947","html_url":"https://github.com/corbella83/PopKorn","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corbella83%2FPopKorn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corbella83%2FPopKorn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corbella83%2FPopKorn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corbella83%2FPopKorn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/corbella83","download_url":"https://codeload.github.com/corbella83/PopKorn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243815611,"owners_count":20352197,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","dependency-injection","injection","java","kotlin","kotlin-dependency-injection","kotlin-library","kotlin-multiplatform","multiplatform"],"created_at":"2024-07-31T01:01:08.063Z","updated_at":"2025-03-16T02:30:44.151Z","avatar_url":"https://github.com/corbella83.png","language":"Kotlin","funding_links":[],"categories":["Libraries","IoC","Dependency Injection"],"sub_categories":["DI","💉 Dependency Injection"],"readme":"[![Maven Central](https://maven-badges.herokuapp.com/maven-central/cc.popkorn/popkorn/badge.svg)](https://search.maven.org/artifact/cc.popkorn/popkorn)\n[![Kotlin](https://img.shields.io/badge/kotlin-1.8.21-blue.svg?logo=kotlin)](http://kotlinlang.org)\n[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)\n[![Slack channel](https://img.shields.io/badge/chat-slack-red.svg?logo=slack)](https://kotlinlang.slack.com/messages/popkorn/)\n\nPopKorn - Kotlin Multiplatform DI\n==========\n\n\nPopKorn is a simple, powerful and lightweight Kotlin Multiplatform Dependency Injector. It doesn't need any modules or components, just use it without writing a single extra file! It supports AND, IOS, JVM, JS and NATIVE.\n\n\nDownload\n--------\nGet it with Gradle:\n\n```groovy\nimplementation 'cc.popkorn:popkorn:2.3.1'\nkapt 'cc.popkorn:popkorn-compiler:2.3.1'\n```\n\nThe Kotlin Gradle Plugin 1.4.0 will automatically resolve platform dependent implementations (jvm, js, iosX64...). But if you are using Kotlin Gradle Plugin below 1.4.0 you will have to specify the platform yourself. In the case of Android/JVM is the following:\n\n```groovy\nimplementation 'cc.popkorn:popkorn-jvm:2.3.1'\nkapt 'cc.popkorn:popkorn-compiler:2.3.1'\n```\n\nWorking with Scopes and Environments\n--------\nScopes are the way to define the life span of an instance. There are 4 types of scopes:\n\n* Scope.BY_APP (default) -\u003e Instance will be created only once, for hence will live forever. Normally for classes that have heavy construction or saves states (Retrofit, OkHttp, RoomDB, etc)\n* Scope.BY_USE -\u003e Instance will be created if no one is using it, meaning will live as long as others are using it. Normally for classes that are just like helpers (dataSources, repositories, useCases, etc...)\n* Scope.BY_HOLDER -\u003e Instance will be created if used with a different holder, will live as long as its holder (container). Normally for instances that needs to be shared by a common parent (presenters, viewModels, etc...)\n* Scope.BY_NEW -\u003e Instance will be created every time it's needed, so won't live at all. Normally for instances that doesn't make sense to reuse (presenters, viewModels, screens, etc...)\n\nEnvironments allow you to have multiple instances of the same object, but in a complete different configuration. For example, you can have 2 different and persistent Retrofit instances. See more examples at bottom.\n\n```kotlin\nval r1 = inject\u003cRetrofit\u003e(\"pro\") // This will inject a persistent instance of Retrofit attached to \"pro\"\nval r2 = inject\u003cRetrofit\u003e(\"des\") // This will inject a persistent instance of Retrofit attached to \"des\"\n// r1 !== r2 as they have different environments.\n```\n\nInjecting Project Classes\n--------\nJust add `@Injectable` to any class...\n\n```kotlin\n@Injectable\nclass HelloWorld\n```\n\n...and inject it anywhere you want:\n\n```kotlin\nval helloWorld = inject\u003cHelloWorld\u003e()\n\n// Or by lazy\nval helloWorld by popkorn\u003cHelloWorld\u003e()\n```\n\nBy default `HelloWorld` will be Scope.BY_APP, but we can change it:\n\n```kotlin\n@Injectable(scope = Scope.BY_NEW)\nclass HelloWorld\n```\n\nAlso, if `HelloWorld` has injectable constructor dependencies, PopKorn will automatically resolve them\n\n```kotlin\n@Injectable\nclass HelloWorld(val helloBarcelona: HelloBarcelona, val helloParis: HelloParis)\n```\n\nand if we have different constructors for the class, we can define environments to distinguish them:\n\n```kotlin\n@Injectable\nclass HelloWorld {\n\n    @ForEnvironments(\"europe\")\n    constructor(val helloBarcelona: HelloBarcelona, val helloParis: HelloParis) : this()\n\n    @ForEnvironments(\"usa\")\n    constructor(val helloNewYork: HelloNewYork, val helloLosAngeles: HelloLosAngeles) : this()\n}\n```\n\nand then can inject it like this:\n\n```kotlin\nval helloWorld = inject\u003cHelloWorld\u003e() // Will inject a HelloWorld instance without parameters\nval helloWorld = inject\u003cHelloWorld\u003e(\"europe\") // Will inject a HelloWorld instance with parameters HelloBarcelona and HelloParis\nval helloWorld = inject\u003cHelloWorld\u003e(\"usa\") // Will inject a HelloWorld instance with parameters HelloNewYork and HelloLosAngeles\n```\n\n### Using Interfaces\n\nLet's now define an interface:\n\n```kotlin\ninterface Hello\n```\n\nand use it in our example\n\n```kotlin\n@Injectable\nclass HelloWorld : Hello\n```\n\nWe can now inject by an interface:\n\n```kotlin\nval helloWorld = inject\u003cHello\u003e() // This will inject a HelloWorld instance \n```\n\nAnd just like before, if you have different implementations of the same interface, you can distinguish them with environments\n\n```kotlin\n@Injectable\n@ForEnvironments(\"planet\")\nclass HelloPlanet : Hello\n```\n\nso,\n\n```kotlin\nval hello = inject\u003cHello\u003e(\"planet\") // This will return an instance of HelloPlanet\nval hello = inject\u003cHello\u003e() // This will return an instance of HelloWorld\n```\n\n### Using runtime arguments (or assisted dependencies)\n\nFor injectable classes with BY_NEW scope, you can have assisted arguments\n\n```kotlin\n@Injectable(BY_NEW)\nclass HelloViewModel(@Assisted val id: Long, val param2: HelloBarcelona, val param2: HelloNewYork) : Hello\n```\n\nthat you provide in runtime as:\n\n```kotlin\nval id = 4\nval hello = inject\u003cHello\u003e {\n    assist(id)\n}\n```\n\nInjecting External Classes\n--------\nIf you want to inject a class out of your code, just define a class and annotate it with `@InjectableProvider`. Notice that you can use as many injectable objects as you need defining them as parameters of your method.\n\n```kotlin\n@InjectableProvider(scope = Scope.BY_APP)\nclass MyRetrofitProvider {\n\n    fun createRetrofit(client: OkHttp): Retrofit {\n        return Retrofit.Builder()\n            .baseUrl(\"my.url\")\n            .client(client)\n            .build()\n    }\n}\n```\n\nand use it the same way:\n\n```kotlin\nval hello = inject\u003cRetrofit\u003e() // This will inject a persistent instance of Retrofit\n```\n\nInjecting Runtime Instances\n--------\nThere is also a way to use custom injection. You can take control of when an instance is injectable and when is not:\n\n```kotlin\nval someInstance = SomeType()\n\npopKorn().addInjectable(someInstance)\n\nval copy1 = inject\u003cSomeType\u003e() // Will inject someInstance\n\npopKorn().removeInjectable(someInstance)\n\nval copy2 = inject\u003cSomeType\u003e() // Will fail, because SomeType is not injectable anymore\n```\n\nIn Android this is very useful when injecting the Context (An instance that is provided and cannot be created)\n\n```kotlin\nclass MyApplication : Application() {\n\n    override fun onCreate() {\n        super.onCreate()\n        popKorn().addInjectable(this, Context::class)\n    }\n}\n```\n\nTesting\n--------\nPopKorn also offers the ability to create injectable classes at any time (ignoring its scope), overriding any dependency you like\n\n```kotlin\nclass Hello(val param: HelloBarcelona, val param: HelloParis)\n\nval hello = popKorn().create\u003cHello\u003e {\n    override(HelloTestBarcelona())\n}\n```\n\nThis will create a hello instance using HelloTestBarcelona instead of the default HelloBarcelona\n\nUsing Android / JVM\n--------\nPopKorn provides full support to Android platforms. You don't need to initialize anything. Just use it as described above.\n\nTo use it from pure java classes, use PopKornCompat:\n\n```java\nHelloWorld helloWorld = PopKornCompat.inject(HelloWorld.class);\n```\n\nTo prevent you to exclude lots of classes from obfuscation, PopKorn saves some mappings that needs to be merged when generating the APK. If you are using multiple modules, Android will take only the last one by default (\nor throw a compilation error depending on the Gradle version), unless the following option it's set in the `build.gradle`:\n\n```groovy\nandroid {\n    packagingOptions {\n        merge 'META-INF/popkorn.provider.mappings'\n        merge 'META-INF/popkorn.resolver.mappings'\n    }\n}\n```\n\nThis is the error that the above fixes:\n\n```text\nExecution failed for task ':app:mergeDebugJavaResource'.\n\u003e A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade\n   \u003e More than one file was found with OS independent path 'META-INF/popkorn.provider.mappings'\n```\n\nUsing IOS\n--------\nPopKorn provides full support to Objective C / Swift platforms. You will need to do the following:\n\nA) In your multiplatform project, write a File (Bridge.kt) on your IOS module and add this 2 functions:\n\n```kotlin\nfun init(creator: (ObjCClass) -\u003e Mapping) = cc.popkorn.setup(creator)\n\nfun getInjector() = InjectorObjC(popKorn())\n```\n\nB) From your IOS project you will need to initialize PopKorn at the beginning of your app (AppDelegate):\n\n```swift\nBridgeKt.doInit { (clazz) -\u003e PopkornMapping in\n            return clazz.alloc() as! PopkornMapping\n        }\n```\n\nC) To be used anywhere like this in ObjectiveC / Swift code\n\n```swift\nlet injector = BridgeKt.getInjector()\n\nlet helloWorld = injector.inject(clazz: HelloWorld.self) as! HelloWorld\n```\n\nYou can also use runtime injections\n\n```swift\nlet someInstance = SomeType()\n\ninjector.addInjectable(instance: someInstance, clazz: SomeType.self)\n\nlet copy1 = injector.inject(clazz: SomeType.self) as! SomeType // Will inject someInstance\n\ninjector.removeInjectable(clazz: SomeType.self)\n\nlet copy2 = injector.inject(clazz: SomeType.self) as! SomeType // Will fail, because SomeType is not injectable anymore\n```\n\nUsing JS / Native\n--------\nPopKorn provides basic support to JS / Native platforms. In your multiplatform project, write a File on your JS / Native module and add this function:\n\n```kotlin\nfun init() {\n    val resolvers: Set\u003cMapping\u003e = hashSetOf(/* LOCATE ALL RESOLVER CLASSES OF TYPE MAPPING THAT POPKORN AUTOGENERATED */)\n    val providers: Set\u003cMapping\u003e = hashSetOf(/* LOCATE ALL PROVIDER CLASSES OF TYPE MAPPING THAT POPKORN AUTOGENERATED */)\n    cc.popkorn.setup(resolvers, providers)\n}\n```\n\nthen call it somewhere to initialize PopKorn. For now, injections for JS / Native can only be done from your multiplatform project. Injections from JS / Native code is not yet available.\n\nMore Examples\n--------\nYou can find out more examples in popkorn-example project\n\n```kotlin\ninterface Location\n\n@Injectable\nclass RealLocation : Location {\n\n    constructor() : this() {\n        // Get LocationManager.GPS_PROVIDER\n    }\n\n    @ForEnvironments(\"network\")\n    constructor() : this() {\n        // Get LocationManager.NETWORK_PROVIDER\n    }\n}\n\n@Injectable(scope = Scope.BY_NEW)\n@ForEnvironments(\"fake\")\nclass FakeLocation : Location\n```\n\nand then\n\n```kotlin\nval r1 = inject\u003cLocation\u003e() // This will inject a persistent instance of RealLocation to get GPS locations\nval r2 = inject\u003cLocation\u003e(\"network\") // This will inject a persistent instance RealLocation to get Network locations\nval r2 = inject\u003cLocation\u003e(\"fake\") // This will inject a volatile instance of FakeLocation\n```\n\nor use it in any constructor of other injectable classes:\n\n```kotlin\nconstructor(real:Location, @WithEnvironment(\"fake\") fake:Location, @WithEnvironment(\"network\") network:Location) {}\n```\n\nLicense\n-------\n\n    Copyright 2019 Pau Corbella\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n    \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorbella83%2FPopKorn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcorbella83%2FPopKorn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorbella83%2FPopKorn/lists"}