Description
PopKorn is a simple, powerful and lightweight Dependency Injector 100% Kotlin. It doesn't need any boilerplate, just use it
PopKorn alternatives and similar packages
Based on the "Kotlin" category.
Alternatively, view PopKorn alternatives based on common mentions on social networks and blogs.
-
CalendarView
A highly customizable calendar view and compose library for Android and Kotlin Multiplatform. -
Balloon
:balloon: Modernized and sophisticated tooltips, fully customizable with an arrow and animations for Android. -
kotlin-android-template
Android + Kotlin + Github Actions + ktlint + Detekt + Gradle Kotlin DSL + buildSrc = โค๏ธ -
NotyKT ๐๏ธ
๐ NotyKT is a complete ๐Kotlin-stack (Backend + Android) ๐ฑ application built to demonstrate the use of Modern development tools with best practices implementation๐ฆธ. -
Material Chip View
Material Chip view. Can be used as tags for categories, contacts or creating text clouds -
DrawableToolbox
๐ ๏ธ The missing drawable toolbox for Android. Create drawables programmatically and get rid of the boring and always repeated drawable.xml files. -
Navigation Toolbar for Android
:octocat: Navigation toolbar is a slide-modeled UI navigation controller made by @Ramotion -
Capturable
๐Jetpack Compose utility library for capturing Composable content and transforming it into Bitmap Image๐ผ๏ธ -
Pdf Viewer For Android
A Lightweight PDF Viewer Android library which only occupies around 80kb while most of the Pdf viewer occupies up to 16MB space. -
SSComposeCookBook
A Collection of major Jetpack compose UI components which are commonly used.๐๐๐ -
Carousel Recyclerview
Carousel Recyclerview let's you create carousel layout with the power of recyclerview by creating custom layout manager. -
Pluto Debug Framework
Android Pluto is a on-device debugging framework for Android applications, which helps intercept Network calls, capture Crashes & ANRs, manipulate application data on-the-go, and much more. -
CrunchyCalendar โ awesome calendar widget for android apps
A beautiful material calendar with endless scroll, range selection and a lot more! -
SSCustomBottomNavigation
Animated TabBar with native control and Jetpack Navigation support..โจ๐๐ -
Permission Flow for Android
Know about real-time state of a Android app Permissions with Kotlin Flow APIs. -
Only
:bouquet: An easy way to persist and run code block only as many times as necessary on Android. -
Nextflix-Composable
Includes jetpack compose, navigation, paging, hilt, retrofit, coil, coroutines, flow.. -
EasyPermissions-ktx
๐ Kotlin version of the popular google/easypermissions wrapper library to simplify basic system permissions logic on Android M or higher. -
Compose Compiler Reports to HTML Generator
A utility (Gradle Plugin + CLI) to convert Jetpack Compose compiler metrics and reports to beautified HTML page. -
MidJourney Images Compose Multiplatform Mobile Application
This application is developed to display the images created by MidJourney. The application is developed with Compose Multiplatform and works on many platforms including Android and iOS platforms. -
Events Calendar
Events Calendar is a user-friendly library that helps you achieve a cool Calendar UI with events mapping. You can customise every pixel of the calendar as per your wish and still achieve in implementing all the functionalities of the native android calendar in addition with adding dots to the calendar which represents the presence of an event on the respective dates. It can be done easily, you are just a few steps away from implementing your own badass looking Calendar for your very own project! -
FlowMVI
A Kotlin Multiplatform MVI library based on coroutines with a rich DSL and a powerful plugin system. -
SSCustomEditTextOutLineBorder
Same as the Outlined text fields presented on the Material Design page but with some dynamic changes. ๐ ๐ -
TimelineView
A customizable and easy-to-use Timeline View library for Android. Works as a RecyclerView decorator (ItemDecoration)
InfluxDB - Purpose built for real-time analytics at any scale.
Do you think we are missing an alternative of PopKorn or a related project?
README
PopKorn - Kotlin Multiplatform DI
PopKorn is a simple, powerful and lightweight Multiplatform Dependency Injector written 100% Kotlin. It doesn't need any boilerplate, just use it! It supports AND, IOS, JVM, JS and NATIVE.
Download
Get it with Gradle:
implementation 'cc.popkorn:popkorn:2.0.0'
kapt 'cc.popkorn:popkorn-compiler:2.0.0'
The 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:
implementation 'cc.popkorn:popkorn-jvm:2.0.0'
kapt 'cc.popkorn:popkorn-compiler:2.0.0'
Working with Scopes and Environments
Scopes are the way to define the life span of an instance. There are 3 types of scopes:
- Scope.BY_APP (default) -> 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)
- Scope.BY_USE -> 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...)
- Scope.BY_NEW -> 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, screens, etc...)
Environments 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.
val r1 = inject<Retrofit>("pro") //This will inject a persistent instance of Retrofit attached to "pro"
val r2 = inject<Retrofit>("des") //This will inject a persistent instance of Retrofit attached to "des"
//r1 !== r2 as they have different environments.
Injecting Project Classes
Just add @Injectable
to any class...
@Injectable
class HelloWorld
...and inject it anywhere you want:
val helloWorld = inject<HelloWorld>()
or
val helloWorld:HelloWorld = inject()
or
val helloWorld = HelloWorld::class.inject()
By default HelloWorld
will be Scope.BY_APP, but we can change it:
@Injectable(scope=Scope.BY_NEW)
class HelloWorld
Also, if HelloWorld
has injectable constructor dependencies, PopKorn will automatically resolve them
@Injectable
class HelloWorld(val helloBarcelona:HelloBarcelona, val helloParis:HelloParis)
and if we have different constructors for the class, we can define environments to distinguish them:
@Injectable
class HelloWorld {
@ForEnviornmen("europe")
constructor(val helloBarcelona:HelloBarcelona, val helloParis:HelloParis):this()
@ForEnviornmen("usa")
constructor(val helloNewYork:HelloNewYork, val helloLosAngeles:HelloLosAngeles):this()
}
and then can inject it like this:
val helloWorld = inject<HelloWorld>() // will inject a HelloWorld instance without parameters
val helloWorld = inject<HelloWorld>("europe") // will inject a HelloWorld instance with parameters HelloBarcelona and HelloParis
val helloWorld = inject<HelloWorld>("usa") // will inject a HelloWorld instance with parameters HelloNewYork and HelloLosAngeles
Using Interfaces
Let's now define an interface:
interface Hello
and use it in our example
@Injectable
class HelloWorld : Hello
We can now inject by an interface:
val helloWorld = inject<Hello>() //This will inject a HelloWorld instance
And just like before, if you have different implementations of the same interface, you can distinguish them with environments
@Injectable
@ForEnvironment("planet")
class HelloPlanet : Hello
so,
val hello = inject<Hello>("planet") // this will return an instance of HelloPlanet
val hello = inject<Hello>() // this will return an instance of HelloWorld
Injecting External Classes
If 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.
@InjectableProvider(scope=Scope.BY_APP)
class MyRetrofitProvider {
fun createRetrofit(client : OkHttp) : Retrofit{
return Retrofit.Builder()
.baseUrl("my.url")
.client(client)
.build()
}
}
and use it the same way:
val hello = inject<Retrofit>() //This will inject a persistent instance of Retrofit
Injecting Runtime Instances
There is also a way to use custom injection. You can take control of when an instance is injectable and when is not:
val someInstance = SomeType()
popKorn().addInjectable(someInstance)
val copy1 = inject<SomeType>() //Will inject someInstance
popKorn().removeInjectable(someInstance)
val copy2 = inject<SomeType>() //Will fail, because SomeType is not injectable anymore
In Android this is very useful when injecting the Context (An instance that is provided and cannot be created)
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
popKorn().addInjectable(this, Context::class)
}
}
Using Android / JVM
PopKorn provides full support to Android platforms. You don't need to initialize anything. Just use it as described above.
To use it from pure java classes, use PopKornCompat:
HelloWorld helloWorld = PopKornCompat.inject(HelloWorld.class);
To 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 (or throw a compilation error depending on the Gradle version), unless the following option it's set in the build.gradle
:
android{
packagingOptions {
merge 'META-INF/popkorn.provider.mappings'
merge 'META-INF/popkorn.resolver.mappings'
}
}
This is the error that the above fixes:
Execution failed for task ':app:mergeDebugJavaResource'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
> More than one file was found with OS independent path 'META-INF/popkorn.provider.mappings'
Using IOS
PopKorn provides full support to Objective C / Swift platforms. You will need to do the following:
A) In your multiplatform project, write a File (Bridge.kt) on your IOS module and add this 2 functions:
fun init(creator:(ObjCClass)-> Mapping) = cc.popkorn.setup(creator)
fun getInjector() = InjectorObjC(popKorn())
B) From your IOS project you will need to initialize PopKorn at the beginning of your app (AppDelegate):
BridgeKt.doInit { (clazz) -> PopkornMapping in
return clazz.alloc() as! PopkornMapping
}
C) To be used anywhere like this in ObjectiveC / Swift code
let injector = BridgeKt.getInjector()
let helloWorld = injector.inject(clazz: HelloWorld.self) as! HelloWorld
You can also use runtime injections
let someInstance = SomeType()
injector.addInjectable(instance: someInstance, clazz: SomeType.self)
let copy1 = injector.inject(clazz: SomeType.self) as! SomeType //Will inject someInstance
injector.removeInjectable(clazz: SomeType.self)
let copy2 = injector.inject(clazz: SomeType.self) as! SomeType //Will fail, because SomeType is not injectable anymore
Using JS / Native
PopKorn provides basic support to JS / Native platforms. In your multiplatform project, write a File on your JS / Native module and add this function:
fun init(){
val resolvers: Set<Mapping> = hashSetOf(/* LOCATE ALL RESOLVER CLASSES OF TYPE MAPPING THAT POPKORN AUTOGENERATED */)
val providers: Set<Mapping> = hashSetOf(/* LOCATE ALL PROVIDER CLASSES OF TYPE MAPPING THAT POPKORN AUTOGENERATED */)
cc.popkorn.setup(resolvers, providers)
}
then 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.
More Examples
You can find out more examples in popkorn-example project
interface Location
@Injectable
class RealLocation:Location{
constructor():this(){
//get LocationManager.GPS_PROVIDER
}
@ForEnvironemnt("network")
constructor():this(){
//get LocationManager.NETWORK_PROVIDER
}
}
@Injectable(scope=Scope.BY_NEW)
@ForEnvironment("fake")
class FakeLocation:Location
and then
val r1 = inject<Location>() //This will inject a persistent instance of RealLocation to get GPS locations
val r2 = inject<Location>("network") //This will inject a persistent instance RealLocation to get Network locations
val r2 = inject<Location>("fake") //This will inject a volatile instance of FakeLocation
or use it in any constructor of other injectable classes:
constructor(real:Location, @WithEnvironment("fake") fake:Location, @WithEnvironment("network") network:Location){}
License
Copyright 2019 Pau Corbella
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*Note that all licence references and agreements mentioned in the PopKorn README section above
are relevant to that project's source code only.