Search code examples
app-storeosx-mavericksosx-yosemiteurl-scheme

URL scheme Mac App Store Search


I want to open the Mac App Store with an URL scheme.

Before october I used the link below

macappstore://ax.search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?q=

Followed by a search term like things.

Any ideas how the new URL scheme looks like on OS X 10.9 Mavericks?


Solution

  • The following, AppleScript-based solution is just a stopgap, but may suffice in certain situations; for instance, I want to perform command-line based App Store searches from Alfred 2, which supports AppleScripts.

    • The script works on OSX 10.8+ (tested up to 10.10, the most recent version as of this writing).
    • On 10.8, it uses the macappstore:// approach, while on 10.9+ it uses GUI scripting - via the accessibility API, not by sending keystrokes, so it should be fairly robust.
    • Thus, on 10.9+, access for assistive devices must initially be enabled specifically for the application executing the script, which requires administrative privileges and - by OS design - several manual steps (which the script attempts to facilitate).
    • To try the script, paste it into AppleScript Editor, place a sample invocation at the top - e.g. my searchAppStore("dash"), then run it.

      # Performs an App Store search via the App Store.app.
      # Example:
      #   my searchAppStore("dash")
      # Works on OS X 10.8+:
      # - 10.8: Uses the macappstore:// URL scheme.
      # - 10.9+: Sadly, GUI scripting (i.e., simulated user input) must be used,
      #         which requires that access for assistive devices be enabled as *one-time setup*
      #         for the application in whose context this script runs.
      #         While this script attempts to facilitate enabling this feature,
      #         user intervention is - by OS design - required.
      on searchAppStore(searchTerm)
      
          if my isPreMavericks() then # assumes: OS X 10.8
      
              # We can use the macappstore:// URL scheme to submit a search.
              tell application "System Events" to open location "macappstore://ax.search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?q=" & searchTerm
              return
      
          else # OS X 10.9+: alas, we must use GUI scripting.
      
              # First, ensure that access for assistive devices is enabled - 
              # otherwise, GUI scripting won't work.
              my ensureAssistiveAccess()
      
              # Activate (and launch, if necessary) the App Store app.
              tell application "App Store" to activate
      
              # Use GUI scripting to simulate an interactive search.
              tell application "System Events"
                  tell application process "App Store"
                      # !! CAVEAT: The spelling of the toolbar UI element changed from 'tool bar' (10.8)
                      # !!         to 'toolbar' (10.9) - if you compile this script on 10.9, you'll end
                      # !!         up with 'toolbar', which will break when PASTED into a 10.8 AppleScript
                      # !!         window. If you're on 10.8 and get an error, change 'toolbar' to 'tool bar'.
                      set searchTextField to get text field 1 of group 7 of tool bar 1 of front window
                      set searchSubmitButton to get button 1 of searchTextField
                      set ok to false
                      repeat with i from 1 to 20 # Timeout is iteration count * delay period below.
                          set value of attribute "AXValue" of searchTextField to searchTerm
                          # !! Sadly, when App Store.app was just launched by this script, attempts to
                          # !! assign to the search field initially fail silently, until some time
                          # !! after startup. We simply keep trying for a while until we succeed.
                          if (value of attribute "AXValue" of searchTextField) = searchTerm then
                              # Click button to submit search.
                              # [If you run this on 10.8]
                              # !! On OS X 10.8, if this script just launched App Store.app,
                              # !! `tell application "App Store" to activate` didn't actually
                              # !! *activate* the app (it just launched it).
                              # !! Hence, we simply activate again here - BEFORE we
                              # !! submit the search - otherwise, it may not work.
                              tell application "App Store" to activate
                              click searchSubmitButton
                              # We're done.
                              return
                          end if
                          delay 0.3
                      end repeat
      
                      # Getting here means that submitting did not succeed within the timeout period.
                      # Raise an error.
                      error "Failed to submit search search term to the App Store application."
      
                  end tell
              end tell
      
          end if
      end searchAppStore
      
      
      # Tries to ensure that access for assistive devices is turned on so as to enable GUI scripting.
      # - Up to 10.8.x, access can be turned on programmatically, on demand - via an admin authorization prompt.
      # - From 10.9, the best we can do is display a GUI prompt, then open System Preferences to the relevant pane, then exit, telling the user to try again after interactively enabling access.
      # Returns:
      #   Only returns if access is already enabled; throws an error otherwise.
      # Example:
      #   my ensureAssistiveAccess() # throws error, if not enabled and couldn't be enabled programmatically (10.9+)
      #   # Alternatively, catch the error: 
      #   try 
      #       my ensureAssistiveAccess()
      #   on error
      #       # Exit quietly, relying on the prompt to have provided sufficient information.
      #       return
      #   end try
      on ensureAssistiveAccess()
          local ok, isPreMavericks, verOs, verMajor, verMinor, btn
          # Determine if access is currently enabled.
          tell application "System Events" to set ok to UI elements enabled
          if not ok then
              # See if we're running 10.8 or below
              set {orgTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {"."}}
              set verOs to system version of (system info)
              set verMajor to first text item of verOs as number
              set verMinor to second text item of verOs as number
              set AppleScript's text item delimiters to orgTIDs
              set isPreMavericks to verMajor ≤ 10 and verMinor < 9
              if isPreMavericks then # 10.8-: we can try to turn it on ourselves, which will prompt for authorization
                  try
                      # Try to turn it on - will prompt for authorization via admin credentials.
                      tell application "System Events"
                          set UI elements enabled to true
                          set ok to UI elements enabled # Check if the user actually provided the authorization.
                      end tell
                  end try
              else # 10.9+: we cannot turn it on ourselves, it has to be enabled *interactively*, *per application*.
                  # Try a dummy GUI scripting operation - which we know will fail - in the hope that this will
                  # get the app at hand registered in System Preferences > Security & Privacy > Privacy > Accessibility.
                  # ?? Does this work?
                  try
                      tell application "System Events" to windows of process "SystemUIServer"
                  end try
                  set appName to name of current application
                  if appName = "osascript" then set appName to "Terminal" # ?? how can we deal with other apps that invoke `osascript`, such as Alfred?
                  set errMsg to "You must turn on ACCESS FOR ASSISTIVE DEVICES for application '" & appName & "' (System Preferences > Security & Privacy > Privacy > Accessibility) first, then retry."
                  try
                      display dialog errMsg & linefeed & linefeed & "Press OK to open System Preferences now; unlock, if necessary, then locate the application in the list and check it." with icon caution
                      # We only get here if the user didn't cancel.
                      # Open System Preferences and show the appropriate pane. (This is the best we can do in guiding the user - further guidance would require the very kind of assistive access we're trying to turn on.)
                      tell application "System Preferences"
                          activate
                          tell pane id "com.apple.preference.security"
                              reveal anchor "Privacy_Assistive"
                          end tell
                      end tell
                  end try
                  # We must return false, as we can't easily and reliably wait for the user to finish the operation.
              end if
          end if
          if not ok then
              if isPreMavericks then # This indicates that the authorization prompt was aborted; for 10.9+, errMsg was set above.         
                  set errMsg to "You must turn on ACCESS FOR ASSISTIVE DEVICES first, via System Preferences > Accessibility > Enable access for assistive devices"
              end if
              error errMsg
          else
              return true
          end if
      end ensureAssistiveAccess
      
      # Indicates if the OS version predates Mavericks (10.9).
      # Example: my isPreMavericks() # -> true on 10.8.x and below
      on isPreMavericks()
          local verOs, verMajor, verMinor
          set {orgTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {"."}}
          set verOs to system version of (system info)
          set verMajor to first text item of verOs as number
          set verMinor to second text item of verOs as number
          set AppleScript's text item delimiters to orgTIDs
          return verMajor ≤ 10 and verMinor < 9
      end isPreMavericks