Home Development for Android Porting to Android

Porting to Android

by admin

Porting to Android

At the end of of this article I announced a plan to make an Android port. Here I will try to describe the problems I encountered and how to solve them. I want to mention right away that I have only 2 months of experience with Android and possibly some of the solutions are dangerous or even not acceptable on this platform.

Engine

The engine (hobby) has been in development for 10 years.
The engine is entirely written in C/C++, supported iOS and Windows before porting to Android.
Logic, rendering, sound – all in C/C++.

File system

An important feature that made porting to Android very easy is the file system of the engine.
Pseudo code :

 class IStream{void setName(string name ) = 0;open() = 0;write() = 0;... = 0;}class FileStream : public IStream{implementation via fopen, fread... POSIX API.}class DataPackStream : public IStream{Implementations for .pak filesCore::Meta* m_packFileStreamMeta;; /// m_packFileStreamMeta-> Create() IStream* of this type will be used to work directly with the .pak file} 

So: all work with files in the engine is based on IStream interface, the architecture of the engine supports an object factory, and its customization.
Example Code :

 Core::FileStream::Type()-> setFactoryMeta(DataPack::DataPackStream::Type());FileStream* filestream1 = FileStream::Create();// the same will happen with new FileStream()FileStream* filestream2 = FileStream::CreateExact();filestream1 will be of type DataPackStreamfilestream2 will be of the FileStream type 

Nothing new and everything is pretty standard.
Since all the resources are forbidden in a .pak file, I had to write my own implementation of IStream specifically to work with Java for the Android system.
Initializing this resource in Java

 AssetFileDescriptor RawAssetsDescriptor = this.getApplicationContext().getResources().openRawResourceFd(R.raw.data000);if (RawAssetsDescriptor != null){FileInputStream fis = RawAssetsDescriptor.createInputStream();NativeMethods.dataPackChannel = fis.getChannel();NativeMethods.dataPackOffset = RawAssetsDescriptor.getStartOffset();NativeMethods.dataPackSize = RawAssetsDescriptor.getLength();} 

Nativ class translates all open, read, seek calls back to Java

 AndroidPackStream class : public IStream { //.... // example of the work read size_t read(void *buffer, size_t size, size_t count) { if( JavaHelpers::m_pClass ) { jmethodID mid = JavaHelpers::GetEnv()-> GetStaticMethodID(JavaHelpers::m_pClass, "freadDataPack", "(I)I");int res = JavaHelpers::GetEnv()-> CallStaticIntMethod(JavaHelpers::m_pClass, mid, (int)size*count);jfieldID field = JavaHelpers::GetEnv()-> GetStaticFieldID(JavaHelpers::m_pClass, "byteBuffer", "Ljava/nio/MappedByteBuffer;");jobject obj = JavaHelpers::GetEnv()-> GetStaticObjectField(JavaHelpers::m_pClass, field);uint8_t* pData=(uint8_t*)JavaHelpers::GetEnv()-> GetDirectBufferAddress(obj);memcpy(buffer, pData, size*count);JavaHelpers::GetEnv()-> DeleteLocalRef(obj);return res/size;}} 

Java implementation of reading this stream with returning data back to the neuter

 public static int freadDataPack(int count){long curPos = dataPackChannel.position();int countReaded = count;byteBuffer = dataPackChannel.map(MapMode.READ_ONLY, dataPackChannel.position(), count);byteBuffer.load();dataPackChannel.position(curPos+countReaded);return countReaded;} 

Important point – apk builder compresses all resources, and we want to read the file as if it just lies in the file system. In order for our .pak file not to be compressed inside the apk – you must change its extension to one of those that will tell the packer not to compress these files when packing (details ponystyle.com/blog/2010/03/26/dealing-with-asset-compression-in-android-apps ). I chose .imy.
Loading resources this way is very fast, for example on Kindle Fire it is faster than on iPad 1.
I should mention that this is a trick to pull if you don’t have a lot of data.
For large amounts of data, you can unpack the data onto a medium internally yourself (e.g. during the first run) and use it directly with the fopen fread functions (in my case, with a non-swapped FileStream) etc.

Sound

OpenAL was used for Windows and iOS. OpenAL for Android was built thanks to pielot.org/2010/12/14/openal-on-android It didn’t work right away, but only after the fixes described in the comments on the website.
Build for Android built only for Arm v7 – because the build port for Arm v6 OpenAL sometimes leads to lags, in iOS OpenAL mixer works faster and without lags (even on ArmV6, such as on the iPod Touch 2G).

Interaction with native code from C/C++

A very simple class mapping is responsible for handling calls to platform dependent implementations
Pseudo code :

 class IPlatfomCommandFeedback{void onResponse(string);};class IPlatfomCommand{string execute(string command, IPlatfomCommandFeedback* feebback);}; 

iOS has its own Objective-C implementation and Android has its own JNI-> Java implementation.

Rendering

Nativ part works using OpenGL, minimal changes were made for Android. As it turned out later, this was not enough. The fact that on Windows and iOS textures are not lost when the application goes into bangraound, but for Android this always happens. The engine already had a texture manager (mostly for debugging) and adding a resource reloading was not difficult.

Assembly

In the very first article I wrote about how I originally compiled iOS using toolchain and I had the makefile configured. That’s where it came in handy for me. I added Android NDK build targets, added step to the Eclipse builders and everything took off. Yes, you can use the build system from Android NDK samples. I only used it to figure out the parameters that are used to call gcc.

OpenFenit AdMob

Integration of both libraries went without problems – strictly according to developers’ instructions

Proguard

This is more or less clear – you just have to make sure that your JNI Native binds are not obusked

Means of development

Hardware : Kindle Fire, and a couple of tablets and friends’ cell phones(for testing).
Software : Eclipse with plugins

Shock number 1

Android Market is not the AppStore. It’s different there. There’s no New category there.
For comparison, the AppStore had 800+ downloads on the first day of release, the second 2000+, the Andoid Market had the official first hundred downloads only on the third day. Promotion activity for both platforms was the same

Shock number 2

If your app is free you can freely distribute apk, anyone can install the app from any source. If you don’t do it, others will do it for you.

Shock number 3

The bestiary of devices is large. The number of problems is correspondingly.

Amazon

The Amazon AppStore for Android review process takes a week, plus a few more days until the app is listed in the AppStore on the Kindle Fire. The number of downloads and momentum is in line with Android Market

Advertisement

Rays of Kindness Corporation Hate – It’s been a week since the ad banner was sent to uproar. So far, silence.

Money

At the moment, the amount of money (remember the game only ads), which brings the iOS version is forty (40) times more than the Android version. It is clear that the comparison is not correct and we have to wait at least another couple of months until the number of regular players per day stabilizes.
UPDATE: In the sound section I described the reason for building only for ArmV7 Android devices.

You may also like