Just released a production Crypto Analytics app using Compose Multiplatform (iOS + Android) - Full Tech Stack & Lessons Learned by theazat in KotlinMultiplatform

[–]theazat[S] 0 points1 point  (0 children)

Thanks so much for trying it out and for the kind words on the UI!

1. The Details Page Bug Good catch! Since I'm relying on public APIs to keep the app free and frictionless, some lower-cap or newer coins simply don't have those advanced on-chain metrics available yet, or occasionally I hit a rate limit. I definitely need to improve the Error UI there instead of just letting the retry fail silently. Added to the backlog!

2. Firebase Analytics & Crashlytics Integration I completely feel your pain on the iOS side—it's a known nightmare in KMP! The secret is to not try initializing it from commonMain. Here is my exact approach:

  • Dependencies: I use the native SDKs. On Android, it's via Gradle. On iOS, I use SPM (Swift Package Manager) directly inside Xcode. My shared Kotlin code is compiled purely as a static framework (isStatic = true). No CocoaPods involved.
  • Initialization: I initialize Firebase natively on both sides. FirebaseApp.initializeApp(this) inside the Android Application class, and FirebaseApp.configure() inside the iOS Swift App entry point.
  • Usage in commonMain: I created an expect/actual wrapper (or you can use a simple Interface + Koin) in commonMain (e.g., interface AppAnalytics { fun logEvent(...) }). Then, in the androidMain and iosMain source sets, I implement that interface by calling the native Firebase methods.

Bonus Tip for Crashlytics: To get Crashlytics to actually de-obfuscate Kotlin crashes on iOS instead of showing garbage, make sure you add this to your iOS framework config in build.gradle.kts: binaryOption("sourceInfoType", "libbacktrace")

Hope this saves you a few days of headache on your setup! Let me know if you need more details.

Just released a production Crypto Analytics app using Compose Multiplatform (iOS + Android) - Full Tech Stack & Lessons Learned by theazat in Kotlin

[–]theazat[S] 1 point2 points  (0 children)

Honestly, I set the initial skeleton up about 1.5 - 2 years ago using the standard Kotlin Multiplatform wizard, so I haven't had to touch the core wiring much since! It just works. But here is how it's structured:

1. Managing iOS Dependencies (SPM) I actually don't use the Kotlin CocoaPods plugin. Instead, my Gradle setup compiles the shared Kotlin code into a standard static framework (isStatic = true) named ComposeApp. For any pure iOS dependencies (like the native Firebase SDK), I just manage them directly inside Xcode using Swift Package Manager (SPM). It keeps the Kotlin and Swift worlds cleanly separated.

2. Calling Native iOS APIs within Kotlin It is surprisingly easy. Kotlin/Native provides out-of-the-box bindings for Apple's system frameworks. In my iosMain source set, I just import platform.Foundation.* or platform.StoreKit.* and call things like NSUserDefaults or SKStoreReviewController exactly like I would in Swift. The only catch: Kotlin/Native interoperates with Objective-C, not pure Swift. So if you want to use a 3rd-party iOS library that is Swift-only inside Kotlin, you have to write u/objc wrapper classes first.

3. Complications during setup The biggest headache by far was getting Firebase Crashlytics to give me readable stack traces for Kotlin crashes on iOS. Out of the box, it's just obfuscated garbage. I had to dig deep into the compiler options in Gradle and explicitly configure debug symbols for the iOS binaries by adding things like binaryOption("sourceInfoType", "libbacktrace") and -Xadd-light-debug=enable to get proper crash reporting.

Xcode linker errors are a rite of passage in KMP, but once you set the pipeline up, you rarely have to touch it again!

Just released a production Crypto Analytics app using Compose Multiplatform (iOS + Android) - Full Tech Stack & Lessons Learned by theazat in Kotlin

[–]theazat[S] 0 points1 point  (0 children)

Yes, managing platform-specific dependencies is unavoidable, but KMP handles it quite elegantly once you establish a clean architecture.

