查看原文
其他

D-KMP 架构:声明式UI + Kotlin跨平台

AndroidPub 2022-07-13

作者 | Sahil Sharma
译者 | 不想翻身的鱼
原文 | https://juejin.cn/post/6955015172343726111

2020年不仅是疫情肆虐的一年,也是 APP 开发的过去和未来的分水岭。

1. D-KMP架构与声明式UI

2021,APP 的未来已经开始,那就是声明式UI和跨平台,它们将永远改变 APP 的架构模式和实现。

未来去创建一个多平台的有85%的共享代码的原生的UI的 APP 将会变得很正常,开发的生产力将大幅度提高,同时也能提高 APP 的质量。

本文将介绍主要的概念,以及它们是怎么优雅的组合到一起的。

过去

这里的过去说的是 APP 一直以来的开发方式:大部分公司都是各自平台开发应用(Android,iOS,Web),在客户端侧没有做代码共享。

为了控制在每个平台侧编写重复的代码,大部分应用倾向于“轻客户端”,将大部分的业务逻辑和数据处理放在唯一可以共享的服务端。

这种方式,服务端会变得“面向UI”。架构会被设计成这样:大部分点击都会触发一个API的调用,接口会返回下一个页面要展示的详细信息,这样一个非常有限的客户端逻辑。其他的客户端逻辑都需要在每个平台维护一套相同的代码,通常会避免这种情况,除非这些逻辑能带来比较有意义的客户体验。

对于客户端侧的共享代码,这些年已经有一些公司在尝试一些方法,但是对于大部分来说都是一次失败的历史,最终还是会把代码还原到只有原生或者平台特性的开发。被大家熟知的案例比如 DropBox(通过共享C++代码),AirBnB(通过RN共享)。换句话说,还没有一个合适的技术可以让这些公司可以实现一个长期安全的投入到共享代码。

未来

2020年,我们经历了两个重要范例增长,两个几乎是并行的:声明式UIKotlin跨平台。这会带来前所未有的机会,会让跨平台和客户端侧的代码共享变成APP开发的更倾向的选择。

声明式UI非常适合跨平台的架构,因为它们是无状态的而且可以做到跟业务逻辑完全解耦。通过把声明式UI和Kotlin跨平台组合到一起,我们可以安全的搭建一个有大量客户端侧共享代码的APP(高达85%),并且在各自原生平台有很高的性能。同时我们还能拥有各自平台原生的UI。

应用现在可以做到“富客户端”,因为客户端侧的逻辑成本不像以前那么高了,因为不再需要每个平台维护同一套逻辑了。应用会变得非常的灵活并且带来很多会给用户体验带来改善,减少用户在点完一个东西需要等待场景。

服务端可以变得完全是“UI无关的”并且集中精力在提供通用数据,删除所有的冗余逻辑,因为数据处理和格式化在客户端层就可以完成。这个同时也能很大程度提高数据吞吐量。

让我们一个个来看一下。首先让我们定义一下这个即将到来的APP开发新纪元的几个核心概念。

D-KMP 架构

未来应用的3个核心概念

  • 声明式UI(Android的Jetpack Compose,iOS的Swift UI)
  • KMP(Kotlin 跨平台)
  • MVI模式(Model-View-Intent)

我们称其为D-KMP架构,表示声明式UI和Kotlin跨平台。MVI模式是为了让两者配合起来更完美。

有一点很必须注意的是,现在展示的 D-KMP架构 是针对全新的项目。

我们讨论的不是往一个现有项目里面逐渐的引入声明式UI和Kotlin 跨平台。我们的目标是简洁的,健壮的,不会过时的的架构,而不会向过去妥协并且是基于创新的技术和范例来构建的。

还有一点需要强调的是 D-KMP 不是一个 lib 库,而是一个架构,完全依赖官方的 framework。

让我们详细的了解下这个架构三个核心的细节,首先看下声明式UI。

声明式UI已经开始在 Android 和 iOS 上发展了

差不多经过10多年,我们开始经历移动框架的非常重要的革命。Android 和 iO S都开始了各自新的UI工具集,并且都是声明式的,受到 React 和 Flutter 它俩的影响。它们将完全取代现有的各自系统定义视图的方式。

Google 在 2019 年的 Google I/O 大会上发布了 Jetpack Compose。2020年8月进入 Alpha 阶段,2021年春季进入 beta 阶段,预计2021年底能发布 1.0 版本。

