Multi-OS Engine Technology Preview from Intel: First-hand Experience in creating an iOS* App Using Java*

This paper summarizes the experience of Auriga*, the software engineering and consulting firm, in their use of the Intel's Multi-OS Engine technology preview from Intel. Software engineers at Auriga created a wireless mobile patient monitoring app that runs on Apple iPad* devices. The app provides data on patient vital signs to the hospital information system via Wi-Fi.  Auriga engineers demonstrated the app at the Intel Developer Forum in San Francisco in August 2015. 

More information about the app and its functionality is available in the Auriga’s blog. This paper walks the reader through Auriga’s experience in using the Multi-OS Engine technology preview to create a native mobile app. The Multi-OS Engine technology preview lets you use Java for the development of native iOS apps, potentially saving significant time and resources in developing Java-based apps and delivering them on multiple platforms. The code for the app is available on Github* https://github.com/moe-applications/Auriga-patient-monitor-application

Multi-OS Engine Technology Preview: Key Benefits

User Interface Elements

The engineers who developed the app said that the key advantage of Multi OS-Engine technology preview is the opportunity to work with native for iOS UI elements just as they would in Xcode*. All elements required for app development were provided by the platform; there was no need to add anything extra. Each element has a thorough description and all characteristics and methods to simplify the development work are there and should be familiar to developers who have iOS development experience.

Java Features

Auriga software engineers report that the greatest advantage of the Multi-OS Engine technology preview is that it enables the use of most Java features. An example is directly below that illustrates how to work with threads and organize files:

Thread<strong>  thread </strong>= <strong>new </strong>Thread() {
<strong>    public void </strong>run() {     
    }
};

<strong>thread</strong>.start();
private void openFileToRead() {
    String fileId = "hb";
    NSBundle mainBundle = NSBundle.mainBundle();
    String pathToFile = mainBundle.pathForResourceOfType(fileId, "dat");
    File file = new File(pathToFile);
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(file);
        DataInputStream dis = new DataInputStream(fis);
        //doing something with input stream
    } catch (IOException e) {
        e.printStackTrace();
    }
}

In the course of app development, Auriga engineers conducted additional research related to managing network functionality. They found that Retrofit* works very well in combination with Http.


Objective-C* Features

Auriga engineers discovered that they could use the Objective-C approach to run certain functions in background. In their case, when starting the app they launched the file-reading process. The way in which to do this is exemplified in the code below.

@Override
@Selector("application:didFinishLaunchingWithOptions:")
public boolean applicationDidFinishLaunchingWithOptions(UIApplication application, NSDictionary launchOptions) {

    performSelectorInBackgroundWithObject(new SEL("initQueueDispatcher"), null);

    return true;
}

@Selector("initQueueDispatcher")
@Generated
public void initQueueDispatcher() {
    QueueDispatcher.sharedQueueDispatcher().initQueue();
}

The launch of separate functions in the main thread also is not a problem:

