I’m looking for a multi-platform alternative to input streams. My concrete task is to fetch an encrypted file from a remote server via https and decrypt it on demand.
In Java land I would an implement InputStream
which proxies the reads to the input stream from the https library. How can I do the same in kotlin targeting multiple platforms.
I see ktor returns an ByteReadChannel, but I don’t know which functions.
I’m lost and don’t know where to start. Thanks for your help in advance.
With Kotlin Multiplatform, you can create different multiplatform projects for multiple platforms, including web, desktop, and other native platforms. Kotlin applications will work on different operating systems, such as macOS, Windows, Linux, Android, iOS, watchOS, and others.
We at Touchlab believe Kotlin Multiplatform is the tech stack of the future. For many platforms, but especially for native mobile.
This class allows an application to create an input stream in which the bytes read are supplied by the contents of a string. Known Indirect Subclasses.
If the framework you are using does not provide you with a full-fledged InputStream
implementation, the only chance left is to write your own. Much like what the ktor developers did: ByteReadChannel
is just an abstraction of "reading bytes from a channel".
This abstraction lives in the common part and allows to write application and business logic around it.
The key to make this work in the context of a Kotlin Multiplatform project is, the actual implementation needs to be provided in the platform specific parts. The JVM specific code of the ktor project actually has an implementation that uses InputStream
: InputStream.toByteReadChannel
.
You certainly don't have to do it like your example from the ktor project and model everything down from byte channels up to file representations. If you want to leverage Kotlin framework classes, Sequences might be handy. This could look something like this:
// in common
interface FileFetcher {
fun fetch(): Sequence<Byte>
}
expect fun fileFetcher(source: String): FileFetcher
// in jvm
class JvmFileFetcher(val input: java.io.InputStream): FileFetcher {
override fun fetch(): Sequence<Byte> = input.readBytes().asSequence()
}
actual fun fileFetcher(source: String): FileFetcher {
val input = java.net.URL(source).openStream()
return JvmFileFetcher(input)
}
You would define an interface FileFetcher
along with a factory function fileFetcher
in the common part. By using the expect
keyword on the fileFetcher
function you need to provide platform-specific implementations for all target platforms you define. Use the FileFetcher
interface in the common part to implement your logic (decrypting file contents etc.). See the documentation for Sequence
for how to work with it.
Then implement the factory function for all platforms and use the actual
keyword on them. You will then need to write platform-specific implementations of FileFetcher
. My example shows how a JVM version of the FileFetcher
interface.
The example is of course very basic and you probably would not want to do it exactly like this (at least some buffering would be needed, I guess). Also, within the JVM part you could also leverage your favorite networking/HTTP library easily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With