Jetpack Compose 会支持 Android 5 以及以上的版本(target API 21)。这就意味着所有新的 Jetpack Compose 的 API 都是向后兼容的,而且不需要新的 Android 版本。这是因为在低版本上 Jetpack Compose 是直接在画布上进行绘制。

Apple 在2019年的 WWDC 上个发布了 Swift UI,随着iOS 13一起发布。今年随着iOS 14的发布已经做了很多改进。

跟 Jetpack Compose 不同的是,Swift UI 的更新是跟 iOS 系统绑定在一起的。新的 Swift UI API 不会向后兼容。但是考虑到所有支持 iOS 13的设备现在也支持 iOS 14(与往常不同,苹果今年没有弃用任何设备),可以很安全的在 target 是 iOS14 的应用使用 Swift UI。

为什么是声明式UI

Jetpack Compose 和 Swift UI 都是声明式UI的框架,它们只是用来表示不同状态下UI应该怎么样展示,而不是直接的管理状态。声明式UI变得越来越流行,也正是因为 React.js 和 Flutter 这来你给个框架,它俩让人们看到了跟无状态的组件交互是一件多么简单的事情。也正是它俩的成功,让 Android 和 iOS 加入到了声明式UI的世界。

使用 Jetpack Compose 你可以忘记 Android 笨重的视图系统和可怕的 Fragments。使用 Swift UI 你可以忘记 VC 这个 UI Kit 和不怎么灵活的 StoryBoard 。这是一个全新的开始。这就是未来!

声明式UI可以让UI布局和ViewModel进行一个彻底的分离,因为不再需要其他层额外的代码(使用findViewById和@IBOutlet)去把两者联系起来。

Jetpack Compose和Swift UI非常的相似。有一些琐碎的语法的(Jetpack Compose用的是Kotlin,Swift UI用的是Swift)以及导航模式不同,但是背后带理念都是一样的。尤其是数据是传递到这些无状态UI框架的方式完全是一样的。也正是因为这一点,ViewModel跟平台无关才显得有意义。后面我们会进一步聊下这方面具体的细节。

Web端的声明式UI

Web端最有名的声明式UI就是React.js(by Facebook),也是真正把声明式UI带向成功的框架。这是一个工业级改变的框架,如果没有React.js的成功,我们现在也可能在Android和iOS上用不了声明式UI。

Kotlin提供了对React.js非常方便的封装,我们可以使用Kotlin/React作为Web的声明式UI。它可以以插件的形式引入到我们的D-KMP架构,就跟Android上的Jetpack Compose和iOS上的Swift UI一样。

在Kotlin/React里面你可以引用所有已有的React.js的组件,可以用到Kotlin语言的相对于JS的优点。你也可以完全用Kotlin创建自定义的组件。可以到 Kotlin/React 文档了解详细的信息。

除了Kotlin/React以外,更有意思的可能就是Compose for Web,也就是Jetpack Compose的Web版本,目前JetBrains(Kotlin的创建者)正在开发。如果说用Kotlin/React 来实现UI还需要额外15%的工作量(相对于85%的KMP的共享代码),Compose for Web会使这块工作量少很多,因为它跟Android的Jetpack Compose非常像。因此我们非常期待它发布的那一天。

桌面端的声明式UI

在我们等待 web版本的同时,JetBrains 已经发布了桌面版的 Compose,可以用来开发 Windows,macOS 和 Linux 的桌面应用。

关于桌面端,值得注意的是 Swift UI 已经支持 macOS 了。用 Swift UI 编写的UI在 iOS,macOS,tvOS 和 watchOS 6 之间是无缝适配的。我们也期望 Jetpack Compose 早日实现多平台的无缝适配(Android,桌面和Web)。

可以想象一下,在不久的将来只要你会 Jetpack Compose 和 Swift UI 就能开发出各个平台非常优秀的应用。

为什么不是一套UI框架可以适配所有平台呢?

你可能在想会不会只有这么一套声明式UI框架可以适配所有的平台。

换句话说,Jetpack Compose 会不会最终适配所有苹果的系统(iOS,macOS,tvOS,watchOS),或者说 Swift UI 最终会不会适配非苹果的设备?

就目前而言,如果这个会发生的话,那也不会是苹果或者谷歌来做,可能是社区或者第三方来做的。我们已经看到 Jetpack Compose 已经被引入到桌面端和Web端,不是谷歌而是 JetBrains。

谷歌和苹果还是会集中精力到各自的系统上面。其实这样对UI的未来是非常健康的。这样就一直有两套独立强大的工具集相互竞争,不断创新。

