Ver Fonte

[feat]键盘插件,对接Flutter的键盘列表API方法

hezihao há 8 meses atrás
pai
commit
790061ef44
19 ficheiros alterados com 445 adições e 157 exclusões
  1. 32 30
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/child/impl/KeyboardSelectComponent.kt
  2. 11 2
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/item/KeyboardSelectViewBinder.kt
  3. 18 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/constant/PluginConfig.kt
  4. 11 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/enums/FlutterMethod.kt
  5. 25 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/enums/KeyboardType.kt
  6. 1 105
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/keyboard/CustomKeyboardService.kt
  7. 31 10
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/model/KeyboardSelectModel.kt
  8. 14 2
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/mvvm/repository/KeyboardRepository.kt
  9. 25 1
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/mvvm/viewmodel/KeyboardViewModel.kt
  10. 34 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/JsonUtil.kt
  11. 0 7
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/BridgeManager.kt
  12. 48 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/FlutterBridgeManager.kt
  13. 11 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/IBridgeApi.kt
  14. 15 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/callback/NativeMethodHandler.kt
  15. 18 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/callback/ResultCallback.kt
  16. 17 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/model/CallResult.kt
  17. 17 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/model/CallResultList.kt
  18. 51 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/util/FlutterMethodCaller.kt
  19. 66 0
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/util/NativeMethodRegistry.kt

+ 32 - 30
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/child/impl/KeyboardSelectComponent.kt

@@ -19,6 +19,7 @@ import com.atmob.keyboard_android.model.KeyboardSelectModel
 import com.atmob.keyboard_android.util.KeyboardHolder
 import com.atmob.keyboard_android.util.recyclerview.GridDivider
 import com.blankj.utilcode.util.ConvertUtils
+import com.blankj.utilcode.util.ToastUtils
 import me.drakeet.multitype.Items
 import me.drakeet.multitype.MultiTypeAdapter
 
@@ -54,7 +55,7 @@ class KeyboardSelectComponent @JvmOverloads constructor(
         }
         vSaveBtn.click {
             val selectKeyboard =
-                mListItems.filterIsInstance<KeyboardSelectModel>().find { it.isSelected }
+                mListItems.filterIsInstance<KeyboardSelectModel>().find { it.isChoose }
             if (selectKeyboard == null) {
                 return@click
             }
@@ -76,12 +77,12 @@ class KeyboardSelectComponent @JvmOverloads constructor(
                     // 先全部取消选中,再选中当前设置的键盘
                     mListItems.forEachIndexed { index, item ->
                         if (item is KeyboardSelectModel) {
-                            item.isSelected = false
+                            item.isChoose = false
                         }
                     }
                     val targetPosition = mListItems.indexOf(item)
                     val targetItem = mListItems[targetPosition] as KeyboardSelectModel
-                    targetItem.isSelected = true
+                    targetItem.isChoose = true
                     notifyDataSetChanged()
                 })
             }
@@ -125,39 +126,40 @@ class KeyboardSelectComponent @JvmOverloads constructor(
     }
 
     /**
-     * 置ViewModel
+     * 置ViewModel
      */
