Kotlin Multiplatform 创建多平台分发库

目标:通过本教程学习如何使用 Kotlin Multiplatform Library 创建多平台分发库(iOS,安卓)。

创建一个项目

1、本教程使用的是Android Studio创建

2、选择 新建工程,选择 Kotlin Multiplatform Library

3、点击next 输入需要创建的项目名称以及存放的位置

4、点击next,输入要创建的库的名称,默认shared

建议都选上 测试单元。

到这项目基本创建完毕,开始进入编写分发库代码阶段。

编写跨平台代码

定义要在公共代码中实现的类和接口

1、在公共模块中创建一个目录 org.jetbrains.base64 用来存放编写代码

2、在新建目录下面创建 Base64.kt 文件

3、在新创建的的文件中定义 Base64Encoder 将字节转换为 Base64格式的接口

bash 复制代码
package org.jetbrains.base64

interface Base64Encoder {
    fun encode(src: ByteArray): ByteArray
}

4、定义对象 Base64Factory 作为公共代码 以提供接口实现实例 Base64Encoder的方式

bash 复制代码
expect object Base64Factory {
    fun createEncoder(): Base64Encoder
}

expext 是在跨平台代码中用到的关键字,被expext 关键字修饰的Base64Factory对象 。对于需要分发的平台,需要使用关键字 actual 关键字予以实现。

此时项目应该会爆红,因为在公共模块中使用关键字 expect 创建了对象,对应的分发平台还没实现,这时需要一一进行实现

提供对应平台代码实现

安卓平台

1、找到安卓模块在模块下面创建一个 org.jetbrains.base64 的新包

2、在新包里面创建 Base64.kt 文件

3、使用关键字 actual 实现公共模块声明的 Base64Factory对象方法

bash 复制代码
package com.example.myapplication.org.jetbrains.base64

import android.annotation.TargetApi
import android.os.Build
import java.util.*

actual object Base64Factory {
    actual fun createEncoder(): Base64Encoder = JvmBase64Encoder
}

object JvmBase64Encoder : Base64Encoder {
    @TargetApi(Build.VERSION_CODES.O)
    override fun encode(src: ByteArray): ByteArray = Base64.getEncoder().encode(src)
    
}

写到这安卓的代码以好,应为安卓可以直接使用api进行转换。

iOS平台

iOS在这方面比较吃亏没有现成的东西可以用,需要自己实现。

1、找到iOS模块,在模块下面创建一个org.jetbrains.base64包

2、在新包下面创建一个 Base64.kt文件

3、实现公共模块的代码

bash 复制代码
package com.example.myapplication.org.jetbrains.base64

private val BASE64_ALPHABET: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
private val BASE64_MASK: Byte = 0x3f
private val BASE64_PAD: Char = '='
private val BASE64_INVERSE_ALPHABET = IntArray(256) {
    BASE64_ALPHABET.indexOf(it.toChar())
}

private fun Int.toBase64(): Char = BASE64_ALPHABET[this]

actual object Base64Factory {
    actual fun createEncoder(): Base64Encoder = NativeBase64Encoder
}

object NativeBase64Encoder : Base64Encoder {
    // encode(src: ByteArray): ByteArray
    override fun encode(src: ByteArray): ByteArray {
        fun ByteArray.getOrZero(index: Int): Int = if (index >= size) 0 else get(index).toInt()
        // 4n / 3 is expected Base64 payload
        val result = ArrayList<Byte>(4 * src.size / 3)
        var index = 0
        while (index < src.size) {
            val symbolsLeft = src.size - index
            val padSize = if (symbolsLeft >= 3) 0 else (3 - symbolsLeft) * 8 / 6
            val chunk = (src.getOrZero(index) shl 16) or (src.getOrZero(index + 1) shl 8) or src.getOrZero(index + 2)
            index += 3

            for (i in 3 downTo padSize) {
                val char = (chunk shr (6 * i)) and BASE64_MASK.toInt()
                result.add(char.toBase64().code.toByte())
            }
            // Fill the pad with '='
            repeat(padSize) { result.add(BASE64_PAD.code.toByte()) }
        }

        return result.toByteArray()
    }

}

