Frequently Asked Questions
- General FAQs
- Skip license key error: The skip.tools license was created with a version of the software that expired on 2024-10-01
- What is Skip?
- What is a “Transpiler”?
- How does Skip compare to other frameworks like Flutter, React Native, Xamarin, and Cordova?
- What is Swift?
- What is SwiftUI?
- What is Kotlin?
- What is Jetpack Compose?
- Do I need to know Kotlin to develop with Skip?
- What are the system requirements for using Skip?
- Can the Skip transpiler run on Linux or Windows?
- Which parts of Skip are free and which parts are commercial?
- How do I use Skip for free software development?
- Which FOSS licenses are approved for using Skip in free mode?
- Which FOSS license is recommended for development?
- License warning “Skip trial will expire in N days”
- Can Skip Apps be distributed on the Apple App Store and the Google Play Store?
- Can I use Skip in a closed-source commercial app?
- What does it mean it be Genuinely Native?
- What is SkipZero?
- Is Skip a cloud-based service? Do you upload my code to your servers?
- How is Skip distributed?
- Do Skip or any of the Skip frameworks collect data for the purposes of user tracking?
- How does Skip compare to low-code or no-code app-building technologies?
- Does Skip use Artificial Intelligence?
- Development FAQs
- What is the minimum iOS version for Skip apps?
- What is the minimum Android version for Skip apps?
- How large are apps that are built using Skip?
- Why is the first build of my app so slow?
- Does Skip need network access?
- Does Skip support large codebases?
- What is parity testing?
- What is SkipStack?
- Can I preview the Kotlin that Skip generates?
- How much runtime overhead does SkipUI add to the Compose side of the app?
- Why does my Android app feel slow?
- What pure Swift libraries can be used by a Skip App?
- How does logging work in Skip?
- How do resources work in Skip?
- How does localization work in Skip?
- How can I use a SQLite database in my Skip App?
- How can I use a Firebase database in my Skip App?
- Can I display Lottie animations in my app?
- Does Skip transpile an app’s metadata, icons, and entitlements?
- How does Skip launch my transpiled app in the Android emulator?
- How can I launch the iOS app without also launching the Android app?
- How does Skip run my transpiled test cases?
- How can I run unit tests against an Android Emulator or Device?
- Can Skip frameworks be built and tested using continuous integration systems?
- Can Skip be used with Xcode Cloud
- Does Skip code use garbage collection?
- Does Skip support Swift language feature ____?
- How does Skip handle ____ difference between Swift and Kotlin?
- How can I check whether my Android build is in debug or release mode?
- How can I check the version of my app at runtime?
General FAQs
Skip license key error: The skip.tools license was created with a version of the software that expired on 2024-10-01
If you are encountering this Skip license key error, you can upgrade to Skip 1.1.6. For more details, see this discussion.
What is Skip?
Skip is an Xcode plugin that transpiles your Swift and SwiftUI into Kotlin and Compose for Android. The Skip build process enables you to continuously iterate on both your iOS and Android app with a single unified codebase, while mixing in as much or as little platform-specific code as you like. To learn more, start with the Skip Tour.
What is a “Transpiler”?
Transpilation is defined as the conversion between programming languages that operate at approximately the same level of abstraction. The SkipStone plugin transpiles your app’s Swift and SwiftUI code into the equivalent Kotlin and Compose, it transpiles your app’s Swift Package Manager project into a buildable Gradle project, and it transpiles your iOS app’s metadata into Android metadata. This is all done automatically by Xcode, the result being that you can build, test, and run your Swift app, and the transpiled Kotlin equivalent app will also be built, tested, and run side-by-side.
How does Skip compare to other frameworks like Flutter, React Native, Xamarin, and Cordova?
Skip is focused on genuinely native app development exclusively for the two dominant mobile platforms – iOS and Android. A comparison table between the various frameworks can be found on the Skip Comparison Matrix.
What is Swift?
Swift is the officially-recommended language for app development for iOS devices, including the iPhone and iPad. Swift integrates seamlessly with Objective-C, the legacy language for iOS development. For information on Swift, see https://developer.apple.com/swift/.
What is SwiftUI?
According to developer.apple.com, SwiftUI “offers a modern, platform-agnostic approach to building your UI and app infrastructure. With SwiftUI, you specify your interface programmatically and let the system display and update that interface dynamically”. Since debuting in 2019, SwiftUI can already be used to build apps for the iPhone, iPad, tvOS, watchOS, visionOS, and other operating systems, and has become the recommended way to create new apps for the iPhone and iPad. Skip brings SwiftUI to the Android platform through the SkipStone transpiler and the SkipUI compatibility framework.
What is Kotlin?
Kotlin is the officially-recommended language for app development for Android devices. Kotlin integrates seamlessly with Java, the legacy language for Android development. For information on Kotlin and Android, see https://developer.android.com/kotlin/.
What is Jetpack Compose?
According to developer.android.com: “Jetpack Compose is Android’s recommended modern toolkit for building native UI.” Jetpack Compose, which debuted in 2019, presents a declarative Kotlin API for platform-agnostic user interfaces.
Do I need to know Kotlin to develop with Skip?
Skip provides several mechanisms to integrate with Kotlin, but you do not need to know any Kotlin in order to build an app with Skip. Skip aims to transparently convert all your Swift code into Kotlin code in a way that makes the Kotlin side invisible to you. You will likely learn some Kotlin as you develop with Skip, however - particularly when debugging your Android app.
What are the system requirements for using Skip?
macOS 13 (ARM or Intel) with the latest Xcode, Android Studio “Koala” (2024.1.1), and Homebrew installed. Additional software is required to build and test transpiled projects for Android. See Skip’s installation instructions.
Can the Skip transpiler run on Linux or Windows?
Skip is implemented as a Swift Package Manager plugin, and so is only available on platforms where SwiftPM plugins are supported. Currently SwiftPM plugins are only supported on macOS.
Which parts of Skip are free and which parts are commercial?
The SkipStone transpiler plugin requires a valid license to use for closed-source app development. Skip’s ecosystem of libraries, including the core SkipStack modules such as SkipFoundation and SkipLib, are all themselves released under a free and open-source software license, and thus are free for anyone to use, modify, and improve. The Skip frameworks do not include any runtime license checks, meaning that you own both the inputs and outputs of your project; only the build-time transpiler requires a license.
How do I use Skip for free software development?
When every Swift and Kotlin source code file in a project begins with an approved free software license header comment, then the SkipStone transpiler plugin will automatically run in free mode, and no license key will be required to use the tool. You must also have a corresponding “LICENSE.LGPL”, “LICENSE.GPL”, or “LICENSE.AGPL” file in the root folder of your published project, whose contents align with the license header comments in the project’s source code.
The following source code header comment will be sufficient attestation for a .swift
or .kt
file to be used in free mode with the LGPL:
// This is free software: you can redistribute and/or modify it
// under the terms of the GNU Lesser General Public License 3.0
// as published by the Free Software Foundation https://fsf.org
When you run skip init --free --appid=some.free.App project-name AppName
, the generated source files will have this header.
Which FOSS licenses are approved for using Skip in free mode?
The GNU General Public License family of software licenses (LGPL, GPL, and AGPL) are all approved for Skip’s free mode. For information on these licenses, see https://www.gnu.org/licenses/.
The Skip frameworks themselves are licensed under the LGPL, which enables Skip to be used to improve them without needing a license key.
Which FOSS license is recommended for development?
We generally recommend the LGPL, which provides a good balance of flexibility and freedom. LGPL libraries can be embedded in closed-source commercial applications. Many popular software components like WebKit, JavaScriptCore, and Qt are distributed under the LGPL.
License warning “Skip trial will expire in N days”
Visit the evaluation page to request a longer evaluation license. If your evaluation has ended, visit the purchase page or to purchase a year-long Skip license.
Can Skip Apps be distributed on the Apple App Store and the Google Play Store?
Yes. Applications built with Skip utilize the user interface toolkits recommended by the platform vendors themselves, and thereby follow the guidelines and principles that are unique to each of these two individual platforms. On the iOS side, the core SkipStack modules can be eliminated from the build (with SkipZero), resulting in an app submission that contains no trace of any Skip libraries whatsoever.
One example of an app that is distributed on the Apple App Store and the Google Play Store is the Skip Showcase app.
Can I use Skip in a closed-source commercial app?
Yes. Skip’s open-source components are released under the LGPL license, which is the same license used by ubiquitous iOS and Android components like JavaScriptCore and WebKit. LGPL libraries can be linked to by closed-source apps, but any changes to the LGPL libraries themselves must be published freely.
What does it mean it be Genuinely Native?
Skip apps are genuinely native, in that they use the vendor-recommended UI toolkits directly, thereby guaranteeing maximum compatibility, accessibility, and performance. They use SwiftUI directly on the iPhone (“SwiftUI is the preferred app-builder technology, because it offers a modern, platform-agnostic approach to building your UI and app infrastructure.” – developer.apple.com) and Compose on Android (“We recommend using Jetpack Compose if you’re looking to build a new app” – android-developers.googleblog.com).
What is SkipZero?
When a Skip app relies only on the core SkipStack modules (SkipUnit, SkipLib, SkipFoundation, SkipModel, and SkipUI), these libraries can be completely excluded from the app build. This means that you can ship a Skip app for Android and iOS, and there will be no vestige of Skip on the iOS side at all. One benefit, among many others, is that your app distribution can be minuscule (e.g., the HelloSkip.ipa sample is under 25KB). This also makes Skip easily “ejectable” from your iOS project, in that you can drop the Skip transpiler at any time and continue to have a fully-functional iOS project.
Is Skip a cloud-based service? Do you upload my code to your servers?
No, and no. The Skip transpiler plugin runs locally on your macOS machine as part of the Xcode build process. The plugin is secured using the standard Xcode plugin sandboxing mechanisms that block network and file system access. Neither your Swift nor your Kotlin code ever leave your machine. The only network requirements are for resolving any external dependencies your project has, either on the SwiftPM side for Swift dependencies, or on the Gradle side for Kotlin dependencies.
How is Skip distributed?
The SkipStone transpiler plugin is distributed as a binary executable artifact and driven by the Skip plugin hosted at https://source.skip.tools/skip.git. In addition, the skip
command-line tool must be installed using the Homebrew command: brew install skiptools/skip/skip
. This will install the skip
utility that can be used to create projects and run tests, as well as the prerequisites for being able to perform local Android testing: gradle
, openjdk
, android-platform-tools
, and android-commandlinetools
.
Do Skip or any of the Skip frameworks collect data for the purposes of user tracking?
The Skip transpiler does not collect any data, perform any telemetry, or otherwise “phone home” unless explicitly requested (e.g., running the skip upgrade
command to check for the latest version of Skip). The Skip frameworks, which are all free and open-source (and which can thus be audited externally), also do not collect any telemetry or track users in any way. We provide this notice to help you fill out Apple’s App Privacy Details and comply with Google’s User Data policies.
Note that when installing skip
using Homebrew, they may use telemetry to report the installation event. See the Homebrew Analytics documentation for their explanation and details on how it can be disabled.
How does Skip compare to low-code or no-code app-building technologies?
Skip is the opposite of no-code/low-code offerings. Skip embraces the dominant emerging UI paradigm of declarative user interfaces written in the same language as the platform-native components. This means Swift for SwiftUI, and Kotlin for Compose.
Does Skip use Artificial Intelligence?
No, Skip is a purely offline transpiler with predictable behavior.
However, AI tools can be very useful for generating Swift and SwiftUI code, especially for getting started with the outline of an iOS app. This code will generally be compatible with SkipUI and the other Skip libraries, which can be a great aid in getting a dual-platform app started quickly.
Development FAQs
What is the minimum iOS version for Skip apps?
iOS 16+. It is estimated at developer.apple.com that 96% of all devices introduced in the last four years use iOS 16 or higher, as measured by devices that transacted on the App Store as of February 4, 2024.
What is the minimum Android version for Skip apps?
Skip targets Android API level 34 (which is the minimum allowed level for submitting new apps to the Play Store, according to https://developer.android.com/google/play/requirements/target-sdk) with a minimum supported version of API level 29. Android API 29 (“Q”; Android 10.0) will run on approximately 84% of active Android devices as of February, 2024, according to https://apilevels.com.
How large are apps that are built using Skip?
For iOS apps utilizing SkipZero, the smallest app.ipa
size is around 50KB. For Android apps, it is around 5MB. This difference is largely due to the fact that Android apps need to bundle the Jetpack Compose libraries with the app itself, whereas SwiftUI is included with iOS.
Why is the first build of my app so slow?
Skip libraries are distributed through SwiftPM as source code, which means that your first build includes building portions of Skip itself as well. Additionally, the first time you build the transpiled Gradle project in order to test and run on Android, the Gradle build system will need to download all of its dependency jars and build tools. This can lead to the initial build of an app downloading many dependencies. The Compose dependencies alone will add around 1GB to the size of the Gradle cache folder, as seen with du -skh ~/.gradle
. But once you have downloaded and cached your project’s dependencies, future builds shouldn’t need to fetch them again.
Does Skip need network access?
Skip itself is a locally-installed Xcode plugin and does not talk to the network, making it suitable for offline use. However, your app’s dependencies will need to be resolved and cached for your app to be built, tested, or run. This means that if you add any new dependencies, either on the Swift side in the Package.swift
, or on the Koltlin side in the build.gradle.kts
(as configured through the module’s Skip/skip.yml
file), you will need to perform a build at least once for the dependencies to be resolved and downloaded.
Does Skip support large codebases?
Skip leverages Swift Package Manager’s support for dependencies between modules, in both local and external git repositories. Skip’s plugin is run individually on each transitive dependency of your project, and the resulting Gradle projects will have these dependencies mirrored. This results in a highly modularizable system, where large codebases can be distributed across multiple modules, each with their individual documentation, test cases, and continuous integration workflows.
What is parity testing?
Skip encourages modularization of large codebases, each with their individual test targets. The command skip test
can be run in a project that contains Skip tests, and both the Swift XCTest
cases and the transpiled Kotlin JUnit
cases will be run, after which the tool will output a markdown table summarizing each of the test results for each of the platforms.
What is SkipStack?
The SkipStack modules are the core compatibility modules that transparently bridge from standard iOS frameworks into their equivalents for Kotlin, Java, and Android.
- SkipUnit bridges the XCTest framework to provide unit testing support through JUnit 4.
- SkipLib bridges the Swift Standard Library for conversion between low-level types and their Kotlin equivalents.
- SkipFoundation provides Java and Android equivalents for the Foundation framework
- SkipModel provides support for Observation through the Compose Runtime framework.
- SkipUI provides an implementation of SwiftUI that bridges to Android’s Jetpack Compose UI components.
The SkipStack frameworks are the fundamental building blocks on which the rest of the Skip ecosystem of libraries is based.
Can I preview the Kotlin that Skip generates?
We provide a “Playground” page at https://skip.tools/playground/ that runs a limited online version of the Skip transpiler in order to preview snippets of transpiled code. When using Skip for development, you can access the transpiled Kotlin it generates at any time.
How much runtime overhead does SkipUI add to the Compose side of the app?
Very little. Many of SkipUI’s views are very simple shims that bridge from their SwiftUI equivalents into Compose, such as Divider.swift simply invoking androidx.compose.material3.Divider
. To support @Environment
and @State
, Skip needs to perform some additional book-keeping that may have some runtime cost.
Why does my Android app feel slow?
There is often a significant difference between Debug and Release build performance on Android devices. Always use a Release build when evaluating real-world performance.
What pure Swift libraries can be used by a Skip App?
Skip uses Swift Package Manager to handle source code dependency resolution. Your app’s transitive dependencies will be automatically resolved and downloaded, but they will only be transpiled into Kotlin if the dependent module has a Skip/skip.yml
file. If your project has non-Skip-enabled dependencies, you can either use them from the Swift side only (and seek alternative implementations through the use of #if SKIP
blocks or custom Kotlin files; for an example, see the LottieMotionView implementation). Skip’s constellation of frameworks are expected to provide most functionality that is commonly needed by modern apps, but you are free to develop your own libraries and frameworks, either from scratch, or by forking an existing repository to add Skip support for the library.
How does logging work in Skip?
The SkipFoundation
framework implements the OSLog
module, so an app can log using a Logger
instance, which will output log messages to the Xcode console for the iOS side of the app. For the Android side, log messages are passed to android.util.Log
and can be viewed from the logcat
tab in Android Studio, or by running adb logcat
from the terminal. Note that the print()
function does not send any output to logcat
, so OSLog.Logger
should be the preferred method of logging.
How do resources work in Skip?
The SkipFoundation
framework implements the Bundle.module
function for accessing resources stored in the standard SwiftPM location of Sources/ModuleName/Resources/
. These resources are automatically bundled in the Gradle project, and will be embedded in the resulting .apk
artifact. Note that unlike Foundation on Darwin platforms, the app archive is not expanded on disk for Android apps, but rather can only be accessed using a streaming interface. SkipFoundation handles this transparently for you, so you can load a resource with try Data(contentsOfURL Bundle.module.url(forResource: "SomeResource", withExtension: "ext"))
. However, you cannot perform random access on a resources URL like you can on iOS. This means that embedded resources, such as a .sqlite
database, would need to first be manually extracted to the app’s storage folder before they can be accessed.
How does localization work in Skip?
Skip supports the standard Localizable.xcstrings
translation source file. These files are automatically updated by Xcode 15 to contain any localization-aware string in your app.
This allows you to have a single translation file that is used by both your iOS and Android app, so that your SwiftUI Text("Hello!")
can be rendered as “Bonjour!” in French.
How can I use a SQLite database in my Skip App?
We have a SkipSQL framework which provides low-level access to the system-installed SQLite3 library on both iOS and Android.
How can I use a Firebase database in my Skip App?
Skip has a SkipFirebase framework module that provides integration with the official Firebase iOS and Android SDKs. Currently the Firestore integration is the most complete.
Can I display Lottie animations in my app?
We have a SkipMotion framework framework and a Lottie Demo app available.
Does Skip transpile an app’s metadata, icons, and entitlements?
Skip currently only handles the generation of the required AndroidMetadata.xml
, which is populated with the elements from your project’s Skip.env
file like PRODUCT_NAME
, BUNDLE_IDENTIFIER
, and MARKETING_VERSION
. Other aspects of your Android app, such as icons, must be customized manually for the app, either using Android Studio, or manually in the Gradle project.
How does Skip launch my transpiled app in the Android emulator?
Skip-enabled app projects have an .xcodeproj
generated for them, which includes an embedded script that, as a side effect of running a build of the app target, will assemble and launch the app using the gradle
command. The app will be launched against the first connected Android emulator or device that is found. To customize which emulator should be used, the ANDROID_SERIAL
environment variable can be set to the identifier of the Android device, as seen with the terminal command adb devices
.
How can I launch the iOS app without also launching the Android app?
By default, whenever you run your iOS app from Xcode, Skip will also transpile and run the Android app. However, you may sometimes want to run only the iOS side of the app for certain time periods, such as when debugging an iOS-specific issue. To do this, follow these instructions in the Building and Running documentation.
How does Skip run my transpiled test cases?
Skip-enabled projects have an XCSkipTests.swift
test case, which is generated as part of the skip init
command (see Getting Started. This test case will use the SkipDrive
module to launch the gradle test
command on the transpiled project. It will then interpret the test results and convert any failures back into XCTest failures, including mapping back the line numbers from the transpiled Kotlin to the original Swift. This will result in a test failure showing up twice in Xcode: once for the Swift XCTest failure, and one for the Kotlin JUnit failure.
How can I run unit tests against an Android Emulator or Device?
By default, your transpiled XCTest cases are run as Kotlin JUnit 4 tests using the SkipUnit framework, and these tests are run in a local JVM using the Robolectric utilities to mock many Android APIs. If you have a connected Android Emulator or Simulator, you can get the identifier from the command adb devices
, and then set the identifier in the environment variable ANDROID_SERIAL
. This can be done from the command-line with ANDROID_SERIAL=emulator-1234 skip test
. In Xcode you can set this variable in the Scheme’s Run Arguments section, then toggle it on or off to switch between the (faster) Robolectric tests and the (higher-fidelity) Android tests.
Can Skip frameworks be built and tested using continuous integration systems?
Skip framework projects contain built-in support for running parity tests for both the Swift and Kotlin sides of a project. These tests can be included in automated continuous integration workflows to ensure that the tests are always passing. We do this ourselves for the various Skip frameworks, such as the SkipLib Actions, which references our standard GitHub CI workflow.
Can Skip be used with Xcode Cloud
You should be able to install Skip for an Xcode Cloud build using Homebrew, as per the documentation at https://developer.apple.com/documentation/xcode/making-dependencies-available-to-xcode-cloud#Use-a-custom-build-script-to-install-a-third-party-dependency-or-tool.
Does Skip code use garbage collection?
Swift does not use garbage collection, but Kotlin/Java does. Your Swift code that is transpiled into Kotlin will run in the same managed, garbage collected Android Runtime environment as every other Android app.
Does Skip support Swift language feature ____?
Skip’s Swift support is detailed in the Swift Support Reference.
How does Skip handle ____ difference between Swift and Kotlin?
Many topics related to the differences between Swift and Kotlin are covered in the Swift Support Reference topics.
How can I check whether my Android build is in debug or release mode?
The traditional #if DEBUG
check doesn’t work on the Android side of your app – it will always resolve to false. One simple way you can do this is add a top-level isDebugBuild
variable that checks the Android ApplicationInfo
for the debuggable flag, as so:
let isDebugBuild: Bool = {
#if SKIP
return (ProcessInfo.processInfo.androidContext.getApplicationInfo().flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0
#elseif DEBUG
return true
#else
return false
#endif
}()
How can I check the version of my app at runtime?
Skip applications do not have the Bundle.main.infoDictionary
that is typically used for checking metadata like the version string. One simple way of getting an app’s version on Android is to use the PackageInfo
metadata like so:
let appVersion: String? = {
#if !SKIP
return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
#else
let context = ProcessInfo.processInfo.androidContext
let packageManager = context.getPackageManager()
let packageInfo = packageManager.getPackageInfo(context.getPackageName(), android.content.pm.PackageManager.GET_META_DATA)
return packageInfo.versionName
#endif
}()