+    @SuppressLint("NotifyDataSetChanged")
     private fun setupViewModel() {
+        KeyboardHolder.getKeyboardService()?.run {
+            getKeyboardViewModel().keyboardList.observe(getLifecycleOwner()) { newKeyboardList ->
+                mListItems.clear()
+
+                val emptyPlaceholderItemHeight = ConvertUtils.dp2px(60f - 16f)
+                // 添加空占位条目
+                mListItems.apply {
+                    add(EmptyPlaceholderModel(emptyPlaceholderItemHeight))
+                    add(EmptyPlaceholderModel(emptyPlaceholderItemHeight))
+                    add(EmptyPlaceholderModel(emptyPlaceholderItemHeight))
+                }
+                // 添加键盘数据
+                mListItems.addAll(newKeyboardList)
+
+                mListAdapter.notifyDataSetChanged()
+            }
+        }
     }
 
     @SuppressLint("NotifyDataSetChanged")
     private fun setData() {
-        // TODO: hezihao,加载键盘列表
-        val emptyPlaceholderItemHeight = ConvertUtils.dp2px(60f - 16f)
-        mListItems.apply {
-            // 添加空占位条目
-            add(EmptyPlaceholderModel(emptyPlaceholderItemHeight))
-            add(EmptyPlaceholderModel(emptyPlaceholderItemHeight))
-            add(EmptyPlaceholderModel(emptyPlaceholderItemHeight))
-            // 添加键盘条目
-            add(
-                KeyboardSelectModel(
-                    "",
-                    "通用键盘",
-                    isSelected = true,
-                    iconDefaultResId = R.mipmap.ic_common_keyboard_icon,
-                    isCommonKeyboard = true
-                )
-            )
-            add(KeyboardSelectModel("", "小蕊"))
-            add(KeyboardSelectModel("", "小胡"))
-            add(KeyboardSelectModel("", "自己&小蕊"))
-            add(KeyboardSelectModel("", "迪丽热巴"))
-            add(KeyboardSelectModel("", "哇咔咔"))
-            add(KeyboardSelectModel("", "小明"))
-            add(KeyboardSelectModel("", "小红"))
-            add(KeyboardSelectModel("", "龙哥"))
+        loadKeyboardList()
+    }
+
+    /**
+     * 加载键盘数据
+     */
+    private fun loadKeyboardList() {
+        KeyboardHolder.getKeyboardService()?.getKeyboardViewModel()?.getKeyboardList {
+            ToastUtils.showShort(it)
         }
-        mListAdapter.notifyDataSetChanged()
     }
 }

+ 11 - 2
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/component/item/KeyboardSelectViewBinder.kt

@@ -8,6 +8,7 @@ import android.widget.ImageView
 import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
 import com.atmob.keyboard_android.R
+import com.atmob.keyboard_android.enums.KeyboardType
 import com.atmob.keyboard_android.ext.click
 import com.atmob.keyboard_android.ext.loadUrlImage
 import com.atmob.keyboard_android.model.KeyboardSelectModel
