Welcome to the August edition of the Skip.tools newsletter! This month we will showcase some of the improvements and advancements we've made to the Skip platform, along with some current events and a peek at our upcoming roadmap.
Skip 1.0
The big news this month was the launch of Skip 1.0! After over a year in development, Skip is finally ready for general production use. The launch has made a big splash, even being featured on the front page of Hacker News. There has never been a better time to start a new project with Skip and bring your app to the entire mobile marketplace!
New FREE Indie Pricing Tier
As part of the general availability of Skip, we are also delighted to announce the new Skip Indie tier, which enables solo developers to use Skip to build their dual-platform projects for free.
Markdown Support
On a technical front, a long-requested feature for SkipUI has been to support SwiftUI's automatic markdown support for Text elements. Well, now it's here! Styling text with simple markdown elements has never been simpler.
Reminder: Skip Showcase on the Stores
The Skip Showcase app (/docs/samples/skipapp-showcase/) has long been our go-to for providing a side-by-side comparison of SwiftUI components with the Jetpack Compose equivalents that SkipUI provides. Browsing thought these components simultaneously on an iPhone and Android device gives a good sense Skip's capabilities and power, and is a great way to demonstrate Skip's benefits to project managers and stakeholders before breaking ground on a new project.
In order to make it even easier to get this handy app on your devices, we've published the Skip Showcase app to both the Apple App Store (https://apps.apple.com/us/app/skip-showcase/id6474885022) as well as the Google Play Store (https://play.google.com/store/apps/details?id=org.appfair.app.Showcase). This enables you to quickly grab a demo app that highlights Skip's power, and feel for yourself the benefit of using a genuinely native app on both platforms. Download it today and see for yourself what Skip can do!
New Skip Showreel Video
We've published a new 3-minute video summarizing Skip's capabilities. This is a great video to share with your colleagues and management to highlight some of the benefits of using Skip to bring your app to the entire matketplace. Check it out at /tour/skip-showreel/
That's all for now!
You can follow us on Mastodon at
https://mas.to/@skiptools, and join in the Skip discussions at
http://forums.skip.dev/. The Skip FAQ at
/docs/faq/
is there to answer any questions, and be sure to check out the video tours at
/tour/. And, as always, you can reach out directly to us on our Slack channel at
/slack/.
We’re thrilled to announce the release of Skip 1.0!
Skip brings Swift app development to Android. Share Swift business logic, or write entire cross-platform apps in SwiftUI.
Skip is the only tool that enables you to develop genuinely native apps for both major mobile platforms with a single codebase. Under the hood, it uses the vendor-recommended technologies on each OS: Swift and SwiftUI on iOS, Kotlin and Compose on Android. So your apps don’t just “look native”, they are native, with no additional resource-hogging runtime and no uncanny-valley UI replicas.
Skip also gives you complete access to platform libraries. Directly call any Swift or Objective C API on iOS, and any Kotlin or Java API on Android - no complex bridging required!
Skip has been in development for over a year. It has an enthusiastic community of users developing a wide range of apps and continually improving Skip’s ecosystem of cross-platform open source libraries.
Welcome to the July edition of the Skip.tools newsletter! This month we will showcase some of the improvements and advancements we've made to the Skip platform, along with some current events and a peek at our upcoming roadmap.
Swift 6 and Kotlin 2 Support
The past couple of months saw two important major releases that affect anyone writing modern iOS and Android apps. Kotlin 2 was released at the end of May, and a preview of Swift 6 was added to the Xcode 16 beta in June. Both of these language releases are evolutionary, but they did include some important changes and enhancements.
Skip has kept pace: we now generate Kotlin 2 Android projects by default, and you can use Swift 6 language features like
typed throws. Some minor Android build file tweaks may be necessary to modernize pre-existing Skip projects, but overall we are delighted how smooth the transition has been. Skip is designed to enable your apps to keep up with the constant evolution of the primary development languages for both iOS and Android.
From Scrumdinger to Scrumskipper
Honed and updated over the years, Apple’s
Scrumdinger tutorial
is an hours-long step-by-step guide to building a complete, modern SwiftUI app. It exercises both built-in UI components and custom drawing, and it takes advantage of Swift language features like Codable for persistence. As its rather unique name implies, the Scrumdinger app allows users to create and manage agile programming scrums on their phones.
In our
blog post, we show how we took the Scrumdinger app and brought it to Android through the power of Skip. This new "Scrumskipper" app demonstrates how an existing iOS-only app can be incrementally turned into a dual-platform iOS+Android app.
Refreshable lists, GeometryReader, and ScrollViewReader
The pull-to-refresh gesture has been a standard affordance in mobile apps for updating list contents for some time now, and SwiftUI has had built-in support for the operation since last year. We've brought this great feature over to Android by bridging SwiftUI’s .refreshable() modifier to an experimental Compose API for supporting the pull-to-refresh operation, enabling you to add in support for list refreshability with one line of code.
In addition, we've added some more advanced SwiftUI API support, including the ability to exactly identify locations in SwiftUI views using GeometryReader and the ability to jump to individual list elements using ScrollViewReader.
User Contributions: SkipAV and SkipFirebase
All the Skip runtime frameworks are free and open-source software, from the low-level
SkipFoundation
to the high level
SkipUI. In addition, we have a whole constellation of optional frameworks that enable additional functionality, from SQLite database support (SkipSQL) to Lottie animations (SkipMotion).
One of our frameworks –
SkipAV
– enables bridging a subset of the AVKit framework for audio and video support. The initial release included only very basic support for playing videos, but recently a user who was interested in the project added support for recording from the microphone, along with some audio playback improvements.
Another of our frameworks,
SkipFirebase, provides support for Google Firebase, a very popular backend-as-a-service platform used in many mobile applications. And while our original release mostly just supported Firestore – the database layer of Firebase – another interested user recently contributed support for the Auth component, which greatly improves the utility of the framework for all Skip users.
These are just two examples of recent community contributions to the Skip ecosystem. If you would like to learn more about how to help improve Skip's support for various Android features, check out our
contribution guide.
That's all for now
You can follow us on Mastodon at
https://mas.to/@skiptools, and join in the Skip discussions at
http://forums.skip.dev/. The Skip FAQ at
/docs/faq/
is there to answer any questions, and be sure to check out the video tours at
/tour/. And, as always, you can reach out directly to us on our Slack channel at
/slack/.
Honed and updated over the years, Apple’s Scrumdinger tutorial ↗ is an hours-long step-by-step guide to building a complete, modern SwiftUI app. It exercises both built-in UI components and custom drawing, and it takes advantage of Swift language features like Codable for persistence. As its rather unique name implies, the Scrumdinger app allows users to create and manage agile programming scrums ↗ on their phones.
This blog post begins where Apple’s tutorial ends. We’ll start with the final Scrumdinger source code and walk you through the process of bringing the full app to Android using Skip. You’ll learn the general steps involved in bringing an existing app to Android, and you’ll become familiar with the types of issues you may encounter and how to overcome them. Let’s get started!
Download and expand the zip file. Assuming you have the latest Xcode ↗ installed, you can run the iPhone app by opening TranscribingSpeechToText/Complete/Scrumdinger.xcodeproj. The first time you attempt to open it, you may need to confirm that you trust the download. Once Xcode has loaded the project, select the iOS Simulator you’d like to use and hit the Run button!
Play around with the app - this is what we’re going to bring to Android. First, however, we need to install Skip.
Skip ↗ is a tool for building fully native iOS and Android apps from a single Swift and SwiftUI codebase. It works by transpiling your Swift into Android’s Kotlin ↗ development language and adapting your SwiftUI to Android’s native Jetpack Compose ↗ UI framework.
Skip’s Android version of Scrumdinger won’t be pixel-identical to the iOS version, and it shouldn’t be. Rather, we believe in using the native UI framework and controls on each platform. This gives the best possible user experience, avoiding the uncanny-valley feel of non-native solutions.
Follow the Getting Started guide to install Skip and your Android environment, including Android Studio ↗. Next, launch Android Studio and open the Virtual Device Manager from the ellipsis menu of the Welcome dialog. From there, Create Device (e.g., “Pixel 6”) and then start the Emulator. Skip needs a connected Android device or Emulator to run the Android version of your app.
Now we’re ready to turn Scrumdinger into a dual-platform Skip app.
It isn’t too hard to update an existing Swift Package Manager package to use Skip. Updating an existing app, however, is a different story. Building for Android requires a specific folder structure and xcodeproj configuration. We recommend creating a new Skip Xcode project, then importing the old project’s code and resources.
Enter the following command in Terminal to initialize Scrumskipper, your dual-platform version of the Scrumdinger app.
This will create a template SwiftUI app and open it in Xcode. Let’s run the template as-is to make sure it’s working: select your desired iOS Simulator in Xcode, and hit the Run button. If you just installed or updated Skip, you may have to trust the Skip plugin:
If all goes well, you should see something like the following:
Great! Next, copy Scrumdinger’s source code to Scrumskipper:
Drag the Scrumdinger/Models and Scrumdinger/Views folders from Scrumdinger’s Xcode window into the Scrumskipper/Sources/Scrumskipper/ folder in Scrumskipper’s window.
Replace Scrumskipper’s ContentView body with the content of Scrumdinger’s primary WindowGroup. Scrumskipper’s ContentView should now look like this:
import SwiftUI
publicstruct ContentView: View {
@StateObjectprivatevar store =ScrumStore()
@Stateprivatevar errorWrapper: ErrorWrapper?
publicinit() {
}
publicvar body: some View {
ScrumsView(scrums: $store.scrums) {
Task {
do {
tryawait store.save(scrums: store.scrums)
} catch {
errorWrapper =ErrorWrapper(error: error,
guidance: "Try again later.")
}
}
}
.task {
do {
tryawait store.load()
} catch {
errorWrapper =ErrorWrapper(error: error,
guidance: "Scrumdinger will load sample data and continue.")
}
}
.sheet(item: $errorWrapper) {
store.scrums= DailyScrum.sampleData
} content: { wrapper in
ErrorView(errorWrapper: wrapper)
}
}
}
#Preview {
ContentView()
}
That’s it! You’ve now created Scrumskipper, a dual-platform app with all of Scrumdinger’s source code.
It’s the moment of truth: hit that Xcode Run button!
Almost immediately, you’ll get an API unavailable error like this one:
This is our first hint that migrating an existing iOS codebase to Android is not trivial, even with Skip. Starting a new app with Skip can be a lot of fun, because it’s relatively easy to avoid problematic patterns and APIs, and you can tackle any issues one at a time as they appear. But when you take on an existing codebase, you get hit with everything at once. Even if Skip perfectly translates 95+% of your original Swift source and API calls - code that was certainly never intended to be cross-platform - that can leave dozens or even hundreds of errors to deal with!
It’s important to remember, though, that while fixing that remaining 5% can be a slog ↗, it is still 20 times less work than a 100% Android rewrite! And once you’ve worked through the errors, you’ll have a wonderfully maintainable, unified Swift and SwiftUI codebase moving forward. So let’s roll up our sleeves and get started, beginning with the error above.
The pictured error message says that the Color(_ name:) constructor isn’t available in Skip. Each of Skip’s major frameworks includes a listing you can consult of the API that is supported on Android. These listings are constantly expanding as we port additional functionality. For example, here is the table of supported SwiftUI.
When an API is unsupported, that does not mean you can’t use it in your app! Skip never forces you to compromise your iOS app. Rather, it means that you have to find a solution for your Android version. That could mean contributing an implementation for the missing API, but more often you’ll just want to take a different Android code path. To keep your iOS code intact but create an alternate Android code path, use #if SKIP (or #if !SKIP) compiler directives. The Skip documentation covers compiler directives and other platform customization techniques in detail. Let’s update the problematic code in Theme.swift to use named colors on iOS, but fall back to a constant color on Android until we implement a solution:
Change:
var mainColor: Color {
Color(rawValue)
}
To:
var mainColor: Color {
#if !SKIP
Color(rawValue)
#else
// TODO
Color.yellow
#endif
}
This technique works for SwiftUI modifiers as well. For example, while Skip is able to translate many of SwiftUI’s accessibility modifiers for Android (in fact Skip’s native-UI approach excels in accessibility), it doesn’t have a translation for the .accessibilityElement(children:) modifier. So, update from this:
HStack {
Label("Length", systemImage: "clock")
Spacer()
Text("\(scrum.lengthInMinutes) minutes")
}
.accessibilityElement(children: .combine)
To this:
HStack {
Label("Length", systemImage: "clock")
Spacer()
Text("\(scrum.lengthInMinutes) minutes")
}
#if !SKIP
.accessibilityElement(children: .combine)
#endif
The iOS version of the app is unaffected, and the Android build can proceed without the unsupported modifier.
Getting Scrumskipper to successfully build as an iOS and Android app is a repetition of the process we began above:
Hit the Run button.
View the next batch of Xcode errors from the transpiler or the Kotlin compiler.
Use compiler directives to exclude the source causing the error from the Android build.
If you see this process through as we did, you’ll end up using #if SKIP and #if !SKIP approximately 25 times in the ~1,500 lines of Scrumdinger’s Swift and SwiftUI source. In addition to the aforementioned Color(_ name:) and .accessibilityElement(children:) APIs, here is a full accounting of Scrumdinger code that causes errors:
The Speech and AVFoundation frameworks used in Scrumdinger are not supported. While Skip does have a minimal AVFoundation implementation for Android, it is not complete as of this writing. These are examples of cases where you would likely use Skip’s dependency support to integrate Android-specific libraries for the missing functionality.
Timer.tolerance is not supported.
.ultraThinMaterial is not supported.
ListFormatter is not supported. We replaced ListFormatter.localizedString(byJoining: attendees.map { $0.name }) with attendees.map { $0.name }.joined(separator: ", ").
SwiftUI’s ProgressViewStyle is not yet supported.
SwiftUI’s LabelStyle is not yet supported.
The Theme enum’s name property causes an error because all Kotlin enums inherit a built-in, non-overridable name property already. We changed the property to themeName.
You can view the final result in the source of our skipapp-scrumskippersample app.
After using compiler directives to work around these errors, we have liftoff! Scrumskipper launches on both the iOS Simulator and Android Emulator. Clearly, however, it needs additional work.
As you explore the app, you’ll find many things that are missing or broken. Fortunately, it turns out that the problems are all easily fixed. View our sample app to see the completed code. We give a brief description of each issue below.
Copying over Scrumdinger’s source code wasn’t quite enough. We forgot to copy its ding.wav resource and more importantly, the Info.plist keys that give the app permission to use the microphone and speech recognition. Without these keys, the iOS app will crash when you attempt to start a meeting.
Scrumdinger uses SF Symbols for all of its in-app images. Android obviously doesn’t include these out of the box, but Skip allows you to easily add symbols to your app. Just place vector images with the desired symbol names in your Module asset catalog, as described here. For the purposes of this demo, we exported the symbols from Apple’s SF Symbols app.
We made two additional tweaks to MeetingView. First, the custom MeetingTimerView was not rendering at all on Android. Layout issues like this are rare, but they do occur. Second, we didn’t want the Android navigation bar background to be visible. We added a couple of #if SKIP blocks to the view body to correct these issues:
Scrums were not being saved and restored in the Android version of the app. It turns out that Scrumdinger saved its state on transition to ScenePhase.inactive, but Android doesn’t use this phase! Android apps transition directly from active to background and back. The following simple change fixed the issue:
Remember how we were going to circle back to the Theme enum’s named colors on Android? We decided to forgo the asset catalog colors altogether and just define each color programmatically with RGB values.
Take a moment to reflect on how amazing it is that Apple’s canonical SwiftUI iPhone sample now runs as a fully native Android app. Though Skip excels at new development and the process for bringing Scrumdinger’s existing code to Android wasn’t trivial, it was still an order of magnitude faster than a re-write and did not risk regressions to the iOS version. Moreover, future maintenance and improvements will be extremely efficient thanks to having a single shared Swift and SwiftUI codebase.
The Android version doesn’t yet have all the features of the iOS one, but additional Android functionality can be added over time. Skip never forces you to compromise your iOS app, provides a fast path to a native Android version using your existing code, and has excellent integration abilities to enhance and specialize your Android app when the effort warrants it.
Welcome to the June edition of the Skip.tools newsletter! This month we will showcase some of the improvements and advancements we've made to the Skip platform, along with some current events and a peek at our upcoming roadmap.
New Skip Intro Video
We've posted a new Skip "Showreel" video, providing a quick 3-minute overview of Skip and the highlights of using it to build native dual-platform apps. You can find it on YouTube at:
https://www.youtube.com/watch?v=lQjaaAqgxp4. This and other videos are also available from our Tour page at:
/tour/. We will be posting new videos in the coming weeks and months, so consider either following us on YouTube, or subscribing to our RSS feed.
Skip Showcase on the Stores
The Skip Showcase app (/docs/samples/skipapp-showcase/) has long been our go-to for providing a side-by-side comparison of SwiftUI components with the Jetpack Compose equivalents that SkipUI provides. Browsing thought these components simultaneously on an iPhone and Android device gives a good sense Skip's capabilities and power, and is a great way to demonstrate Skip's benefits to project managers and stakeholders before breaking ground on a new project.
In order to make it even easier to get this handy app on your devices, we've published the Skip Showcase app to both the
Apple App Store
as well as the
Google Play Store. This enables you to quickly grab a demo app that highlights Skip's power, and feel for yourself the benefit of using a genuinely native app on both platforms. Download it today and see for yourself what Skip can do!
New Framework: SkipKeychain
Using the Keychain has long been the standard way to store bits of sensitive data, such as passwords and notes, on your iOS device. We're happy to announce a brand-new SkipKeychain module that provides an API to read and write sensitive data both on iOS and Android. As with the rest of Skip's library ecosystem, it is free and open-source and available on GitHub at:
https://github.com/skiptools/skip-keychain/. We're only on version 0.0.1 right now, but we expect to be able to iterate quickly to add features and functionality that the community wants to see in this nascent project.
Skip and Kotlin Multiplatform
Skip and Kotlin Multiplatform (KMP) are two sides of the same coin. Skip brings your Swift/iOS codebase to Android, and KMP brings your Kotlin/Android codebase to iOS. Many people have assumed that this diametrical opposition means that the two technologies are incompatible. But this is not the case! KMP modules can be embedded in Skip apps, and they work seamlessly, for the most part, with the Swift-to-Kotlin code transpilation that Skip provides. Check out our deep dive into the integration at
/blog/skip-and-kotlin-multiplatform/
and learn how you can take your business-logic KMP modules and integrate them in both the iOS and Android sides of your Skip app.
Skip Slack Group
By popular demand, we are starting to migrate away from our gitter.im Matrix chat system to a new Skiptools Slack group. Going forward, this will be the preferred medium for live discussions and getting technical help. The Skip team will be standing by to answer questions and help with any issues that members of the community may encounter. You can sign up and join the conversation at:
/slack/.
Skip and Fastlane
The last mile of app development can be the most grueling. Taking your tested and polished 1.0 app and getting it into the hands of your users ought to be quick and simple, but it isn't. Running the gauntlet of the app store submission process is hard enough when you only target one platform, but when you target both iOS and Android, you need to contend with a plethora of hurdles for both the Apple App Store and the Google Play Store.
Fortunately, the popular Fastlane tool (
https://fastlane.tools/
) has evolved over the years to help alleviate some of the drudgery of submitting new apps, as well as updated releases, to these storefronts. And we're happy to report that new projects created with the `skip init` command will now include Fastlane templates that provide everything you need to automate your app distributions. Read more about it on our blog post:
/blog/skip-and-fastlane/.
WWDC, Google I/O, and Skip
Google I/O 2024 and WWDC 2024, the preeminent conferences for Google and Apple developers alike, went back-to-back in June. These exciting events unveiled a lot of new features to the languages and frameworks that are used daily by mobile app developers. We here on the Skip team are working hard to take advantage of many of the new features that were announced.
Language evolution was announced as well: Kotlin 2.0 (final) was released, and Swift 6.0 (beta) was offered up in preview. As we march towards a Skip 1.0 release, we are going to make sure that all the code we process and generate is compatible with both these next-generation language releases, and takes advantages of as many of the new features as possible, while still remaining compatible with prior source and binary releases. Skip 1.0 is right around the corner, and it will be right up to date with the latest and greatest!
Thanks!
You can follow us on Mastodon at
https://mas.to/@skiptools, and join in the Skip discussions at
http://forums.skip.dev/. The Skip FAQ at
/docs/faq/
is there to answer any questions, and be sure to check out the video tours at
/tour/. And, as always, you can reach out directly to us on our Slack channel at
/slack/.