文章目录

  • 平台差异化代码的使用场景
    • 差异化代码的基本实现
  • Demo 及注意点
    • expect & actual 实现方式
      • 在 Common 中建立一个 expect 类或 Top-Level 方法
      • 完成 actual 实现
        • Android 示例:
        • iOS 示例:
    • 注入式实现
      • 定义
      • 注入实现
        • Android 示例:
        • iOS 示例:

平台差异化代码的使用场景

由于 KMM 运行在各平台时,实际上是翻译成了各平台专用的库,如:Android 上就会将共享模块编译成 Dalvik Bytecode 然后打包成 AAR 文件,而 iOS 上会打包成 Apple Framework,所以,一些平台相关的、不可共享的具体实现代码,就必须利用各平台的 API 来实现

举个简单的例子,公共模块有一个统一的业务逻辑——获取手机型号,控制逻辑可以在 KMM 的 common 代码库中实现,且它并不关系具体的实现逻辑,而实际需要获取手机型号字符串的方法,Android 需要调用 android.os.Build.MODEL 获取,而 iOS 需要通过 UIDevice.current.model 来获取

类似的平台强相关功能,就需要在 KMM 中利用平台差异化代码实现

差异化代码的基本实现

这里需要再次引用 Kotlin 官方的一张图

如图所示,在 KMM 中,Common 库中可以将需要差异化实现的 classfun 使用 expect 关键字修饰,expect 字面意思是:期望,这里代表需要各平台具体实现,之后在 Android、iOS 对应的库中,再使用 actual 关键字来创建对应的 classfun ,即可完成差异化代码的构建,在 App 中调用 Common 中使用 expect 修饰的内容时,将自动执行不同平台的 actual 内容

Demo 及注意点

expect & actual 实现方式

这种方式是官方推荐的一种平台差异化功能实现方式,实际操作时也比较简单

在 Common 中建立一个 expect 类或 Top-Level 方法

如图所示,创建 expect 类或方法,有点类似 Kotlin 和 Java 中的 interface

在完成基本的代码以后,此时可以看到 IDE 已经报错了,提示没有找到给 Android 使用的 JVM 实现,以及给 iOS 使用的 Native 实现

完成 actual 实现

此时不要使用 Option + Enter(Windows:Alt + Enter) 来靠 IDE 自动创建, 需要分别在 androidMain 和 iosMain 目录中,创建expect 内容包名、类名、方法签名(包括方法名、参数类型及名称)完全一致的 actual 内容,否则会报错

Android 示例:

// AndroidImpl.ktpackage com.coderyuan.myfirstkmmimport android.util.Logactual class PlatformSpecific {         actual fun method1(): String {             return "Android-Method1"    }    actual fun method2() {             println("Android-Method2")    }}actual fun platformTestFunc(v1: Int, v2: String) {         Log.i("Android-Func", "v1: $v1, v2: $v2")}

iOS 示例:

// iOSImpl.ktpackage com.coderyuan.myfirstkmmimport platform.Foundation.NSLogactual class PlatformSpecific {         actual fun method1(): String {             return "iOS-Method1"    }    actual fun method2() {             println("iOS-Method2")    }}actual fun platformTestFunc(v1: Int, v2: String) {         NSLog("iOS-Func: v1: %d, v2: %s", v1, v2)}

完成上面的双端功能实现以后,如果在 Android 或 iOS 主 App 中调用 Common 中的方法,将会执行各自实现的 actual 方法

注入式实现

除了官方的 expect & actual 实现模式,还可以使用类似 IoC 的注入式实现,我们可以利用 Interface 或 Block 的形式来让双端实现需要的差异化功能

如果使用过 Spring Framework 或 Dagger,此实现则不难理解

定义

首先,在 Common 中定义好需要注入的方法,可以使用接口或闭包,并使用单例来承载,如下代码所示:

// PlatformSpecificMgr.ktpackage com.coderyuan.myfirstkmmimport kotlin.native.concurrent.ThreadLocal// 单例注意使用 @ThreadLocal 注解,以便给 var 变量赋值@ThreadLocalobject PlatformSpecificMgr {         var ifuncImpl: IFunc? = null    var printLogBlockImpl: MyPrintLogBlock? = null}// 由于 iOS 端并不能为 object 生成类方法,所以需要单独写个 Top-Level 变量val sharedInstance = PlatformSpecificMgrinterface IFunc {         fun printLogMethod(tag: String, content: String)    fun printLogMethod(tag: String, ts: Long, content: String)}typealias MyPrintLogBlock = ((tag: String, type: Int, content: String) -> Unit)