@@ -32,11 +33,19 @@ class KeyboardSelectViewBinder(
         item: KeyboardSelectModel
     ) {
         val context = holder.itemView.context
-        holder.vIcon.loadUrlImage(item.icon, item.iconDefaultResId)
+
+        val isSystemKeyboard = KeyboardType.isSystem(item.type)
+        val iconDefaultResId = if (isSystemKeyboard) {
+            R.mipmap.ic_common_keyboard_icon
+        } else {
+            R.mipmap.ic_keyboard_default_icon
+        }
+
+        holder.vIcon.loadUrlImage(item.imageUrl, iconDefaultResId)
         holder.vName.text = item.name
 
         // 选中
-        if (item.isSelected) {
+        if (item.isChoose) {
             holder.itemContainer.setBackgroundResource(R.drawable.bg_keyboard_selected)
             holder.vName.apply {
                 setTextColor(context.resources.getColor(R.color.text_color_white))

+ 18 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/constant/PluginConfig.kt

@@ -0,0 +1,18 @@
+package com.atmob.keyboard_android.constant
+
+/**
+ * 插件配置
+ */
+interface PluginConfig {
+    companion object {
+        /**
+         * Flutter端引擎Id
+         */
+        const val FLUTTER_ENGINE_ID = "my_engine_id"
+
+        /**
+         * 通道名称,和Flutter端要一一对应
+         */
+        const val FLUTTER_METHOD_CHANNEL_NAME = "keyboard_android"
+    }
+}

+ 11 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/enums/FlutterMethod.kt

@@ -0,0 +1,11 @@
+package com.atmob.keyboard_android.enums
+
+/**
+ * Flutter方法名
+ */
+enum class FlutterMethod(val methodName: String) {
+    /**
+     * 获取键盘列表
+     */
+    GET_KEYBOARD_LIST("getKeyboardList")
+}

+ 25 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/enums/KeyboardType.kt

@@ -0,0 +1,25 @@
+package com.atmob.keyboard_android.enums
+
+/**
+ * 键盘类型
+ */
+enum class KeyboardType(val type: String) {
+    /**
+     * 系统键盘
+     */
+    SYSTEM("system"),
+
+    /**
+     * 自定义键盘
+     */
+    CUSTOM("custom");
+
+    companion object {
+        /**
+         * 是否系统键盘
+         */
+        fun isSystem(type: String): Boolean {
+            return SYSTEM.type == type
+        }
+    }
+}

+ 1 - 105
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/keyboard/CustomKeyboardService.kt

@@ -10,12 +10,7 @@ import com.atmob.keyboard_android.keyboard.ext.InputMethodLifecycleService
 import com.atmob.keyboard_android.mvvm.ViewModelManager
 import com.atmob.keyboard_android.mvvm.viewmodel.KeyboardViewModel
 import com.atmob.keyboard_android.util.ClipboardHelper
-import com.atmob.keyboard_android.util.InputMethodUtil
 import com.atmob.keyboard_android.util.KeyboardHolder
-import com.atmob.keyboard_android.util.LogUtil
-import io.flutter.embedding.engine.FlutterEngineCache
-import io.flutter.plugin.common.MethodCall
-import io.flutter.plugin.common.MethodChannel
 
 /**
  * 自定义键盘的输入法服务
@@ -23,21 +18,6 @@ import io.flutter.plugin.common.MethodChannel
 class CustomKeyboardService : InputMethodLifecycleService(), ICustomKeyboardService,
     ClipboardHelper.OnUserClipboardDataUpdateListener {
     /**
-     * 用于与 Flutter 端通信的 MethodChannel
-     */
-    private lateinit var mMethodChannel: MethodChannel
-
-    /**
-     * 保存键盘视图
-     */
-    private var vKeyboardView: View? = null
-
-    /**
-     * 存储按键映射
-     */
-    private var mKeyMappings: List<Pair<String, String>> = listOf()
-
-    /**
      * 键盘ViewModel
      */
     private val mKeyboardViewModel by lazy {
@@ -53,49 +33,16 @@ class CustomKeyboardService : InputMethodLifecycleService(), ICustomKeyboardServ
         super.onCreate()
         // 保存输入法Service的实例
         KeyboardHolder.attachKeyboardService(this)
-
-        val flutterEngine = FlutterEngineCache.getInstance().get("my_engine_id")
-        if (flutterEngine != null) {
-            mMethodChannel =
-                MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "keyboard_android")
-
-            // 设置 MethodChannel 的回调
-            mMethodChannel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
-                when (call.method) {
-                    "inputText" -> {
-                        val text = call.argument<String>("text")
-                        if (text != null) {
-                            InputMethodUtil.inputText(this.currentInputConnection, text)
-                        }
-                    }
-
-                    else -> {
-                        result.notImplemented()
-                    }
-                }
-            }
-        } else {
-            LogUtil.e("FlutterEngine 未找到,MethodChannel 无法初始化")
-        }
-
         // 监听用户的剪切板
         ClipboardHelper.registerClipboardListener(this)
     }
 
     override fun onCreateInputView(): View {
-        val keyboardView = layoutInflater.inflate(R.layout.keyboard_layout, null)
-        vKeyboardView = keyboardView
-
-        // 获取按键映射
-        fetchKeyMappings()
-
-        return keyboardView
+        return layoutInflater.inflate(R.layout.keyboard_layout, null)
     }
 
     override fun onStartInputView(info: EditorInfo?, restarting: Boolean) {
         super.onStartInputView(info, restarting)
-        // 重新获取按键映射
-        fetchKeyMappings()
     }
 
     override fun onDestroy() {
@@ -104,57 +51,6 @@ class CustomKeyboardService : InputMethodLifecycleService(), ICustomKeyboardServ
         ClipboardHelper.unRegisterClipboardListener(this)
     }
 
-    /**
-     * 通过 KeyboardAndroidPlugin 获取按键映射
-     */
-    private fun fetchKeyMappings() {
-        // 通过 methodChannel 获取按键映射
-        mMethodChannel.invokeMethod("getKeyMappings", null, object : MethodChannel.Result {
-            override fun success(result: Any?) {
-                // 如果获取成功,处理键映射
-                if (result is List<*>) {
-                    mKeyMappings = result.filterIsInstance<Map<String, String>>().map {
-                        it["label"]!! to it["method"]!!
-                    }
-                    LogUtil.d("按键映射获取成功: $mKeyMappings")
-                }
-            }
-
-            override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
-                LogUtil.d("获取按键映射失败: $errorMessage")
-            }
-
-            override fun notImplemented() {
-                LogUtil.d("Flutter 端未实现 getKeyMappings 方法")
-            }
-        })
-    }
-
-    /**
-     * 动态调用 Flutter 获取文本
-     *
-     * @param methodName 方法名
-     * @param currentContent 当前输入连接
-     */
-    private fun sendDynamicTextRequest(methodName: String, currentContent: String) {
-        mMethodChannel.invokeMethod(
-            "sendDynamicTextRequest",
-            mapOf("method" to methodName, "currentContent" to currentContent),
-            object : MethodChannel.Result {
-                override fun success(result: Any?) {
-                    LogUtil.d("sendDynamicTextRequest 请求已发送")
-                }
-
-                override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
-                    LogUtil.d("获取动态文本失败: $errorMessage")
-                }
-
-                override fun notImplemented() {
-                    LogUtil.d("Flutter 端未实现 sendDynamicTextRequest 方法")
-                }
-            })
-    }
-
     override fun getKeyboardWindow(): Window {
         return window!!.window!!
     }

