Получить ApplicationContext из модуля KMM

#android #kotlin #kotlin-multiplatform #kotlin-native

#Android #kotlin #kotlin -мультиплатформенный #kotlin- родной

Вопрос:

В настоящее время я разрабатываю простой модуль KMM, который необходим Context для выполнения некоторых операций. Я знаю о способах достижения этого с помощью расширения Application класса и внедрения зависимостей. Что я пытаюсь сделать прямо сейчас — сделать этот модуль доступным из коробки без необходимости изменять manifest или вводить вручную при запуске. Мне просто интересно, является ли плохой практикой делать что-то подобное:

 @SuppressLint("StaticFieldLeak")
object SomeUtil {

    private val context = Activity().applicationContext

}
 

Поскольку applicationContext возвращает Context для всего приложения, и мы инициализируем его один раз, будет ли утечка? Или есть какие-то другие моменты, чтобы не делать этого?

Может быть, есть какие-то другие возможности для получения контекста приложения из модуля? Я видел несколько примеров извлечения его из потоков, но, насколько я понимаю, это будет (или уже) устаревшим.

UPD: это вызывает ошибку. Activity() кажется null , да. Итак, есть идеи, как добиться этого без DI и «MyApplication»?

Ответ №1:

Ну, я бы начал с того, что это на самом деле не вопрос KMM. Это относится только к коду Android.

Насколько я знаю, нет, нет способа статически глобально получить доступ к контексту приложения без некоторых полу-хакерских решений. Это давняя проблема, которая на самом деле не имеет хорошего решения.

Crashlytics делает (делал?) Что-то странное, регистрируя ContentProvider, единственная цель которого — получить приложение и сделать его доступным. Предполагая, что вы публикуетесь как aar, он зарегистрирует ContentProvider для вас.

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

Я бы не рекомендовал этого делать. Я очень предпочитаю настраивать инициализацию контекста библиотеки самостоятельно, но вы можете попробовать маршрут ContentProvider.

Комментарии:

1. Просматривая веб-страницы, я также обнаружил это , что также похоже на то, чего магглы не должны делать. Так что я тоже смотрю в DI, что немного разочаровывает

2. «Ну, я бы начал с того, что это на самом деле не вопрос KMM». Как наличие разных аргументов для разных платформ зависит от Android и не связано с KMM?

Ответ №2:

Это распространенная проблема в библиотеках Android — как получить контекст приложения, не имея доступа к кодовой базе приложения? Вот почему вы часто инициализируете библиотеки с помощью чего-то вроде SharedPrefHelper.init(applicationContext) в вашем Application.onCreate()

Поскольку общий код KMM является библиотекой, вы сталкиваетесь с аналогичной проблемой. Android app startup — это библиотека androidx, созданная для решения этой проблемы (а также для повышения производительности запуска).

Примерный пример (все в общем коде):

 // 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>

 

Ответ №3:

Короткий ответ: введите его в конструктор или как параметр метода:

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

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

Экземпляры контекста (а также Activity, Application, Service) создаются и уничтожаются Android Framework, и создание экземпляров вручную (или mocking), вероятно, будет работать во время компиляции, но они будут вызывать исключения во время выполнения