Swift on Android
Total Page:16
File Type:pdf, Size:1020Kb
Swift on Android Eric Wing blurrrsdk.com try! Swift Tokyo 2017 Need to be quick… Android dev is a large topic for the uninitiated • (Obligatory) Why Swift on Android? • A native language that is cross-platform (like C & C++) • I’ll assume everybody here already here already sees the value • Note: I put extra things in my slides that, I won’t have time to talk about, but are to help you in the future when you refer back to the talk. Yes, the real Apple Swift My Background: Worn lots of hats • Prove to you I actually know what I’m talking about • Not just an Android dev • Also a seasoned Mac/iOS dev (and other platforms too) • I will act as your bridge between worlds • I look at this holistically from the vantage point of computer history & fundamentals Globalstar: Satellites & Rockets • Global communication system based on constellation of satellites and ground stations • Launch satellites into space with rockets! • (Not relevant for this talk, but I’m told it sounds cool) From Cross-platform to Native Cocoa • Cross-platform, Scientific Visualization • End of the Unix Wars => Microsoft Windows domination • Mac OS X: A Unix with a user-friendly UI • Meld cross-platform OpenGL sci-viz with native Cocoa UI for best experience Open Source Projects • Got involved in some open source projects • Usually related to improving Apple platform support LuaCocoa • Wrote world’s first full-featured bridge between Lua & Cocoa • Obj-C runtime + libffi + Mac OS X 10.5 BridgeSupport • Complete API coverage including C APIs • Dual mode: Obj-C garbage collection & traditional • PowerPC/Intel, 32-bit/64-bit Universal Binaries Beginning iPhone Games Development Commercial Game Engines Corona SDK Platino (Lua) (JavaScript) • Primary platforms: iOS & Android • Also: Mac & Windows First “proper” Swift/Android app https://youtu.be/7fVC0245Io8 https://youtu.be/w6FY_qSi8yY Ouroboros: Eternal cycle of life & death What’s old is new again • Nothing in this talk is “new” • Simply re-applying old concepts in different ways • Compilers / Native code • C / Application Binary Interface (ABI) • Unix / Linux / Android • Recognizing this may make this topic easier to understand C interoperability • C is the most portable language • Every platform has a C compiler (even the web with Emscripten) • The C ABI is stable and everything is built on it • Most languages have a way to talk to C • Swift provides one of the easiest & most direct ways • Decades of pre-existing software • A lot still useful today Language vs. Libraries • Helpful to not confuse the two Swift “standard” libraries • Swift C library • AppKit / UIKit • Darwin • libdispatch • swiftCore • Core Graphics • GlibC • Foundation • Core Audio • Bionic Minimal Many Language vs. Libraries • Using Swift on Android (or other platforms) doesn’t mean using Cocoa Native • Swift C • libdispatch • UIKit iOS • swiftCore library • Foundation • Core Audio App • Darwin • Swift C Native • Android SDK • swiftCore library Android App • OpenSL ES • Bionic Cross-platform • SDL • swiftCore Game • OpenAL App Development vs. Server Development (i.e. Extra things that Swift on Linux devs don’t do) • Binaries must run on end-users native machines • All dependencies must be bundled with app or provided by the OS • Should not require installers or users to pre-install additional things • And never root access! • Apps have resources that must be bundled • e.g. images, sounds, data sets • Ideal: Third-party libraries can also be in binary form (requires stable ABI) We need to build real user-facing (Android) apps (Mostly) Okay Wrong Wrong Android NDK (Native Development Kit) • All Android apps must be written using the Android SDK which is in Java • Android NDK (Native Development Kit) allows you to create dynamic libraries using native code • All GUI APIs (and almost everything else) are exclusive to the Android SDK, i.e. Java only • Your Android app must use Java’s loadLibrary to load the dynamic libraries, and then communicate using JNI Swift & the Android NDK • NDK intended for C & C++, but Swift works too • Swift itself is written in C++ (which has consequences we’ll get too) • Your Swift programs are compiled to native code • So your programs live on the NDK side • Thus you must use the Android NDK The Android NDK “Really Does Suck” • John Carmack - “Half-baked”, “Really does suck” • Second class citizen on Android • IDE and build systems not well integrated • Almost no Android libraries are provided in the NDK • Lots of things are broken, slow to get fixed, if ever • Word on the street (few years ago): Only 2 full-time Google engineers + a few part time • Consistent with number of Google employees on NDK mailing list • No slight intended on those 2 engineers. Valiant effort. Google treats them as the black sheep. • Google: Among the richest, powerful companies in the world with #1 dominance in mobile, and this is the best effort Google chooses to put in Bionic (Android’s C standard library) • Android does not use glibc (unlike “real” Linux) • Wrote their own called “Bionic” • Doesn’t care about POSIX compliance • Doesn’t even care about ANSI compliance • 8 years into Android, still terrible Lua 5.2 (2013) builds with Turbo C 1.0 (1990) for MS- DOS without modification https://youtu.be/-jvLY5pUwic Lua 5.2 (2013) builds with Turbo C 1.0 (1990) for MS- DOS without modification https://youtu.be/-jvLY5pUwic Android NDK (r11c) fails to compile Lua Insights into Bionic https://mail-index.netbsd.org/tech-userlevel/2012/07/25/msg006571.html Terrible performance bug for strlcpy • Wrote a test program to run Test262 suite on JavaScriptCore • Runs through 11,000+ files • Used strlcpy • Mac, iOS so fast that I didn’t think about it • Android took: 9000 ms • Switch to strncpy + manual NULL term: 14 ms • Maybe I should be impressed they provide this function at all? Android SDK/Java isn’t that much better • Get a list of files (‘ls’) in a directory of an APK is well known to have a serious performance bug • Get list 11,000+ files: I killed the process after 3 hours of waiting Android file system and the .apk • Files that ship with your app are inside the “.apk” (think .zip) • Can’t use standard C file family (fopen, fread) • Needs a “God” object from the Java Android Activity or Context class • AAsset* AAssetManager_open(AAssetManager *mgr, const char *filename, int mode); • Existing cross-platform (ANSI) C/C++ libraries won’t work without modification • Places outside the .apk can use C file family • “Internal Storage”, but may not have much storage space • “External Storage”, but may not exist or have correct access permissions Dynamic Library System wonky too • System.loadLibrary doesn’t automatically load dependencies • Load must be manually done & in the correct order • Will silently ignore if a library by the same name is already loaded • Never use soname versioning and never use symlinks • (Android further tightened the soname rules in 6.0 and 7.0) • (Lots of other gotchas I’m omitting for time) Fight Club • What is the First Rule of Library Programming? • You do not use C++ • What is the Second Rule of Library Programming? • ? Swift & C++ (and how it affects you) • Swift is implemented in C++ and uses the C++ standard library • Swift has runtime dependencies that use C++ and the C++ standard library • Swift’s standard libraries are implemented in C++ and use the C++ standard library • Thus C++ issues are propagated forward to you (inherited) Android NDK and C++ • Android NDK provides 5 different C++ standard libraries you have to choose from • libstdc++, gabi++, stlport, gnustl, libc++ • All are incompatible with each other • NDK API level doesn't help either • C++ standard library does not guarantee a stable ABI so every NDK update potentially breaks • If you dynamically link • You must bundle with your app because Android does not ship one with the OS • In contrast Apple, ships system wide and tries to keep the ABI stable/backwards compatible Android NDK and C++ • In the real world… • People build binaries of libraries and share them • People don’t upgrade NDKs at the same time and versions get mixed • People use multiple libraries, all built under different NDK versions • So the final application must include a copy all these different C++ library versions • But Android doesn’t name versions differently • So files overwrite each other • And bad things can happen • In contrast, Microsoft Visual Studio at least has the sense to put the version number in the file name (e.g. msvcp140.dll) Android NDK and C++ • So we should statically link, right? Android NDK and C++ • So we should statically link, right? Android NDK and C++ • So we should statically link, right? • Android documentation warnings: Android NDK and C++ • So Lose, Lose • Thanks (for nothing) Google • In practice, I personally found static linking to work better Fight Club • What is the Second Rule of Library Programming? • You do not use C++ • Unfortunately, Swift uses a ton of it, so we must pay • Static linking possible, but altering the Swift build system is sooooo hard :( Let’s build Swift for Android: Dependency hell • Android comes with almost no libraries for the NDK, so we must build all Swift dependencies • Remember: we build user-facing apps • All dependencies must be bundled with app (or statically linked) libICU (used by swiftCore): Let’s talk about the “(Mostly)” (Mostly) Okay libICU: “DLL hell” problem • Android manufacturers or Android itself may use libICU internally • If it is used, when we load our library, the attempt silently fails and we call into the internal one