+ 31 - 10
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/model/KeyboardSelectModel.kt

@@ -1,20 +1,41 @@
 package com.atmob.keyboard_android.model
 
-import com.atmob.keyboard_android.R
 import java.io.Serializable
 
 /**
  * 键盘选择模型
  */
 data class KeyboardSelectModel(
-    // 键盘图标Url
-    val icon: String,
-    // 键盘名称
+    /**
+     * 键盘Id
+     */
+    val id: String,
+    /**
+     * 键盘类型,system:系统键盘、custom:定制键盘
+     */
+    val type: String,
+    /**
+     * 键盘名称
+     */
     val name: String,
-    // 是否选中
-    var isSelected: Boolean = false,
-    // 键盘图标,默认资源Id,加载失败时使用
-    val iconDefaultResId: Int = R.mipmap.ic_keyboard_default_icon,
-    // 是否通用键盘
-    val isCommonKeyboard: Boolean = false
+    /**
+     * 性别
+     */
+    val gender: Int,
+    /**
+     * 生日
+     */
+    val birthday: String,
+    /**
+     * 亲密度
+     */
+    val intimacy: Int,
+    /**
+     * 键盘图标Url
+     */
+    val imageUrl: String,
+    /**
+     * 是否选中
+     */
+    var isChoose: Boolean = false
 ) : Serializable

+ 14 - 2
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/mvvm/repository/KeyboardRepository.kt

@@ -1,8 +1,20 @@
 package com.atmob.keyboard_android.mvvm.repository
 
+import com.atmob.keyboard_android.model.KeyboardSelectModel
+import com.atmob.keyboard_android.util.bridge.FlutterBridgeManager
+import com.atmob.keyboard_android.util.bridge.model.CallResultList
+
 /**
  * 键盘Repository
  */
