j2objc

Determine current platform in j2objc


What is the best way to determine the current platform (Android vs. iOS) when working with j2objc?

Or a more general question: How to use different code for Android and iOS, for example when handling database access or networking?


Solution

  • To determine the current platform, use System.getProperty("os.name"). A j2objc-translated app will return either "iPhone", "iPhone Simulator" or "Mac OS X".

    To run different code on Android and iOS, it's common to define an interface or abstract class as the API for shared code use, then implement/subclass with Android and iOS versions. You can dynamically load the right class at runtime using the os.name test above.

    If the only difference between the Android and iOS versions is native code, however, a single class can be shared. Because OCNI native snippets are inside Java comments, they disappear when compiled with javac. So one class with native Objective C can work on all platforms:

    class MyDataSource {
      native int readCustomerCount()/*-[
        <iOS Objective C code>
      ]-*/;
    
      native void writeCustomerCount(int count)/*-[
        <iOS Objective C code>
      ]-*/;
    }
    

    All javac sees:

    class MyDataSource {
      native int readCustomerCount();
      native void writeCustomerCount(int count);
    }
    

    Next, follow the JNI patterns to build with the Android NDK. Here is a discussion on getting started with JNI on Android. The steps are to run javah on your class files with native code to create .h header files, then write matching C or C++ files that implements each function. Here's a JNI header file for the above class (minus the comments):

    /* Header for class MyDataSource */
    #include <jni.h>
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    JNIEXPORT jint JNICALL Java_MyDataSource_readCustomerCount
      (JNIEnv *, jobject);
    
    JNIEXPORT void JNICALL Java_MyDataSource_writeCustomerCount
      (JNIEnv *, jobject, jint);
    
    #ifdef __cplusplus
    }
    #endif
    

    The last step is to load your native library, so the JVM can find and run your native code. Add this to the above class:

    static {
      System.loadLibrary("mydatasrc");
    }