JavaScript in iOS with Scriptable

January 13, 2020

This is note 3 of 5 in a series on publishing automation.

When Apple acquired Workflow, rebranded it as ‎Shortcuts and then shipped it on every home screen that downloaded iOS 13, iOS suddenly became a lot more flexible. Apple’s first party apps and major third party apps alike shipped with built in shortcuts like “Send a message to Mom” and “Create an event with Zach”. Bear, my favorite note taking app and target of desire to use as an authoring tool for this website, also shipped with a host of neat shortcuts. To name a few:

  • Create Bear Note from URL
  • Search in Bear
  • Create Bear Note
  • Open Bear Note
  • Get Contents of Bear Note

Absent however from the list was something that could be used to extend Bear as a publishing tool. Something like “Post Bear Note to a URL,” albeit unlikely, would have made that goal immediately attainable. Instead, it became clear that despite this lengthy introduction, Workflow wasn’t the tool for the problem we're solving: make a custom network request in iOS. If possible, then we could write a cloud function, deploy it on this website, handle the payload and then post it to our CMS of choice (Contentful in my case). The CMS would then trigger a webhook in Netlify, automatically deploying a new version of this site.

Running code in iOS

To achieve such a thing, there are a few options. The most popular one, and the only one that shipped with shortcuts available by default, is Pythonista for iOS, a fully-fledged Python IDE for iOS. The only thing is, I prefer to write JavaScript, which I use daily at work. Pythonista would be the perfect option for, well, Pythonistas, given its years of continuous support and consistently high quality updates, but for JS developers there's another option: Scriptable.

Scriptable as glue for automation

Scriptable is perfect for our case. Written by Simon B. Støvring and using Apple’s JavaScriptCore, the app does a fantastic job of wrapping iOS APIs in JavaScript and allowing them to be used just like we might use the web APIs native to browsers. It’s a weird feeling at first because the APIs are domain-specific, but after a bit of tinkering I etched out this script:

// This script publishes a note from Bear to https://tyhopp.com

// Get shared note text
let note = args.plainTexts[0];

// Make POST request to publish note
let endpoint = 'https://tyhopp.com/.netlify/functions/bear-to-contentful';
let request = new Request(endpoint);
request.headers = {
// Secret Contentful access key
'bear-to-contentful':XXXXXXXXXX',
'Content-Type': 'application/json'
};
request.body = JSON.stringify(note);
request.method = 'PUT';
let response = await request.loadString();

// Show response message
let alert = new Alert()
alert.title = response
alert.addCancelAction("OK")
await alert.presentAlert()

Script.complete();

The documentation for the different classes is most readily available within the Scritable app, so if you’re interested to do something similar do be sure to give the app a whirl. For the script above, here are the key things to note:

  • When we’re on a Bear note and click ‘Share’, we can then select ’Run Script’ with Scriptable.
  • This passes the content of the shared Bear note to Scriptable, which can be accessed through args.plainTexts .
  • Once we have the content of the Bear note in Scriptable, we create a new Request and fill the required headers, body and method properties on the request.
  • We then wait for the response, and show a message in an Alert with whatever our API returns.

And done! We now can make a network request with the content of our Bear note. The next step is the most code-heavy and arguably most interesting from a technical perspective: writing an AWS Lambda function via Netlify for us to call from Scriptable. In the next two articles I’ll cover that process exactly:

  • AWS Lambda functions via Netlify (TBD)
  • Programmatic publishing to Contentful (TBD)

Previous articles in this series:

Thanks for reading ❤️

If you're jazzed about this post, feel free to tweet this article 🐦

If I missed something, please do drop me a message and I'll fix it 🔨

Otherwise, read more articles! ✍️