Marquee Effect in SwiftUI

Marquee Effect is when a long-view (typically text-based) has its content moving horizontally to disclose full content. Like this: It’s fairly simple (albeit not straightforward) to do in SwiftUI. Android’s Jetpack Compose has it out of the box. As does also HTML: <marquee>. In this tutorial we’re going to use shaders and .distortionEffect modifier so this solution will be working for iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0 and further. This tutorial also goes through the process step-by-step, if you just need the full code, I’m leaving it in the end of this blogpost. ...

March 15, 2024 · 7 min

Localizable properties in Firestore. Swift example

Have you ever had some content stored in Firebase Firestore that you’d want to be localized? The most straightforward solution would be to have localization string on client and send localization keys from Firebase making all the localization happen on client but in this short article I’d like to show you an example of how you could store localizations actually on Firestore. Let’s say you want your app to support English and Ukrainian. Every text you send from Firestore should therefore have these 2 translations. Now how can we do that? Easy: every text would be an object (or map in Firestore terms) instead of a String and the object will hold different translations. Here’s how it might look like: ...

March 11, 2023 · 5 min

How to make iOS App Ad Hoc distribution

What you need to know before you start: Every device you want the app on should provide you its UDID Every device with iOS 16 and higher should enable Developer Mode So let’s start: Develop an app Decide which devices should have access to the app Retrieve their UDIDs (there are several ways, find the one that fits you and the users most) Add UDIDs to the eligible devices’ list Archive app You’ll need to store your .ipa file as well as a certain .plist file somewhere. Decide where and prepare to upload files there Select “Export” and chose “Ad Hoc Distribution” there. Click “Next” Here you get to chose App Thinning and whether to include a preassembled manifest.plist file. For the sake simplicity you can set thinning to “None” but if you know what it is and how to use it - go for it. Next option is whether you want to have a generated .plist file or not. You might try this option but it requires you to know the link your app will be under in advance (so right now, even before you generated the .ipa file) and have 2 images: 57x57 and 512x512. But you don’t have to do it now, just a little bit later I’ll show exactly how this .plist file should look like so you can copy-paste it and use right away. Click “Next” If you checked “Include manifest” in previous step you’ll need to fill some fields there. Then click “Next” In this step you just select whether you want or not to sign the app automatically. If you’ve ever distributed app to the App Store you should be familiar with this step. If you’re not then you most probably need to check “Automatically manage signing”. Click “Next” and wait some loading Final step in which you check all the details and click “Export”. Select directory on your Mac to export the app to and you’re done! At least here, in Xcode Organizer :) Once it’s exported, you’ll find a folder with .ipa file(s) in it. Depending on what you’ve selected earlier you might find a manifest.plist file there too. Upload the .ipa file(s) to the internet and now it’s time to prepare manifest.plist If you’ve generated manifest earlier, you can skip this step. If you haven’t - go to any text editor, create a file with a .plist extension and put this code inside. Don’t forget to insert .ipa link, bundle identifier, bundle version and title in the places I marked 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>items</key> <array> <dict> <key>assets</key> <array> <dict> <key>kind</key> <string>software-package</string> <key>url</key> <string>[insert .ipa link here]</string> </dict> </array> <key>metadata</key> <dict> <key>bundle-identifier</key> <string>[insert bundle identifier here]</string> <key>bundle-version</key> <string>[insert bundle version here]</string> <key>kind</key> <string>software</string> <key>platform-identifier</key> <string>com.apple.platform.iphoneos</string> <key>title</key> <string>[insert app title here]</string> </dict> </dict> </array> </dict> </plist> If you generated this manifest in step 8, you’ll have a slightly larger file with fields for images. And if you opted-in the app thinning it will be even larger – including different app versions ...

January 26, 2023 · 4 min

Ways to monetize your app

