Hi! In this tutorial I will teach you how I coded InstantCamera. This tutorial is targeted towards a more advanced audience, and if you don't know how to program tweaks at all, I highly recommend my iOS 14 Tweak Development Beginner Tutorial or PinAnim tutorial:
However, if you have already read that tutorial, let's get started!
The Goal & Plan
The goal of this tweak is to capture a photo as soon as the user taps the Camera shortcut button on the Lock Screen. The button looks like this, if you forgot:
The simplest way to do that, is to replace the Force Touch gesture. Then, we will have another tweak that is injected into the Camera app and calls a method to take a photo as soon as the camera is ready (there is still a slight varying delay).
We also need to know from the Camera tweak whether the app has been launched from the Shortcut button, or regularly (e.g. from Home Screen). In latter case, we don't need to instantly capture a photo.
Set up the SpringBoard project
Let's get started.
cd to your projects directory, run the
nic.pl script from Theos and fill out the information. This will be the project that gets injected into SpringBoard. Later we will need to also create a subproject for Camera. Don't forget to run
make spm and open the project in your favorite IDE (I'm using Xcode for this tutorial).
Inspecting using FLEXing
Now we need to know what exactly to hook. Let's start with the Shortcut button as it's the most logical thing to start from.
Bring up FLEX and select the button (You may need to move away some other views that are overlapping the button):
You will find that the class for buttons is
CSQuickActionsButton and for the parent view it's
CSQuickActionsView. Try finding a method that could be hooked to make the button not have a long delay until Camera app finally opens. (Due to limitations of the blog editor I'm writing this in, I cannot hide that image below, so don't look at it just yet if you don't want to spoil the answer)
There is a method that is executed when user begins a touch.
The method we are looking for is
-(void)handleButtonTouchBegan:(id)arg1 ;. We can hook it, and check if the button's type corresponds to camera's and call
-(void)handleButtonPress ; right away.
Instantly open Camera app on short button touch
I create a new global variable here
shouldCapturePhoto – we will need it later to differenciate shortcut button press and regular app opening.
You also need to add headers in
If you encounter a
symbol(s) not found error, make sure to add
CoverSheet private framework to
PRIVATE_FRAMEWORKS variable in the Makefile. Insert a new line after CFLAGS in Makefile of Camera project –
InstantCamera_PRIVATE_FRAMEWORKS = CoverSheet
Compile the project using
make do THEOS_PACKAGE_SCHEME=rootless and now the camera button should open Camera app instantly.
Switching to "photo" mode
We need a way to switch to photo capture mode as soon as the app opens. Try searching for a method in one of UIViewControllers inside Camera. If you don't know the name of view controller, you can select one of the views in the hierarchy, tap "i" and select "Nearest View Controller":
UIViewController that contains the method we are looking for is in
-(void)changeToMode:(NSInteger)arg0 device:(NSInteger)arg1 animated:(BOOL)arg2 ; inside
-(BOOL)capturePhoto;, which we will need later.
Set up the Camera project
cd to your project directory and run
nic.pl once again. Choose a different identifier, for example
net.sourceloc.instantcamera.camera. Target process should be
Camera with the first letter capitalized. Bundle Filter should be
com.apple.camera, as that is the Bundle ID for the Camera app.
Now with the project setup, lets hook the app delegate's
applicationDidBecomeActive, so the code gets executed on every app enter, and execute the found method mentioned in the "Solution" drop-down from there:
However, just like we did before, we also need to check if app was opened using the Shortcut button. Remember how I mentioned
shouldCapturePhoto earlier? The easiest method would be to send a notification from Camera to SpringBoard, signaling that the app has entered foreground, and then SpringBoard should respond with another notification if Camera needs to take a photo. It's a workaround, and I'm sure there's a better way to do that using semaphores, but I don't know how :P
I'm temporarily using a delay of
1.0 seconds here with
asyncAfter(deadline:exeute:). We will change that in a moment.
To be able to access
viewfinderViewController you will need a property defined in
And in SpringBoard project:
Compile the project, press the camera button and the phone should first switch to Camera mode and shortly after take a photo... but not instantly :) Let's find a method that gets executed when the camera is ready.
Capture photo when the camera is ready
This method took me the longest to find. I've been searching for methods with names "ready","blur", "opacity", "alpha", "switch" in all sorts of UIViewControllers and in UIViews inside Camera. And I finally found something that looked promising inside
I found it by decompiling the entire CameraUI's framework binary in Binary Ninja (could've been done just by using GitHub Search, but I was already in the decompiler at the time) and searching for "didChange":
Here's how it could've been found if I used GitHub Search (using qingralf's dumped iOS 16 headers):
Let's try logging something using RemoteLog (i have the wrapper function called
And sure enough we see the output once the mode has been changed and camera is ready to take a picture:
Let's execute take the delegate, cast it and capture a photo:
Make sure to also remove the temporary delay we made before:
Let's compile aaaand...
Error. Just like before, insert a new line after CFLAGS in Makefile of Camera project –
InstantCameraCamera_PRIVATE_FRAMEWORKS = CameraUI
Compile again and you now the tweak should be complete. Try taking a photo by using the shortcut button on Lock Screen!
credits to icraze for bootloopware