29 comments

[ 5.2 ms ] story [ 77.0 ms ] thread
If you're going to get rid of all your Kotlin std lib usages by explicitly replacing them, after inspecting the actual class files generated by the compiler, with standard Java methods (and hope that no future change will re-introduce them) and you care so much about the size of your jars, I would say you're better off simply going back to Java, perhaps using the very latest version (since you're willing to use Kotlin that shouldn't be a problem) which has lots of niceties and to me, at least, looks a lot better than using Kotlin with these kinds of hacks. Add a nullability static analysis check and you're gold.
Disagree. A lot of the value of Kotlin is stuff that doesn't even make it into the binary, like scope functions.
The takeaway is "make sure you use a tool like R8 or ProGuard to remove unused code paths". That's where most of the savings came from, and the advice applies to Java projects as well.

But true, if you care about every last byte, you might use Java instead. You might also use another language entirely.

At that point, why not use Rust or Go or D or whatever with significantly smaller binary sizes and (un-optimized) faster speeds.
Not on Android
Rust has first class support for Android.
Cool, so I can start a new service and bind activities to it from Rust without having to deal with a nasty JNI or an unstable ABI that changes under my feet?
What do you mean by "first class support" here? Some quick searches doesn't give me results that goes in this sense (nothing official from the rust and/or android projects).
That's hardly the full story. Rust provides all the support it is able to provide for Android, yes. But it still relies on the NDK and has to sit behind a JNI layer. A "Kotlin vs Rust" comparison for Android is apples and oranges.
On Android you are stuck with Java8 so GP's point melts away.
I love D but it's ecosystem just isn't there. If you need the jvm ecosystem you're probably better off with Graal.
The goal here was to get the binary size to be small enough, not the smallest it could possibly be. The tool was written in 2 hours because I used a language I was proficient in. While I love me some Rust it would easily double if not triple the time it would take me to build the thing in the first place
If that's the real Jake Wharton, I have to say I am a big fan of the tools/libs (and their quality) you wrote for Android. They were especially useful 7-5 years ago, when the "official" libs were pathetically crappy :).
Doesn't it make more sense to look at this work as proof-of-concept for what the Kotlin compiler could do automatically?
The final section of the post was a Java port and size comparison. It also noted that while it was smaller, I simply don't want to use Java and the minute any external dependency is added (such as for CLI parsing) I'm right back to needing R8 for minifying.

I removed that part since the post was long enough.

If you have used Kotlin you would have known that no sane person wants to go back to Java after being exposed to Kotlin.
What a silly way to look at things.

If it matters, I've been programming more in Kotlin than in Java nowadays, and I have no trouble at all going back to Java... it's a nice language for its age and it gets the job done robustly. I even prefer Java for small applications that I want to distribute to users as small jars, for example. Kotlin has some nice benefits, but it's not a panacea that makes Java irrelevant - it actually strengthens the Java ecosystem in my opinion - it's another tool for the Java developer to use when appropriate.

> - val old = args[0].let(::File).readText() > - val new = args[1].let(::File).readText() > + val old = args[0].let(Paths::get).let(Paths::readString) > + val new = args[0].let(Paths::get).let(Paths::readString)

Missed index. 0!=1.

That’s an impressive catch. I would never have noticed this. How did you get this good at code review?
It helps that the correct code is just above the buggy replacement…
Reading lots of code. And as the other commenter says, it's a bit easier when the correct code is right above it.
It used to help a lot (30-40%) to sort the class files of a librarly on canonical name before you add them to its jar. Class files contain that name, and are (typically) small. Your compression factor will grow. (maybe that trick is standard now)
Removing `-dontobfuscate` will change all the package, type, and function names to be single letters for the same result of greater compression.

The goal here was to just get it small enough, not the smallest it could possibly be.

Looks like most of the size reduction was from running R8. The rest seems meaningless.
any idea how to get the swift upload network traffic down?

My 500K objc ipa ported to swift http://mro.name/ShaarliOS now is ~8MB (OTA test ipa), ~28MB for production upload causing ~300MB traffic until finally uploaded via xcrun, taking 1h on my rural uplink.

Has anybody an idea how to get back to sane dimensions?