Swift 6 Unveiled: Key Updates and a Comparison With C++

With the official announcement of Swift 6, Apple has released major updates to its programming language. In this post, we will review the latest features, discuss the pros and cons, and also compare Swift 6 to C++.

Initially intended for developing applications on iOS and macOS, Swift has transformed into a multi-paradigm language, retaining its emphasis on application development. It is one of the most popular languages used in the development of mobile and desktop applications, games, and even backend services. 

Let’s look into the new features of Swift 6 released in June 2024 and how it improves development as well as a comparison to C++.

Swift’s Timeline: How the 6th Version came to Light

Apple has a reputation for releasing products that are beautiful and user obsessed, and their programming language Swift aligns with that sentiment. Swift was made publicly available with iOS 8 in 2014, but previous developments can be dated back to the 90’s when algorithms were crafted for the NeXT system, which served as a precursor for what we nowadays know as macOS and iOS.

Unlike a majority of programming languages which have one single forebear, Swift seems to draw influence from a multitude of languages, including but not limited to, C++, Python, and even obsoleted programming languages like Haskell and Objective C. Swift is said to have been created over the span of several years by Apple engineers,TURNING It into a multi functional, high performing language in Turn.

When initially released, Swift had a rich 500 page accompanying document elaborating its tools. Soon after, Swift 2.0 was released with heightened performance features alongside improved error management in 2015. The same retouching was prevalent throughout the introduction of Swift 3.0 in 2016, where the deprecation of older syntactic constructs was accompanied by more major outline changes. 

Swift became even more polished four years later with the introduction of version 4.0, increasing stability and resilience of APIs. Then came 2019, with the release of Swift 5 which brought the long awaited ABI stability, making long term expansion planning highly accessible with newfound support frameworks. Then, on June 11, 2024 Apple released Swift 6, boasting the most advanced features and optimizations to date.

Swift 6: Features, Benefits, and Future Outlook

Swift targets developers who build applications on Apple ecosystems as it prioritizes easy adoption, rapid development cycles, and enhanced performance. It has gone through several changes since inception and seeks to address the pitfalls of existing programming languages. 

Objective-C’s successor, Swift, clearly has an advantage through its straightforward and compact form which has made code easier to understand and written with much more efficiency. Readability has been enhanced a lot due to rapid development in code.

Speed optimization is another element of development in Swift programming—for a presumed simple language, Swift is extremely fast. It benchmarks saying it is three times faster than Objective-C and up to eight times more efficient than Python. With the introduction of Swift 6, Apple aims to surpass those limits and now compete directly with C++ for speed of execution.

Key Advantages:

  • Modern Libraries and Frameworks – Swift provides an extensive ecosystem of pre-built libraries and frameworks, enabling developers to write efficient, high-quality code with minimal effort.
  • Open-Source Community – Unlike many Apple technologies, Swift is open source, allowing developers worldwide to contribute, fix bugs, and introduce new features—ensuring continuous improvement.
  • Enhanced Security – Swift improves memory management and reduces vulnerabilities, making applications more resistant to unauthorized data access and potential exploits.
  • Reduced Critical Errors – Swift’s improved scripting capabilities minimize the risk of runtime crashes and critical failures, resulting in more stable software.
  • Live Coding and Visualization – Developers can instantly preview code execution in a sandbox environment, helping them quickly identify and fix errors, thereby speeding up the development process.
  • Dynamic Libraries – Swift supports dynamic linking, allowing developers to push updates and bug fixes without requiring a full OS update.

Swift’s Limitations and Challenges

Despite its strengths, Swift is not without its limitations. It remains a specialized language primarily designed for iOS and macOS development. While there were discussions about adapting Swift for Android, the project has not materialized.

Moreover, combining Swift with older Objective C applications can be difficult. Although Apple has a bridging method, it usually creates issues with software compilation and maintenance. Fortunately, these integration problems have been eased with the changes made in Swift 6.  

Prospective use for Swift looks good in the long run. There is an increasing need for proficient Swift developers as the macOS and iOS ecosystems expand. Considering Apple’s continuous investment in the language, Swift is not likely to be terminated in the coming ten years. Its open-source framework guarantees that the community will take active responsibility in its growth, causing innovations to surge.  

