Translating your Swift source code to Kotlin isn’t enough to build a complete app. iOS apps rely heavily on the Swift standard library as well as fundamental frameworks like Foundation, Observation, and SwiftUI. SkipStack is Skip’s Android-specific reimplementations of these app building blocks as free, open source libraries. Visit them at our GitHub page.

These libraries are vital, and Skip welcomes community contributions in all forms. Each library’s README includes background information such as its current status, any important implementation strategies employed, etc. Please review the README before contributing. When you are ready to submit an update, create a standard GitHub pull request. Skip’s development team will attempt to address PRs as quickly as possible.

You are not required to donate your updates back to Skip. But we sincerely hope that you will: your improvements to Skip’s open source libraries will benefit all Skip developers, and by extension all users of Skip-backed apps.

Local Skip Libraries

If you’d like to make local changes to Skip’s libraries while working on an app - or to work on SkipUI and exercise your changes with its Showcase app - you will want to configure Xcode to use local library versions rather than the current Skip distributions. This is easily accomplished with an Xcode Workspace.

  1. Clone the repositories you’d like to work on. We find it most convenient to make the clone directory a peer of your app directory.

     > ls
     hello-skip/ skip-foundation/ skip-ui/ 
  2. Use Xcode to create a new Workspace in the same directory.
  3. Add your app’s .xcodeproj file to the Workspace.
  4. Add your local module directories to the Workspace. Adding these local packages should override the distributions specified in Package.swift.
  5. Use the Workspace to iterate on your app and the libraries in tandem.

You are now set up to work on SkipStack libraries! This is a great way to fix any issues or add any missing functionality that is affecting your app, while potentially helping the entire Skip community.

Working in Android Studio

Launching your app from Android Studio will not use your Workspace’s updated local libraries by default. If you’d like to work in Android Studio, edit your app’s Android/settings.gradle.kts file to point Android Studio at Xcode’s build. There are instructions for doing so in the settings.gradle.kts file itself:

// In order to build and debug in an IDE using locally-sourced modules,
// temporarily override this setting with the known-local BUILT_PRODUCTS_DIR,
// which can be found in Xcode's Reports Navigator Build log for the app in the
// environment settings list of the "Run custom shell script 'Run skip gradle'" log entry
// builtProductsDir = "/Users/marc/Library/Developer/Xcode/DerivedData/Skip-App-aqywrhrzhkbvfseiqgxuufbdwdft/Build/Products/Debug-iphonesimulator"

Uncomment the last line that sets builtProductsDir, and set the correct path to your Workspace’s derived data. Then follow the steps to open your app in Android Studio.

When switching the builtProductsDir, it is a good idea to delete the .build/ folder in your app directory (e.g. rm -rf hello-skip/.build). And if Android Studio appears to be stuck on the official library releases rather than your local versions, use its File → Sync Project with Gradle Files command to force Android Studio to re-evaluate settings.gradle.kts.

Community Libraries

Skip’s suite of free, open source libraries provides the building blocks you need to build best-in-class dual-platform apps. But Skip can’t cover every use case out of the box. We expect that many app developers will write your own dual-platform libraries to interface with iOS and Android frameworks. If you write a dual-platform library that you think might be useful to other Skip users, please consider opening it up to the Skip community. Contact us to have your library listed as a Skip community library.

When writing a dual-platform library that vends the functionality of a standard iOS framework, consider exactly mirroring that framework’s API, just as Skip mirrors Foundation, SwiftUI, etc. This follows Skip’s philosophy of transparent adoption. It also means less work for you to implement the iOS side!


If you’re working on cross-platform functionality that involves heavy use of Kotlin API, you might find it faster to open your module in Android Studio and iterate there even if you want the final code to be in Swift. The idea is to prototype in Android Studio using Kotlin, then back-port the solution to your Swift codebase. We have found this particularly useful when implementing SwiftUI features on top of Compose. Android Studio provides robust autocompletion, inline documentation, and automatic imports of the myriad of Compose packages. It is also extremely fast to build and run, which helps a lot when you’re experimenting. Our general strategy when implementing a major SkipUI module feature is:

  1. Make sure you’re set up for local library development. Don’t forget to point Android Studio at your local libraries.
  2. Stub out the feature in Swift and Xcode.
  3. Build your app (in the case of SkipUI work, we use the Showcase app) so that your Swift stubs are transpiled.
  4. Open the app in Android Studio.
  5. Iterate on the implementation in Android Studio using pure Kotlin/Compose. Yes, this involves editing the transpiled file containing your stubs, and you may even have to override the file’s read-only flag to do so. Take care not to run an Xcode build during this phase, because it will overwrite the file with its own transpilation.
  6. Once you have settled on your Android implementation, use it to fill in your Swift stubs. You can do this by separating it into an included Kotlin file whose API you call from Swift, or by back-porting the Kotlin you wrote into inline Swift.

Again, we only recommend this process when your implementation is going to require heavy use of Kotlin API and a healthy amount of iteration and experimentation. In that case, the speed of using Android’s native IDE to figure out what works more than makes up for the extra few minutes it takes to clean up the final solution.