我希望在我的自定义键盘扩展应用中检测使用我的扩展的应用程序。我们能否在键盘扩展中检测有关使用我的扩展的应用程序的任何信息?我认为这是不可能的。如果有人对此有了解,请分享一下。
谢谢。
谢谢。
您可以在您的UIInputViewController中尝试此代码
override public func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let parentViewController = self.parentViewController {
var hostBundleID = parentViewController.valueForKey("_hostBundleID")
println(hostBundleID)
}
}
但我不确定当你发布到App Store时,苹果是否会批准。
_hostBundleID
的官方文档在哪里? - PangvalueForKey("_hostBundleID")
返回nil
。 - Daniel SaidiSwift 5 版本
适用于 iOS 16 及更早版本
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
}
}
适用于iOS 16+
#import <dlfcn.h>
+ (nullable NSString *)hostBundleIDWithInputVC:(UIInputViewController *)vc {
NSString *bundleID = nil;
@try {
bundleID = [vc.parentViewController valueForKey:@"_hostBundleID"];
} @catch (NSException *exception) {
NSLog(@"hostBundleID Get Failure 1 %@", exception);
} @finally {
}
if(XMUtils.validString(bundleID) && ![bundleID isEqual:@"<null>"]) {
return bundleID;
}
// 云控禁止xpc取法
// xpc取法 逆向自xx输入法 主要解决iOS16上获取不到的问题
@try {
id hostPid = [vc.parentViewController valueForKey:@"_hostPID"];
if (hostPid) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id serverIns = [NSClassFromString(@"PKService") performSelector:NSSelectorFromString(@"defaultService")];
id lities = [serverIns performSelector:NSSelectorFromString(@"personalities")];
id infos = [lities objectForKey:[NSBundle mainBundle].bundleIdentifier];
id info = [infos objectForKey:hostPid];
id con = [info performSelector:NSSelectorFromString(@"connection")];
id xpcCon = [con performSelector:NSSelectorFromString(@"_xpcConnection")];
#pragma clang diagnostic pop
const char * (* cfunc)(id) = dlsym(RTLD_DEFAULT, "xpc_connection_copy_bundle_id");
if (cfunc != nil && xpcCon != nil) {
const char *res = cfunc(xpcCon);
bundleID = [NSString stringWithUTF8String:res];
return bundleID;
}
}
} @catch (NSException *exception) {
NSLog(@"hostBundleID Get Failure 2 %@", exception);
} @finally {
}
return nil;
}
{{链接1:来自博客}}
要求iOS系统版本为16或以上,"_hostBundleID"的值为nil。