Skip to content

Commit 883078e

Browse files
authored
Merge pull request #5 from p-x9/feature/support-app-kit
Support MacOS Application
2 parents d6eb354 + 547c1de commit 883078e

File tree

7 files changed

+142
-14
lines changed

7 files changed

+142
-14
lines changed

src/device.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ def info(args: argparse.Namespace, debugger: lldb.SBDebugger, result: lldb.SBCom
4040
file_path = os.path.realpath(__file__)
4141
dir_name = os.path.dirname(file_path)
4242

43-
script_ret = subprocess.run(f"cat {dir_name}/swift/device.swift", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
43+
swift_file_name = "deviceMacOS" if util.isAppKit(debugger) else "deviceIOS"
44+
45+
script_ret = subprocess.run(f"cat {dir_name}/swift/{swift_file_name}.swift",
46+
shell=True,
47+
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
48+
text=True)
4449

4550
script = script_ret.stdout
4651
script += """

src/file.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ def tree(args: argparse.Namespace, debugger: lldb.SBDebugger, result: lldb.SBCom
9595

9696

9797
def open(args: argparse.Namespace, debugger: lldb.SBDebugger, result: lldb.SBCommandReturnObject) -> None:
98-
if not util.isIOSSimulator(debugger):
99-
print("Supported only simulator")
98+
if not (util.isIOSSimulator(debugger) or util.isMacOS(debugger)):
99+
print("Supported only simulator or macOS")
100100
return
101101

102102
shell = "open -R "

src/swift/device.swift src/swift/deviceIOS.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ func printDeviceInfo() {
99
print("System Name: \(currentDevice.systemName)")
1010
print("System Version: \(currentDevice.systemVersion)")
1111
if let identifierForVendor = currentDevice.identifierForVendor {
12-
print("Identifier (UDID): \(identifierForVendor.uuidString)")
12+
print("Id For Vendor: \(identifierForVendor.uuidString)")
1313
}
1414
}

src/swift/deviceMacOS.swift

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Foundation
2+
import SystemConfiguration
3+
4+
func printDeviceInfo() {
5+
let processInfo = ProcessInfo.processInfo
6+
7+
print("[Device Info]")
8+
if let name = SCDynamicStoreCopyComputerName(nil, nil) {
9+
print("Name: \(name)")
10+
}
11+
12+
if let model = sysctlByString(key: "hw.model") {
13+
print("Model: \(model)")
14+
}
15+
16+
print("System Name: macOS")
17+
print("System Version: \(processInfo.operatingSystemVersionString)")
18+
19+
if let cpu = sysctlByString(key: "machdep.cpu.brand_string") {
20+
print("CPU: \(cpu)")
21+
}
22+
}
23+
24+
func sysctlByString(key: String) -> String? {
25+
var size: size_t = 0
26+
sysctlbyname(key, nil, &size, nil, 0)
27+
var value = [CChar](repeating: 0, count: Int(size))
28+
sysctlbyname(key, &value, &size, nil, 0)
29+
30+
return String(cString: value)
31+
}

src/swift/tree.swift

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
import UIKit
1+
// import UIKit
2+
// typealias NSUIView = UIView
3+
// typealias NSUIViewController = UIViewController
4+
// typealias NSUIWindow = UIWindow
5+
// typealias NSUIApplication = UIApplication
26

3-
func windowHierarchy(_ window: UIWindow?, indentation: String = "", isLast: Bool = true, mode: String = "normal", depth: Int? = nil) {
7+
func windowHierarchy(_ window: NSUIWindow?, indentation: String = "", isLast: Bool = true, mode: String = "normal", depth: Int? = nil) {
48
guard let window = window else { return }
59

610
let currentDepth = indentation.replacingOccurrences(of: "", with: " ").count / 3
@@ -25,12 +29,17 @@ func windowHierarchy(_ window: UIWindow?, indentation: String = "", isLast: Bool
2529
result += windowDescription
2630
print(result)
2731

28-
if let rootViewController = window.rootViewController {
29-
viewControllerHierarchy(rootViewController, indentation: indentation + (isLast ? " " : ""), isLast: true, mode: mode, depth: depth)
32+
var rootViewController: NSUIViewController?
33+
if window.responds(to: Selector(("rootViewController"))) { // for iOS
34+
rootViewController = window.perform(Selector(("rootViewController"))).takeUnretainedValue() as? NSUIViewController
35+
} else if window.responds(to: Selector(("contentViewController"))) { // for macOS
36+
rootViewController = window.perform(Selector(("contentViewController"))).takeUnretainedValue() as? NSUIViewController
3037
}
38+
39+
viewControllerHierarchy(rootViewController, indentation: indentation + (isLast ? " " : ""), isLast: true, mode: mode, depth: depth)
3140
}
3241

33-
func viewControllerHierarchy(_ viewController: UIViewController?, indentation: String = "", isLast: Bool = true, mode: String = "normal", depth: Int? = nil) {
42+
func viewControllerHierarchy(_ viewController: NSUIViewController?, indentation: String = "", isLast: Bool = true, mode: String = "normal", depth: Int? = nil) {
3443
guard let viewController = viewController else { return }
3544

3645
let currentDepth = indentation.replacingOccurrences(of: "", with: " ").count / 3
@@ -68,7 +77,7 @@ func viewControllerHierarchy(_ viewController: UIViewController?, indentation: S
6877
}
6978
}
7079

71-
func viewHierarchy(_ view: UIView?, indentation: String = "", isLast: Bool = true, mode: String = "normal", depth: Int? = nil) {
80+
func viewHierarchy(_ view: NSUIView?, indentation: String = "", isLast: Bool = true, mode: String = "normal", depth: Int? = nil) {
7281
guard let view = view else { return }
7382

7483
let currentDepth = indentation.replacingOccurrences(of: "", with: " ").count / 3

src/ui.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,26 @@ def tree(args: argparse.Namespace, debugger: lldb.SBDebugger, result: lldb.SBCom
6363
except ValueError:
6464
pass
6565

66-
script = script_ret.stdout
66+
script = ''
67+
68+
if util.isUIKit(debugger):
69+
script += """
70+
import UIKit
71+
typealias NSUIView = UIView
72+
typealias NSUIViewController = UIViewController
73+
typealias NSUIWindow = UIWindow
74+
typealias NSUIApplication = UIApplication
75+
"""
76+
elif util.isAppKit(debugger):
77+
script += """
78+
import AppKit
79+
typealias NSUIView = NSView
80+
typealias NSUIViewController = NSViewController
81+
typealias NSUIWindow = NSWindow
82+
typealias NSUIApplication = NSApplication
83+
"""
84+
85+
script += script_ret.stdout
6786
if args.window:
6887
script += f"\n windowHierarchy({args.window}, mode: \"{mode}\", depth: {depth})"
6988
elif args.view:
@@ -73,7 +92,7 @@ def tree(args: argparse.Namespace, debugger: lldb.SBDebugger, result: lldb.SBCom
7392
elif args.layer:
7493
script += f"\n layerHierarchy({args.layer}, mode: \"{mode}\", depth: {depth})"
7594
else:
76-
script += f"\n windowHierarchy(UIApplication.shared.keyWindow, mode: \"{mode}\", depth: {depth})"
95+
script += f"\n windowHierarchy(NSUIApplication.shared.keyWindow, mode: \"{mode}\", depth: {depth})"
7796

7897
_ = util.exp_script(
7998
debugger,

src/util.py

+66-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import lldb
22
import argparse
3-
from typing import Optional
3+
from typing import Optional, cast
44

55

66
def exp_script(
@@ -23,7 +23,7 @@ def exp_script(
2323
options.SetIgnoreBreakpoints(True)
2424
options.SetTrapExceptions(False)
2525
options.SetTryAllThreads(True)
26-
options.SetFetchDynamicValue(lldb.eDynamicCanRunTarget)
26+
options.SetFetchDynamicValue(lldb.eNoDynamicValues)
2727
options.SetUnwindOnError(True)
2828
options.SetGenerateDebugInfo(True)
2929

@@ -51,5 +51,69 @@ def isIOSSimulator(debugger: lldb.SBDebugger) -> bool:
5151
return False
5252

5353

54+
def isAppKit(debugger: lldb.SBDebugger) -> bool:
55+
script = """
56+
@import Foundation;
57+
Class app = NSClassFromString(@"NSApplication");
58+
BOOL val = (BOOL)(app != nil)
59+
val ? @"YES" : @"NO";
60+
"""
61+
ret = exp_script(debugger, script, lang=lldb.eLanguageTypeObjC)
62+
63+
if ret and ret.GetObjectDescription() == 'YES':
64+
return True
65+
else:
66+
return False
67+
68+
69+
def isUIKit(debugger: lldb.SBDebugger) -> bool:
70+
script = """
71+
@import Foundation;
72+
Class app = NSClassFromString(@"UIApplication");
73+
BOOL val = (BOOL)(app != nil)
74+
val ? @"YES" : @"NO";
75+
"""
76+
ret = exp_script(debugger, script, lang=lldb.eLanguageTypeObjC)
77+
if ret and ret.GetObjectDescription() == 'YES':
78+
return True
79+
else:
80+
return False
81+
82+
83+
def isMacOS(debugger: lldb.SBDebugger) -> bool:
84+
model = sysctlbyname(debugger, "hw.model")
85+
if model:
86+
return 'Mac' in model and not isIOSSimulator(debugger)
87+
else:
88+
return isAppKit(debugger)
89+
90+
91+
def isIOS(debugger: lldb.SBDebugger) -> bool:
92+
machine = sysctlbyname(debugger, "hw.machine")
93+
if machine:
94+
return 'iP' in machine or isIOSSimulator(debugger)
95+
else:
96+
return isUIKit(debugger)
97+
98+
99+
def sysctlbyname(debugger: lldb.SBDebugger, key: str) -> Optional[str]:
100+
script = """
101+
size_t size = 0;
102+
sysctlbyname([name UTF8String], NULL, &size, NULL, 0);
103+
char *machine = (char *)malloc(size);
104+
sysctlbyname([name UTF8String], machine, &size, NULL, 0);
105+
106+
NSString *result = [NSString stringWithUTF8String:machine];
107+
free(machine);
108+
result;
109+
"""
110+
111+
ret = exp_script(debugger, script, lang=lldb.eLanguageTypeObjC)
112+
if ret:
113+
return cast(str, ret.GetObjectDescription())
114+
else:
115+
return None
116+
117+
54118
class HelpFormatter(argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter):
55119
pass

0 commit comments

Comments
 (0)