Introduction WORK IN PROGRESS!!
This article details the steps taken in creating the Android port of the libswift library.
To build the Android application you will need the following:
- Android SDK
- a running Java environment
- Preferably Eclipse with the SKD & AVDmanager plugin for creating Android apps
- At least one Android emulator (I used versions 1.6 and 2.2)
- the Android NDK that provides cross compilation tools for ARM processors
Libswift uses few libraries and it's very portable. Anyway the android NDK doesn't include any library except libc.
To compile libswift we will need the stdlib that needs to be compiled and included in the NDK.
Statically compile swift is not a bit issue, it can be easily archived by using a different compiler (not the NDK) that supports cross-compilation to ARM processor.
The problem is that you will end up with a standalone application that can't be linked to the hardware resources and doesn't have any access permission for the system.
The trick is to be able to create a library that can be used by a java front-end application. We can than give disk/network access right to the java application.
The above picture taken from http://marakana.com shows how the linking between the c++ library and the java front-end works.
The Java Native Interface (jni) is been used to call the native C++ library
- Prepare the environment. Look at the requirement above
- Create a new Eclispe project.
- Create a scheletron of the native library calls in the src dir using the "native" key in the declaration.
- I used NativeLib.java and implemented the functions start, stop, and progress (to report the current download status)
- Create the c header file based on the above scheletron.
- in the "bin" dir run "javah -jni com. ... .NativeLib" in my case
- this will create the file com_ .. _NativeLib.h in yourbin dir
- create a jni dir in the base project dir
- move the new header file in the jni dir
- Put the Swift sources in the jni dir
- an interface has to be provided to the jni header file
- the new interface can be implemented based on the content of the previous header file. This will also change data structures from/to jni/c++.
- Create android's Makefile, called Android.mk, inside the jni dir
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE := swift
LOCAL_SRC_FILES := swift.cpp sha1.cpp compat.cpp sendrecv.cpp send_control.cpp hashtree.cpp bin64.cpp bins.cpp channel.cpp datagram.cpp transfer.cpp httpgw.cpp
LOCAL_CFLAGS += -D__NEW__
- Now we need to compile everything using the NDK. As previously mentioned we need to first include all the needed libraries, such as the stdlib, in the NDK to be able to compile. There are several ways to archive it, I'll not mention them here since it's a long process and Google will help you :-).
- Create a project directory (in my case I called it swift) in the apps dir of the NDK root directory.
- Create a Application.mk in the above directory
APP_PROJECT_PATH := $(call my-dir)/project
APP_MODULES := swift_demo
- In the above directory create a symbolic link called "project" that points to the root dir of Eclipse's project
- Run ndk-build located in NDK's root directory from your project dir
- This should compile everything and create the library that we'll be using in our application
- If you have some errors than run: make APP=<name of your module> (in my case "swift") from your NDK's root dir
- Use "-B V1" options for debugging
- If the compilation process went fine you will find the new library inside the "lib" dir in your Eclipse project
- Now the hardest part is done and the integration with the app's interface is almost complete
- Instantiate the NativeLib in your UI java application and call the native methods.
- create a layout, file main.xml
- IMPORTANT: you need to give rights to the application for using the internet and for writing on the SD
Modifications to libwsift:
- all the unneeded files can be removed (everything except .cpp and .h files)
- swift.cpp has to be modified and changed to accept function calls from java
- providing library calls (I just implemented the start(root_hash, tracker) function)
- handling and converting JNI datastructures in C++
- _S_IREAD and _S_IWRITE are apparently undefined. for the moment I set them to 0000400 (read) and 0000200 (write)
- NDK's compiler is way more strict that g++. Some things have to change.. like casting to const some variables
- an Android.mk file has to be created. This will substitute the Makefile
- the video player will reproduce only audio tracks on the emulator > 1.5. It still works correctly on the real device. The problem occurs with h264 video files (and mp4, m4v container). Video playback regression in 1.5 .