-object KeyboardRepository {
-
+class KeyboardRepository {
+    /**
+     * 获取键盘列表
+     */
+    fun getKeyboardList(
+        onSuccess: (resultObj: CallResultList<KeyboardSelectModel>) -> Unit,
+        onFail: (msg: String) -> Unit
+    ) {
+        FlutterBridgeManager.getKeyboardList(onSuccess, onFail)
+    }
 }

+ 25 - 1
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/mvvm/viewmodel/KeyboardViewModel.kt

@@ -7,12 +7,19 @@ import com.atmob.keyboard_android.R
 import com.atmob.keyboard_android.enums.HelpMode
 import com.atmob.keyboard_android.enums.KeyboardGlobalType
 import com.atmob.keyboard_android.enums.Tab
+import com.atmob.keyboard_android.model.KeyboardSelectModel
+import com.atmob.keyboard_android.mvvm.repository.KeyboardRepository
 import com.atmob.keyboard_android.util.ContextUtil
 
 /**
  * 键盘ViewModel
  */
 class KeyboardViewModel : ViewModel() {
+    /**
+     * 仓库层
+     */
+    private val mKeyboardRepository = KeyboardRepository()
+
     // ----------------------------------- 响应式变量 -----------------------------------
 
     /**
@@ -77,7 +84,13 @@ class KeyboardViewModel : ViewModel() {
     private val _userClipboardData = MutableLiveData("")
     val userClipboardData: LiveData<String> = _userClipboardData
 
-    // ----------------------------------- 更新方法 -----------------------------------
+    /**
+     * 键盘列表数据
+     */
+    private val _keyboardList = MutableLiveData<List<KeyboardSelectModel>>()
+    val keyboardList: LiveData<List<KeyboardSelectModel>> = _keyboardList
+
+    // ----------------------------------- 更新状态方法 -----------------------------------
 
     /**
      * 更新,登录页,是否显示
@@ -148,4 +161,15 @@ class KeyboardViewModel : ViewModel() {
     fun updateUserClipboardData(newText: String) {
         _userClipboardData.value = newText
     }
+
+    // ----------------------------------- 获取业务数据方法 -----------------------------------
+
+    /**
+     * 获取键盘列表
+     */
+    fun getKeyboardList(onFail: (msg: String) -> Unit) {
+        mKeyboardRepository.getKeyboardList(onSuccess = {
+            _keyboardList.value = it.data
+        }, onFail)
+    }
 }

+ 34 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/JsonUtil.kt

@@ -0,0 +1,34 @@
+package com.atmob.keyboard_android.util
+
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+
+/**
+ * Json工具类
+ */
+class JsonUtil {
+    companion object {
+        private val sGson = Gson()
+
+        /**
+         * 解析Json为实体类
+         */
+        fun <T> parseJson(json: String): T {
+            return sGson.fromJson<T>(json, object : TypeToken<T>() {})
+        }
+
+        /**
+         * 解析Json为实体类
+         */
+        fun <T> parseJsonByClass(json: String, clazz: Class<T>): T {
+            return sGson.fromJson<T>(json, clazz)
+        }
+
+        /**
+         * 将对象,转为Json字符串
+         */
+        fun toJson(obj: Any): String {
+            return sGson.toJson(obj)
+        }
+    }
+}

+ 0 - 7
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/BridgeManager.kt

@@ -1,7 +0,0 @@
-package com.atmob.keyboard_android.util.bridge
-
-/**
- * 交互管理器,封装原生端和Flutter端的交互方法
- */
-class BridgeManager {
-}

+ 48 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/FlutterBridgeManager.kt

@@ -0,0 +1,48 @@
+package com.atmob.keyboard_android.util.bridge
+
+import com.atmob.keyboard_android.constant.PluginConfig
+import com.atmob.keyboard_android.enums.FlutterMethod
+import com.atmob.keyboard_android.model.KeyboardSelectModel
+import com.atmob.keyboard_android.util.bridge.model.CallResultList
+import com.atmob.keyboard_android.util.bridge.util.FlutterMethodCaller
+import com.atmob.keyboard_android.util.bridge.util.NativeMethodRegistry
+import io.flutter.embedding.engine.FlutterEngineCache
+
+/**
+ * 交互管理器,封装原生端和Flutter端的交互方法
+ */
+object FlutterBridgeManager : IBridgeApi {
+    /**
+     * 原生调Flutter
+     */
+    private val mFlutterMethodCaller = FlutterMethodCaller()
+
+    /**
+     * 暴露原生方法给Flutter调用
+     */
+    private val mNativeMethodRegistry = NativeMethodRegistry()
+
+    init {
+        val flutterEngine = FlutterEngineCache.getInstance().get(PluginConfig.FLUTTER_ENGINE_ID)
+        if (flutterEngine == null) {
+            throw IllegalArgumentException("FlutterEngine 未找到,MethodChannel 无法初始化")
+        }
+        mFlutterMethodCaller.init(flutterEngine)
+        mNativeMethodRegistry.init(flutterEngine)
+    }
+
+    override fun isLogin(): Boolean {
+        return false
+    }
+
+    override fun getKeyboardList(
+        onSuccess: (resultObj: CallResultList<KeyboardSelectModel>) -> Unit,
+        onFail: (msg: String) -> Unit
+    ) {
+        mFlutterMethodCaller.callMethod<CallResultList<KeyboardSelectModel>>(
+            FlutterMethod.GET_KEYBOARD_LIST.methodName,
+            onSuccess = onSuccess,
+            onFail = onFail
+        )
+    }
+}

+ 11 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/IBridgeApi.kt

@@ -1,5 +1,8 @@
 package com.atmob.keyboard_android.util.bridge
 
+import com.atmob.keyboard_android.model.KeyboardSelectModel
+import com.atmob.keyboard_android.util.bridge.model.CallResultList
+
 /**
  * 定义桥接交互API
  */
@@ -8,4 +11,12 @@ interface IBridgeApi {
      * 用户是否已登录
      */
     fun isLogin(): Boolean
+
+    /**
+     * 获取键盘列表
+     */
+    fun getKeyboardList(
+        onSuccess: (resultObj: CallResultList<KeyboardSelectModel>) -> Unit,
+        onFail: (msg: String) -> Unit
+    )
 }

+ 15 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/callback/NativeMethodHandler.kt

@@ -0,0 +1,15 @@
+package com.atmob.keyboard_android.util.bridge.callback
+
+/**
+ * 原生方法处理器,封装Flutter的调用
+ */
+interface NativeMethodHandler {
+    /**
+     * 方法被Flutter调用
+     *
+     * @param methodName 方法名
+     * @param args 方法参数
+     * @param resultCallback 回调结果
+     */
+    fun onMethodCall(methodName: String, args: String, resultCallback: ResultCallback)
+}

+ 18 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/callback/ResultCallback.kt

@@ -0,0 +1,18 @@
+package com.atmob.keyboard_android.util.bridge.callback
+
+/**
+ * 结果回调
+ */
+interface ResultCallback {
+    /**
+     * 回调Flutter端,处理成功
+     *
+     * @param data 返回给Flutter端的结果数据
+     */
+    fun onSuccess(data: Any)
+
+    /**
+     * 回调Flutter端,处理失败
+     */
+    fun onFail()
+}

+ 17 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/model/CallResult.kt

@@ -0,0 +1,17 @@
+package com.atmob.keyboard_android.util.bridge.model
+
+import java.io.Serializable
+
+/**
+ * 调用Flutter方法,通用结构
+ */
+data class CallResult<T>(
+    /**
+     * 响应码
+     */
+    val code: Int,
+    /**
+     * 响应数据
+     */
+    val data: T
+) : Serializable

+ 17 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/model/CallResultList.kt

@@ -0,0 +1,17 @@
+package com.atmob.keyboard_android.util.bridge.model
+
+import java.io.Serializable
+
+/**
+ * 调用Flutter方法,列表型,通用结构
+ */
+data class CallResultList<T>(
+    /**
+     * 响应码
+     */
+    val code: Int,
+    /**
+     * 响应数据
+     */
+    val data: List<T>
+) : Serializable

+ 51 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/util/FlutterMethodCaller.kt

@@ -0,0 +1,51 @@
+package com.atmob.keyboard_android.util.bridge.util
+
+import com.atmob.keyboard_android.constant.PluginConfig
+import com.atmob.keyboard_android.util.JsonUtil
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.MethodChannel
+
+/**
+ * Flutter方法调用者
+ */
+class FlutterMethodCaller {
+    /**
+     * 用于与 Flutter 端通信的 MethodChannel
+     */
+    private lateinit var mMethodChannel: MethodChannel
+
+    /**
+     * 初始化
+     */
+    fun init(engine: FlutterEngine) {
+        mMethodChannel = MethodChannel(
+            engine.dartExecutor.binaryMessenger,
+            PluginConfig.FLUTTER_METHOD_CHANNEL_NAME
+        )
+    }
+
+    /**
+     * 调用Flutter方法
+     */
+    fun <T> callMethod(
+        methodName: String, args: Any? = null,
+        onSuccess: ((resultObj: T) -> Unit)? = null,
+        onFail: ((msg: String) -> Unit)? = null
+    ) {
+        mMethodChannel.invokeMethod(methodName, args, object : MethodChannel.Result {
+            override fun success(result: Any?) {
+                val resultJson = result.toString()
+                val resultObj = JsonUtil.parseJson<T>(resultJson)
+                onSuccess?.invoke(resultObj)
+            }
+
+            override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
+                onFail?.invoke(errorMessage ?: "call error")
+            }
+
+            override fun notImplemented() {
+                onFail?.invoke("method not implemented")
+            }
+        })
+    }
+}

