Skip to content

Instantly share code, notes, and snippets.

@foxicode
Created May 25, 2020 18:55
Show Gist options
  • Select an option

  • Save foxicode/ac227c658dc74e452ea8e4197f827060 to your computer and use it in GitHub Desktop.

Select an option

Save foxicode/ac227c658dc74e452ea8e4197f827060 to your computer and use it in GitHub Desktop.
Dynamic version of FrameworkViewController
import UIKit
import Darwin
class FrameworkViewController: UIViewController {
@IBOutlet weak var vPluginContainer: UIView!
var timer: Timer?
typealias startFuncPrototype = @convention(c) (Double, Double) -> Void
typealias tickFuncPrototype = @convention(c) (TimeInterval) -> Void
typealias setUpdatePropertyPrototype = @convention(c) (@escaping (_ tag: Int, _ property: String, _ value: Any) -> Void) -> Void
typealias setAddWidgetPrototype = @convention(c) (@escaping (_ widget: String, _ properties: [String: Any]) -> Void) -> Void
var handle: UnsafeMutableRawPointer?
var tickFunc: tickFuncPrototype?
deinit {
if let handle = handle {
dlclose(handle)
}
}
@IBAction func runPlugin() {
if let handle = handle {
dlclose(handle)
}
handle = dlopen("/Volumes/Extra/Work/DynamicLights", RTLD_LAZY)
if handle == nil { return }
let updateProperty: (_ tag: Int, _ property: String, _ value: Any) -> Void = { [weak self] (tag, property, value) in
guard let w = self?.vPluginContainer.viewWithTag(tag) else { return }
switch property {
case "color":
if let strValue = value as? String,
let color = UIColor(hex: strValue) {
w.backgroundColor = color
}
default:
break
}
}
let addWidget: (_ widget: String, _ properties: [String: Any]) -> Void = { [weak self] (widgetName, widgetProperties) in
switch widgetName {
case "Circle":
guard let x = widgetProperties["x"] as? Double,
let y = widgetProperties["y"] as? Double,
let r = widgetProperties["radius"] as? Double else {
break
}
let color = widgetProperties["color"] as? String ?? "#ffffff"
let tag = widgetProperties["tag"] as? Int ?? 0
let v = UIView(frame: CGRect(x: x - r, y: y - r, width: r * 2, height: r * 2))
v.layer.cornerRadius = CGFloat(r)
v.tag = tag
let uiColor = UIColor(hex: color) ?? .black
v.backgroundColor = uiColor
self?.vPluginContainer.addSubview(v)
default:
print("Unknown widget - \(widgetName)")
}
}
if let setUpdatePropertySym = dlsym(handle!, "set_update_property_func") {
let setUpdatePropertyFunc = unsafeBitCast(setUpdatePropertySym, to: setUpdatePropertyPrototype.self)
setUpdatePropertyFunc(updateProperty)
}
if let setAddWidgetSym = dlsym(handle!, "set_add_widget_func") {
let setAddWidgetFunc = unsafeBitCast(setAddWidgetSym, to: setAddWidgetPrototype.self)
setAddWidgetFunc(addWidget)
}
if let startSym = dlsym(handle!, "lights_start") {
let startFunc = unsafeBitCast(startSym, to: startFuncPrototype.self)
startFunc(Double(vPluginContainer.bounds.width), Double(vPluginContainer.bounds.height))
}
if let tickSym = dlsym(handle!, "lights_tick") {
tickFunc = unsafeBitCast(tickSym, to: tickFuncPrototype.self)
}
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
}
@objc func tick() {
if let tickFunc = tickFunc {
tickFunc(0.01)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment