2016-03-21 12 views
2

Ich möchte ein privates Framework auf iOS von einer Swift App verwenden. Ich bin mir bewusst, warum dies eine schlechte Idee ist, aber es wird während des Testens nützlich sein, so dass die Beschränkungen des App Stores kein Problem sind und ich habe ziemlich ausführlich nach Alternativen gesucht.Wie verwende ich ein privates iOS-Framework von Swift?

Was würde Ich mag zu tun ist etwas entlang der Linien von dieser:

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

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

Das Problem ist, dass dies ein Linker-Fehler verursacht:

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

Wenn ich den Rahmen verknüpfen direkt eher Wenn Sie dlopen() verwenden, funktioniert es auf dem Simulator einwandfrei, kann aber nicht für ein tatsächliches Gerät erstellt werden, da das im SDK bereitgestellte Framework nur für den Simulator bestimmt ist und nicht während eines Geräte-Builds verknüpft wird.

Ich habe versucht, diese Aufrufe in Objective-C statt, falls es nur die .Type Besetzung war, die Probleme verursacht, aber das hilft nicht. Wenn ich von Swift auf das zurückgegebene Objekt zugreife, erhalte ich immer noch denselben Fehler.

Ich denke, ich könnte einen Wrapper in Objective-C erstellen, der alle Aufrufe an die Klasse gerade durchgibt, aber das scheint übermäßig. Gibt es eine elegantere Lösung für dieses Problem?

+0

Keine Swift Gestänges gegen statische Rahmenbedingungen. – matt

+0

Ich bin mir nicht sicher, was Sie hier meinen, es gibt keinen statischen Rahmen. –

+0

OK, nur überprüfen. – matt

Antwort

3

Ich fand eine Lösung, die einige manuelle Arbeit erfordert, aber funktioniert in reinem Swift.

Der Trick besteht darin, ein @objc-Protokoll in Swift zu erstellen, das den Objective-C-Methoden entspricht, und dann eine unsichere Umwandlung in diesen Protokolltyp durchzuführen. In meinem Fall sieht das Protokoll so aus:

@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; 
} 

Dies wurde von einer Klasse-Dump-Ausgabe von Hand konvertiert. Wenn jemand einen schnelleren Weg kennt, würde ich es gerne wissen.

Sobald Sie dieses Protokoll haben, können Sie einfach wie folgt vor:

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

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