iOS 15 revamps the extension system built into iOS and iPad OS. This update lets us build full-fledged extensions for iOS users, including JS/CSS injection, full user-interfaces written in web languages, and more.
One annoyance I hit a lot when I'm browsing on my iPhone is the Reddit "Open in App" prompts. Sometimes you can "Continue in Safari" but other times, the prompts are completely blocking, like this:
If I found a Reddit thread or subreddit through a Google search, I probably don't want to open the app. Some people don't like using the app at all. It's a pretty dark design pattern designed to move people to the app, for seemingly no benefit to the user. So we'll create an extension to block these intrusive popups!
You'll need macOS Monterey, which is available in a public beta, and the newest version of Xcode, which you can download from the Mac App Store.
Open Xcode and hit New Project. In the template selection menu, search for "safari" and choose
Safari Extension App.
Choose a name for your extension, I made mine
Viewwit, and hit Next. Choose a folder and hit Create.
You'll notice two main folders in your project, which represent two targets - the main app, and the Safari Extension.
This project template is designed for web developers! So, the main app has all of the Swift needed for a simple extension already written, and it has a Resources folder with an HTML file,
Main.html, for designing the app interface.
For now, we'll focus on the Extension folder. This folder also has a Resources folder with all of the HTML/CSS/JS for a basic extension. It also includes a
manifest.json which tells Safari about your extension - which files are used for what, which permissions your extension needs, etc. All of this follows the same standards as Chrome extension development, which is pretty nice because it means there's lots of information online about the manifest fields and extension development.
For my extension, I needed to add a script to modify the page HTML. This is a simple extension which doesn't need any background processes, so I commented out the JS in
background.js and removed its declaration from the manifest file.
When you open the
content.js file, you'll see a message system set up. I also didn't need that, so I deleted it. I replaced this code with simple JS to use document.querySelector to find the elements we need to delete and delete them, and run that function on an interval. For most cases, you would want to use
window.onload or the
DOMContentLoaded event, but the Reddit pop-ups load after those events, so I needed the interval.
How did I find which elements need to be hidden? If you don't have the
Develop menu on your Mac Safari top action bar, go to Safari > Preferences > Advanced > Show Develop menu in menu bar and enable it. Then connect your iOS Device to your Mac (this also works with any open Simulator). Go to Safari on your iOS device and go to any site. Then in the macOS Develop menu, hover over your device, and you can see your iOS device open tabs. Click one to open the full dev tools for your iOS tab on your computer! You can hover over elements, and edit or delete them as needed.
manifest.json, fill in the name and description for your extension.
content_scripts field. You should see a URL matcher checking for
example.com. Replace that with the domain relevant to your extension, for example:
"js": [ "content.js" ],
"matches": [ "*://*.reddit.com/*" ],
(I also added the run_at field to start my interval as early as possible)
I also added
"*://reddit.com/*" to the
permissions field array.
If you want to match all URLs, add
"<all_urls>" to your
You can test your extension by running it on an iOS simulator or on your device. You need to enable the extension in Safari or in Settings after installing the app.
I designed a basic logo in Excalidraw.
Then I used PWA Builder's Image Generator to generate extension Icons from the logo. I renamed the appropriate sizes to match the existing images in
Resources/images, and dropped them in that folder to replace the template images.
Finally, I used AppIcon.co, dropped in my 512x512 image from PWA Builder, and generated the icons for my app.
Additionally, I updated the content in both HTML files, the extension
popup.html and the app's
popup.html I added static content saying the extension is active, and in
Main.html I added instructions on how to enable the extension. You can build much more complex functionality in
popup.html and connect it to the webpage or your app, but I didn't need that for my use-case. Check out Apple's docs and examples on this for more info!
Lastly, I archived a build of my app, and prepared it for submission in App Store Connect. There are lots of tutorials on how to do this online :)
In this post, we walked through the process of building an iOS 15 Safari extension. We covered how to start a Safari extension, how to work with iOS web dev tools on a Mac, and the basic files involved in building the extension's functionality. This is a really powerful system and I can't wait to see what people build with it!
Follow me here or on Twitter for more articles and some tweets, sometimes they're even funny! Feel free to DM me for any questions!