2. Kotlin 跨平台和 MVI模式

1.4版本 Kotlin跨平台真的来了

随着2020年8月份Kotlin 1.4的发布,Kotlin跨平台已经不再是实验性阶段,已经是 Alpha 了。

现在,其实我们已经可以开始应用这项技术到我们的产品上了,虽然后面还会有一些改变和改进,但是目前的稳定性已经很好了。

如果目前还有什么会阻塞我们实现这个 D-KMP项目的话,它们都来自UI部分(Jetpack Compose还处在密切开发中,但是随着 Navigation 组件的发布已经越来越好了)而不是KMP的部分。

由于 Kotlin 在 JVM 社区的成功,2017年谷歌宣布将 Kotlin 作为 Android 第一支持的语言。2019年谷歌将 Kotlin 指定为 Android 开发的首选语言(取代了Java)。

现在 Kotlin 已经演进为一个跨平台的语言,拥有将代码编译到3个不同的平台:

  • JVM(Android和服务端)
  • Native(iOS、macOS,Window,Linux)
  • JavaScript(Web,同时提供对React封装)

正是因为这个,我们现在可以用Kotlin开发共享代码直接运行到各个平台上。

目前有两个不同首字母用到跨平台上面:

  • KMM = Kotlin Multiplatform Mobile(只是Android和iOS)
  • KMP = Kotlin Multiplatform(也包括桌面端和Web)

自从Kotlin 1.4开始,已经有一个固定的KMM的门户入口,专门用来说明怎么在移动端开发开始跨平台。对于不熟悉 Kotlin 跨平台的人来说是非常好的材料。

Kotlin 并不是唯一实现跨平台的编程语言。同时也是一个非常有趣的编程语言,同时避免了很多的模板代码。它有很多你能想象的高级特性:协程,可计算属性,属性委托,扩展函数,高阶函数,lambda等等。

Kotlin 很快的成为了一门主流的编程语言。用 Kotlin 写的代码肯定会持续数十年的。作为一个长期项目来用肯定是没问题的。

KMP vs Flutter vs ReactNative

当说起跨平台,2个主流的框架大家听的最多的可能是 FlutterReact Native ,这两个框架都可以让你进行共享代码,

同时你也可能听到大家不喜欢这些框架,因为它们限制了大家定制各个平台的原生UI。

Kotlin跨平台的到来,同时提供了这两个优点:

  • 在所有平台共享代码
  • 能自由的定制各个平台的UI

在 KMP 里面,共享的代码是用 Kotlin 写的,但是最终会编译成一个原生的库:Android 上是一个 jar包,iOS 上是一个 OC 的 framework,web 上是一个 js 的库。因为这样,原生的UI层在各自的平台上可以很自然和共享代码进行交互。

在 Flutter 里面,代码是用 Dart 来写的,最终会编译成一个原生的库,在 Android 上是通过 NDK,iOS上是 LLVM,Web 上是 JS。但是与 KMP 不同的是,Flutter 需要开启一个自己的引擎,会对包体积的影响比较大。Flutter 不使用原生的UI,它使用的是自己的声明式UI widget是通过 Skia 的图像引擎一个像素一个像素画出来的。这两年有很多人在用 Flutter,因为 Flutter 提供的声明式UI方式而不是传统的 Android 和 iOS 的 View。但是现在声明式的UI已经在 Android 和 iOS 的原生端开始加速支持了,这样 Flutter 的主要优势已经不在了。Jetpack Compose 和 SwiftUI 可以让你全速的构建一个顶级的APP。

在React Native,代码是用javascript写的,只能通过运行JS代码的C/C++桥跟native 层进行通信。UI的组件是对Android和iOS原生组件的封装,开发者对于UI的控制非常有限。RN整个的架构也证明性能不是特别好,甚至Facebook自己也慢慢的要放弃RN了。2018年AirBnB就宣布RN的时代结束了。

语言很重要:Kotlin vs Dart vs JavaScript

另外一个 KMP 相对于 Flutter 和 RN 的优势就是编程语言。与 Dart 和 JS 相比,Kotlin 是下一代顶级语言,它具有可靠性和简洁的特点。在 Kotlin 很轻松的就能写出高质量的代码,因为它具备了非常智能的特性,比如协程,可计算属性,高阶函数等等。

D-KMP架构下平台特有的代码只有15%