注入实现

此时,我们需要在 Android 及 iOS App 主工程的代码中注入具体的实现

根据需要,选择合适的生命周期,也可以使用懒加载形式的注入,比如,在 Android App 的 Application 类中注入,在 iOS App 的 AppDelegate 类中注入

Android 示例:

// Android App 主工程中的 MyApplication.ktpackage com.coderyuan.myfirstkmm.androidimport android.app.Applicationimport android.util.Logimport com.coderyuan.myfirstkmm.IFuncimport com.coderyuan.myfirstkmm.PlatformSpecificMgrclass MyApplication: Application() {         override fun onCreate() {             super.onCreate()        PlatformSpecificMgr.ifuncImpl = object : IFunc {                 override fun printLogMethod(tag: String, content: String) {                     Log.i(tag, content)            }            override fun printLogMethod(tag: String, ts: Long, content: String) {                     Log.i(tag, "time: ${       ts}, $content")            }        }        PlatformSpecificMgr.printLogBlockImpl = {      tag: String, type: Int, content: String ->            Log.i(tag, "type: ${       type}, $content")        }    }}

iOS 示例:

////  AppDelegate.swift//  iosApp////  Created by yuanguozheng on 2021/5/28.//  Copyright © 2021 orgName. All rights reserved.//import Foundationimport UIKitimport sharedimport os.logclass MyAppDelegate: NSObject, UIApplicationDelegate {         func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {                     let mgr = PlatformSpecificMgr.init()        mgr.ifuncImpl = LogImpl.init()                mgr.printLogBlockImpl = {      (tag: String, type: KotlinInt, content: String) -> Void in            let log = String(format: "%@: %@, type: %d", tag, content, type.intValue)            print(log)        }                return true    }}class LogImpl : IFunc {         func printLogMethod(tag: String, ts: Int64, content: String) {             let log = String(format: "%@: %@, time: %l", tag, content, ts)        print(log)    }        func printLogMethod(tag: String, content: String) {             let log = String(format: "%@: %@", tag, content)        print(log)    }}

那么,在使用时,可以按照如下的代码进行调用

// Android 代码 或 Common 中调用// print a simple logPlatformSpecificMgr?.ifuncImpl?.printLogMethod("MyLog", "test")// print a simple logPlatformSpecificMgr?.ifuncImpl?.printLogMethod("MyLog", 1234567890 ,"test")// print a log with types by blockPlatformSpecificMgr?.printLogBlockImpl?.invoke("LogBlock", 1, "testBlock")

iOS 调用示例:

// print a simple logPlatformSpecificMgrKt.sharedInstance.ifuncImpl?.printLogMethod(tag: "AAA", content: "BBB")// print a log with types by blockPlatformSpecificMgrKt.sharedInstance.printLogBlockImpl?("CCC", 1, "ZZZ")

在 iOS 模拟器中运行一下,可以看到打出的 Log

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. python list.sort()根据多个关键字排序的方法实现
  3. android auto 能微信_5分钟搞定Flutter与Android(安卓)的交互(内
  4. Android(安卓)高工面试必考题(二):Android的事件分发机制设计与实现
  5. 【Android(安卓)UI设计与开发】第06期:底部菜单栏(一)使用TabActivi
  6. android 连接远程数据库
  7. Android高手进阶教程(二十五)之---Android(安卓)中的AIDL!!!
  8. 安卓(android)开发应该怎么学?需要哪些基础知识?
  9. Android(安卓)ROM研究---制作Nexus S上的ROM

随机推荐

  1. ANDROID NDK使用第三方静态库的方法
  2. ListView下拉刷新,上拉自动加载更多
  3. android 扫面无线网络
  4. android最简单的生成二维码demo
  5. Android 应用退出的几种方法
  6. 如何判断Edittext是否为空
  7. AndroidGUI14:各种Dialog常用技巧
  8. android Studio 低版本升级gradle3.0以上
  9. Android Sdcard 可用空间大小
  10. Android中如何使用基于回调的事件处理