Swift facing the issue of not being able to support multiple platforms makes its adoption limited to the Apple ecosystem. While this ensures advanced optimization for macOS and iOS applications, it restricts Swift’s usability beyond Apple products.  

Still, within the Apple ecosystem, Swift provides unmatched performance, security, usability, and versatility, making it a resilient choice for developers.

What’s New in Swift 6: A Comprehensive Overview

The last five years of Swift’s development is encapsulated in its sixth version which has been marked as the most important change. The update comes with numerous improvements to the overall functionality and user experience. This release, as specialists have noted, contains important new features related to the usability of the code, protection of information, parallel processing, along with other system resource management features for more constrained environments. There is still room for improvement down the line, but for now Swift has set itself up nicely with further innovations planned for the coming years.

Key Features of Swift 6

Full Parallelism Support

Parallelism has been a major focus in Swift 6, especially when it comes to executing multiple tasks concurrently. One of the standout features of this release is the introduction of full parallelism checking, which is now enabled by default. This change, a step up from the optional checking in previous versions, ensures better performance in multi-threaded applications and reduces the likelihood of errors when handling concurrent tasks.

Swift 6 also improves the accuracy of parallelism checking by eliminating false positives, particularly in the case of data races that were common in version 5.10. A key change here is SE-0414, which introduces the concept of sendability. This feature enables the compiler to verify that certain parts of the code can safely run concurrently, based on the types of data that can be sent across threads. The result is a more intuitive and efficient approach to parallelism, making it easier for developers to work with concurrent tasks.

Non-Copyable Data Types

Swift has traditionally allowed all value types and reference types to be copied. With Swift 6, however, non-copyable data types are now a reality. This feature is particularly useful in scenarios where data needs to be treated as unique resources. By preventing unnecessary copies, Swift 6 minimizes resource leaks and enhances coding convenience, making it easier to manage and handle unique resources in a program.

Seamless Integration with C++

One of the most exciting new features in Swift 6 is its ability to seamlessly interact with C++. Developers can now integrate C++ virtual methods, arguments, and standard library elements directly into Swift, eliminating the need for time-consuming transitions between languages. This deepened interoperability allows for smoother integration of C++ elements into Swift projects, ensuring a more fluid developer experience.

Additionally, Swift 6 improves the security of data by minimizing vulnerabilities that could occur when integrating with C++. This makes Swift 6 an even more attractive choice for developers working in cross-platform environments.

Enhanced Error Handling

Swift 6 also introduces one of the most robust error handling mechanisms in the industry. Bugs are automatically detected and addressed during the early stages of program development, saving time and reducing the likelihood of errors going unnoticed until later in the process. This feature helps developers create more reliable code by identifying potential issues proactively.

Function Replacement and Specialized Capabilities

Earlier versions of Swift introduced certain functions that were kept hidden or in an experimental phase. In Swift 6, these features have been fully realized, offering specialized capabilities related to variables and data management in parallel environments. These additions enhance the flexibility and power of the language, enabling developers to better manipulate data in complex, multi-threaded scenarios.

Package Iteration

Swift 6 introduces a feature that allows for iteration by packages, enabling developers to bypass parameters introduced in earlier versions. This functionality is particularly useful when dealing with tuples (ordered sets of data) and allows for a more streamlined and efficient coding process. By simplifying iteration, Swift 6 makes it easier to compare and manipulate data in complex applications.

How Swift 6 Changes the Development Landscape

The Swift 6 update has been widely hailed by the developer community as a positive and necessary evolution of the language. One of the most notable improvements is the language’s enhanced focus on parallelism, which now allows developers to write code that can handle concurrency more easily and efficiently. Features like automatic parallelism checking and the refined sendability concept significantly reduce the cognitive load required to work with concurrent tasks, speeding up the development process.

In addition to parallelism, the update places a strong emphasis on data safety, particularly in the context of data races—a common issue in multi-threaded programming. Swift 6’s automatic data isolation and protection mechanisms provide built-in safeguards that minimize the risk of data corruption or race conditions. This means developers can write secure, efficient parallel code with confidence, making it easier to build robust applications that scale.

