从 KMM 模块获取 applicationContext

Posted

技术标签:

【中文标题】从 KMM 模块获取 applicationContext【英文标题】:Get applicationContext from a KMM module 【发布时间】:2021-05-21 23:51:27 【问题描述】:

我目前正在开发一个简单的 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 路由。

【讨论】:

在浏览网页时我还发现了this,这似乎也是麻瓜不应该做的事情。所以我也在看DI,有点失望【参考方案2】:

这是 android 库中的一个常见问题 - 如何在不访问应用程序代码库的情况下获取应用程序上下文?这就是为什么您经常在 Application.onCreate() 中使用 SharedPrefHelper.init(applicationContext) 之类的东西来初始化库

由于 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 框架创建和销毁,手动创建(或模拟)实例可能会在编译时起作用,但它们会在运行时引发异常

【讨论】:

以上是关于从 KMM 模块获取 applicationContext的主要内容,如果未能解决你的问题,请参考以下文章

KMM:如何将共享模块引用到现有的 iOS 项目中

KMM - 如何将改造添加到 :shared 模块 (commonMain)

如何在 KMM(kotlin 本机)共享模块中读取 Swift 框架库中生成的对象数组

Android Studio:KMM 项目的“共享”模块目录一直未被标记为源根目录

无法将 io.ktor 导入 Android Studio 中 KMM 的通用模块

KMM 入门处理多线程