问题
I need to programatically download an app from iTunes using JXA. I've done the following:
var its = SystemEvents.processes.byName('iTunes');
delay(3);
its.windows[0].buttons.byName('Get').click();
There is no element selected. I've tried clicking on buttons[0...7] and none of those are the 'Get' button. I assume the button I need is inside a document, biut the JXA documentation clearly states that button elements are children of Window, not of Document. Any ideas on how to click on the corrent button?
回答1:
A "leaf" UI element such as a button will be at the bottom of a potentially complex hierarchy of UI elements, which is especially true in the case of iTunes.
To give you a sense, here's an example object specifier for the Get
button on a free app's App Store page (assuming you've already ensured that this page is active):
Application("System Events")
.applicationProcesses.byName("iTunes")
.windows.byName("iTunes")
.splitterGroups.at(0)
.scrollAreas.at(0)
.uiElements.at(0)
.groups.at(3)
.buttons.at(0)
The problem is that this object specifier differs across pages, so ideally you'd just apply a filter to all UI elements (via the window's entireContents
property) to retrieve the button of interest:
// Get an array of all UI elements in iTunes window.
uiElems = Application("System Events").applicationProcesses['iTunes']
.windows[0].entireContents()
// Find all buttons whose description contains 'Get'.
btns = uiElems.filter(function(el) {
try {
return el.role() == 'AXButton'
&&
el.description().match(/\bGet\b/)
} catch (e) {}
})
// Click on the 1st button found.
btns[0].click()
Here's the catch: on my reasonably recent machine, this takes about 20 seconds(!).
I would image that a .whose
-style filter would be faster, but I couldn't get it to work in this instance, because exceptions must be caught - as above - but .whose
does not seem to support embedded exception handlers.
If you're willing to make assumptions about a lower level in the hierarchy in whose subtree the button can be found, you can speed things up considerably:
// Get the group UI elements in one of which the 'Get' button is located.
grps = Application("System Events").applicationProcesses['iTunes'].
windows[0].splitterGroups[0].scrollAreas[0].uiElements[0].groups
// Loop over groups
count = grps.length
for (i = 0; i < count; ++i) {
// In the group at hand, find all buttons whose description contains 'Get'.
btns = grps[i].entireContents().filter(function(el) {
try {
return el.role() == 'AXButton'
&&
el.description().match(/\bGet\b/)
} catch (e) {}
})
// Exit loop, if a 'Get' button was found.
if (btns.length > 0) break
}
if (btns.length == 0) {
console.log('ERROR: No "Get" button found.')
} else {
// Click on the 1st button found.
btns[0].click()
}
This runs in less than 1 sec. on my machine.
UI automation (GUI scripting) is tricky business, unfortunately.
For interactive exploration, there's the Accessibility Inspector developer tool that comes with Xcode, but using it is non-trivial, especially when it comes to translating findings into code.
来源:https://stackoverflow.com/questions/33232154/javascript-automation-click-download-button-in-itunes