Ultimately, Swift 6 enhances the language’s capabilities, transforming it into a more powerful, secure, and efficient tool suitable for developing a wide range of applications. Whether building mobile apps, desktop software, server-side programs, or complex system applications, Swift 6 equips developers with the tools they need to create high-quality, high-performance solutions.

Comparing Swift 6 and C++: A Comprehensive Analysis

With the release of Swift 6, Apple proudly asserts that the language has become not only faster but also safer, potentially surpassing C++ in terms of efficiency. Originally designed as a potential alternative to C++, Swift has steadily evolved to address the vulnerabilities that were inherent in C++.

In this comparison, we’ll examine key aspects of both Swift 6 and C++ to evaluate how they measure up in different parameters:

1. Speed

True to its name, Swift is designed for speed. From its inception, the language was built to outperform other programming languages in execution speed. Swift 6 has surpassed the latest version of Python in terms of speed and, in some cases, even outpaces C++ in specific algorithms. This makes Swift an appealing choice for applications that demand high performance.

2. Performance

The improved speed of Swift 6 translates directly into better performance. Code execution in Swift is faster, and this speed boost contributes to more efficient application performance without overloading device resources, as often happens with C++ and other languages. Swift 6 ensures optimal performance while keeping resource consumption at manageable levels, making it ideal for applications running on mobile or desktop platforms.

3. Code Simplicity

Swift’s clean and simple syntax is one of its most compelling features. Designed with developer productivity in mind, Swift’s syntax is intuitive and free of unnecessary complexity, unlike C++’s often convoluted structure. Swift 6 improves on this foundation, removing even more cumbersome elements to make the language feel closer to a natural language. This approach reduces the likelihood of non-obvious errors and makes working with the language more accessible. In contrast, C++ still tends to be more difficult to learn, requiring a deep understanding of complex concepts like pointers and manual memory management.

4. Memory Management

Swift 6 introduces Automatic Reference Counting (ARC), an innovative memory management system that automatically tracks and cleans up unused resources. This feature eliminates the need for developers to manually manage memory allocation and deallocation, significantly reducing the risk of memory leaks. C++ requires more manual intervention in this area, relying on developers to handle memory management themselves, which can lead to errors and inefficiencies.

5. Security

Security is another area where Swift 6 stands out. The language has built-in features that minimize the risk of unauthorized access to sensitive data. Additionally, Swift 6 excels at detecting developer bugs early in the development process, reducing the chances of subtle, critical errors slipping through the cracks. Unlike C++, which can be prone to vulnerabilities such as buffer overflows and pointer errors, Swift 6’s more predictable behavior makes testing and debugging easier, ensuring a safer development environment.

6. Open Source and Community Support

Apple’s decision to make Swift an open-source language has significantly contributed to its growth and adaptability. Swift can now be used by anyone—from seasoned professionals to self-taught developers. The open-source nature also allows Swift to be ported to third-party systems, expanding its utility and supporting the creation of new libraries that further enhance its capabilities.

While Apple has traditionally been known for its closed development ecosystem, this strategic move has allowed the Swift community to flourish, offering contributions that help improve the language. Swift’s official resources are readily accessible, with Apple providing comprehensive tutorials and an integrated development environment (IDE) for macOS users. Swift Playgrounds also allows developers to experiment with code and test applications in real-time, further simplifying the learning curve.

Areas Where C++ Still Holds an Edge

Despite Swift 6’s many advantages, C++ is not without its strengths. Swift’s biggest drawback remains its narrow specialization—the language is primarily designed for developing applications on Apple platforms. While Swift applications can technically run on Windows and Linux, the process is cumbersome, making Swift unsuitable for cross-platform development. This is where C++, a universal language, excels. C++ can run on virtually any platform, making it a more practical choice for applications that need to operate across multiple operating systems.

Additionally, Swift’s relatively small Russian-speaking community may limit its appeal in certain regions, though this is a minor consideration compared to the vast global community supporting C++. The size of the community directly impacts the availability of resources, tools, and peer support, which is crucial for language adoption and innovation.