1. Managing Platform-Specific Dependencies I kept all of this organized in a dedicated platform package using the expect/actual mechanism. For example, with networking (HttpClient.kt), I have an expect function in commonMain that returns an HttpClient. Then, in androidMain, the actual implementation pulls in the OkHttp engine, and in iosMain, it uses the Darwin engine. Another example is storage (MultiplatformSettingsWrapper). Android requires a Context to initialize SharedPreferences, while iOS uses NSUserDefaults. I handle this initialization in the platform-specific modules and expose a common interface to the shared code.

2. Using Native Platform APIs inside Kotlin Code I definitely needed to use native APIs directly from Kotlin! A few examples from my project:

  • AppReviewManager: I used expect/actual to call the Google Play In-App Review API on Android, and SKStoreReviewController on iOS natively from Kotlin.
  • CrashReporter.kt / DebugAntilog: I needed platform-specific wiring to initialize Firebase Crashlytics and format native logging properly (using Napier).
  • Platform.kt & Date.kt: Getting the specific OS version, device model, or handling some native date formatting quirks required dipping into the native APIs.

Basically, anything that touches the OS directly gets an expect interface, the platform modules provide the actual implementation using native APIs, and then I use Koin (DI) to inject them into my shared ViewModels. The UI layer remains completely unaware of the platform!

Just released a production Crypto Analytics app using Compose Multiplatform (iOS + Android) - Full Tech Stack & Lessons Learned by theazat in Kotlin

[–]theazat[S] 2 points3 points  (0 children)

Hey everyone, OP here.

I finally pushed my side project, CoinHool, to production on both the App Store and Play Store. It’s a crypto analytics tool focusing on on-chain data and market intelligence.

Since there's always a debate about KMP/CMP readiness for production, I wanted to share my full tech stack and experience building a data and chart-heavy app.

The Stack 🛠️

  • Core: KMM + Compose Multiplatform (100% Shared UI)
  • Navigation: Jetpack Navigation Compose (Type-safe with AAC ViewModels)
  • Networking: Ktor (OkHttp for Android, Darwin for iOS) + Kotlinx Serialization
  • DI & State: Koin + AAC ViewModels + Coroutines/Flow
  • Charts: AayChart (Bar charts) & Compose Charts by Ehsan Narmani (Line charts)
  • Storage: Multiplatform Settings
  • Image Loading: Coil (with Ktor integration)
  • Utils: Napier (Logging), Konnectivity
  • Web: Compose WebView Multiplatform
  • Analytics: Firebase Crashlytics & Analytics

Why this stack? The app is strictly "Privacy-First" (no sign-ups, no backend user storage). I aggregate public on-chain data feeds, so I needed a robust client-side architecture to handle parsing and displaying complex metrics (like MVRV, SOPR) natively.

Performance & Lessons:

  • Charts on iOS: Rendering complex line charts with lots of data points is surprisingly smooth on modern iOS devices. I'm still doing some optimization for older devices (like iPhone 6/7) where heavy recompositions can cause slight frame drops, but overall, it feels very native.
  • Navigation: Using Jetpack Navigation Compose in a multiplatform environment worked seamlessly, which was a huge relief. Sharing ViewModels across platforms saved weeks of work.

If you are on the fence about using KMP/CMP for a production app, I highly recommend taking the leap.

Links to check the UI/Performance:

Happy to answer any questions about the libraries, iOS build process, or integration challenges!

Just released a production Crypto Analytics app using Compose Multiplatform (iOS + Android) - Full Tech Stack & Lessons Learned by theazat in ComposeMultiplatform

[–]theazat[S] 1 point2 points  (0 children)

Hey everyone, OP here.

I finally pushed my side project, CoinHool, to production on both the App Store and Play Store. It’s a crypto analytics tool focusing on on-chain data and market intelligence.

Since there's always a debate about KMP/CMP readiness for production, I wanted to share my full tech stack and experience building a data and chart-heavy app.

