kotlin跨平台
There are dozens of cross-platform technologies, which promise you "write-once run-anywhere" experience out of the box without any considerable drawbacks. But in the end, we all know it's not 100% true.
有数十种跨平台技术 ,这些技术可保证您立即“随处写一次”的体验,而没有任何明显的缺点。 但最终,我们都知道这不是100%正确。
To be honest, there are only a few viable solutions for cross-platform application development when it comes to the mobile world: React Native, Flutter and Kotlin Multiplatform.
坦白地说,在移动世界中,仅有几种可行的跨平台应用程序开发解决方案 : React Native , Flutter和Kotlin Multiplatform 。
The latter is the youngest player in the field, but the most promising one. It's super-flexible, concentrates on sharing business-logic, ensures native UI/UX, and enables native development experience.
后者是该领域中最年轻的球员,但最有前途的球员。 它非常灵活 ,专注于共享 业务逻辑 ,确保本机 UI / UX,并提供本机开发体验 。
In this article, I want to share our migration journey of native iOS and Android apps to Kotlin Multiplatform. I'll emphasize both, pros and cons, of chosen technology + some workarounds for bugs we've faced in the process.
在本文中,我想分享我们从本地iOS和Android应用到Kotlin Multiplatform的迁移过程 。 我要强调这两者对我们所面临的过程中的错误选择的技术的优劣 ,+一些解决方法。
简报 (Briefing)
Codeforces WatchR is an open-source mobile client for Codeforces platform, where thousands of programmers compete in weekly algorithmic challenges. There are both, iOS and Android apps, which are available in stores.
Codeforces WatchR是Codeforces平台的开源移动客户端,成千上万的程序员在每周的算法挑战中竞争。 商店中有iOS和Android应用程序。
![Image for post](https://miro.medium.com/max/9999/1*9RwXmlg5T8deqFZGbBgwfg.png)
Codeforces API is far from being mobile-first, so a lot of business-logic happens directly on devices, which includes, but not limited to — caching server data, merging data sets, extra-features not supported by the server.
Codeforces API远非移动优先,因此许多业务逻辑直接在设备上发生,包括但不限于-缓存服务器数据,合并数据集以及服务器不支持的其他功能。
This is the perfect use case for Kotlin Multiplatform, which allows sharing business-logic in the form of a library (Android) or framework (iOS) compiled to binaries, flawlessly executed by native platforms.
这是Kotlin Multiplatform的完美用例,它允许以编译为二进制文件的库 (Android)或框架 (iOS)的形式共享业务逻辑,并由本机平台完美地执行。
Migration has been done in multiple steps:
迁移已完成多个步骤:
Migration to SQLDelight (more details in this article)
迁移到SQLDelight ( 本文中的更多详细信息)
开始 (Starting)
We are huge fans of Redux pattern, which perfectly works with Kotlin Multiplatform. But unfortunately, the library we are used to (ReKotlin) hasn't been yet ported to KMP (you can't just use Android libs in KMP project).
我们是Redux模式的忠实拥护者,该模式可与Kotlin Multiplatform完美配合。 但是不幸的是,我们习惯使用的库( ReKotlin )尚未移植到KMP(您不能仅在KMP项目中使用Android库 )。
So along with the basic setup of modules and Gradle scripts, we were forced to copy/paste official ReKotlin code, which is thankfully 100% Kotlin without any dependency on Android-specific stuff. Publishing your own KMP library is a tedious task, so it was decided to go with the simplest solution.
因此,随着模块和Gradle 脚本 的 基本设置 ,我们被迫复制/粘贴官方ReKotlin代码,这是值得庆幸的是100%不Kotlin在Android上特有的东西,任何依赖。 发布自己的KMP库是一项繁琐的工作,因此决定采用最简单的解决方案。
I won't describe project setup in details, because there are already many great starter projects and articles on the topic. For example, KaMPKit from Touchlab or kotlin-multiplatform-template from Guillermo Orellana.
我不会详细描述项目设置,因为已经有很多关于该主题的入门项目和文章。 例如, KaMPKit从Touchlab或Kotlin-多模板的吉列尔莫·奥雷利亚纳 。
加速中 (Speeding up)
As mentioned previously, it's not possible to use Android libraries in KMP module out of the box, but there are already many alternatives, which have covered about 100% of our needs.
如前所述,无法在开箱即用的KMP模块中使用Android库,但是已经有许多 替代方案 ,它们满足了我们大约100%的需求。
Some of the core libraries are developed and supported by JetBrains, other ones — by the community. The full list of what's available up to date can be found here: https://github.com/AAkira/Kotlin-Multiplatform-Libraries.
一些核心库由JetBrains开发和支持,其他则由社区提供。 可以在此处找到最新可用内容的完整列表: https : //github.com/AAkira/Kotlin-Multiplatform-Libraries 。
KMP database library SQLDelight is probably one of the best solutions, which I worked with on Android. It allows you to write almost pure SQL code, which then used to generate 100% Kotlin class wrappers.
KMP数据库库SQLDelight可能是最好的解决方案之一,我在Android上使用它 。 它允许您编写几乎纯净SQL代码 ,然后用于生成100%Kotlin类包装器。
In our case, 100% of database code is written in a common module and shared between iOS / Android. Using Kotlin libraries in Swift has many caveats, so I would recommend to hide them behind your custom interfaces.
在我们的案例中, 数据库代码的100%编写在一个通用模块中,并在iOS / Android之间共享 。 在Swift中使用Kotlin库有很多警告,所以我建议将它们隐藏在自定义 界面的后面。
Ktor is a nice alternative to Retrofit even though it's quite different and you need to get used to it. But again, if you hide 3rd parties behind your custom interfaces (repository in this case), changing the networking library is an easy task.
Ktor是一个不错的选择 , 改造 ,即使它是相当不同的 ,你需要去适应它。 但是同样,如果您将第3方隐藏在自定义 界面 (在本例中为存储库)的后面,则更改网络库是一件容易的事。
突破 (Breakthrough)
Once the database and network levels were migrated to KMP, we had a chance to move the business-logic. With Redux all your business-logic should be located in Action or Request (for async code) classes.
一旦数据库和网络级别迁移到KMP,我们就有机会移动业务逻辑 。 使用Redux,您的所有业务逻辑都应位于Action或Request (用于异步代码)类中。
Not that easy! We actually needed to move all Redux to common module (store, state, middleware, etc.), not just actions. There we had some code relying on Android-specific classes, which took us a few days to decouple.
没那么容易! 实际上,我们需要将所有Redux移至通用模块(存储,状态,中间件等),而不仅仅是动作。 在那里,我们有一些代码依赖于Android特定的类 ,这花了我们几天的时间才解耦。
That's it! We've moved all we wanted to KMP module. It's time to bind shared code to iOS project: copy/paste it as sub-folder of Android app, configure Kotlin XCode Sync and CocoaPods Gradle plugins, import it in Swift. Voilà.
而已! 我们已经将所有想要的东西移到了KMP模块上。 现在是时候将共享代码绑定到iOS 项目 :将其复制/粘贴为Android应用的子文件夹 ,配置Kotlin XCode Sync和CocoaPods Gradle插件,将其导入Swift中。 Voilà。
打败?! (Defeat?!)
"Nothing works" was the first phrase I've heard from our iOS dev, which tried to reuse the common KMP module. I've checked and nothing really worked!
我没有从我们的iOS开发人员那里听到第一句话,它试图重用通用的KMP模块。 我检查了一下, 什么都没有 做 !
![Image for post](https://miro.medium.com/max/9999/1*HUcztOr1DNrsnRJltpZpyQ.png)
But why? What's a problem? Can we fix it?
但为什么? 怎么了 我们可以解决吗?
There were a few problems actually, which we were able to fix in 2 days:
实际上有一些问题 ,我们可以在两天内解决:
Kotlin/Native initialises global variables in alphabetical order, which is quite painful with Redux where you have store, middleware and reducers declared as global variables. As a workaround we needed to add
z
to package name ofstore
to make sure it's initialised in the last turn.Kotlin / Native 按字母 顺序初始化全局 变量 ,这对于Redux来说是很痛苦的,在Redux中,您将store , 中间件和reducer声明为全局变量。 作为一种解决方法,我们需要在
store
包名称中添加z
,以确保它在上一轮初始化。Changing context in coroutines didn't work, at least with a
CustomScope
from kotlin-multiplatform-template, which we used. Removed allwithContext
calls from the common code.至少在我们使用的kotlin-multiplatform-template中的
CustomScope
,无法在协程中更改上下文。 从通用代码中删除了所有withContext
调用。For some reason
===
didn't work as expected within Kotlin/Native, even though printed addressed were the same. Changed them to==
.由于某些原因
===
在Kotlin / Native中无法按预期工作,即使打印的地址相同。 将它们更改为==
。Kotlin libraries aren't accessible in iOS code, if you add them as
implementation
in KMP module, which is expected. But if you add them asapi
all classes are prefixed with library name to prevent name clashing.如果您将Kotlin库添加为KMP模块中的
implementation
,则无法在iOS代码中访问它们。 但是,如果将它们添加为api
所有类都以库名作为前缀,以防止名称冲突。But your own classes aren't prefixed and sometimes you are trying to use the wrong class from iOS framework.
Platform
is one of such examples, which we needed to use ascommon.Platform
at the end.但是您自己的类没有前缀,有时您尝试使用iOS框架中的错误类。
Platform
就是这样的例子之一,我们需要在最后使用它们作为common.Platform
。All classes should extend other classes or
Any
. Otherwise you will have messed up generics, which are limited even without this problem.所有类都应扩展其他类或
Any
。 否则,您将搞砸泛型,即使没有此问题,泛型也受到限制。
But at the end, it was rather the victory with a great benefit of consistency between our previously inconsistent apps.
但是最后,这是胜利 ,而我们以前不一致的应用程序之间的一致性带来了巨大的好处。
终点线 (Finish line)
![Image for post](https://miro.medium.com/max/9999/1*5gB66VqF5gWylJYyHJQ9Fg.png)
Kotlin Multiplatform is a young, but very promising technology, which can bring many advantages for your development team. But you need to make sure that you have enough time and knowledge to tackle challenges.
Kotlin Multiplatform是一项年轻但非常有前途的技术,可以为您的开发团队带来很多优势 。 但是,您需要确保您有足够的 时间和知识来应对挑战 。
Android dev experience won't be changed a lot. iOS devs will need some time to adapt, learn some Kotlin programming and dig deeper into how Kotlin -> ObjC -> Swift conversion works :)
Android 开发人员的 经验不会改变太多。 iOS 开发人员将需要一些时间来适应 , 学习 Kotlin编程并深入研究Kotlin-> ObjC-> Swift转换的工作方式:)
翻译自: https://medium.com/xorum-io/kotlin-multiplatform-ready-steady-40b5c48abda6
kotlin跨平台