Another area where C++ maintains a slight advantage is its tight integration with Objective-C. While Swift 6 offers seamless integration with Objective-C, this requires developers to be proficient in both languages. Beginners who are just starting to learn iOS development must often master both languages to effectively work with existing Apple applications.

Swift 6 vs. C++

For Apple platform development, Swift 6 clearly emerges as the preferred language. Its speed, performance, simplicity, security features, and robust community support make it the ideal choice for developers creating apps for iOS, macOS, and beyond. However, due to Swift’s specialized focus, it is not as versatile as C++, which continues to be the dominant language for cross-platform and system-level development.

While Swift 6 offers impressive advancements and enhancements, C++ remains the more functional and practical choice for projects that require broad compatibility and system-level control. For developers targeting Apple devices, Swift 6 is undoubtedly the future; for those needing flexibility across multiple platforms, C++ retains its relevance

Mobile Development Trends to Follow in 2024

The mobile development industry witnessed tremendous innovations and shifts in the year 2023. The implementation of new programming languages and libraries, as well as the introduction of new tools and technologies, results in rapid growth in mobile development. Looking into 2024, the mobile development sector will be influenced by these several trends. Here’s what technologies to focus on, what will be in demand, and what developers need to monitor.

Artificial Intelligence: A Game-Changer in Mobile Development

Artificial Intelligence (AI) remains the most prominent and promising direction in mobile development for 2024. According to the McKinsey Global Institute, AI has the potential to increase company profits by $4.4 trillion annually. As AI continues to revolutionize industries across the board, mobile developers are increasingly incorporating generative AI into everyday applications.

Machine Learning (ML) technologies have already found a strong foothold in mobile development. Libraries for image recognition, text scanning, voice and video processing, and tools for improving app performance, such as those combating memory leaks, are just the beginning. FaceID, for instance, relies heavily on ML to enable secure and seamless authentication.

Since late 2022, there has been an explosion in the development of AI systems, and generative AI technologies like ChatGPT are now at the forefront of this revolution. In the Russian market, Yandex’s Yandex GPT is also making waves. Moving into 2024, companies are increasingly integrating AI-based solutions into their apps. This integration is not limited to improving user experiences through better content recommendations and personalized services but extends to tasks like automatic translation and smart user interaction.

For mobile developers, AI’s role is expanding beyond app functionality to the very development process itself. AI-driven tools are now capable of generating and optimizing code, which could significantly speed up the development cycle. However, questions still remain about the quality and safety of AI-generated code—particularly in terms of security and performance. Despite these concerns, the trend toward AI-enhanced development is undeniable and promises to evolve further in 2024.

Cross-Platform Development: Kotlin Multiplatform and Flutter Take Center Stage

Cross-platform mobile development has been a growing trend for several years, allowing developers to build apps for multiple platforms with a single codebase. In 2024, two solutions are leading the charge: Kotlin Multiplatform (KMP) by JetBrains and Flutter by Google. These technologies are not only popular but continue to evolve and improve, making them key players in the cross-platform development space.

Kotlin Multiplatform (KMP) is gaining traction as a versatile SDK for developing apps across Android, iOS, and other platforms. With its strong Kotlin ecosystem, KMP allows developers to share code between platforms while maintaining the ability to write platform-specific code where necessary. The result is a streamlined development process that reduces redundancy without sacrificing performance.

Flutter, Google’s open-source UI toolkit, is another heavyweight in the cross-platform development world. Known for its fast development cycle and rich set of pre-designed widgets, Flutter continues to evolve with regular updates that enhance its capabilities, performance, and integration with various platforms. Flutter’s flexibility makes it an appealing choice for developers seeking to create beautiful, natively compiled applications for mobile, web, and desktop from a single codebase.

Both KMP and Flutter will see further advancements in 2024, with JetBrains conducting an annual survey to gauge the growing popularity of Kotlin and KMP. Expect these tools to introduce new features, optimizations, and capabilities that make cross-platform mobile development even more efficient and powerful.

Source: https://www.jetbrains.com/lp/devecosystem-2023/kotlin/