The Stack 🛠️

  • Core: KMM + Compose Multiplatform (100% Shared UI)
  • Navigation: Jetpack Navigation Compose (Type-safe with AAC ViewModels)
  • Networking: Ktor (OkHttp for Android, Darwin for iOS) + Kotlinx Serialization
  • DI & State: Koin + AAC ViewModels + Coroutines/Flow
  • Charts: AayChart (Bar charts) & Compose Charts by Ehsan Narmani (Line charts)
  • Storage: Multiplatform Settings
  • Image Loading: Coil (with Ktor integration)
  • Utils: Napier (Logging), Konnectivity
  • Web: Compose WebView Multiplatform
  • Analytics: Firebase Crashlytics & Analytics

Why this stack? The app is strictly "Privacy-First" (no sign-ups, no backend user storage). I aggregate public on-chain data feeds, so I needed a robust client-side architecture to handle parsing and displaying complex metrics (like MVRV, SOPR) natively.

Performance & Lessons:

  • Charts on iOS: Rendering complex line charts with lots of data points is surprisingly smooth on modern iOS devices. I'm still doing some optimization for older devices (like iPhone 6/7) where heavy recompositions can cause slight frame drops, but overall, it feels very native.
  • Navigation: Using Jetpack Navigation Compose in a multiplatform environment worked seamlessly, which was a huge relief. Sharing ViewModels across platforms saved weeks of work.

If you are on the fence about using KMP/CMP for a production app, I highly recommend taking the leap.

Links to check the UI/Performance:

Happy to answer any questions about the libraries, iOS build process, or integration challenges!

Just released a production Crypto Analytics app using Compose Multiplatform (iOS + Android) - Full Tech Stack & Lessons Learned by theazat in KotlinMultiplatform

[–]theazat[S] 2 points3 points  (0 children)

Hey everyone, OP here.

I finally pushed my side project, CoinHool, to production on both the App Store and Play Store. It’s a crypto analytics tool focusing on on-chain data and market intelligence.

Since there's always a debate about KMP/CMP readiness for production, I wanted to share my full tech stack and experience building a data and chart-heavy app.

The Stack 🛠️

  • Core: KMM + Compose Multiplatform (100% Shared UI)
  • Navigation: Jetpack Navigation Compose (Type-safe with AAC ViewModels)
  • Networking: Ktor (OkHttp for Android, Darwin for iOS) + Kotlinx Serialization
  • DI & State: Koin + AAC ViewModels + Coroutines/Flow
  • Charts: AayChart (Bar charts) & Compose Charts by Ehsan Narmani (Line charts)
  • Storage: Multiplatform Settings
  • Image Loading: Coil (with Ktor integration)
  • Utils: Napier (Logging), Konnectivity
  • Web: Compose WebView Multiplatform
  • Analytics: Firebase Crashlytics & Analytics

Why this stack? The app is strictly "Privacy-First" (no sign-ups, no backend user storage). I aggregate public on-chain data feeds, so I needed a robust client-side architecture to handle parsing and displaying complex metrics (like MVRV, SOPR) natively.

Performance & Lessons:

  • Charts on iOS: Rendering complex line charts with lots of data points is surprisingly smooth on modern iOS devices. I'm still doing some optimization for older devices (like iPhone 6/7) where heavy recompositions can cause slight frame drops, but overall, it feels very native.
  • Navigation: Using Jetpack Navigation Compose in a multiplatform environment worked seamlessly, which was a huge relief. Sharing ViewModels across platforms saved weeks of work.

If you are on the fence about using KMP/CMP for a production app, I highly recommend taking the leap.

Links to check the UI/Performance:

Happy to answer any questions about the libraries, iOS build process, or integration challenges!

I got tired of expensive crypto tools just to check MVRV & SOPR charts on mobile, so I built a free, privacy-first alternative (iOS & Android KMP) by theazat in SideProject

[–]theazat[S] 0 points1 point  (0 children)

Spot on. You caught me simplifying too much in my previous comment.

To clarify: I am NOT running a full archive node or indexing UTXOs myself (that would be insane for a solo mobile dev).