此时可能有人会认为 “好,我知道KMP很牛。我知道声明式UI最终会来到 Android 和 iOS 平台。但是这种方式我仍然还要给各自平台画UI,这也会造成很多重复工作!”

答案是“NO!并没有很多重复的工作”

在新的原生声明式UI平台下,UI层是非常轻的。在我们目前用 D-KMP 架构构建的 APP 里,从整个代码量来看UI层大约只占了15%的代码量。并且 UI 是所有的平台特有的代码,其他的全是 KMP 的共享代码。

这额外的15%的代码是完全值得的,因为它可以让我们给各个平台自由定制,而不是像 Flutter 和 RN 有很多的限制。Android 和 iOS 是两个不同的平台有很多的不同。一个顶级的 APP 需要保持各个平台真实的 UI/UX 模式的。

从我们的经验来看,一旦我们在 Android 端写了 Jetpack Compose 的 UI,就可以直接到 iOS 上 SwiftUI 实现出来。代码的结构几乎是一样的。对于一个简单的 APP,要不了一天时间。

在两个框架还有一些相同的组件,虽然名字不同。例如,你想要把多个文本水平放置在一个布局内,Android 端 Jetpack Compose 是 Row,iOS 端 SwiftUI 是 HStack,文本的组件在两个框架里面都是 Text,只是语法有点不一样。一旦你熟悉了这些小小的不同点,完成一端的声明式UI后,你可以快速复制到另外一个上面。

所有的数据都来自于页面的状态,由 KMP 共享的代码提供。在各自平台的声明式UI,只需要关心 view,其实是一个很轻的工作。

重要的是声明式UI不需要处理数据。啥也不用管直接展示就好。这也会大量减少平台相关的bug。

一旦共享的代码不担心bug,在各自平台上所有的事情就会推进的很顺利。这也是为什么不需要过于在意在各自平台上开发一套UI。

MVI模式:D-KMP架构的第三个核心

我们一开始就提到,MVI模式(代表Model-View-Intent) 是这个结构的第三个核心部分。背后主要的概念是单项数据流,这也是它跟之前的 MVC,MVP,MVVM 不同的地方。MVI 是响应式模式,让 APP 的行为更加的一致性和可预测性,你可以认为它是 MVVM 的演进。

在 MVI 模式下,View的状态只有唯一的可信数据源。任何时候状态都是有可变的数据组成,并且只能被 Model 修改。所有的事情都是单向的。用户触发了一个事件/intent。Model做出相应并执行一些操作之后改变状态。然后新的状态被反映到 View 上面。

在我们的 D-KMP 架构下,我们在 KMP 的共享代码里面实现 MVI 的 Model(可见下面的图)这个可以让我们在共享代码里面进行状态管理,这个非常重要!

也正是因为这样,我们平台特有的代码只是声明式 UI 的那一层,这一层是很轻的并且是无状态的,因为它完全把状态的管理委托给了 KMP 的 ViewModel。

3. D-KMP的分层和团队组织

D-KMP 架构下的 ViewModel 类

在我们的 D-KMP 架构下,ViewModel 是一个 Kotlin 跨平台的类,它有5个组件:

class DKMPViewModel(repo: Repository) {
    val stateFlow: StateFlow<AppState>
        get() = stateManager.mutableStateFlow
    private val stateManager by lazy { StateManager(repo) }
    val navigation by lazy { Navigation(stateManager) }
    val stateProvider by lazy { StateProvider(stateManager) }
    val events by lazy { Events(stateManager) }
}

简单的描述一下这几个组件。

StateFlow

ViewModel 里面的 StateFlow 是负责触发UI层进行重组的组件,每当它的值发生改变就会触发UI重组。

从上面的定义你可以发现,它的类型是一个叫 AppState 的数据类,定义的非常简单只持有了一个 recompositionIndex 的属性:

data class AppState (
    val recompositionIndex : Int = 0
)

StateFlow 是一个只读组件,从读/写版本中读取自己的值(通过一个getter的属性计算),MutableStateFlow 被定义为 StateManager 组件的一个属性。

StateManager

StateManager 是我们 ViewModel 的核心类。它管理者屏幕的状态和协程的scope。它还持有了 MutableStateFlow 这个负责修改 AppState 这个 StateFlow 的值然后触发UI的重组。

class StateManager(repo: Repository) {
  internal val mutableStateFlow = MutableStateFlow(AppState())
  val screenStatesMap : MutableMap<ScreenIdentifier, ScreenState> = mutableMapOf()
  val screenScopesMap : MutableMap<ScreenIdentifier,CoroutineScope> = mutableMapOf()
  
