WKWebView implementation for Pythonista.
Available as a single file on GitHub. Run the file as-is to try out some of the capabilities; check the end of the file for demo code.
Credits: This would not exist without @JonB and @mithrendal (Pythonista forum handles).
WKWebView matches ui.WebView API as defined in Pythonista docs. For example:
v = WKWebView() v.present() v.load_html('<body>Hello world</body>') v.load_url('http://omz-software.com/pythonista/')
For compatibility, there is also the same delegate API that ui.WebView has, with
webview_should_start_load etc. methods.
Mismatches with ui.WebView
Synchronous vs. asynchronous JS evaluation
eval_js_async method, with an optional
callback argument that will be called with a single argument containing the result of the JS evaluation (or None).
We also provide a synchronous
eval_js method, which essentially waits for the callback before returning the result. For this to work, you have to call the
eval_js method outside the main UI thread, e.g. from a method decorated with
Handling page scaling
UIWebView had a property called
scales_page_to_fit, WKWebView does not. See below for the various
disable methods that can be used instead.
Additional features and notes
Looks like Pythonista has the specific plist entry required to allow fetching non-secure http urls.
Cache and timeouts
For remote (non-file)
load_url requests, there are two additional options:
Trueto skip the local cache, default is
timeoutto a specific timeout value, default is 10 (seconds)
You can also explicitly clear all data types from the default data store with the
clear_cache instance method. The method takes an optional parameter, a plain function that will be called when the async cache clearing operation is finished:
def cleared(): print('Cache cleared') WKWebView().clear_cache(cleared)
Following media playback options are available as WKWebView constructor parameters:
inline_media- whether HTML5 videos play inline or use the native full-screen controller. The default value for iPhone is False and the default value for iPad is True.
airplay_media- whether AirPlay is allowed. The default value is True.
pip_media- whether HTML5 videos can play picture-in-picture. The default value is True.
Other url schemes
If you try to open a url not natively supported by WKWebView, such as
tel: for phone numbers, the
webbrowser module is used to open it.
There is a new property,
swipe_navigation, False by default. If set to True, horizontal swipes navigate backwards and forwards in the browsing history.
Note that browsing history is only updated for calls to
load_html is ignored (Apple feature that has some security justification).
By default, no Apple data detectors are active for WKWebView. You can activate them by including one or a tuple of the following values as the
data_detectors argument to the constructor: NONE, PHONE_NUMBER, LINK, ADDRESS, CALENDAR_EVENT, TRACKING_NUMBER, FLIGHT_NUMBER, LOOKUP_SUGGESTION, ALL.
For example, activating just the phone and link detectors:
v = WKWebView(data_detectors=(WKWebView.PHONE_NUMBER, WKWebView.LINK))
Messages from JS to Python
WKWebView comes with support for JS-to-container messages. Use this by subclassing WKWebView and implementing methods that start with
on_ and accept one message argument. These methods are then callable from JS with the pithy
window.webkit.messageHandler.<name>.postMessage call, where
<name> corresponds to whatever you have on the method name after the
Here's a minimal example:
class MagicWebView(WKWebView): def on_magic(self, message): print('WKWebView magic ' + message) html = '<body><button onclick="window.webkit.messageHandlers.magic.postMessage(\'spell\')">Cast a spell</button></body>' v = MagicWebView() v.load_html(html)
Note that JS postMessage must have a parameter, and the message argument to the Python handler is always a string version of that parameter. For structured data, you need to use e.g. JSON at both ends.
User scripts a.k.a. script injection
WKWebView supports defining JS scripts that will be automatically loaded with every page.
add_script(js_script, add_to_end=True) method for this.
Scripts are added to all frames. Removing scripts is currently not implemented.
Following two convenience methods are also available:
add_style(css)to add a style tag containing the given CSS style definition.
add_meta(name, content)to add a meta tag with the given name and content.
Making a web page behave more like an app
These methods set various style and meta tags to disable typical web interaction modes:
disable_scrolling(alias for setting
There is also a convenience method,
disable_all, which calls all of the above.
Note that disabling user selection will also disable the automatic data detection of e.g. phone numbers, described earlier.
present your app as a 'panel', you can easily switch between the tabs for your web page and this console.
Or you can just create a WKWebView manually for quick experimentation, like in the usage example below.
Setting a custom user agent
WKWebView has a
user_agent property that can be used to retrieve or set a value reported to the server when requesting pages.