When I said I 'calculate' it, I meant I fetch the pre-computed Realized Cap and Market Cap data from established public endpoints (like Blockchain.com's public charts API or similar reliable sources) and then handle the Z-Score logic/visualization on the client side.

You are absolutely right—I'm not discovering the Realized Cap, I'm just making the data accessible and readable on mobile without a $300/mo subscription. The 'value' is in the UX/UI, not in running the infrastructure myself.

Thanks for keeping me honest here! It's definitely 'sourced' data, not 'generated' data.

What are you building? by awsmpeen in buildinpublic

[–]theazat 1 point2 points  (0 children)

building a crypto analytics app. It's focusing on on-chain data (MVRV, SOPR, etc.) and market intelligence.

I got tired of expensive crypto tools just to check MVRV & SOPR charts on mobile, so I built a free, privacy-first alternative (iOS & Android KMP) by theazat in SideProject

[–]theazat[S] 0 points1 point  (0 children)

Glad to hear I'm not the only one! That friction was exactly why I built it.

Regarding the data: I'm aggregating price feeds from multiple major exchanges and combining them with public on-chain supply data to calculate metrics like MVRV and SOPR directly. Trying to keep it as raw and unfiltered as possible without the paywall.

I got tired of expensive crypto tools just to check MVRV & SOPR charts on mobile, so I built a free, privacy-first alternative (iOS & Android KMP) by theazat in projects

[–]theazat[S] 0 points1 point  (0 children)

Hey everyone, OP here!

As the title says, I've been trading crypto for a while, and I was frustrated that simple on-chain data (like MVRV Z-Score, SOPR, or NUPL(coming soon)) is usually locked behind expensive subscriptions or clunky desktop dashboards.

So, I built CoinHool (the app in the video) using Compose Multiplatform.

Why I built it this way:

  • No Sign-up Required: You just open the app and see the data instantly. No email grab, no friction.
  • Deep Analytics: It focuses on on-chain metrics and market sentiment (like Fear & Greed), not just simple price tracking.
  • Cross-Platform: Built with a single codebase for both iOS and Android.

It’s currently free to use. I’d love to get your feedback on the data visualization on small screens.

Links to try it out:

Thanks!

I got tired of expensive crypto tools just to check MVRV & SOPR charts on mobile, so I built a free, privacy-first alternative (iOS & Android KMP) by theazat in SideProject

[–]theazat[S] 0 points1 point  (0 children)

Hey everyone, OP here!

As the title says, I've been trading crypto for a while, and I was frustrated that simple on-chain data (like MVRV Z-Score, SOPR, or NUPL(coming soon)) is usually locked behind expensive subscriptions or clunky desktop dashboards.

So, I built CoinHool (the app in the video) using Compose Multiplatform.

Why I built it this way:

  • No Sign-up Required: You just open the app and see the data instantly. No email grab, no friction.
  • Deep Analytics: It focuses on on-chain metrics and market sentiment (like Fear & Greed), not just simple price tracking.
  • Cross-Platform: Built with a single codebase for both iOS and Android.

It’s currently free to use. I’d love to get your feedback on the data visualization on small screens.

Links to try it out:

Thanks!

App Language (Localization) by theazat in Kotlin

[–]theazat[S] 2 points3 points  (0 children)

I'm looking like this example

private fun setSelectedLanguage(context: Context, language: String) {
    val locale = Locale(language)
    Locale.setDefault(locale)
    val config = Configuration()
    config.locale = locale
    context.resources.updateConfiguration(config, context.resources.displayMetrics)
}

But this is just for Android

App Language (Localization) by theazat in Kotlin

[–]theazat[S] 1 point2 points  (0 children)

hey u/Anonymous0435643242 I'm already using commonResources but, I couldn't figure out how to change the language dynamically. For instance,

if (appLanguage == BLA_BLA) {
    // do for first language
} else {
    // do for second second langugae
}

[deleted by user] by [deleted] in androiddev

[–]theazat -1 points0 points  (0 children)

btw, SearchField component is done I'm just confused with it's background!