1. 程式人生 > Android開發 >iOS Keyboard Extension 開發資料

iOS Keyboard Extension 開發資料

keyboard_architecture_2x.png

Apple 在 iOS 8 裡就引入了 Keyboard Extension,但網上相關但開發但資料很少,我在開發中也遇到了不少坑,為了給大家分享下這方面但知識,所以才有了這篇文章。 Custom Keyboard 要實現起來也非常簡單,我們只需要在專案裡新建一個 Custom Keyboard Extension 的 Target,Xcode 就自動會給我們建立一個 KeyboardViewController,開發者通過這個類就可以做簡單的開發了。但是往往實際情況並沒有那麼簡單。我們可能需要在鍵盤請求網路資料,或者和Containing App 通訊等等,這時我們會遇到很多問題。這邊文章我會講述一下常見的問題和解法。


概要

  • Extension 如何通訊
  • 檢測鍵盤是否已經新增
  • 檢測鍵盤是否啟用
  • 播放系統聲音
  • 檢測是否已經獲取(最高訪問許可權) RequestsOpenAccess
  • 鍵盤切換方法

Extension 如何通訊

detailed_communication_2x.png

這是蘋果官方給出的一張圖,Containing App 是我們的主 App,Host app 是 Extension 所執行的第三方 App(比如微信),為了方便理解下面我們會把 Containing App 稱為“主 App”,Host App 稱為“第三方 App”。

總結如下:

  1. App extension 無法直接與主 App 通訊(簡單的理解它們就是兩個不同的程式,extension 啟動了並不代表主App也會啟動)
  2. App extension 可以通過 open URL 和主 App通訊,但這條鏈路只是單向的(因為App extension 沒有 openURL 之類接受訊息的入口)
  3. 主 App 和 App extension 可以通過讀寫共同的檔案資源來通訊(比如 UserDefault,前提需要加到同一個 AppGroups
  4. 另外一個官方沒提到的方法:可以用更底層的 DarwinNotify 來建立 Extension 和 Containing app 之間的通訊,可以參考下面的?開源庫

choefele/CCHDarwinNotificationCenter

通過 App Groups 共同維護 UserDefault 是一種比較簡單的通訊方法。但是開發者也需要注意的是如果我們的鍵盤沒有獲取到沒有完全訪問許可權,鍵盤是隻能讀取,沒法修改 UserDefault 的值的(如果這個 UserDefault 是 Containing app 建立的)。另外一點是 DarwinNotify 現在同樣也需要完全訪問許可權了。

最後給大家一個忠告: 千萬一定要在真機上除錯!

檢測鍵盤是否已經新增

var isKeyboardEnabled: Bool {
  guard let keyboards = UserDefaults.standard.object(forKey: "AppleKeyboards") as? [String] else {
    return false
  }
  return keyboards.contains("你的 extension bundle id")
}
複製程式碼

檢測鍵盤是否已經啟用

鍵盤型別的應用往往有個需求是:當使用者第一次切換到我們開發的 Keyboard,需要在主 App 顯示歡迎?圖文或者開啟引導流程。我們可以通過 openURL 的方式來通知主App。

// Step1: 在 keyboard 中呼叫
// 開啟主APP,比如 openURL(scheme:"yourAppScheme://actived")
func openURL(scheme: String) {
  let url = URL(string: scheme)!
  let context = NSExtensionContext()
  context.open(url,completionHandler: nil)
  var responder = self as UIResponder?
  let selectorOpenURL = sel_registerName("openURL:")
  while (responder != nil) {
    if responder!.responds(to: selectorOpenURL) {
      responder!.perform(selectorOpenURL,with: url)
      break
    }
    responder = responder?.next
  }
}

// step2:
// app 在前臺的時候接收通知
func application(_ app: UIApplication,open url: URL,options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
  if url.scheme == "yourAppScheme" && url.host == "actived" {
    // do something
  }
  return true
}
複製程式碼

這裡要注意的是openURL 會喚起主 App(如果主 App 不在前臺),所以這裡需要額外做判斷。

播放系統聲音

// 直接上程式碼
// 點選: SystemSoundID = 1123
// 刪除按鈕: SystemSoundID = 1155
// 系統鍵盤: SystemSoundID = 1156
AudioServicesPlaySystemSound(SystemSoundID)
複製程式碼

檢測是否已經獲取(最高訪問許可權) RequestsOpenAccess

// Keyboard Extension
override var hasFullAccess: Bool {
  if #available(iOS 11.0,*) {
    return super.hasFullAccess// super is UIInputViewController.
  }
  if #available(iOS 10.0,*) {
    let original: String? = UIPasteboard.general.string
    UIPasteboard.general.string = " "
    let val: Bool = UIPasteboard.general.hasStrings
    if let str = original {
      UIPasteboard.general.string = str
    }
    return val
  }
  return UIPasteboard.general.isKind(of: UIPasteboard.self)
}
複製程式碼

主 App 沒有直接獲取的方法,但我們可以通過上面提到的通訊方法,在 Keyboard Extension 中把狀態傳過去

全面螢幕隱藏切換 keyboard 按鍵

在全屏但裝置系統會給我們預設提供切換鍵盤但按鈕,所以我們開發的鍵盤就不需要提供此按鈕了,我們可以通過以下方式來判斷:

// needsInputModeSwitchKey
var needsSwitchKey: Bool {
	if #available(iOSApplicationExtension 11.0,*) {
		return needsInputModeSwitchKey
	} else {
		return true
	}
}
複製程式碼

其他資料

Custom Keyboard

Custom Keyboards - Extensions - iOS - Human Interface Guidelines - Apple Developer

求關注,求點贊?