How to detect in which app my custom keyboard used and show different button? E.g. in Twitter I would add @ to string I post into input field and in Reddit /r/
Edit: See above. Things have changed.
This is not possible. An extension runs sandboxed and is only fed information from the API and cannot access anything else. The keyboard can only receive text context changes and activate/deactivate calls. Being able to detect an app lies outside of the extension sandbox and therefore is impossible.
It is possible through following code. As you'll get bundle identifier of the app where you're using your custom keyboard.
Swift
let hostBundleID = self.parentViewController!.valueForKey("_hostBundleID")
let currentHostBundleID = String(hostBundleID)
print(currentHostBundleID);
From bundle identifier you can find app name easily.
Edit: See above. Things have changed.
This is not possible. An extension runs sandboxed and is only fed information from the API and cannot access anything else. The keyboard can only receive text context changes and activate/deactivate calls. Being able to detect an app lies outside of the extension sandbox and therefore is impossible.
Here is the updated solution that also supports iOS 16 and 17:
extension KeyboardViewController {
var hostBundleId: String? {
if let id = hostBundleIdValueBefore16 { return id }
return hostBundleIdValueFor16
}
private var hostBundleIdValueBefore16: String? {
let value = parent?.value(forKey: "_hostBundleID") as? String
return value != "<null>" ? value: nil
}
private var hostBundleIdValueFor16: String? {
guard let pid = parent?.value(forKey: "_hostPID") else { return nil }
let selector = NSSelectorFromString("defaultService")
guard let anyClass: AnyObject = NSClassFromString("PKService"),
let pkService = anyClass as? NSObjectProtocol,
pkService.responds(to: selector),
let serverInis = pkService.perform(selector).takeUnretainedValue() as? NSObjectProtocol
else { return nil }
let lities = serverInis.perform(NSSelectorFromString("personalities")).takeUnretainedValue()
let bundleId = Bundle.main.bundleIdentifier ?? ""
guard let infos = lities.object(forKey: bundleId) as? AnyObject,
let info = infos.object(forKey: pid) as? AnyObject,
let con = info.perform(NSSelectorFromString("connection")).takeUnretainedValue() as? NSObjectProtocol
else { return nil }
let xpcCon = con.perform(NSSelectorFromString("_xpcConnection")).takeUnretainedValue()
let handle = dlopen("/usr/lib/libc.dylib", RTLD_NOW)
let sym = dlsym(handle, "xpc_connection_copy_bundle_id")
typealias xpcFunc = @convention(c) (AnyObject) -> UnsafePointer<CChar>
let cFunc = unsafeBitCast(sym, to: xpcFunc.self)
let response = cFunc(xpcCon)
let hostBundleId = NSString(utf8String: response)
return hostBundleId as String?
}
}
Note that you may get rejected by Apple for using this code. However, some apps managed to pass the Apple Review.
Credits: KeyboardKit
Usage:
print(hostBundleId)
// Output in Apple Notes: com.apple.mobilenotes
Make sure you are inside your KeyboardController class.
© 2022 - 2024 — McMap. All rights reserved.