  internal val dataRepository by lazy { repo }
  fun triggerRecomposition() {
      mutableStateFlow.value = AppState(mutableStateFlow.value.recompositionIndex+1)
  }
}

Navigation

Navigation 被所有平台共享,很好的保证了多平台的一致性。也正是因为这个,不同平台的页面可以用几乎相同的语法来定义。下面贴上了我们实例工程 maste/detail 里面的的页面定义(github仓库的链接在本文最后)。

Compose上面(Kotlin):

SwiftUI上面(Swift):

StateProvider

StateProvider 给页面提供状态。UI重组的时候会调用,并且从 StateManager 的 screenStatesMap 里面获取数据。

...
  Screen.CountriesList -> CountriesListScreen (
    countriesListState = stateProviders.get(screenIdentifier)
    ...
  )
...

Events

Events 是定义在共享代码里面的函数,可以被各自平台的UI层调用。它们通常是执行一些能盖面APP状态的操作,然后触发新UI的重组。

...
  Screen.CountriesList -> CountriesListScreen (
      ...
      onFavoriteIconClick = { events.selectFavorite(countryName = it) }
  )
...

在文章的最后我贴了 github 仓库链接,可以把代码拉下来自己跑一下可能更容易理解这些组件。

ViewModel 文件的组织

平台特性代码

关于平台特性的代码,首先我们需要通过平台特性的工厂方法创建一个 DKMPViewModel 的实例。

在 Android 侧,需要把 applicationContext 作为参数传进去。因为在 Android 的框架下很多东西没有应用上下文无法工作,比如 sqlite 数据库。

DKMPViewModel.Factory.getAndroidInstance(context)

在iOS侧,我们不需要任何参数。

DKMPViewModel.Factory.getIosInstance()

收集数据流(StateFlow)

我们架构里面非常重要的一个一部分就是 StateFlow(跟平台无关的观察者),它可以通过监听 AppState 状态的变化,来触发UI层的重组(recomposition)。

在我们的框架里面你需要记住一点,AppState 就是一个 recompositionIndex 的值,每次 StateManager 调用 triggerRecomposition() 会让它的值加+1。

每次进行重组,UI 都能通过 StateProvider 拿到一个新的状态。

接下来我们看一下如何在各个平台上配置 StateFlow。

Android侧

在 Android 上使用 StateFlow 非常的直接,一行代码就能搞定。是因为 Android 团队已经实现了 StateFlow 里面的 collectAsState() 方法作为 Jetpack Compose 这个库的一部分。

lass DKMPApp : Application() {
    lateinit var model: DKMPViewModel
    override fun onCreate() {
        super.onCreate()
        model = DKMPViewModel.Factory.getAndroidInstance(this)
    }
}
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val model = (application as DKMPApp).model
        setContent {
            MyTheme {
                MainComposable(model)
            }
        }
    }
}
@Composable
fun MainComposable(model: DKMPViewModel) {
    val appState by model.stateFlow.collectAsState()
    val dkmpNav = appState.getNavigation(model)
    dkmpNav.Router()
}

iOS侧

目前在 iOS 上收集数据流还需要写一些模板代码,但是我们希望 JetBrains 能尽快优化一下。同时我们需要初始化一个“listener”在平台特性的ViewModel上:


class AppObservableObject: ObservableObject {
    let model : DKMPViewModel = DKMPViewModel.Factory().getIosInstance()
    var dkmpNav : Navigation {
        return self.appState.getNavigation(model: self.model)
    }
   @Published var appState : AppState = AppState()
    init() {
        model.onChange { newState in
            self.appState = newState
        }
    }
}
@main
struct iosApp: App {
    @StateObject var appObj = AppObservableObject()
    var body: some Scene {
        WindowGroup {
            MainView(appObj: appObj)
        }
    }
}
struct MainView: View {
    @ObservedObject var appObj: AppObservableObject
    var body: some View {
        let dkmpNav = appObj.dkmpNav
        dkmpNav.router()
    }
}

onChange 是作为一个扩展函数加到 ViewModel 上面,只有 iOS 需要。

fun DKMPViewModel.onChange(provideNewState: ((AppState) -> Unit)) : Closeable {
    val job = Job()
    stateFlow.onEach {
        provideNewState(it)
    }.launchIn(
        CoroutineScope(Dispatchers.Main + job)
    )
    return object : Closeable {
        override fun close() {
            job.cancel()
        }
    }
}

D-KMP数据层

