Swift 5 Version
This works for iOS 16 and older
import Foundation
import UIKit
extension UIInputViewController {
func hostBundleId() -> String? {
if let parentViewController = parent {
if let hostBundleId = parentViewController.value(forKey: "_hostBundleID") as? String,
hostBundleId != "<null>" {
return hostBundleId
} else if let hostPID = parentViewController.value(forKey: "_hostPID") {
let selector = NSSelectorFromString("defaultService")
if let anyClass: AnyObject = NSClassFromString("PKService"),
let pkService = anyClass as? NSObjectProtocol,
pkService.responds(to: selector),
let serverInis = pkService.perform(selector).takeUnretainedValue() as? NSObjectProtocol {
let lities = serverInis.perform(NSSelectorFromString("personalities")).takeUnretainedValue()
let bundleId = Bundle.main.bundleIdentifier ?? ""
if let infos = lities.object(forKey: bundleId) as? AnyObject,
let info = infos.object(forKey: hostPID) as? AnyObject,
let con = info.perform(NSSelectorFromString("connection")).takeUnretainedValue() as? NSObjectProtocol {
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?
}
}
}
}
return nil
}
}