Android


13
Nov 13

OpenFL multidensity screens

The multiscreen assets management could be a pain, if not well handled.

Here is some of my guidelines, for creating an universal app who will work on any OS / device / platform, and who will look great.

We gonna focus on Android & iOs, but all those tips are universal and will work on any other platform.

A bit of background:

For more background on dpi / ppi / screen buckets / density you should read :

- That article:
It’s android related, but it’s quite universal and teach you the essentials things you need to know.

- And this one:
The article is not updated for xxhdpi & ldpi, but gives you basis knowledge on how to scale yours assets for each density.

teehanlax_density_conversion

Assets management:

For iOS it’s quite easy you have only two assets size to handle ( retina and non-retina )

For Android, if you target a truly universal app you need 5 assets sizes:
- xxhdpi ( @3.0x )
- xhdpi ( @2.0x )
- hdpi ( @1.5x )
- mdpi ( @1.0x )
- ldpi ( @0.75x )
You’ve probably notice than the mdpi & xhdpi are the same density than the iOS retina / non-retina display so we gonna use the same assets for both os.

For iOS:

Like i’ve said early, it’s quite easy all you have to do is to know if your device is retina or not.
To do so, you can use the “dpiScale” property on the Stage class ( if dpiScale == 2 then it’s retina ).

For Android:

All you need to know is which screenbucket you device uses.
There is no NME / OpenFL method to do so, i the use “getScreen_bucket” method of my HypSystem native extension.¬†It return a string ( xhdpi , hdpi… )

Ok and now ?

Now than you know which screen bucket you must use, the easier way to do is to extends the “openfl.Assets” class.
By example a method to retrieve a bitmapdata:

1
2
3
public function getBitmapData( sName : String , useCache:Bool = true):BitmapData{
return Assets.getBitmapData( PATH + sName , useCache );
}

22
Oct 13

HypVideo

HypVideo is a new native extensions for OpenFL which allow to do video playback on Android & iOS.
For now it allow only to play remote video.

Setup:

HypMedias is on HaxeLib, you can install it by using:

1
haxelib install HypMedias

The project is on github too : https://github.com/hyperfiction/HypMedias

HypMedias use a dependency called “inthebox-macros”, you must install it too:

1
haxelib install inthebox-macros

Android:

On iOS there is nothing to do, but on android you need to add the following activity to your AndroidManifest:

1
2
3
4
5
6
7
<!-- HypMedias -->
<activity
   android:name="fr.hyperfiction.hypmedias.HypVideoActivity"
   android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
   android:label="HypMedias"
   android:screenOrientation="landscape"
/>

Usage:

This is really easy to use :

1
2
3
4
5
6
7
8
9
10
11
12
import fr.hyperfiction.hypmedias.HypVideo;
import fr.hyperfiction.hypmedias.HypVideo.HypVideoEvent;

var v = HypVideo.getInstance( );
v.addEventListener( HypVideoEvent.PLAYBACK_COMPLETE , _onHypVideo_event );
v.addEventListener( HypVideoEvent.PLAYBACK_ERROR , _onHypVideo_event );
v.addEventListener( HypVideoEvent.PLAYBACK_INFO , _onHypVideo_event );
v.addEventListener( HypVideoEvent.PLAYBACK_PAUSE , _onHypVideo_event );
v.addEventListener( HypVideoEvent.PLAYBACK_PLAY , _onHypVideo_event );
v.addEventListener( HypVideoEvent.PLAYBACK_SEEK , _onHypVideo_event );
v.addEventListener( HypVideoEvent.PLAYBACK_STOP , _onHypVideo_event );
v.playRemote("VIDEOURL");

5
Apr 13

HypFacebook : Facebook native extension for Haxe NME

Haxe NME goes social.

You can by now use Facebook in your Haxe NME project ( for iOS & Android targets only ).

Grab it at : https://github.com/shoebox/HypFacebook

The twitter extension ( for iOS / Android / CPP ) will be soon available too.


20
Jan 13

NativeMirror : Easier way to make JNI/CPP calls from haxe

It’s still useful to know how to make native calls from haxe manually ( for debugging by example ) but there is a quicker and easier way.
It’s stricly type, flexible and simple.
It use a simple macro you can find here : here.

All you have to do is to add it on build of yours haxe class.

1
2
3
package org.shoebox.test;
@:build(org.shoebox.utils.JNIMirror.build( )) class Test{
}

Then all you need to do is to create mirrors for the native methods.
 

Mirrors for JNI Methods

Basic example:

In the following case the JNI class name and method name are not defined.
So the macro use the same classpath classname and function name than on the haxe side.

1
2
@JNI
static public function test( s : String , i : Int ) : String {}
If the haxe method name or package is not the same on the java side:

You can customize both by adding argments to the JNI meta:

1
2
@JNI("org.shoebox.Test","TestFunc")
static public function test( s : String , i : Int ) : String {}
For non native types:

It works too for non-native type if the class exists on both side ( with the same package and class name ).
By example we are trying to get the instance of the java class Test inside haxe, the method is defined this way:

1
2
3
@JNI
static public function getInstance( ):Test{
}

 

For CPP Methods

It works the same way, but the first meta argument ( library_name ) must be always defined ( for now ).
The second meta argument ( method_name ) is optional.

1
2
@CPP("library_name","method_name")
public function test_cpp( instance : Dynamic , sTest : String , i : Int , b : Bool ) : Void {}

Hope it helps.


6
Jan 13

NME Native Extension Part 1 – Android : Calling Java methods from Haxe

The JNI class (nme.JNI) allow native haxe code to call Java methods.

For static method the function call is :

1
nme.JNI.createStaticMethod( package_name , "method_name" , signature )

for non-static method it’s :

1
nme.JNI.createMemberMethod( package_name , "method_name" , signature )

Package name:

The package is the full class package and class name separated by slash ( example: “org.shoebox.Test” is “org/shoebox/Test” )

The signature :

The signature of the method is a string:
( mapped arguments type ) return_type

First thing to know is than the arguments type must be mapped for Java.

For the basics types just follow the following table:

For the non basic types ( by example a class instance ) the mapping is:

Lpackage/of/the/ClassName;

Some examples:

On the java side :

1
2
3
4
5
static public DemoJNI getInstance( ){}

static public boolean test_ret_bool( ){}

public boolean test_method_nonstatic( i : Int , b : boolean ){}

 

On the haxe side for the statics methods :

1
2
3
4
var f1 = nme.JNI.createStaticMethod( "org/shoebox/DemoJNI" , "getInstance" , "()Lorg/shoebox/DemoJNI;" );
var instance = f1( );
var f2 = nme.JNI.createStaticMethod "org/shoebox/DemoJNI" , "test_ret_boo" , "()Z" );
var b = f2( );

 

For member methods calls you must pass as argument the JNI class instance ( by example the result of the getInstance( ) method )

1
2
var f3 = nme.JNI.createMemberMethod "org/shoebox/DemoJNI" , "test_method_nonstatic" , "(IZ)Z" );
f3( instance , 10 , false );

Quite easy isn’t it ? When you have understand the java mapping it’s quite easy to call any java method from Haxe.