Upgrade to Pro — share decks privately, control downloads, hide ads and more …

building android apps with haskell

building android apps with haskell

a basic overview on how to build android apps with haskell

Moritz Angermann

January 11, 2018
Tweet

More Decks by Moritz Angermann

Other Decks in Programming

Transcript

  1. Who • Moritz Angermann / zw3rk • mobile and dekstop

    apps blog: https:/ /medium.com/@zw3rk twitter: @angerman_io, @zw3rktech, @mobilehaskell Moritz Angermann, Haskell.sg November Meetup, Singapore
  2. Prerequisites • LLVM 5 - http:/ /releases.llvm.org/download.html#5.0.1 • Android Cross

    Compiler - http:/ /hackage.mobilehaskell.org • Toolchain Wrapper - https:/ /github.com/zw3rk/toolchain-wrapper • Android Studio - https:/ /developer.android.com/studio/index.html • (A recent cabal - https:/ /github.com/haskell/cabal/) Moritz Angermann, Haskell.sg November Meetup, Singapore
  3. Installing LLVM & GHC Cross Compiler $ curl -L -O

    http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-x86_64-apple-darwin.tar.xz $ tar xjf clang+llvm-5.0.0-x86_64-apple-darwin.tar.xz $ export PATH=$PWD/clang+llvm-5.0.0-x86_64-apple-darwin/bin:$PATH $ curl -L -O http://hackage.mobilehaskell.org/.../ghc-8.4.0.20180109-x86_64-linux-android.tar.xz $ curl -L -O http://hackage.mobilehaskell.org/.../ghc-8.4.0.20180109-armv7-linux-androideabi.tar.xz $ curl -L -O http://hackage.mobilehaskell.org/.../ghc-8.4.0.20180109-aarch64-linux-android.tar.xz $ mkdir ghc-{x86_64,armv7,aarch64} $ tar xjf ghc-8.4.0.20180109-x86_64-linux-android.tar.xz -C ghc-x86_64 $ tar xjf ghc-8.4.0.20180109-armv7-linux-androideabi.tar.xz -C ghc-armv7 $ tar xjf ghc-8.4.0.20180109-aarch64-linux-android.tar.xz -C ghc-aarch64 $ export PATH=$PWD/ghc-x86_64/bin:$PWD/ghc-armv7/bin:$PWD/ghc-aarch64/bin:$PATH Moritz Angermann, Haskell.sg November Meetup, Singapore
  4. Installing the Toolchain Wrapper # Clone it, bootstrap it and

    add it to PATH $ git clone https://github.com/zw3rk/toolchain-wrapper $ (cd toolchain-wrapper && ./bootstrap) $ export PATH=$PWD/toolchain-wrapper:$PATH Modify the toolchain config: - toolchain-wrapper/android-toolchain.config (macOS) - toolchain-wrapper/linux-android-toolchain.config (linux) to match your installed Android NDK. Moritz Angermann, Haskell.sg November Meetup, Singapore
  5. The Application • Create the application in Android Studio •

    Create a small Haskell library • Link the Haskell library with the application • Run some trivial Haskell code Moritz Angermann, Haskell.sg November Meetup, Singapore
  6. The Glorious Haskell library {-# LANGUAGE ForeignFunctionInterface #-} module MeetupDemo

    where import Foreign.C foreign export ccall "hs_hello" hello :: IO CString hello :: IO CString hello = newCString "Hello from Haskell" Moritz Angermann, Haskell.sg November Meetup, Singapore
  7. Building the Static library $ x86_64-linux-android-ghc -fllvmng -staticlib -fPIC \

    -o hs-libs/x86_64/libHSmeetupdemo.a \ -odir build/hs/x86_64 -hidir build/hs/x86_64 src/main/hs/Lib.hs [1 of 1] Compiling MeetupDemo ( src/main/hs/Lib.hs, src/main/hs/Lib.o ) Linking hs-libs/x86_64/libHSmeetupdemo.a ... Moritz Angermann, Haskell.sg November Meetup, Singapore
  8. Adjust the app/build.gradle: add abiFilters defaultConfig { applicationId "com.zw3rk.meetupdemo" minSdkVersion

    21 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" } } ndk { abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a' } } Moritz Angermann, Haskell.sg November Meetup, Singapore
  9. Adjust the CMakeLists.txt cmake_minimum_required(VERSION 3.4.1) add_library( native-lib SHARED src/main/cpp/native-lib.cpp )

    find_library( log-lib log ) find_library( c-lib c ) find_library( z-lib z ) find_library( hs-lib HSmeetupdemo PATHS ${PROJECT_SOURCE_DIR}/hs-libs/${ANDROID_ABI} NO_CMAKE_FIND_ROOT_PATH ) target_link_libraries( native-lib ${log-lib} ${hs-lib} ${c-lib} ${z-lib} ) Moritz Angermann, Haskell.sg November Meetup, Singapore
  10. Adapting the JNI glue (1) #include <jni.h> #include <string> extern

    "C" JNIEXPORT jstring JNICALL Java_com_zw3rk_meetupdemo_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } Moritz Angermann, Haskell.sg November Meetup, Singapore
  11. Adapting the JNI glue (2) extern "C" { extern void

    hs_init(int * argc, char ** argv[]); extern void hs_hello(); } extern "C" JNIEXPORT void JNICALL Java_com_zw3rk_meetupdemo_MainActivity_hsInit(JNIEnv *env, jobject /* this */) { hs_init(NULL,NULL); } Moritz Angermann, Haskell.sg November Meetup, Singapore
  12. Adapting the JNI glue (3) extern "C" JNIEXPORT jstring JNICALL

    Java_com_zw3rk_meetupdemo_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { return env->NewStringUTF(hs_hello()); } Moritz Angermann, Haskell.sg November Meetup, Singapore
  13. Adapting the Main Activity class MainActivity : AppCompatActivity() { override

    fun onCreate(savedInstanceState: Bundle?) { hsInit() super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) sample_text.text = stringFromJNI() } external fun stringFromJNI(): String external fun hsInit() companion object { init { System.loadLibrary("native-lib") } } } Moritz Angermann, Haskell.sg November Meetup, Singapore
  14. Notes • Building for iOS is very similar. Just drag

    the archive into Xcode and link; glue code easier in Obj-C. • Building with cabal It is possible, requires a very recent cabal from git and some manual intervention (haskell/cabal#4939; haskell/cabal#4972) • Make sure you keep your package databases separate! This could and should be handled better by cabal and ghc. • User Guide and Tutorials are coming mobile-haskell-user-guilde.rtfd.io Moritz Angermann, Haskell.sg November Meetup, Singapore
  15. Code Source code can be found at - github.com/angerman/2018-01-MeetupDemo Run

    the Makefile in the app folder then building with Android Studio. Moritz Angermann, Haskell.sg November Meetup, Singapore