Khaled Garbaya

Engineering Leader, Software Developer & Educator

Creating Duell Lib

In this multipart article I will show you how to create duell library with different backends. The example library will show a platform native popup with “hello world” message, in html5 a browser popup, UIAlertView in IOS and PopupWindow in Android.

Structure of a duell lib

A duell library can be full haxe code or a mix of haxe code and native code which will be the one we create today. The structure of duell library can be like so. If you excute duell create libraryProject you will get a template of a duell library with the following structure.

1├── backends(1) 2│ ├── sample_android 3│ │ ├── duell_library.xml 4│ │ ├── java 5│ │ │ └── com 6│ │ │ └── test 7│ │ │ └── ExternalInterface.java 8│ │ └── sample 9│ │ └── ExternSample.hx 10│ ├── sample_html5 11│ │ ├── duell_library.xml 12│ │ └── sample 13│ │ ├── ExternSample.hx 14│ │ └── ExternShared.hx 15│ ├── sample_ios 16│ │ ├── duell_library.xml 17│ │ ├── project 18│ │ │ ├── Build.xml 19│ │ │ └── src 20│ │ │ └── ExternalInterface.mm 21│ │ └── sample 22│ │ └── ExternSample.hx 23│ └── sample_shared 24│ ├── duell_library.xml 25│ └── sample 26│ └── ExternShared.hx 27├── duell_library.xml(2) 28├── sample 29│ ├── Common.hx 30│ ├── ExternSample.hx(3) 31│ └── ExternShared.hx 32└── schema.xsd 33

let's go through some stuff here.

1. backends folder

this folder will contain all the library's backends like html5, android, ios and even you can share a backend across platform if you want. It can be named whatever you want and it is not even required because everything is configurable in the duell_library.xml, it is a matter of organization. The big benefit of the backends is the clear seperation between each platform implementation this is beneficial team wise so you can have one developer with javascript expertise to focus on the html5 side and another one at the same time with IOS expertise coding the ios backend they just need to respect the API defined in the Externs.

2. duell_library.xml

Any duell library is recognized by its duell_library.xml, this is how the duell tool will know it and parse its configuration. Every backend have duell_library.xml also so you can have some extra configuration specific to a platform.

3. Externs

The idea behind the externs is to have a clean way to define the common API between the backends to respect and for developer to know what this duell library will do without caring about backends implementations.

Coding

Before we start

In this article I will assume that you already installed duell tool if not make sure to check my previous articles and you ran these commands.

1$ haxelib install duell 2$ haxelib run duell self_setup 3$ duell setup mac 4$ duell setup android 5

You may noticed that there is no duell setup html5, because we don't need one.

Folder structure

I will start with template provided by the duell tool and rename/remove some stuff so we'll end up with the following.

1├── backends 2│ ├── alert_android 3│ │ ├── com 4│ │ │ └── khaled 5│ │ │ └── alert 6│ │ │ └── NativeAlert.hx 7│ │ ├── duell_library.xml 8│ │ └── java 9│ │ └── com 10│ │ └── khaled 11│ │ └── alertnative 12│ │ └── ExternalInterface.java 13│ ├── alert_html5 14│ │ ├── com 15│ │ │ └── khaled 16│ │ │ └── nativealert 17│ │ │ └── NativeAlert.hx 18│ │ └── duell_library.xml 19│ └── alert_ios 20│ ├── com 21│ │ └── khaled 22│ │ └── alert 23│ │ └── NativeAlert.hx 24│ ├── duell_library.xml 25│ └── project 26│ ├── Build.xml 27│ └── src 28│ └── ExternalInterface.mm 29├── com 30│ └── khaled 31│ └── alert 32│ └── NativeAlert.hx(1) 33├── duell_library.xml 34└── schema.xsd 35

You don't have to create this manually, just clone the the sample library from here inside of that you will find the folder called alert that contain our library. Let's define our API first and to do that we need to create an extern class, number one in the tree. The class contains one static method called alert that accept a string as message.

1package com.khaled.alert; 2 3/** 4 The logic of this class is distributed through the different backends. 5**/ 6extern class NativeAlert 7{ 8 /** 9 Does "alert" different in each platform. 10 **/ 11 public static function alert(message: String = ""): Void; 12} 13

Now that we defined our API let's implement it in the native backends.

HTML5 Backend

I will start first with the easiest one, the html5 backend, since it will be only haxe code.Navigate to backends/alert_html5/ directory and change the com.khaled.alert.NativeAlert class like so.

