Before

must to understand some recommendations and limitations that the keyboard extension has:

  1. 自定义键盘需要适配iPadOS的展示(横竖屏、收缩和展开模式)。适配iPhone的旋转
  2. 如果设计支持,需要尊重用户对于浅色、深色模式的选择
  3. 自定义键盘是独立运行的,程序需要遵循一些限制,比如内存。内存使用需要在30MB以内。最好能测试和调试所有功能,并尽一切可能优化它
  4. 如果要支持不同的语言需要重新创建新的。

问题合集

如何使用SwiftUI构建Custom Keyboard Extension界面

使用UIHostingController引入了SwiftUI构建的View

class KeyboardViewController: UIInputViewController {
    // some code
    override func viewDidLoad() {
        super.viewDidLoad()
        let hostingController = UIHostingController(rootView: KeyboardView(viewController: self))
        view.addSubview(hostingController.view)
        addChild(hostingController)

        self.nextKeyboardButton = UIButton(type: .system)
        // some code
    }
    // some code
}
struct KeyboardView: View {
    var viewController: KeyboardViewController
    var body: some View {
        // some view as you designed
    }
}

Reference

how to create keyboard app extension in swiftui?

在Custom Keyboard Extension中展示主程序的CoreData的数据

根据下面的这篇文章可以解决将CoreData中的数据在键盘中展示的问题
通过使用AppGroup并在CoreData中配置一个StoreDescription进行解决。

Reference

Core Data and App extensions: Sharing a single database
除了介绍实现键盘与主程序数据共享的能力外,还介绍了如何通过数据监听实现数据变更后的同步变化(项目中未使用)。

在Custom Keyboard Extension中展示主程序更新后的数据

背景

展示了自定义的键盘后,如果在主程序中更新了数据,但是唤起的自定义键盘的数据还是老的,展示的不是最新的数据,只有在键盘设置中删除后重新开启才能展示最新的数据,如何让它能在主程序更新后,唤起时自动展示最新的数据

解决方式

方案一

因为CoreData会将数据加载到内存中,每一次Fetch动作,CoreData会判断是否最新的,是最新的就会从内存返回。这就导致在主app的程序中更新后,键盘的程序并不能感知到数据发生了变更,所以需要手动发送消息进行通知。
根据文章的解决方案是监听消息。

方案二

根据申请的技术支持沟通内容看,还有一种方案是在keyboard的Target中的查询动作之前让Context执行reset()方法,通过重置context,让程序重新去数据库中拉取数据。

Reference

Consuming Relevant Store Changes

申请的技术支持

修改Keyboard名称

在设置中添加扩展键盘时,如果直接显示默认的名称的话,看起来没那么直接,想要将键盘的名称调整成xxxx 键盘进行展示。

需要在这个Info中增加一个字段,就可以展示出来了

Keyboard结合CoreData和CloudKit产生的问题

数据不再同步到iCloud

根据文档修改了PersistenceController当中的container的StoreDescriptions

这样之后发现,虽然使用了icloudKit的Container,但是数据不会从本地传到icloud上了。通过开发文档中关于NSPersistentCloudKitContainer的描述发现,NSPersistentCloudKitContainer本身包含了一个store description,上面的代码把默认的描述对象覆盖了,导致不再连接icloud

我将上面的代码做了调整container.persistentStoreDescriptions.append(sotreDescription),这样我保留了CloudKitContainer中默认的Description。运行后产生了另一个问题Keyboard扩展中数据展示与主程序不一致。在主程序中展示了从其他设备同步过来的数据,但是在键盘扩展中只展示本机保存过的数据,并且在主程序中的添加和修改不会同步到键盘扩展中。
原因应该是数据存储到了第一个Description,但是因为不是指定group开头的,所以键盘获取不到,它只能获取到之前存在group.leozhou.tomemo下的数据。

解决方案

Reference

Apple Developer

App Extension Programming Guide - Custom Keyboard
Apple 官方对于Customer Keyboard的文档

Other

Create custom keyboards in iOS

Custom Keyboard Extensions: Getting Started
基于摩斯密码的app创建对应的键盘,但是是基于Storyboard的

【Youtube】Swift iOS8 App Extensions Tutorial: Today Extension

【Youtube】IOS KEYBOARD EXTENSIONS by John Estropia - Tokyo iOS Meetup : May 12, 2018