Swift 在运行时公开从框架加载的类的接口

Swift 在运行时公开从框架加载的类的接口,swift,dylib,dlopen,Swift,Dylib,Dlopen,我想加载和操纵 私有StoreKitUI.framework中的对象 首先,我尝试在运行时加载框架: guard case let libHandle = dlopen("/System/Library/PrivateFrameworks/StoreKitUI.framework/StoreKitUI", RTLD_NOW) where libHandle != nil else { fatalError("StoreKitUI not found") } 然后,我验证是否可以找到SK

我想加载和操纵 私有
StoreKitUI.framework
中的对象

首先,我尝试在运行时加载框架:

guard case let libHandle = dlopen("/System/Library/PrivateFrameworks/StoreKitUI.framework/StoreKitUI", RTLD_NOW) where libHandle != nil else {
    fatalError("StoreKitUI not found")
}
然后,我验证是否可以找到
SKUIImageColorAnalyzer
类:

guard let analyzerClass: AnyClass = NSClassFromString("SKUIImageColorAnalyzer")  else {
    fatalError("SKUIImageColorAnalyzer lookup failed")
}
我想在
SKUIImageColorAnalyzer
上使用
analyzeImage:
类方法,它接收
UIImage
进行分析,并返回
SKUIAnalyzedImageColors
对象。我通过验证
SKUIImageColorAnalyzer
对象上是否存在
analyzeImage:
选择器来执行此操作,并重新创建函数:

let selector: Selector = "analyzeImage:"
guard case let method = class_getClassMethod(analyzerClass, selector) where method != nil else {
    fatalError("failed to look up \(selector)")
}

// recreate the method's implementation function
typealias Prototype = @convention(c) (AnyClass, Selector, UIImage) -> AnyObject? // returns an SKUIAnalyzedImageColors object
let opaqueIMP = method_getImplementation(method)
let function = unsafeBitCast(opaqueIMP, Prototype.self)
let img = UIImage(named: "someImage.jpg")!
let analyzedImageColors = function(analyzerClass, selector, img) // <SKUIAnalyzedImageColors: 0x7f90d3408eb0>
现在,我可以获取一个
UIImage
对象,并将其作为参数传递给函数:

let selector: Selector = "analyzeImage:"
guard case let method = class_getClassMethod(analyzerClass, selector) where method != nil else {
    fatalError("failed to look up \(selector)")
}

// recreate the method's implementation function
typealias Prototype = @convention(c) (AnyClass, Selector, UIImage) -> AnyObject? // returns an SKUIAnalyzedImageColors object
let opaqueIMP = method_getImplementation(method)
let function = unsafeBitCast(opaqueIMP, Prototype.self)
let img = UIImage(named: "someImage.jpg")!
let analyzedImageColors = function(analyzerClass, selector, img) // <SKUIAnalyzedImageColors: 0x7f90d3408eb0>

这仍然需要我使用
valueForKey
。有没有办法从运行时加载的框架中公开类上的公共接口?

执行动态Objective-C操作的最简单方法是使用Objective-C

ImageAnalyzer.h:

如果您确实想在Swift中完成这一切,请首先声明要使用的
SKUIAnalyzedImageColors
Objective-C界面的部分:

@objc protocol ImageColors {
    var backgroundColor: UIColor { get }
    var isBackgroundLight: Bool { get }
    var textPrimaryColor: UIColor { get }
    var textSecondaryColor: UIColor { get }
}
然后使用
unsafeBitCast
将不透明对象实例强制转换为所需的Objective-C界面:

let img = UIImage(named: "someImage.jpg")!
let rawAnalyzedImageColors = function(analyzerClass, selector, img) 

let analyzedImageColors = unsafeBitCast(rawAnalyzedImageColors, ImageColors.self)
print("Background color: \(analyzedImageColors.backgroundColor)")

谢谢,但我真的在寻找一个不使用Objective-C的纯Swift解决方案。如果我想使用Objective-C,我可以从框架中获取转储的头文件,并通过桥接头文件导入它们,以公开类和接口。此外,您的纯Swift解决方案仍然需要我通过协议公开接口。有没有一种方法可以动态加载该对象的接口,而不必手动声明所有内容?我非常欣赏您的反射方法,+1不管。@JAL无论您使用Objective-C还是Swift,您都必须声明您想要使用的接口,然后将该对象强制转换到该接口。其余部分由编译器和运行时负责。如果它是一个公共框架,那么它将提供一个为您声明公共接口的头。因为它是私有的,你必须自己声明接口。我理解。我想我只是希望从框架加载类也能加载每个对象的接口。看来反射方法是Swift的最佳实现。谢谢
@objc protocol ImageColors {
    var backgroundColor: UIColor { get }
    var isBackgroundLight: Bool { get }
    var textPrimaryColor: UIColor { get }
    var textSecondaryColor: UIColor { get }
}
let img = UIImage(named: "someImage.jpg")!
let rawAnalyzedImageColors = function(analyzerClass, selector, img) 

let analyzedImageColors = unsafeBitCast(rawAnalyzedImageColors, ImageColors.self)
print("Background color: \(analyzedImageColors.backgroundColor)")