通过上一篇文章的介绍跳转,相信大家都会使用Accessibility API
的AXUIElement
。那今天我们继续第二遍文章,这次将介绍AXObserver
,一个可以通过具体Key值进行监控。如window的size、position的变化。
AXObserver
从apple的官方文档可以找到,有两种方式可以创建AXObserver
:
1.public func AXObserverCreate(_ application: pid_t, _ callback: AXObserverCallback, _ outObserver: UnsafeMutablePointer<AXObserver?>) -> AXError
2.public func AXObserverCreateWithInfoCallback(_ application: pid_t, _ callback: AXObserverCallbackWithInfo, _ outObserver: UnsafeMutablePointer<AXObserver?>) -> AXError
通过这里,发现要成功创建一个AXObserver
,需要以下几点要素
- pid:程序的进程ID
- callback:用于接收监听的回调。是一个闭包类型.而这个callback有两种类型,一种是
AXObserverCallback
,另外一种是AXObserverCallbackWithInfo
- outObserver:inout类型的对象,用于接收
AXObserver
- AXError: 这个是返回值,用于判断你的
AXObserver
是否成功创建了。
那么对于callback的回调类型AXObserverCallback
和AXObserverCallbackWithInfo
有什么不同呢?我们先看看官方文档的定义
1. public typealias AXObserverCallback = @convention(c) (AXObserver, AXUIElement, CFString, UnsafeMutableRawPointer?) -> Void
2. public typealias AXObserverCallbackWithInfo = @convention(c) (AXObserver, AXUIElement, CFString, CFDictionary, UnsafeMutableRawPointer?) -> Void
从官方的文档中,我们可以发现这个闭包都是无返回,但参数基本一致,只是AXObserverCallbackWithInfo
比AXObserverCallback
对了一个字典项CFDictionary
- AXObserver:这个就是正在监听的AXObserver对象
- AXUIElement:这个就是被监听的AXUIElement对象
- CFString:这个就是监听对象的键值,其实就是你要监听的对象的那一个行为的键值
- UnsafeMutableRawPointer?: 这个就是调用者,可以为nil
- CFDictionary: 只有AXObserverCallbackWithInfo这个才拥有,其实就和我们NSNotification中的userInfo一样。
了解完了,那就上代码
定义回调CallBack
AXObserverCallback
let _observerCallback:AXObserverCallback = { (observer, element, notification, refcon) in
print("AXObserverCallback did called")
}
AXObserverCallbackWithInfo
let _observerCallbackWithInfo: AXObserverCallbackWithInfo = { (observer, element, notification, userInfo, refcon)
print("it will called when element did modify")
}
创建AXObserver
对象
通过AXObserverCallback
创建的AXObserver
var observer : AXObserver?
let error:AXError = AXObserverCreate(pid, _observerCallback, &observer)
通过AXObserverCallbackWithInfo
创建的AXObserver
var observer : AXObserver?
let error:AXError = AXObserverCreateWithInfoCallback(pid, _observerCallbackWithInfo, &observer)
添加通知
let selfPtr = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
let error : AXError = AXObserverAddNotification(observer, element, kAXWindowMovedNotification, selfPtr)
kAXWindowMovedNotification
这个就是Observer的key了。具体可以查阅AXNotificationConstants.h
添加完通知后,还需要把它添加到RunLoop才算完成:
CFRunLoopAddSource(CFRunLoopGetCurrent(), observer.runLoopSource(), CFRunLoopMode.defaultMode)
移除通知
首先我们要移除RunLoop
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), observer.runLoopSource(), CFRunLoopMode.defaultMode)
然后移除Key的通知
let error : AXError = AXObserverRemoveNotification(observer, element, kAXWindowMovedNotification)
关于通知和回调的refcon: UnsafeMutableRawPointer?
的Get&Set
在添加通知和回调CallBack中,可以看到参数里面都有一个refcon: UnsafeMutableRawPointer?
1. public func AXObserverAddNotification(_ observer: AXObserver, _ element: AXUIElement, _ notification: CFString,_ refcon: UnsafeMutableRawPointer?) -> AXError
2. public typealias AXObserverCallback = @convention(c) (AXObserver, AXUIElement, CFString, UnsafeMutableRawPointer?) -> Void
那我们该如何传值和取值呢?
在需要传值的函数的时候,需要转换一下:
//self 就是你要传过去的对象,这里的self在我的代码其实对应的是ViewController
let selfPtr = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
let error : AXError = AXObserverAddNotification(observer, element, kAXWindowMovedNotification, selfPtr)
那么如何在回调中取值呢?同样也需要转换一下:
let _observerCallbackWithInfo: AXObserverCallbackWithInfo = { (observer, element, notification, userInfo, refcon) in
if let ref = refcon{
//因为在传值的时候,我传了一个self(其实是ViewController的对象),所以在转换的时候就变成ViewController
let obj : ViewController = Unmanaged<ViewController>.fromOpaque(ref).takeUnretainedValue()
obj.observerLogView.string += log
}
}