Hacking with private APIs on iPad

Jan 11 2019 12:00 PM

Using private APIs can be fun. When working with private APIs, I usually prefer to write code in Objective-C, since the runtime makes it a lot easier to use classes and call methods Apple doesn’t want you to. That’s of course when I’m working in Xcode on my Mac.

But what if I want to use my other computer? You know, the one I can carry with me a lot more easily than my 15” MacBook Pro. I just recently got the new 12” iPad Pro and I wanted to do some hacking with private APIs on the go. It’s not as convenient as using ObjC and Xcode on a Mac, but it can be done. I’m going to share what I found in this brief article.

Swift Playgrounds

The best way to interact with native iOS API on iOS itself is Swift Playgrounds. It supports most built-in frameworks and you can pretty much write anything you want using the app.

To use private APIs tho, you have to interact with the runtime, and that can become very verbose and ugly in Swift. The following is an example of how to load a private framework, instantiate and show one of its view controllers using Swift Playgrounds on iPad:

import PlaygroundSupport
import UIKit
import ObjectiveC

assert(Bundle(path: "/System/Library/PrivateFrameworks/AvatarUI.framework")!.load())

let AVTSplashScreenViewController = NSClassFromString("AVTSplashScreenViewController") as! UIViewController.Type

PlaygroundPage.current.liveView = AVTSplashScreenViewController.init()

This is what you get when you run the code above:

That’s great, but as soon as you want to do more complex things, you start having to use NSSelectorFromString, performSelector, etc and that can be quite ugly. I generally use Swift Playgrounds only for very simple tests when dealing with private APIs.


JSBox is a great app that allows you to write javascript code and interact with the runtime using its bridging support. To reference something from Objective-C land all you have to do is use $objc("ClassNameHere"). You can invoke any method with invoke("method:name:here:", arg0, arg1, arg2) and the app itself provides lots of utilities for UI development and for calling into other iOS APIs.

Another advantage of JSBox is that it supports Shortcuts and has an intents UI extension, so you can write a JSBox script and invoke it via Shortcuts without having to launch the app for the script to run. You can even show UI inside the Siri interface. Here’s an example, showing how you can create a JSBox script that renders the Face ID unlock animation:

This is the result:


Pythonista is another great option since it allows you to call native APIs with an Objective-C bridge. Between the three options I’m showing in this article, I think Pythonista offers the best syntax for calling ObjC methods.

Here’s how you can write a Pythonista script that shows the iOS power down UI when run:

And here’s the result:


The best development environment to work with private APIs is still Xcode on the Mac, but there’s a lot that can be done on iOS, especially the iPad. Of the three options shown in this article, it is hard to name a favorite because each one has advantages and disadvantages, but the one I’ve been using the most, especially because of its flexibility and integration with Shortcuts, is JSBox.

I hope this article has been helpful. As always, you can reach me on Twitter.