I’ve been learning lately about monetization strategies for an app for me as an indie developer for quite some time. In this short article I’ll gladly share my learnings. So without further ado: There are 7 main strategies to monetize your app: Free - this is actually a way to not monetize yours app but it’s worth mentioning, let it be a starting point. Apps with this type are free have all their features free to everyone Paid - this is a good old way to sell your app. User is required to pay once upon first installation for apps of this type. After that they’re able to access the app and it’s features forever without any other payment Freemium - this type is similar to Free, it also allows to install the app without any payment. However in the app there are features that are unavailable unless the user pays for them. As soon as they pay, the features are always open for them. There’s a variation of this type where the IAP (in-app purchase) is based on credits which the user spends to use features. After they spend the credits they got to purchase new ones Paymium - combines Paid and Freemium in a way that the user pays for initial installation, gets access to some features and in order to use some other features, has to pay. Again, both single-time IAP and credit system can be used Subscription - this type of monetization is the one that actually makes predictable recurring revenue possible. Having an app with subscription means that users will pay on weekly/monthly/yearly basis to have access to certain (or even all) features. As soon as their subscription expires they aren’t able to use that set of features anymore until they subscribe again Limited support - this is the type of monetization which is a subscription and not a subscription at the same time (Schrödinger sends greetings). The app in this category unlocks certain or all features forever after a one-time payment. However after some time the app doesn’t get free updates anymore or new features are unavailable until the user pays again for the next time period of new updates and features. Variation of this type would be to make a paid app and then, after some time, release not a new version of the app but a new app itself, e.g. YourApp and YourApp 2. Users who bought the first app will continue using it but as well as new users they will have an option to purchase a new app with all features from previous app and also new ones Ads - here and there in the app there are ads shown to the user. It can be a static banner, a dynamic targeted ad or anything in between. This type of monetizations works best if the app has a huge user base. The more users the more money ads will bring. Ads can also be combined with IAPs and especially with credit system: users would watch an ad to get credits Also back in the days combination of Free and Paid types was fairly popular. The idea is to have 2 apps: a free app with limited capabilities and features and a paid app with full set of features. Users would download the free version, see if they like it and if they need more features and consider purchasing the paid app. ...

January 8, 2023 · 3 min

Custom icon for SwiftUI MenuBarExtra

If you tired already the new API for macOS Ventura - MenuBarExtra - you might have stumbled upon the fact that while SF Symbols work just great for the Manu Bar Icon, custom icons aren’t working as expected. There’s no obvious reason for that, looks like SwiftUI is doing some trickery under the hood and this trickery isn’t really adjustable. But there’s a way of making it work, so let’s dive right in and see what works and what doesn’t! ...

December 13, 2022 · 2 min

Glare effect in SwiftUI

In this blogpost we’re going to create this fancy glare effect in SwiftUI: The effect kinda shows the glancing texture of View’s surface. Essentially the effect consists of a main View and a mask blended together. Let’s add a text and style it first: 1 2 3 4 5 6 7 let glareView = Text("Hello world!") .font(.system(size: 50, weight: .heavy, design: .rounded)) .foregroundStyle(LinearGradient( colors: [.blue, .mint], startPoint: .topLeading, endPoint: .bottomTrailing )) Here’s how it looks like: Now, the glare “line” is this very view masked by an animated Rectangle. Let’s implement that mask: ...

December 13, 2022 · 6 min

OS version availability check in @SceneBuilder

There are times when you might need to show different root views depending on the available OS version. For example you may have a new API that can be only used in the latest OS version. The problem with this is that body of your App structure wouldn’t allow that: 1 2 3 4 5 6 7 8 9 10 @main struct YourApp: App { var body: some Scene { if #available macOS(13.0, *) { // Error ... } else { ... } } } The reason is that implicitly body of the App is @SceneBuilder (the same way body of the View is implicitly a @ViewBuilder) and @SceneBuilder doesn’t allow to have a version check inside it. It would be allowed in an ordinary property though, like this: ...

January 13, 2022 · 1 min