App Clips give people the power to discover and download a small part of your app at a moment's notice to complete tasks and transactions. Explore tips and best practices to help you create compact App Clips that emphasize modern features and elegant design. Learn how you can build reliable and secure App Clips to ensure that people can always access your experience when scanning a physical App Clip Code or viewing it through your website. And we'll take you through specific strategies for testing an App Clip before releasing it to the world.
♪ ♪ Hello and welcome. I’m Brian Goldberg, an engineer on the App Clips team. I can’t wait to show you some great tips and techniques to build light and fast App Clips. Let’s get started. App Clips are a great way for your customers to quickly access and experience what your app has to offer. An App Clip is a small part of your app that’s discoverable and downloaded at the moment it’s needed.
App Clips are deeply integrated into the OS. They can be invoked in Safari and Messages as well as out in the real world by scanning an App Clip Code, a QR code, or by tapping an NFC tag. App Clips are also surfaced in Maps and Siri suggestions. This session is loaded with best practices and troubleshooting tips that will help you build and deliver great experiences for your customers. I’ll show you a plan for getting your clip under the size limit.
Maybe your App Clip isn’t being surfaced on your web page or the App Clip card does not appear when you scan a code.
Perhaps you’re looking for some tips on maintaining quality in your code base, while taking on the added complexity that comes with adopting new features.
And maybe you’re curious to know what functionality you can leverage that’s specific and unique to App Clips. Whether you’re building from scratch or adding a clip target to an existing app, I’ll walk you through real-world issues developers face on a daily basis, and I’ll give you actionable next steps for building better clips and apps. Even when your users are in areas with good mobile network coverage, their download speeds can vary.
To ensure that App Clips can be provided on demand at a moment’s notice, the maximum size of an App Clip is limited.
Therefore, as a developer, it’s important to optimize your content for size. It’s good to know early on and often during development if your clip is compact enough to be delivered on-demand.
Many of you are familiar with the iterative process of profiling and optimization in software development.
I’d like to show you a process where you can use Xcode to generate a size report and export an IPA for each device variant.
Then I'll walk you through a set of basic and advanced optimizations you can perform to reduce the size of your App Clip. The goal is to avoid being surprised at app submission time if your clip is over the limit. I put together a fun example for us to look at. It’s a version of the Fruta sample that has a number of gotchas that put it over the size limit. The gotchas are simple to illustrate some key points. Your apps are undoubtedly more complicated and have tons more features, so please use my example as a starting point for further exploration. Let’s start by launching into Xcode to go through the steps to generate the size report and export the IPA files, and we’ll uncover these gotchas and learn how to fix them together.
First select the full app scheme.
Then go to the Product menu and choose Archive.
This builds the project using the configuration specified in the scheme editor.
When the organizer opens, click Distribute App. Choose Development.
Now select your App Clip.
In the App Thinning dropdown, choose all compatible device variants. Make sure that rebuild from bitcode is checked.
When the archive is done preparing, click Export.
Then select a location on the file system to export to.
Now open the Export folder in Finder...
And then open the App Thinning Size Report.txt.
There’s a section for each device variant.
The second to the last line in each section will tell us the uncompressed size for that variant. That’s what we’re interested in. Looking at the size, this tells me two things. One, I’m over the size limit. Two, I’m not seeing the effects of app thinning because all the device variants are around the same size.
Let’s close the size report and dig a bit deeper to see why that is.
Open the Apps subfolder. Rename one of the variant IPAs extension to .zip, and confirm. Double-click to uncompress. Open the Payload folder and Control-click to show the package contents.
Let’s look closely. Looks like my images are individual bundle resources. Perhaps I’ll save some space if I put these in an asset catalog.
I see a documentation zip and a README file that don’t belong here in the installable product.
There’s a framework being used by my clip. I bet that’s taking up some space too.
I see some localization folders present, and I know that sometimes these files can grow if left unchecked.
The compiled executable is relatively small... but maybe there’s a way to get it even smaller. Every little bit helps. Let’s continue on and see what can be done to fix some of these issues. That process of generating a size report and looking through the IPA was very helpful because it identified a number of steps I can take to reduce the App Clip size. Let’s start with some basic steps first, and then we’ll move on to more advanced techniques. We’ll double-check the build settings, we’ll go over the benefits of using asset catalogs, we’ll exclude any files from making their way to the final product that don’t belong, and we’ll go through our code and settings and refactor for size reduction. Keep in mind the optimizations we’ll cover apply to both your app and App Clip, so feel free to apply these tips to both types of products. Now let’s explore each topic in more detail. The compiled code portion of the App Clip package certainly wasn’t the largest contributor to the clip’s size. It was definitely the assets, which we’ll get to in a moment. But every little bit helps. By default, Xcode will build using the smallest, fastest optimization setting, but let’s double-check to make sure that’s what’s set in my project. Make sure the full app is set as the active scheme and Option-click to display the scheme settings. Our archive build should be set to release, but it looks like I changed it at some point and forgot to change it back. I was also experimenting a bit in build settings and moved the release optimization level off of the default. Let’s change it back so that we’re using the best combination of small binary size and fast runtime execution. Most of the time, as in my case, assets like images, audio, and video take up the most space. The most important step you can take to reduce the impact these assets have on your App Clip size is to use asset catalogs, and this is for two reasons. One, the media you add to asset catalogs is automatically optimized as part of the Xcode build process. And two, when customers download your app or clip, the product they download will be made small enough to only contain assets suitable for their device. This is also known as app thinning, and we should certainly take advantage of it.
In my project, I really should have put those images in an asset catalog. We can actually do even better. I’ll create a second asset catalog, and I’ll move all the images that are shared between my app and App Clip into this catalog.
Let’s bring both catalogs side by side.
We’ll move the icons and colors into the shared catalog.
Then we’ll put the ingredient and smoothie images into the shared catalog.
Since the recipe images are only needed by the full app, I’ll put those in the unshared catalog so they don’t count against the size of my App Clip. I’ll make sure to remove those images that I copied over to the asset library.
And last, I’ll use the target membership editor to exclude the unshared asset catalog from my App Clip. For a deep dive on the asset catalog, check out the sessions on optimizing storage in your app and optimizing app assets.
Earlier, we inspected the IPA on the file system, and we saw a few things that didn’t belong like a README file and a zip containing documentation. Let’s go ahead and use the target membership editor in Xcode to exclude these files from all of our build products. Ensure you’re only including code in your App Clip target that’s necessary for the task being performed.
I find it helpful to look in the build phases to get an overview of every source file that is contributing to my App Clip. If I see something that looks unnecessary, I remove it from the list of sources and rebuild. The recipe and rewards functionality of Fruta are necessary for the full app but not the App Clip, so let’s remove those files. You can even let the compiler assist. If there are build errors, either the file was necessary, there’s more to remove, or perhaps there’s code that needs to be conditionally compiled out of the App Clip target. Over time, localized strings files can become inflated with duplicates and unused strings.
Inspect the strings files and delete anything that’s not needed. Similar to what we did for asset catalogs, you can create a dedicated strings file so that you aren’t including your full app’s localized strings with your App Clip.
I’ve covered some basic optimizations you can implement today to get your App Clip ready for submission.
Now suppose, as part of this iterative process, you measure again, you look at the size report, and you still aren’t where you need to be. That’s OK. I have several advanced optimization strategies for you to consider.
First, evaluate your external dependencies and take their size into consideration. Remember, App Clips are bite-sized versions of your app, so make sure you are only linking what's needed for your clip’s functionality. Remember that SmoothieAccountLogin framework that was adding to my App Clip’s size? Most of the time, there’s an Apple framework already integrated into the OS that will help you accomplish your goal.
Using one of these built-in frameworks is free, and it’ll make your app and App Clip lighter and faster, which means it’ll download faster, launch faster, and allow your customers to complete the task at hand faster.
Use Sign in with Apple to make it easy for users to sign in to your service with just their Apple ID. For payments, Apple Pay is fast and easy both for you, the developer, and for your customers. For communication over the network, use NSURLSession. For 3D graphics, leverage RealityKit and Metal. For more in-depth authentication flows, check out ASWebAuthenticationSession. It’s almost always the assets and not the code that pushes the size of an App Clip over the limit. More often than not, those assets are images. In the basic steps, I moved all my images to asset catalogs to take advantage of built-in optimization and app thinning. Sometimes that’s not enough and you need to take further action to reduce the size of your images. The format and options you use when saving the source image can often have a profound effect both on size and quality. So how do you make the best choice? Generally speaking, a PNG image will consume more space than a JPEG image, so use PNG if you need a specific feature that format provides like transparency...
Or when JPEG's lossy compression would result in an unacceptable loss of quality. These examples contain high-frequency features, crisp edges, and defined highlights. The lossless compression of PNG will preserve these features much better than JPEG.
And while we’re on the subject of PNG, consider PNG8 for non-photographic material.
The image on the right was saved out as PNG8 for a huge reduction in file size. When you export your images, do a side-by-side comparison to make sure your optimizations hold up. A reduction in color depth can save a lot of space but is only appropriate for certain imagery that won’t suffer from quantization artifacts.
For photographic material, when you need to save space, use JPEG and lean a bit on lossy compression. You don’t have to accept your content creation tool’s defaults when saving your images. In my case, I reduced the file size significantly without a perceptible loss in quality.
Let me show you a little trick that you might be able to use in your project to make sure your image quality holds up under various optimizations. I temporarily replaced the pineapple with a mango that was saved out as a higher compression ratio. This lets me do a quick A/B comparison in the actual app to verify my changes didn’t result in a loss of quality.
For video, encode using the latest standards like HEVC.
As a general rule, compress audio using AAC or MP3 codecs, and experiment with a reduced bit rate. Quite often, super-high bit rates aren’t necessary, and a lower bit rate clip won’t result in a perceptible drop in quality. For certain kinds of images like interface controls, logos, and icons, representing them in SVG format can lead to significant space savings, and because it’s a vector format, it will look great rendered at any size.
Speaking of the SVG format, we love it so much we chose it to back SF Symbols, which I highly recommend. There are over 2,000 configurable symbols to choose from. They come in a wide range of weights and scales that automatically align with text labels, and dynamic type is supported out of the box.
Here’s some code to get you started using SF symbols in your project. This code snippet shows how a similar text style can be applied to both a label and a symbol image. A baseline constraint keeps the label and symbol image aligned perfectly. Instead of including several variations of an image in your asset catalog, include one base image and build the variations needed at runtime. Check out the Fruta sample for a fantastic example of how this is put into practice. Instead of using a separate image for each presentation of the orange ingredient-- one for this collection view, another for the full image view with vertical text and controls, and a third for the ingredient card back...
This one single image serves as the backing asset for three distinct uses. The result is a significant space savings achieved by constructing the variations at runtime. Finally, if you’ve completed all the other steps and still have assets that put your clip over the size limit, consider lazily loading those assets from a content delivery network.
For example, ship good quality but lower resolution placeholder assets with your App Clip and use the new Async image API to replace these assets progressively after launch.
Check out the What’s new in SwiftUI session for more. And a tip: use the network link conditioner to test your App Clip under a variety of different bandwidth scenarios to make sure you aren’t introducing any delays for your customers in completing the task at hand. With these advanced optimizations, we’ve reached the end of the first topic. You can explore further and discover more techniques in the developer documentation for reducing your app’s size.
Say you’ve released your App Clip to production and you don’t see it offered as expected when you view your website in Safari. Or maybe you scanned a QR code and were directed to Safari instead of seeing the App Clip card.
Generally, these issues fall into a couple of different buckets: registration of the experience and associated domain configuration. Let’s do a quick terminology refresher, and then I’ll go over some steps you can take to fix the issues. In App Store Connect, you have the ability to add two types of experiences. All App Clips must have a default experience. For the default experience, you specify metadata that populates the App Clip card when invoked from your web page in Safari or when someone sends a link to your web page in Messages. In order to take advantage of physical invocation like QR scanning, NFC, and App Clip Codes, you need to be sure to add an advanced experience.
Keep in mind, registration takes time to propagate to devices, so changes made in App Store Connect won’t be instantly available. For an in-depth look at registering experiences, please see the sessions for What’s new in App Store Connect and Configure and link Your App Clips. Prior to displaying UI that surfaces your App Clip, the OS checks to make sure that the invocation domain is verifiably associated with your App Clip. In other words, that means the URL viewed in Safari or encoded in a QR code must have a secure association via entitlements and an AASA file with your app and App Clip. If this is not configured properly, your clip will not be surfaced. For more information on establishing this secure association, please see the What’s new in Universal Links session and the Configure and link your App Clips session.
Let’s say you’ve configured everything and you check Safari and you expect to see your App Clip card presented inline like this.
But unfortunately you just see your web page and nothing else appears. So what might be the problem, and what troubleshooting steps can you take? First, verify the syntax of your meta tag and make sure it looks similar to this template. Replace the yellow placeholders with your full app’s App Store ID and your App Clip’s bundleID respectively.
I’ll show you a technique I use to make sure the meta tag is constructed correctly. Navigate to your web page in Safari and open the web inspector. Expand the head element and look closely at the source. Then check the node attributes to ensure your meta tag is parsed correctly and that your App Clip bundleID is exactly the same as what is shown in Xcode and App Store Connect. Is forwarding or redirection interfering with domain validation? Example.com is not considered equal to www.example.com as far as the domain validation machinery is concerned. The important thing to remember here is that the domain serving the content, the domain that’s at the end of the redirection chain, should be the domain that serves the AASA file and is included in your associated domain’s entitlement.
Also remember that Safari won’t display the full App Clip card or the Smart App banner if private browsing is enabled. If you’re still stuck, verify the AASA passes validation in the ASC portal.
You can use the SWCutil command line tool to retrieve an AASA file from your web site at the expected location. This is very similar to the operation performed by App Store Connect. You can use this to ensure there are no errors preventing App Store Connect from retrieving the file. Check the JSON output for common mistakes such as bundleID specified instead of applicationID.
For more information, please check out the What’s new in App Store Connect session as well as the What’s new in Universal Links session. Now for physical invocation like App Clip Codes, QR codes, and NFC tags, here is the expected experience.
If not fully configured, your web page will be offered in Safari instead of your customers seeing the App Clip card in Camera.
Many times the reason this occurs is because an advanced experience has not been created for the URL encoded in your physical codes. Even if your QR code URL is the same as your website URL and your experience displays perfectly in Safari, it’s still necessary to create an advanced experience in App Store Connect to power your physical codes. Remember this slide from when we were troubleshooting Safari invocation? For web traffic, all redirects are followed prior to domain validation. I’d like to make you aware of a subtle yet important difference in the way domain validation is handled for physical codes. Say you’ve been using a unique domain in your QR code URLs and have been forwarding that to your website to provide consistency across platforms. You’re already serving an AASA file from that domain for customers that enter directly through the web. Now, here comes the subtle difference. For code scanning, it’s necessary to add the exact domain to your App Clip’s entitlements and serve an AASA file as well from this domain. The reason behind this is to give quick feedback to the user that is scanning a physical code. And we avoid performing network requests that would typically result in following a redirection chain. Changes to advanced experiences or site association take time to propagate to devices.
If you’ve made sure the URL you’ve been scanning has been added as an advanced experience and you still don’t see the App Clip card, try clearing the experience cache in Developer settings. On to the next topic. You’ve undertaken some additional complexity in your project, and the upside is that you now have a more modern, platform-following experience. I’d like to show you some steps you can take to embrace the extra functionality while maintaining the level of quality you’ve worked so hard to achieve up to this point.
Let’s take a look at a diagram that shows functionality for a basic restaurant app. In this example, customers start by browsing the restaurant’s menu. Next, they can customize a burger or a cocktail and then checkout. After that, they see their order status and options for order pickup.
Now let’s say the restaurant would like to enhance the experience by adding two features: pay at the table with a QR code and send the burger you customized to a friend as a link so they can order one too.
This will require some significant redesign because both of these features rely on launching directly to the checkout step. The requested features are really great opportunities for an App Clip, but shoehorning it into the current design will create a lot of additional complexity. What steps can be taken to make the app more flexible? First, I’d like encourage you to create flattened, modular functionality where each component of your app is independent and can be directly launched into. This approach is much more suited to deep linking, which is fundamental to how App Clips are invoked and provided state. Design the checkout module to be directly invoked by providing, say, a list of menu items, which you can encode in a URL. By representing the order as a URL embedded in a visual code, you give your customers the ability to pay for their check at the table. Once a food item is encodable in a URL, you can use this paradigm to encourage your customers to share what they’ve ordered with their friends so they can buy the same thing too.
With very little overhead remaining, you’re able to adopt App Clips and increase your reach by providing this functionality on demand to customers that haven’t yet downloaded your app. I just showed some ways to think a bit differently about the design of your application, to unlock extra functionality while keeping the overhead to a minimum. Now let’s look at how to minimize some of the boilerplate code that’s involved in offering an App Clip. In your app’s code, you are likely responding to life cycle events, typically with these methods that are called when your app is launched or resumed from background.
Adopting App Clips adds another set of these same exact life cycle methods. You might be tempted to place code in your App Clip’s life cycle methods that extracts the URL from the UserActivity and uses that extracted URL to derive some state and show some UI.
The concept is sound, but before doing that, I suggest refactoring so that the code that handles both your app and App Clip launch is shared. This eliminates a whole class of bugs and headaches of trying to maintain similar functionality in separate launch paths between your App Clip and full app.
Consider creating a method like respondTo that takes the user activity as a parameter. Use this method as the main entry point of your app and clip by directly calling it from all of the relevant life cycle methods.
Now you’re executing code that’s common to both your app and clip, which greatly reduces the overhead. Perhaps you respond to that user activity by extracting restaurant menu items from the URL to facilitate the customer paying the check at the table. Since this is all code that’s shared, you can make changes once and get the benefits in both your app and App Clip. Any discussion on adopting modern features in your project while maintaining quality would not be complete without mentioning testing. There are two techniques specific to App Clips that I’d like to remind you about.
For iterative development, when building and running in Xcode, set the _XCAppClipURL environment variable to an invocation URL of your choice. When you run your clip, the URL you set here will be passed through to your clip just as it would be on a customer’s device.
To see your in-development clip surfaced by the OS similar to production devices, navigate to Developer settings and create a local experience.
You really need to try this out before submitting your clip to get a better feel for how your customers will use your App Clip on their devices. Otherwise, you’re missing out on some great opportunities to test many of the ways your clip can be invoked, like scanning a code in Camera. It’s also a great way to try out new features in seed builds before they’re available in production like the new App Clip card experience in Safari.
I’ve just skimmed the surface on how awesome local experiences are for testing App Clips. For more, please see this year’s What’s new in App Clips session and, for a detailed description on testing App Clips, please see the developer documentation titled Testing Your App Clip’s Launch Experience. Last, there’s some functionality that’s specific to App Clips that all developers should take advantage of.
When App Clips were introduced, two streamlined permissions items were made available just for App Clips. These items are called ephemeral notifications and location confirmation. You’re able to provide pre-authorization for your customers to take advantage of right on the App Clip card. Ephemeral notifications lets you send notifications for 24 hours since your App Clip was last launched, and location confirmation helps you confirm the customer is within an area you expect without asking for or needing to know their precise location. This helps prevent an accidental payment at the wrong gas station or ordering a smoothie from a Fruta shop in the wrong town.
As a developer, you opt in to this functionality in your Info.plist. Now your App Clips have access to these unique permissions without interrupting the launch of your experience with alerts that ask for more than you actually need.
Location confirmation is only available for physical invocations like an NFC tag, an App Clip Code, or a QR code. Customers can opt out of location confirmation for the current session or for all requests.
Please be sure to handle these states appropriately by checking the error from confirmAcquired and offer the customer helpful guidance on what occurred and perhaps options to resume their transaction under more favorable conditions. A quick note about profiles and signing in Xcode. Most of you have enabled automatically manage signing in the Signing and Capabilities section of your project settings, which is fantastic.
If you’re manually managing signing, make sure you obtain a recent profile. One immediate benefit is when your customers upgrade from your App Clip to your full app, their data will be migrated faster. This is one of the many benefits to you that we’re constantly working on. Having a recent profile ensures that your app and clip have the capabilities necessary to take advantage of these improvements.
You’ve now learned some great techniques to build light and fast App Clips. It’s time to wrap it all up. I’ve covered basic and advanced techniques to get your clip small enough to be delivered lightning-quick on demand. I showed you how to ensure your App Clip is being invoked where and how you expect. I showed some best practices for getting your project ready for deep linking, to adopt App Clips and universal links. And I covered functionality that’s unique and streamlined for App Clips. I hope you can launch Xcode today and use some of these tips to make your App Clip lighter and faster. Please be sure to check out my colleague Yongjun’s session on What’s new in App Clips this year. Thank you, and have a wonderful WWDC. [upbeat music]
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.