In the fall of 2023, something that many developers and fans of KMP technology were waiting for happened. The technology moved to the Stable status and became completely ready for full use. This means that many issues that were relevant for the Alpha and Beta versions of the SDK were resolved. For example, they improved support for Kotlin/Native, work with multithreading, memory, etc. One of the goals of the roadmap for 2024 was to implement direct interaction between the Kotlin and Swift languages. Despite the fact that Google developers are the authors of the competing product Flutter, the company officially places a big bet on KMP. Cross-platform support is included in many solutions. So we advise you to take a closer look at this product.

Another trend related to cross-platform development is the use of Compose Multi Platform to implement a cross-platform UI. This declarative framework combines technologies such as Compose for Desktop, Compose iOS, Compose for Web, and Jetpack Compose for Android, and allows you to quickly and relatively easily create a common UI for different platforms. In 2023, the alpha version of Compose for iOS was released. In 2024, the Beta version is expected to be released, which will include improvements in working with the native iOS UI, as well as support for a cross-platform solution for navigation.

In global trends in mobile development, solutions such as React Native, hybrid development on Cordova and ionic, and Xamarin remain popular. The trend for PWA development also continues.

Native development

Technologies and frameworks change, native development remains. This is the foundation of foundations, the base that every developer should know. Using native languages ​​and tools, as well as the Native First approach, will always be relevant. In addition, for the implementation of projects with complex logic, complex UI, it is worth choosing native development.

Every year, developers of iOS/Android platforms, as well as Swift and Kotlin languages, release many new and interesting solutions, which they talk about at thematic conferences WWDC and Google I/O.

Particular attention should be paid to the growing trend towards declarative development in mobile applications. The SwiftUI and Jetpack Compose frameworks are actively developing, steadily improving, becoming more convenient and reliable in operation. They are increasingly used in the development of applications of varying complexity. Many libraries and ready-made solutions tailored for SwiftUI and Jetpack Compose. We can say that this is a new standard for mobile development for Android and iOS.

It is also worth paying attention to supplementing mobile applications with interactive widgets that will help draw attention to applications and provide instant access to a number of functions.

Virtual reality

In 2023, at the WWDC conference, Apple presented one of the most high-profile new products – Vision Pro virtual reality glasses running on the VisionOS platform. Of course, this is far from the first such device in the world, and similar devices have long been used in the gaming industry. The emphasis is on unique immersive technologies, improved sound and image quality. As part of the creation of the device, large-scale developments were carried out in the field of spatial computing. VisionOS support was included in such tools as: ARKit, RealityKit, Unity, RealityComposer, etc. Both the toolkit and documentation are currently available to all interested developers. The start of sales of the device itself is scheduled for 2024-2025.

Recently, the creators of Vision Pro announced the imminent launch of an app store for virtual reality glasses. This means that in 2024 we will see a boom in various applications for AR/VR devices: games, virtual fitting rooms, interior design applications, immersive movie viewing, listening to music, etc. In addition, according to Statista, by 2028 the number of AR and VR market users in the world will reach 3674.0 million users.

Both Google and Apple are also focusing on improving the immersive user experience on standard smartphones, watches, and tablets.

Not just smartphones. IoT

Every year, new various devices running Android and iOS are released. These are not only smartphones and tablets, but also watches, smart TVs, game consoles, fitness trackers, car computers, and smart home devices. OS development companies are interested not only in supporting new capabilities of devices and gadgets, but also in improving the tools for third-party developers.

The use of NFC, Bluetooth in applications is still relevant. Yahoo Finance predicts growth in the NFC field from 2023 to 2030 by 33.1 billion US dollars.

Security, improved network operation

Preservation of confidential information has been and remains one of the main tasks of developers. This is evidenced by the Gartner forecast. The introduction of enhanced security measures (biometric authentication, use of blockchain, etc.) is very relevant in 2024. Also, special attention should be paid to stable and secure operation of the network, including work with cloud services, with NFC, when connecting to other devices. Modern mobile OS offer a wide range of native tools for implementing and supporting secure operation of applications.

Let’s sum it up

In 2024, mobile platforms, languages ​​and development tools will continue to evolve. The main areas that we recommend paying attention to will be:

  • native development;
  • cross-platform;
  • development for various mobile devices, IoT;
  • support and use of Russian technologies;
  • security, network operations;
  • AR/VR.