+ 66 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/bridge/util/NativeMethodRegistry.kt

@@ -0,0 +1,66 @@
+package com.atmob.keyboard_android.util.bridge.util
+
+import com.atmob.keyboard_android.constant.PluginConfig
+import com.atmob.keyboard_android.util.bridge.callback.NativeMethodHandler
+import com.atmob.keyboard_android.util.bridge.callback.ResultCallback
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import java.util.concurrent.ConcurrentHashMap
+
+/**
+ * 原生端方法注册表,提供方法给Flutter端
+ */
+class NativeMethodRegistry {
+    /**
+     * 注册表
+     */
+    private val mMethodMap = ConcurrentHashMap<String, NativeMethodHandler>()
+
+    /**
+     * 用于与 Flutter 端通信的 MethodChannel
+     */
+    private lateinit var mMethodChannel: MethodChannel
+
+    /**
+     * 初始化
+     */
+    fun init(engine: FlutterEngine) {
+        mMethodChannel = MethodChannel(
+            engine.dartExecutor.binaryMessenger,
+            PluginConfig.FLUTTER_METHOD_CHANNEL_NAME
+        )
+        // 注册方法给Flutter
+        mMethodChannel.setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
+            // 方法名
+            val methodName = call.method
+            // 方法参数
+            val args = call.arguments<String>() ?: ""
+            // 通过方法名,查找到方法处理器
+            val nativeMethodHandler = mMethodMap[methodName]
+            nativeMethodHandler?.onMethodCall(methodName, args, object : ResultCallback {
+                override fun onSuccess(data: Any) {
+                    result.success(data)
+                }
+
+                override fun onFail() {
+                    result.error("-1", "error", null)
+                }
+            })
+        }
+    }
+
+    /**
+     * 注册原生方法
+     */
+    fun registerNativeMethod(methodName: String, methodHandler: NativeMethodHandler) {
+        mMethodMap[methodName] = methodHandler
+    }
+
+    /**
+     * 取消注册原生方法
+     */
+    fun unRegisterNativeMethod(methodName: String) {
+        mMethodMap.remove(methodName)
+    }
+}