appex — Utilities for Pythonista’s App Extensions

The appex module provides functions for interacting with Pythonista’s app extensions that allow you to use Python scripting within other apps on iOS.

Pythonista 3 provides two different app extensions which are affected by this module: the share extension and the Today widget.

The Share Extension

Pythonista’s share extension allows you to process data from other apps through the standard iOS share sheet.

To use it for the first time, you have to invoke the share sheet in some app that supports it, e.g. Safari, then tap either “More...” (iOS 12 and earlier) or “Edit Actions...” (iOS 13+) turn on the “Run Pythonista Script” action. You only need to do this once – after you’ve activated the action, it will show up automatically.

After it’s activated, you can invoke a “Mini Pythonista” from almost any app that uses the share sheet. The share extension includes an interactive console, a basic script editor, and you can add shortcut icons for running your favorite scripts quickly.

When an app uses the share sheet, it typically passes some data to it – e.g. the current page’s URL in Safari, text in Notes, or an image in Photos. You can access (and process) that data using the functions in this module, e.g. appex.get_url(), appex.get_text() etc.

Special considerations for running scripts in the share extension:

  • When you present a ui.View (using ui.View.present()), the presentation style is ignored. On iPhone, the presentation is always full-screen, on iPad, the view will cover the main view of the app extension, and it’s not possible to create full-screen views.
  • Some functions, most importantly webbrowser.open(), will not work within a share extension script. The notification module is also unavailable.
  • The camera is not available to app extensions, so photos.capture_image() will not work.

The Today Widget

The Today widget allows you to run a single script within a widget that is quickly accessible from anywhere on iOS, by pulling down Notification Center (and showing the “Today” tab), on the first page of the home screen, or even from the lock screen (by swiping right).

To activate the Today widget, you have to tap the Edit button in the Today view, and select the Pythonista widget. You also have to select a script that the widget should run – you can do this in Pythonista’s settings. To get started, you may want to try one of the scripts in the included Examples/Widget folder.

Note

The Today widget requires iOS 10 or later, and only supports Python 3.

The selected script will run every time the widget is shown. Typically, it will use the set_widget_view() function to show a simple user interface (created with the ui module) in the widget.

Compared to the share extension, the capabilities of the Today widget are more limited. Only a subset of Pythonista’s APIs are available, and it gets a significantly smaller amount of RAM from the system than both the main app and the share extension.

Special considerations for running scripts in the Today widget:

Warning

Memory is very limited in the widget – if your script runs well in the main app, but you see a “Could not load” message in the widget (or the widget is empty), it is likely that your script used too much memory and was terminated by the system. You can also try rebooting your device when this happens.

  • Dialogs (everything in the dialogs, console.alert() etc.) are not available in the widget.
  • The ui.View.present() method is not available. To show a user interface in the widget, you have to use the set_widget_view() function.
  • If you find the widget getting stuck, you can terminate the process manually by tapping and holding it with two fingers for about 3 seconds.

Functions

appex.is_running_extension()

Return True if the script is running within an app extension (share extension or widget), False otherwise.

In case you want to test your script in the main app, you can e.g. use this to load dummy data to replace the share sheet’s input.

appex.is_widget()

Return True if the script is running within the Today widget, False otherwise.

appex.finish(js=None)

Close the share sheet extension. The optional js parameter is only relevant when the extension is shown in Safari. It specifies a piece of JavaScript code that is evaluated in the context of the current web page, after the Pythonista sheet is closed. Calling this function from the main app has no effect.

appex.get_attachments(uti='public.data')

Return a list of attachments that match the given type identifier. In most cases, it is a lot easier to use the type-specific functions (like get_image(), get_url()...) instead.

appex.get_images(image_type='pil')

Return a list of images in the input of the share sheet. image_type can be either ‘ui’ or ‘pil’. If the type is ‘ui’, ui.Image instances will be returned, otherwise PIL images. If there are no images in the input, the return value will be an empty list.

appex.get_image(image_type='pil)

Return the first image in the input of the share sheet. image_type can be either ‘ui’ or ‘pil’. If the type is ‘ui’, a ui.Image instance will be returned, otherwise a PIL image. If there are no images in the input, the return value will be an empty list.

appex.get_image_data()

Return raw image data for the first image in the share sheet’s input. The data is returned as a byte string. If there is no image in the input, the return value is None.

appex.get_images_data()

Return raw image data for all images in the share sheet’s input. The data is returned as a list of byte strings. If there are no images in the input, the return value is an empty list.

appex.get_text()

Return text input of the share sheet (as a unicode string). If there is no text in the input, the return value is None.

appex.get_urls()

Return a list of URLs in the share sheet’s input. If there are no URLs in the input, the return value is an empty list.

appex.get_url()

Return the first URL in the share sheet’s input. If there is no URL in the input, the return value is None.

appex.get_file_paths()

Return a list of file paths in the share sheet’s input. If there are no file paths in the input, the return value is an empty list.

appex.get_file_path()

Return the first file path in the share sheet’s input. If there is no file path in the input, the return value is None.

appex.get_vcards()

Return a list of VCard records in the share sheet’s input. Each record is represented as a string. If there are no Vcards in the input, the return value is an empty list.

appex.get_vcard()

Return the first VCard record in the share sheet’s input. The record is represented as a string. If there are no Vcards in the input, the return value is None.

appex.get_web_page_info()

When the share sheet is shown in Safari, return information about the currently loaded page. The return value is a dict, and usually contains the following keys (all values are unicode strings):

  • 'url': The full URL of the page (document.URL) – if you need only this value, you can use get_url() instead (which also works in other apps)
  • 'title': The title of the page (document.title)
  • 'html': The HTML source code of the page – Please note that this is constructed from document.documentElement.outerHTML, and may not necessarily be exactly the same as what was loaded from the server (e.g. in case of DOM manipulation via JavaScript etc.)
  • 'selection_html': Selected text (in HTML format, preserves formatting, links etc.)
  • 'selection_text': Selected text (as plain text)
  • 'cookie': The value of document.cookie
  • 'referrer': The value of document.referrer

Missing values are represented by an empty string.

If the share sheet is shown in another app (not Safari), or if information about the current page cannot be retrieved, an empty dict is returned.

appex.get_widget_view()

Return the view that is currently shown in the Today widget (or None if no view was set via set_widget_view()).

appex.set_widget_view(view)

Set the widget’s view to a ui.View object. The view is automatically resized to fill the widget, and the view’s current height is used as the expanded height of the widget (when the “Show More” button is tapped). If the view’s height is <= 120, the widget does not show a “Shore More” button, and only the compact widget display mode is used.

To remove the current view from the widget, pass None instead of a view object.

If the script is running in the main app, a simulated widget view is shown.