简体   繁体   中英

Get applicationContext from a KMM module

I'm currently developing a simple KMM module, which needs Context in order to perform some operations. I am aware of ways to achieve that with extending Application class and making dependency injection. What am I trying to do right now - to make this module available out of the box with no need to modify manifest or make manual injection on start up. I am just wondering is it a bad practice to make something like so:

@SuppressLint("StaticFieldLeak")
object SomeUtil {

    private val context = Activity().applicationContext

}

Since applicationContext return the Context for the whole app and we're initializing it once will there be a leak? Or are there some other points not to make it?

Maybe there are some other possibilities to get app context from the module? I've seen some examples of retrieving it from threads, but as I understand this will be (or is already) deprecated.

UPD: This causes an error. Activity() seems to be null . So any ideas how to achieve that without DI and "MyApplication"?

Well, I'd start with saying this isn't really a KMM question. This only applies to the Android code.

As far as I know, no, there's no way to statically, globally get access to the application context without some semi-hacky solutions. This is a long standing problem that doesn't really have a good solution.

Crashlytics does (did?) something weird by registering a ContentProvider who's only purpose is to get the application and make that available. Assuming you're publishing as an aar, it would register the ContentProvider for you.

https://firebase.googleblog.com/2016/12/how-does-firebase-initialize-on-android.html

I wouldn't recommend that. I greatly prefer configuring library context init myself, but you can try the ContentProvider route.

Short answer: Inject it in constructor or as method param:

class SomeUtil(private val context: Context) {
   ....
}

object SomeUtil {
   fun someMethod(context: Context) { .... }
}

Context (but also Activity, Application, Service) instances are created and destroyed by Android framework and creating instances manually (or mocking) will probably work at compile time, but they will cause exceptions at runtime

This is a common problem in android libraries - how to get the app context without having access to the application codebase? It's why you often init libraries with something like SharedPrefHelper.init(applicationContext) in your Application.onCreate()

As KMM shared code is a library you get a similar problem. Android app startup is an androidx lib built to solve this (as well as improving startup performance).

Rough sample (everything in shared code):

// In androidMain
class MySqlDelightInitialiser : Initializer<SqlDriver> {
    override fun create(context: Context): SqlDriver {
        val driver = createDriver(context)
        MyLibraryObject.init(context, driver)
        return driver
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return emptyList()
    }
}

// In androidMain/AndroidManifest
<application>
    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.sql-delight-initialiser"
        android:exported="false"
        tools:node="merge"
        tools:replace="android:authorities"
        >
        <meta-data
            android:name="my.package.SqlDelightInitialiser"
            android:value="androidx.startup"
            />
    </provider>
</application>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM