我有一个管理器类,它有一个Android和iOS impl(来自第三方库)。“ex. MyManagerImpl()"。要构造第三方管理器,iOS不需要上下文,但Android需要。我创建了一个公共类“MyManager”,它提取了需要在commonMain中调用的所有公共方法。
//commonMain
expect class MyManager {
fun method1()
companion object Factory {
makeManager(): MyManager
}
}
val manager = MyManager.Factory.makeManager() // ex intended usage
//androidMain
MyManagerImpl(context: Context) {
fun method1()
}
actual class MyManager private constructor(manager: MyManagerImpl) {
..
actual companion object Factory {
override fun makeManager(): MyManager {
return MyManager(MyManagerImpl(?how to get context?))
}
}
}
//iosMain
MyManagerImpl() {
fun method1()
}
actual class MyManager private constructor(manager: MyManagerImpl) {
..
actual companion object Factory {
override fun makeManager(): MyManager {
return MyManager(MyManagerImpl())
}
}
}
合并两个实现的最干净的方法是什么?即使它们有不同的构造函数依赖关系,也有可能这样做吗?我们希望能够在commonMain中懒惰地构造类。这可能吗?
6条答案
按热度按时间dohp0rv51#
上下文的依赖注入
SQLDelight
SqlDriver
也有同样的问题,它需要Android上的上下文,但在iOS上不需要。使用Kodein-DI或Koin,通过使用上下文注入,无需任何混乱的静态变量就可以做到这一点。基本概念是expect/actual用于创建特定于平台的工厂类(
ManagerFactory
)。在Android上,
ManagerFactory
的actual
实现将上下文作为参数,可以从DI上下文中获取(对于Android上的Kodein-DI,请参见androidXModule
code和docs)。一旦在android和iOS DI模块中定义了工厂类,就可以在公共模块中注入/检索它,并将检索到的
MyManager
示例绑定到DI中,然后在需要时使用它。使用Kodein-DI时,它看起来如下所示:
公用主电源
机器人主页
iosMain
2mbi3lxu2#
一般来说,没有一种非常干净的方法可以做到这一点。没有办法从Android全局获取一个
Context
。虽然不太漂亮,但我会这样做:如果你想从任何代码调用它,在app start上初始化
Context
。在静态引用中保存它不会出现在每个人的最佳实践列表中,但这不是一个技术问题。或者,你可以用Activity
做类似的事情,但这有它自己的一系列问题。hfyxw5xn3#
下面是我们为数据库工厂解决这个问题所做的工作(没有依赖注入,因为我们还没有设置它):
我们在底层(没有其他依赖项)模块中创建了一个名为
AppContext
的类,在commonMain
中我们有expected
类:那么在
androidMain
中我们有:iosMain
的实现与commonMain
的实现相同,但使用了actual
(如果需要访问其他属性,可以执行与实际Android实现类似的操作):这里的关键是,它具有相同的
expected
和actual
构造函数,因此编译器认为它具有相同的签名并且是相同的类,但实际上,我们为Android
和iOS
公开了不同的实现。我们在应用程序启动时创建这个
AppContext
,并将其传递给 Bootstrap ,然后再传递给DbFactory
,这样我们就可以创建相应的数据库。以及
createSqlDriver
的expected
和actual
实现:commonMain
:androidMain
:iosMain
:yr9zkbsy4#
我们是这样做的(例如bundleId -也许它会帮助你):
安卓主界面:
IOS主界面:
izj3ouym5#
我想出了另一个"hacky"解决方案,它不需要静态引用:
然后,您必须将
PlatformDependencies
的示例与平台根gradle项目中的特定值绑定。拥有一个只包含特定于平台的deps的对象允许您使用它来构造DI模块层次结构中的任何依赖于平台的类。
它还远远谈不上优雅的解决方案,依赖于规则,并在一定程度上将平台的细节泄漏到一个公共代码中,但它是有效的。
chy5wohz6#
您可以在Android上使用App Startup Library获取Android特定代码中的上下文,而无需公开与iOS不同的API。
基本上,您可以将App Startup添加到Android模块依赖项中,在
AndroidManifest
中添加一个提供者条目,并实现Initializer
接口:Android将在应用启动时使用有效上下文自动调用create
方法。然后,您可以在需要时在任何地方使用
applicationContext
。