public void heartRate(PatientRealData data) {
   performSelectorOnMainThreadWithObjectWaitUntilDone(new SEL("updatePatientData:"), 
}

@Selector("updatePatientData:")
@Generated
public void updatePatientData(PatientRealData data) {
    mHrLabel.setText(String.valueOf(data.getHeartRate()));
}

The access to resources is identical to that of most iOS APIs. Developers can simply do the following to receive the image "alarm_on.png" from resources and assign it to the button:

UIImage image = UIImage.imageNamed("alarm_on");
mAlarmButton.setImageForState(image, UIControlState.Normal);

While writing in Java, Auriga reports that it is very convenient that the syntax for the iOS API is hardly different from the original Objective-C. For example, the menu based on UITableViewController has been added in the following way:

@com.intel.moe.natj.general.ann.Runtime(ObjCRuntime.class)
@ObjCClassName("PatientsTableVC")
@RegisterOnStartup
public class PatientsTableVC extends UITableViewController {

    static {
        NatJ.register();
    }

    @Generated("NatJ")
    @Owned
    @Selector("alloc")
    public static native PatientsTableVC alloc();

    @Generated("NatJ")
    @Owned
    @Selector("init")
    public native PatientsTableVC init();

    @Generated("NatJ")
    protected PatientsTableVC(Pointer peer) {
        super(peer);
    }

    private ArrayList<PatientInfo> mPatients = new ArrayList<PatientInfo>();

    @Selector("prefersStatusBarHidden")
    @Override
    public boolean prefersStatusBarHidden() {
        return true;
    }

    @Selector("viewDidLoad")
    @Override
    public void viewDidLoad() {
        setTitle("Select patient:");
    }

    @Selector("numberOfSectionsInTableView:")
    @Override
    @NInt
    public long numberOfSectionsInTableView(UITableView tableView) {
        return 1;
    }

    @Selector("tableView:numberOfRowsInSection:")
    @Override
    @NInt
    public long tableViewNumberOfRowsInSection(UITableView tableView, long section) {
        return mPatients.size();
    }

    @Selector("tableView:cellForRowAtIndexPath:")
    @Override
    public UITableViewCell tableViewCellForRowAtIndexPath(UITableView tableView, NSIndexPath indexPath) {

        String reusableId = "patientCell";
        UITableViewCell cell = 
            (UITableViewCell) tableView.dequeueReusableCellWithIdentifierForIndexPath(reusableId, indexPath);
        PatientInfo patient = mPatients.get((int) indexPath.row());
        cell.textLabel().setText(patient.description());

        return cell;
    }

    @Selector("prepareForSegue:sender:")
    @Generated
    public void prepareForSegueSender(UIStoryboardSegue segue, NSObject sender) {
        NSIndexPath indexPath = tableView().indexPathForSelectedRow();
        PatientInfo patient = mPatients.get((int) indexPath.row());
        MainMonitorVC controller = (MainMonitorVC) segue.destinationViewController();
        controller.setPatient(patient);
    }
}

Multi-OS Engine Technology Preview Plugin for Android Studio*

Auriga engineers reported that another key advantage Multi-OS Engine technology preview is the depth of its plugin integration into Android Studio. The tools they needed for development were basically, provided in Android Studio. They also found that it was easy to set up the project for both iOS and Android platforms. Auriga engineers found that all they needed to do was set up the configuration for Android and iOS versions, launch, and switch between them by choosing the one you need now. The Android Studio functionality needed to switch is depicted directly below:

Adding Waveforms

To implement the display of “running” waveforms Auriga engineers used the C code created when working with the OpenGL* API to use that code they wrote the UIWaveFormVC controller in Objective-C with C-code added. This controller renders in OpenGL View relevant points based on input data with pre-set speed and color. A code sample to this effect is directly below:

UIWaveFormVC.h
@interface UIWaveFormVC : GLKViewController
@property (nonatomic, strong) DPSampleQueue * inputQueue;

- (void)setDataQueue:(DPSampleQueue *) dataQueue;
- (void)setWaveColor:(UIColor *)waveColor;
- (void)setSampleFreq:(float)sampleFreq;

UIWaveFormVC.m
#import "UIWaveFormVC.h"
@interface UIWaveFormVC ()
@property (strong, nonatomic) EAGLContext * context;
@end
- (void)setDataQueue:(DPSampleQueue *) dataQueue {
    self.inputQueue = dataQueue;
}
- (void)viewDidLoad {
    [super viewDidLoad];
self.context = 

						

After that, all the work is done using Java code. To transfer data to UIWaveFormVC they call the method prepareForSequeSender(), which enables reception of the instance of the controller’s class before its display and transfer of data. The source code for this is directly below:

@com.intel.moe.natj.general.ann.Runtime(ObjCRuntime.class)
@ObjCClassName("MainMonitorVC")
@RegisterOnStartup
public class MainMonitorVC extends UIViewController {
    static {
        NatJ.register();
    }

    @Selector("alloc")
    public static native MainMonitorVC alloc();

    @Selector("init")
    public native MainMonitorVC init();

    @Generated("NatJ")
    protected MainMonitorVC(Pointer peer) {
        super(peer);
    }
    private QueueDispatcher mQueueDispatcher = null;

    @Selector("prepareForSegue:sender:")
    @Generated
    public void prepareForSegueSender(UIStoryboardSegue segue, NSObject sender) {
        if (segue.identifier() == null) return;

        UIWaveFormVC controller = (UIWaveFormVC) (segue.destinationViewController());
        controller.setDataQueue(sharedQueueDispatcher().queueWithID(segue.identifier()));
        controller.setSampleFreq(SAMPLE_FREQ);
        controller.setWaveColor(WAVE_GREEN);
   }
                    
    private QueueDispatcher sharedQueueDispatcher() {
        if (mQueueDispatcher == null) {
            mQueueDispatcher = QueueDispatcher.sharedQueueDispatcher();
	  mQueueDispatcher.startDataLoading();
        }
        return mQueueDispatcher;
    }
    
}

Multi-OS Engine Technology Preview: Problems and Downsides

  • Because of the lack of ODBC driver’s support for the database it is problematic to create one unified database for both Android and iOS versions.
  • To make https work you need put in some extra effort. You have to manually add certificates of Android’s build.
  • Sometimes, when using third party libraries developers will need to make changes to ProGuard* configuration. But there is no option to do this for the plugin in Multi-OS Engine technology preview using the standard approach via Gradle. In the end Auriga engineers had to add required flags manually.


Developers can do this in proguard.cfg that is located in /Applications/Intel/multi_os_engine/tools. Take care to add the flags at the end of the document. In their case, Auriga added the following flags in order to use Retrofit:

-keepattributes *Annotation*

-keep class retrofit.** { *; }

-keepclasseswithmembers class * {

@retrofit.http.* <methods>; }

-keepattributes Signature

  • There is no option to edit the storyboard in Android Studio, we had to design an interface in Xcode.

On balance, however, Auriga software engineers are happy to continue using the Multi-OS Engine technology preview for mobile projects. It offers a great opportunity to gain unique experience and expertise and to prove our competence in tackling complex R&D tasks.

For more complete information about compiler optimizations, see our Optimization Notice.