Testing Camera and Gallery in Android: Emulating Image Loading in UI Tests

Author: Dmitrii Nikitin, a Android Team Leader at Quadcode with over 7 years of experience in developing scalable mobile solutions and leading Android development teams.

A lot of Android apps request the user to upload images. Social media apps, document scanners, cloud storage providers, you name it. These scenarios are left without any automated tests because developers would rather not try to open the camera or the gallery.

But the fact is, such difficulties can be surpassed. In this article, I will discuss simulating the camera and gallery behavior in emulators, injecting specific images for testing purposes, intent mocking, and how to know when such methods are not enough for thorough testing.

Emulating Camera Images in Android Emulator

The Android emulator is able to display arbitrary images as camera sources, which is extremely convenient if you’re writing flows like “take a picture” or “scan a document” and you’d like the camera to display the same image under all circumstances.

Setting Up Custom Camera Images

The emulator uses a scene configuration file located at:

$ANDROID_HOME/emulator/resources/Toren1BD.posters

You can add a poster block to this file with these attributes:

poster custom
size 1.45 1.45
position 0.05 -0.15 -1.4
rotation -13 0 0
default custom-poster.jpg

This setting determines:

  • default: The path to the image used as the camera feed
  • size, position, rotation: Image size, position, and rotation angle parameters in the scene

Automating Image Setup

You can automatize this process through a shell command:

sed -i ’1s,^,poster custom\n size 1.45 1.45\n position 0.05 -0.15 -1.4\n rotation -13 0 0\n default custom-poster.jpg\n,’ $ANDROID_HOME/emulator/resources/Toren1BD.posters

Here is a Kotlin script that copies the required file into the correct position:

class SetupCameraImageScenario(private val imageFileName: String): BaseScenario<ScenarioData>() {
    override val steps: TestContext<ScenarioData>.() -> Unit = {
        val androidHome = System.getenv("ANDROID_HOME") ?: error("ANDROID_HOME is required")
        val posterPath = "$androidHome/emulator/resources/custom-poster.jpg"
        val localImagePath = "src/androidTest/resources/$imageFileName"
        val cmd = "cp $localImagePath $posterPath"
        Runtime.getRuntime().exec(cmd).waitFor()
    }
}

Injecting Images into Gallery

(Intent.ACTION_PICK) is less of a pain than camera testing, but with one crucial gotcha: copying to internal storage alone is not enough. If you simply copy an image file, it will not appear in the system picker.

An image must be written to the correct folder to be pickable, and must also be registered in MediaStore.

Proper Gallery Image Setup

The process involves:

  1. Declaring the name, type, and path of the image (e.g., Pictures/Test)
  2. Obtaining a URI from MediaStore and storing the image content into it

You can implement it as follows:

class SetupGalleryImageScenario(private val imageFileName: String) : BaseScenario<Unit>() {
    override val steps: TestContext<Unit>.() -> Unit = {
        step("Adding image to MediaStore") {
            val context = InstrumentationRegistry.getInstrumentation().targetContext
            val resolver = context.contentResolver
            
            val values = ContentValues().apply {
                put(MediaStore.Images.Media.DISPLAY_NAME, imageFileName)
                put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
                put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/Test")
            }
            
            val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
            checkNotNull(uri) { "Failed to insert image into MediaStore" }
            
            resolver.openOutputStream(uri)?.use { output ->
                val assetStream = context.assets.open(imageFileName)
                assetStream.copyTo(output)
            }
        }
    }
}

Now that test is opening the gallery, the required image will be visible among the options.

Selecting Images from Gallery

After you’ve placed the image in the MediaStore, you need to call Intent.ACTION_PICK and select the appropriate file in the UI. That’s where UiAutomator is useful, as the picker UI varies across versions and Android:

  • Photo Picker (Android 13+)
  • System file picker or gallery on older Android versions

In order to support both, create a wrapper:

class ChooseImageScenario<ScenarioData>(
    onOpenFilePicker: () -> Unit,
) : BaseScenario<ScenarioData>() {
    override val steps: TestContext<ScenarioData>.() -> Unit = {
        if (PickVisualMedia.isPhotoPickerAvailable(appContext)) {
            scenario(ChooseImageInPhotoPickerScenario(onOpenFilePicker))
        } else {
            scenario(ChooseImageInFilesScenario(onOpenFilePicker))
        }
    }
}

