手撸一个Flutter插件实现跨苹果全家桶云同步持久化Key Value数据

前言
作为一个客户端开发者,后端开发一直是我的弱项 。虽然GPT的横空出世,让我对后端的开发有一点眉目 。但是现实是,能不触碰就不触碰,因为人的精力是有限,如何在有限的时间里发挥最大的作用一直是我的一个追求 。所以回到本次主题,我自己上线的一个产品,目前已经成功上线了iOS以及Mac端,如何在不开发后端的情况下实现同步轻量级数据呢?答案是利用Cloud Kit 。Cloud Kit是苹果官方API,用于同步同意账号下设备的数据,包括Key Value 、云、云等等 。通过翻阅pub类似的库,我发现了有以下几个pub包是可以参考的、,但是他们都不是我想要的,要么是不支持Mac、要么是只能同步存储文件,但是我想要同步的其实只是轻量级持久化数据(也是就是iOS下的,基于键值存储) 。所以没办法了,肝了一晚上我手撸了一个插件,完美的支持了跨苹果设备iOS、Mac、iPad等的轻量级Key Value数据同步 。
开发过程全解析
如何创建插件虽然已经很简单,这里我还是点一下 。
flutter create icloud_kv_storage -t plugincd ./icloud_kv_storage//指定platformsflutter create ./ -t plugin --platforms iosflutter create ./ -t plugin --platforms macos
由于是肝了一晚上的产品,非常赶,第一版先只支持同步数据,后续再支持别的基础数据,如int、、bool等 。
///获取真正的Key,我内部Key都加了flutter前缀,如果要拿真实的Key可以使用此方法String getRealKey(String key) {throw UnimplementedError('getRealKey()) has not been implemented.');}///原生的CallBack 用于实时刷新数据(如果多台苹果设备都在线,支持实时同步void setNativeCallBack({required GetNativeCallBackFuture onCallBack}) {}///保存数据接口,这里用范型方便后续拓展,虽然第一版只支持StringFuture write({required String key,required T value}) {throw UnimplementedError('write({required String key,required String value}) has not been implemented.');}///读取一个Key的数据接口,同理也是范型Future read({required String key}) {throw UnimplementedError('read({required String key}) has not been implemented.');}///删除一个keyFuture delete({required String key}) {throw UnimplementedError('delete({required String key}) has not been implemented.');}
iOS和Mac实际都是共用框架,所以我们只需要编写同一套Swift实现,即可同时满足iOS以及Mac 。
1.首先定义实现协议
enum CKCommandType: String {case DELETE_VALUEcase GET_VALUEcase SAVE_VALUEcase EMPTY = ""}protocol CKCommandHandlerProtocol {var COMMAND_NAME: CKCommandType { get }func evaluateExecution(command: String) -> Boolfunc handle(command: String, arguments: Dictionary, result: @escaping FlutterResult) -> Void}
2.实现增删改查对应的协议
查询一个key对应的协议实现
class CKGetValueHandler: CKCommandHandlerProtocol {var COMMAND_NAME: CKCommandType = .GET_VALUEfunc evaluateExecution(command: String) -> Bool {return CKCommandType(rawValue: command) == COMMAND_NAME}func handle(command: String, arguments: Dictionary, result: @escaping FlutterResult) {if (!evaluateExecution(command: command)) {return}if let key = arguments["key"] as? String {let store = NSUbiquitousKeyValueStore.defaultresult(store.object(forKey: key))} else {result(FlutterError.init(code: "Error", message: "Cannot pass key and value parameter", details: nil))}}}
删除一个Key的实现
class CKDeleteValueHandler: CKCommandHandlerProtocol {var COMMAND_NAME: CKCommandType = .DELETE_VALUEfunc evaluateExecution(command: String) -> Bool {return CKCommandType(rawValue: command) == COMMAND_NAME}func handle(command: String, arguments: Dictionary, result: @escaping FlutterResult) {if (!evaluateExecution(command: command)) {return}if let key = arguments["key"] as? String {let store = NSUbiquitousKeyValueStore.defaultstore.removeObject(forKey: key)result(true)} else {result(FlutterError.init(code: "Error", message: "Cannot pass key parameter", details: nil))}}}