Swift自定义键盘打开容器应用后如何返回宿主应用?
解决方案思路
方案1:直接在键盘扩展内实现录音(推荐)
iOS 10及以上版本允许键盘扩展请求麦克风权限,无需跳转容器应用,完全规避返回宿主的问题:
- 在键盘扩展的
Info.plist中添加NSMicrophoneUsageDescription,填写麦克风使用说明文本。 - 请求权限并实现录音:
import AVFoundation AVAudioSession.sharedInstance().requestRecordPermission { granted in DispatchQueue.main.async { if granted { // 初始化录音逻辑,临时文件可存在App Group目录或扩展沙盒 let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent("recording.m4a") let recorder = try? AVAudioRecorder(url: tempURL, settings: [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 44100.0, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ]) recorder?.record() } else { // 提示用户前往设置开启麦克风权限 } } } - 录音完成后,直接通过
textDocumentProxy.insertText(_:)把识别后的文本插入宿主应用的输入框。
方案2:容器应用后台录音+App Group共享数据
如果必须依赖容器应用处理录音(比如复杂的语音识别逻辑),可以用以下方式实现无感知返回:
- 给键盘扩展和容器应用配置App Group,用于跨进程共享数据和状态。
- 键盘扩展通过自定义URL scheme打开容器应用,传递启动录音的指令(例如
your-container-scheme://start-recording)。 - 容器应用启动后,立刻启动后台录音任务,完成后主动回到后台:
var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid func handleRecordingRequest() { // 启动后台任务,避免被系统终止 backgroundTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: { UIApplication.shared.endBackgroundTask(self.backgroundTaskID) self.backgroundTaskID = .invalid }) // 初始化录音,保存到App Group共享目录 let sharedURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "your.app.group.id")?.appendingPathComponent("recording.m4a") let recorder = try? AVAudioRecorder(url: sharedURL!, settings: [:]) recorder?.record() // 录音完成后标记状态,通知键盘扩展 UserDefaults(suiteName: "your.app.group.id")?.set(true, forKey: "recordingCompleted") // 主动回到后台,系统会自动返回宿主应用 UIApplication.shared.resignActive() } - 键盘扩展通过监听
UserDefaults的变化,获取录音完成通知,读取共享的音频文件处理后插入文本。
关于SwiftKey实现的推测
SwiftKey的听写功能大概率是直接在键盘扩展内完成的——你看到的短暂界面可能是扩展内的自定义弹窗,而非容器应用跳转。跳转容器应用会打断用户操作,体验远不如直接在扩展内处理,这也是主流输入法的通用做法。
内容的提问来源于stack exchange,提问作者Yotam
相关产品推荐
相关产品推荐

