swift - 如何使用 Swift 的私有(private) iOS 框架?

标签 swift

我想通过 Swift 应用在 iOS 上使用私有(private)框架。我很清楚为什么这是个坏主意,但它在测试期间会很有用,因此 App Store 的限制不是问题,我已经非常详尽地研究了替代方案。

我想做的是类似这样的事情:

dlopen("/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation".fileSystemRepresentation,RTLD_LOCAL);

let eventsclass = NSClassFromString("UIASyntheticEvents") as? UIASyntheticEvents.Type
eventGenerator = eventsclass!.sharedEventGenerator() as! UIASyntheticEvents

问题是这会导致链接器错误:

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_UIASyntheticEvents", referenced from:
      type metadata accessor for __ObjC.UIASyntheticEvents in Test.o

如果我直接链接框架而不是使用 dlopen(),它将在模拟器上正常工作,但无法为实际设备构建,因为 SDK 中提供的框架仅适用于模拟器,不会链接在设备构建期间。

我曾尝试在 Objective-C 中进行这些调用,以防只是 .Type 转换导致问题,但这无济于事。如果我从 Swift 访问返回的对象,我仍然会遇到同样的错误。

我想我可以在 Objective-C 中创建一个包装器,它直接将所有调用传递给类,但这似乎太过分了。这个问题有更优雅的解决方案吗?

最佳答案

我找到了一种解决方案,它需要一些手动工作,但可以在纯 Swift 中运行。

诀窍是在 Swift 中创建一个匹配 Objective-C 方法的 @objc 协议(protocol),然后对该协议(protocol)类型进行不安全转换。就我而言,协议(protocol)如下所示:

@objc protocol UIASyntheticEvents {
    static func sharedEventGenerator() -> UIASyntheticEvents

    //@property(readonly) struct __IOHIDEventSystemClient *ioSystemClient; // @synthesize ioSystemClient=_ioSystemClient;
    var voiceOverStyleTouchEventsEnabled: Bool { get set }
    var activePointCount: UInt64 { get set }
    //@property(nonatomic) CDStruct_3eca2549 *activePoints; // @synthesize activePoints=_activePoints;
    var gsScreenScale: Double { get set }
    var gsScreenSize: CGSize { get set }
    var screenSize: CGSize { get set }
    var screen: UIScreen { get set }
    var onScreenRect: CGRect { get set }

    func sendPinchCloseWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, inRect: CGRect)
    func sendPinchOpenWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, inRect: CGRect)
    func sendDragWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double, withFlick: Bool, inRect: CGRect)
    func sendRotate(_: CGPoint, withRadius: Double, rotation: Double, duration: Double, touchCount: UInt64)
    func sendMultifingerDragWithPointArray(_: UnsafePointer<CGPoint>, numPoints: Int32, duration: Double, numFingers: Int32)
    func sendPinchCloseWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
    func sendPinchOpenWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
    func sendFlickWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
    func sendDragWithStartPoint(_: CGPoint, endPoint: CGPoint, duration: Double)
    func sendTaps(_: Int, location: CGPoint, withNumberOfTouches: Int, inRect: CGRect)
    func sendDoubleFingerTap(_: CGPoint)
    func sendDoubleTap(_: CGPoint)
    func _sendTap(_: CGPoint, withPressure: Double)
    func sendTap(_: CGPoint)
    func _setMajorRadiusForAllPoints(_: Double)
    func _setPressureForAllPoints(_: Double)
    func moveToPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64, duration: Double)
    func _moveLastTouchPoint(_: CGPoint)
    func liftUp(_: CGPoint)
    func liftUp(_: CGPoint, touchCount: UInt64)
    func liftUpAtPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64)
    func touchDown(_: CGPoint)
    func touchDown(_: CGPoint, touchCount: UInt64)
    func touchDownAtPoints(_: UnsafePointer<CGPoint>, touchCount: UInt64)
    func shake()
    func setRinger(_: Bool)
    func holdVolumeDown(_: Double)
    func clickVolumeDown()
    func holdVolumeUp(_: Double)
    func clickVolumeUp()
    func holdLock(_: Double)
    func clickLock()
    func lockDevice()
    func holdMenu(_: Double)
    func clickMenu()
    func _sendSimpleEvent(_: Int)
    func setOrientation(_: Int32)
    func sendAccelerometerX(_: Double, Y: Double, Z: Double, duration: Double)
    func sendAccelerometerX(_: Double, Y: Double, Z: Double)
    func _updateTouchPoints(_: UnsafePointer<CGPoint>, count: UInt64)
    func _sendHIDVendorDefinedEvent(_: UInt32, usage: UInt32, data: UnsafePointer<UInt8>, dataLength: UInt32) -> Bool
    func _sendHIDScrollEventX(_: Double, Y: Double, Z: Double) -> Bool
    func _sendHIDKeyboardEventPage(_: UInt32, usage: UInt32, duration: Double) -> Bool
    //- (_Bool)_sendHIDEvent:(struct __IOHIDEvent *)arg1;
    //- (struct __IOHIDEvent *)_UIACreateIOHIDEventType:(unsigned int)arg1;    func _isEdgePoint(_: CGPoint) -> Bool
    func _normalizePoint(_: CGPoint) -> CGPoint
    //- (void)dealloc;
    func _initScreenProperties()
    //- (id)init;
}

这是从类转储输出中手动转换而来的。如果有人知道更快的方法,我很想知道。

有了这个协议(protocol)后,您可以简单地执行以下操作:

    dlopen("/Developer/Library/PrivateFrameworks/UIAutomation.framework/UIAutomation".fileSystemRepresentation,RTLD_LOCAL)

    let eventsclass = unsafeBitCast(NSClassFromString("UIASyntheticEvents"), UIASyntheticEvents.Type.self)
    eventGenerator = eventsclass.sharedEventGenerator()

关于swift - 如何使用 Swift 的私有(private) iOS 框架?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36137371/

相关文章:

swift - 如何从 Outlet Collection 获取文本字段值以进行密码验证?

ios - 使用 Cocoa pods 设置 RealmSwift

ios - 如何对 Playground CIFilter 错误消息进行故障排除

swift - 如何在 Swift 中获取数字的整数部分和小数部分

ios - UIAccessibility 在自定义 View 上宣布 n 个元素

swift - Foundation 的字符串编码不是网站所期望的

ios - 更改导航栏底部边框颜色 Swift

swift - UIAlertView clickedButtonAtIndex

ios - 可重复使用的 .xib + cocoa 类组件,如何在 Storyboard 中自动调整 super View 的大小和样式?

ios - 适用于 IOS 的 Google Maps API map 显示为黑屏,左下角带有 Google Logo