到此,公共模块,安卓模块以及iOS模块代码已经编写完毕。可以在测试类中测试刚才编写的代码。

在先写之前,将 encodeToString 方法添加到 默认实现Base64Encoder 的接口中,该方法 将字节数组转换成字符串,方便测试。

bash 复制代码
interface Base64Encoder {
    fun encode(src: ByteArray): ByteArray

    fun encodeToString(src: ByteArray): String {
        val encoded = encode(src)
        return buildString(encoded.size) {
            encoded.forEach { append(it.toInt().toChar()) }
        }
    }

}

公共模块

bash 复制代码
object JvmBase64Encoder : Base64Encoder {
    @TargetApi(Build.VERSION_CODES.O)
    override fun encode(src: ByteArray): ByteArray = Base64.getEncoder().encode(src)
    @TargetApi(Build.VERSION_CODES.O)
    override fun encodeToString(src: ByteArray): String = Base64.getEncoder().encodeToString(src)
}

安卓模块

bash 复制代码
object NativeBase64Encoder : Base64Encoder {
    // encode(src: ByteArray): ByteArray
    override fun encode(src: ByteArray): ByteArray {
        fun ByteArray.getOrZero(index: Int): Int = if (index >= size) 0 else get(index).toInt()
        // 4n / 3 is expected Base64 payload
        val result = ArrayList<Byte>(4 * src.size / 3)
        var index = 0
        while (index < src.size) {
            val symbolsLeft = src.size - index
            val padSize = if (symbolsLeft >= 3) 0 else (3 - symbolsLeft) * 8 / 6
            val chunk = (src.getOrZero(index) shl 16) or (src.getOrZero(index + 1) shl 8) or src.getOrZero(index + 2)
            index += 3

            for (i in 3 downTo padSize) {
                val char = (chunk shr (6 * i)) and BASE64_MASK.toInt()
                result.add(char.toBase64().code.toByte())
            }
            // Fill the pad with '='
            repeat(padSize) { result.add(BASE64_PAD.code.toByte()) }
        }

        return result.toByteArray()
    }

    // encodeToString(src: ByteArray): String
    override fun encodeToString(src: ByteArray): String {
        return super.encodeToString(src)
    }

}

iOS 模块

至此,用于测试转换以及各模块代码已经编写完毕。剩下的就是便携测试模块代码。

相关推荐
eqwaak01 分钟前
动态图表导出与视频生成:精通Matplotlib Animation与FFmpeg
开发语言·python·ffmpeg·音视频·matplotlib
刘新明19892 分钟前
Frida辅助分析OLLVM虚假控制流程(下)
java·开发语言·前端
2501_9151063219 分钟前
苹果软件加固与 iOS App 混淆完整指南,IPA 文件加密、无源码混淆与代码保护实战
android·ios·小程序·https·uni-app·iphone·webview
第二只羽毛24 分钟前
重载和继承的实践
java·开发语言
2501_9159214327 分钟前
iOS 26 崩溃日志解析,新版系统下崩溃获取与诊断策略
android·ios·小程序·uni-app·cocoa·iphone·策略模式
光军oi1 小时前
全栈开发杂谈————JAVA微服务全套技术栈详解
java·开发语言·微服务
帮帮志1 小时前
目录【系列文章目录】-(关于帮帮志,关于作者)
java·开发语言·python·链表·交互
qiuiuiu4131 小时前
正点原子RK3568学习日记-GIT
linux·c语言·开发语言·单片机
草莓熊Lotso1 小时前
《C++ STL list 完全指南:从基础操作到特性对比,解锁链表容器高效用法》
开发语言·c++·list
二王一个今2 小时前
Python打包成exe(windows)或者app(mac)
开发语言·python·macos