在我们的 D-KMP 架构下,我们希望 ViewModel 和数据层是完全分离的。

数据层由 Repository 组成,Repository 从各种数据源获取数据,比如 webservice,运行时对象,平台配置,平台服务,sqlite 数据库,实时数据库,本地文件等等。

Repository 也负责管理本地的缓存机制,这样也能保证更好的做到只写一次,在各个平台上都能运行。不需要再各自平台再实现一遍。

Repository 的角色是负责处理数据然后将未经格式化的数据给 ViewModel,在 ViewModel 里面对数据进行格式化。

ViewModel 不需要关心数据源,数据源或者缓存都是由 Repository 来负责管理。

KMP库

在 KMP 里面,我们当然不能用平台特有的库。但是也不用担心,因为新的 KMP 库会比旧的库做的更好。有的完全是用 Kotlin 重写了,有的可能是底层对原生库的封装。不管怎么样,你可以不用关心它具体是怎么实现的。

下面这个面,总结一些重要库目前的KMP支持情况:

对于声明式UI,StateFlow 和 Coroutines。我们快速地过一下其他几个吧:

  • Ktor Http Client 由 JetBrains 开发,可以说是目前最好的 KMP 网路库。它在给各自平台封装了原生的Http client。
  • Serialization 由JetB开发,是一个非常简单的序列化数据的库。经常和 Ktor Http client 一起使用,用来解析JSON数据。
  • SqlDelight,由Square开发。提供跨平台的本地SQLite数据库解决方案。
  • 跨平台设置,由 Russell Wolf (TouchLab) 开发。Android侧是对 SharedPreferences 的封装,iOS 是 NSUserDefaults,JS 是 Storage。

除了已经存在的 KMP库,任何人都可以自己开发一个KMP的库。用 expect/actual 的特性来实现,这样就能将各自平台特性给封装起来。

有一些KMP库可能马上会发布:

  • Location,对 Android 和 iOS 定位服务 API 的封装。
  • In-App-Purchases,包装 Google Play 和 appStore 的 In-App-PurchasesAPI
  • Firebase,官方的KMP实现比如 Analytics,FireStore,Authentication 等。不过也不用担心已经有三方对整个 Firebase 做了封装。

现在让我们看一下 D-KMP架构下怎么来组织开发团队,其实跟传统的APP开发还是有比较大的不同的。我们有4个主要的角色:

  • 声明式UI 开发( JetpackCompose 和 SwiftUI )
  • ViewModel 开发(KMP)
  • 数据层开发(KMP)
  • 后端开发(Kotlin/JVM?Gloang?)

声明式UI开发

我们坚信在 D-KMP 的团队里面,UI开发应该是跨平台的,负责实现 Jetpack Compose 和 SwiftUI 的实现。考虑从到声明式UI框架的简单特点,同一个开发者来负责两端完全是可行的(也是有趣的)。聚焦到两个框架上,可以让开发者能更好的理解UI的发展趋势,以及实现更好的用户体验。

ViewModel 开发

这个角色非常重要,某种程度上需要承担一些管理的任务。是整个开发过程中的中心位置,需要对整个工程很了解。ViewModel 的开发者需要同UI开发者一起定义所有页面状态的对象,还要和数据层开发者一起定义需要的数据。同时 ViewModel 开发者还需要组织国际化的问题。

数据层(DataLayer)开发

这是一个对技术要求非常高的角色。数据层开发需要处理所有跟数据有关的东西,包括数据的缓存机制等等。数据开发需要组织好所有的数据,有时候甚至包括平台特性的数据源,比如定位或者蓝牙服务。这个角色需要对 Kotlin 跨平台非常熟悉,有时候设置需要写一些自定义的跨平台库。

后端(Backend)开发

在 D-KMP 的团队里面,这个角色仍然重要,因为需要和所有的app团队进行合作(Android,iOS,Web),但是又没有平台特性开发那么重要。在 D-KMP 架构下,后端开关直接和数据层开发打交道。数据层开发把 APP 需要哪些数据定好。后端开发不需要了解具体 APP层发生了什么。Webservice 可以用任意的语言开发,比如 Golang。如果你对Kotlin全栈感兴趣的话,也可以用 Ktor 这个框架,用的 Kotlin/JVM 技术。在服务端用 Kotlin 来写还有另外一个好处,可以让 APP 的数据层和服务端共用数据类的定义。

KMP 示例工程


-- End --


推荐阅读


加好友进交流群,技术干货聊不停



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存