Both approaches start in the same way by calling onOpenFilePicker() (typcally a button click in the UI), then:

  • ChooseImageInPhotoPickerScenario: Locates and taps the image within Photo Picker
  • ChooseImageInFilesScenario: Opens the system file manager (for example, locating the file name via UiSelector().text(“test_image.jpg”) and opening it)

This approach covers both kinds of scenarios, making picking an image general and robust.

Intent Mocking: When Real Camera or Gallery Isn’t Necessary

Most of the tests will not require opening actual camera or gallery apps. To test app response after an image is received, you can mock the response of the external app using Espresso Intents or Kaspresso.

For example, when you’re testing that a user “took a picture” and subsequently the UI displays the correct picture or triggers a button, you don’t need to open the camera. You can simulate the result to get this accomplished:

val resultIntent = Intent().apply {
    putExtra("some_result_key", "mocked_value")
}
Intents.intending(IntentMatchers.hasAction(MediaStore.ACTION_IMAGE_CAPTURE))
    .respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, resultIntent))

When startActivityForResult(.) is invoked by the app to launch the camera, the test gets an immediate precooked result, such as the image being captured and returned. The camera is not launched, so the test is fast and predictable.

This strategy proves useful when:

  • You are less concerned about selection or capture process but more concerned about processing outcomes
  • You have to make test execution faster
  • You need to avoid dependencies on different versions of camera/galleries on devices

When Mocking Isn’t Sufficient

Sometimes it’s also necessary to stress-test not just that the app returns results correctly, but that it acts correctly in actual usage, such as when the user isn’t using it and the system boots it out of RAM. An example of that is DNKA (Death Not Killed by Android).

Understanding DNKA

DNKA happens when Android quietly unloads your app because of memory pressure, loss of focus, or dev settings explicit unloading. onSaveInstanceState() may be invoked but onDestroy() may not. Users come back in and expect the app to “restore” itself into the same state. Ensure that you:

  • Check if ViewModel and State are properly rebuilt
  • Check that the screen crashes if no saved state exists
  • Check that SavedStateHandle is as expected
  • If user interaction (photo selection, form input, etc.) is preserved

Enabling DNKA

The simplest way of enabling behavior in which Android terminates activities forcefully is through developer system settings:

Developer Options → Always Finish Activities

You can achieve with ADB:

adb shell settings put global always_finish_activities 1
# 1 to enable, 0 to disable

That background aside, any external activity launch (camera or gallery) will result in your Activity destroyed. When you go back to the app, it’ll need to recreate state from scratch, precisely what we’d like to test.

Why Intent Mocks Don’t Help Here

When using mocked intents:

Intents.intending(IntentMatchers.hasAction(MediaStore.ACTION_IMAGE_CAPTURE))
    .respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, resultIntent))

The external application is never started, so Android won’t even unload your Activity. The mock is instant responsive, so it’s not possible to test DNKA scenarios.

When Real Intents Are Necessary

To verify DNKA behavior, Android actually needs to unload the Activity. This means actually performing an actual external Intents: take a picture, select from the gallery, or third-party apps. Only this is capable of simulating when users open another application and your application “dies” in the background.

Conclusion

Automated testing sometimes has added the requirement to “see” images, and this issue is not as sneaky as it may seem. Testing photo loading from camera or gallery choice actually doesn’t involve real devices or manual testing. Emulators let you pre-place required images and simulate them as though users just selected or took files.

While intent mocking can be sufficient in some cases, for others complete “real” experience is necessary in order to guarantee recovery from activity cancellation. The trick is choosing the right method for your specific test scenario. 

Understanding these methods enables you to gain complete testing of image-related functionality so that your app handles well in happy path and edge case scenarios like system-induced process death. With proper setup, you can create robust, stable tests for the full gamut of user activity across camera and gallery functionality.

Whether you are writing tests for profile picture uploads, document scanning, or something else that involves images, these practices provide the foundation for good automated testing without jeopardizing coverage or reliability.