1package com.khaled.alert; 2import js.Browser; 3class NativeAlert 4{ 5 /** 6 Native Alert in html5 7 **/ 8 public static function alert(message: String = ""): Void 9 { 10 // alert(message) in javascript 11 Browser.alert(message); 12 } 13} 14

IOS Backend

Thanks to the awesome hxcpp backend for haxe we can communicate with Objective C, this will require some configuration and a little bit more code. First let's add some configuration specific to the ios backend, remember when I mentioned that each backend have duell_library.xml, for this case the configuration will be simple we just need to specify the ndll name and the path to its Build.xml configuration. And Yes Duell tool can build ndlls at runtime. backends/alert_ios/duell_library.xml should look like so.

1<?xml version="1.0" encoding="utf-8"?> 2<library xmlns="duell"> 3 <!-- Special configuration for the iOS backend goes here. --> 4 5 <ndll name="alert_ios" build-file-path="project/Build.xml" bin-path="ndll" /> 6 7</library> 8

This bring us to the Build.xml file and if you are used to hxcpp this should be straight forward for you.

1<xml> 2 3 <include name="${HXCPP}/build-tool/BuildCommon.xml"/> 4 5 <files id="src"> 6 7 <include name="${haxelib:duell_duellbuildios}/native/native.xml" /> 8 9 <!-- Our external interface that will contain the native code for the alert popup --> 10 <file name="src/ExternalInterface.mm"/> 11 12 </files> 13 14 <target id="NDLL" output="${LIBPREFIX}alert_ios${DBG}${LIBEXTRA}" tool="linker" toolid="${STD_MODULE_LINK}"> 15 16 <outdir name="../ndll/${BINDIR}"/> 17 <files id="src"/> 18 19 </target> 20 21 <target id="default"> 22 23 <target id="NDLL"/> 24 25 </target> 26 27</xml> 28

now the haxe side of the native extension which is backends/alert_ios/com/khaled/alert/NativeAlert.hx

1package com.khaled.alert; 2import cpp.Lib; 3class NativeAlert 4{ 5 /** 6 Native Alert in ios 7 **/ 8 /// link to function in the native side 9 public static alertNative = Lib.load("alert_ios", "alert_ios_alert_native", 1); 10 public static function alert(message: String = ""): Void 11 { 12 /// call the native function 13 alertNative(message); 14 } 15} 16

Native side is a mix of cpp code and objective C which should be easy to understand if you have done some native extension before. The backends/alert_ios/project/src/ExternalInterface.mm should look like so

1#ifndef STATIC_LINK 2#define IMPLEMENT_API 3#endif 4 5#include <hx/CFFI.h> 6#include <Foundation/Foundation.h> 7 8 9static value alert_ios_alert_native(value hxString) 10{ 11 /// convert value to NSString 12 NSString *messageString = [NSString stringWithCString:val_get_string(hxString) encoding:NSUTF8StringEncoding]; 13 14 // do alert native using UIAlertView 15 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Native ios Alert" 16 message:messageString 17 delegate:nil 18 cancelButtonTitle:@"OK" 19 otherButtonTitles:nil]; 20 [alert show]; 21 [alert release]; 22 23 return alloc_null(); 24} 25 26DEFINE_PRIM(alert_ios_alert_native, 1); 27 28 29extern "C" int alert_ios_register_prims() { return 0; } 30

Android Backend

First we need to tell the tool where is the java source which is done in the duell_library.xml

1<?xml version="1.0" encoding="utf-8"?> 2<library xmlns="duell"> 3 <!-- Special configuration for the Android backend goes here. --> 4 5 <platform-config> 6 <android> 7 <java-source name="ALERT_JAVA" path="java" /> 8 </android> 9 </platform-config> 10</library> 11

if you noticed there is a folder called java that contains our java code. so if you have let say a java class like com.khaled.nativealert.NativeAlert it should be in java/com/khaled/nativealert directory and should look like so

1package com.khaled.nativealert; 2/// duell activity is created by the duell build android plugin 3import org.haxe.duell.DuellActivity; 4 5public class ExternalInterface 6{ 7 public static void alert(String messageString) 8 { 9 AlertDialog alertDialog = new AlertDialog.Builder(DuellActivity.getInstance().this).create(); 10 alertDialog.setTitle("Android Alert"); 11 alertDialog.setMessage(messageString); 12 alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", 13 new DialogInterface.OnClickListener() { 14 public void onClick(DialogInterface dialog, int which) { 15 dialog.dismiss(); 16 } 17 }); 18 alertDialog.show(); 19 } 20} 21

You may noticed the usage of DuellActivity in the code which is already provided by the build plugin, in ios also you can have access to the DUELLAppDelegate which I will cover in other articles. Now haxe code in backends/alert_android/com/khaled/NativeAlert.hx

1package com.khaled.alert; 2import hxjni.JNI; 3class NativeAlert 4{ 5 /** 6 Native Alert in android 7 **/ 8 private static var alertNative = JNI.createStaticMethod("com/khaled/alertnative/ExternalInterface", 9 "alert", "(Ljava/lang/String;)V"); 10 11 public static function alert(message: String = ""): Void 12 { 13 alertNative(message); 14 } 15} 16

Connecting everything together

Now we need to tell the tool which backend to pick and when which can be done in the top duell_library.xml config file

1<?xml version="1.0" encoding="utf-8"?> 2<library xmlns="duell"> 3 <!-- Setting up independent backends. For further native configuration check available libraries. --> 4 <include path="backends/alert_ios/duell_library.xml" if="ios" /> 5 <include path="backends/alert_android/duell_library.xml" if="android" /> 6 <include path="backends/alert_html5/duell_library.xml" if="html5" /> 7 8</library> 9

As you can see here we are telling the duell tool what to pick as a backend for each platform. In the next article I will show how to add the library to the lib_list and how to use in a duell project, until then happy hxCoding.

Cheers, Khaled

Next one in your inbox

no spam only content