iOS help: pass a callback function from haxe to cpp

What is the correct way to pass a callback function from HX code to CPP in an iOS extension?

I tried this:

Haxe side:

public static function Init() {
  var initF = cpp.Lib.load("myextension", "myextension_init", 1);
  initF(cpp.Callable.fromStaticFunction(MyCallback));
}

private static var _callback: Null<String->String->Void> = null;

public static function dispatchEvent(event: String, message: String): Void  {
  trace("Callback received: "+event+": "+message);
  if(_callback != null) _callback(event, message);
}

private static function MyCallback(event: cpp.ConstCharStar, data: cpp.ConstCharStar): Void {
  trace("Callback: ('"+event+"‘), (’"+data+"')");
  MainLoop.runInMainThread(() -> dispatchEvent((event: String), (data: String)));
}

CPP side:

using namespace myextension;

static void myextension_init (value callback) {
  std::cout 
    << "INIT callback type: " 
    << val_type(callback) 
    << ", function: " 
    << val_is_function(callback) 
    << "\n";
}
DEFINE_PRIM (myextension_init, 1);

When calling Init(), I get the following output from myextension_init:

INIT callback type: 258, function: 0

I tried to find what type is 258, but couldn’t. The types enum in CFFI just doesn’t have this number…

I am still researching on iOS extensions for lime (as I don’t have macbook/xcode) but I think in an iOS extension, you should use CFFI Prime or handle the value as a closure

Read this : CFFI / CFFI Prime : everything I know · Issue #1 · snowkit/hxcpp-guide · GitHub

Also Instead of cpp.Lib.load, use cpp.Prime.load

Thanks! I came across the same link when googling, but the article doesn’t seem to explain how to pass a function from Haxe to Cpp…

I mean, calling CPP functions from Haxe code works fine for me using cpp.Lib.load, with passing and returning parameters, but not if I’m trying to pass a callback function from Haxe to CPP to store it in CPP code and call when needed.

OK I managed to make it working by using an inline function as a parameter for callback. This function calls the actual callback function from the extension class, so the working version is below. It has the actual code from the extension, not the example code as above, there is much more code, but I only put the code related to the topic here.

Haxe side:

package extension.appodeal;


#if ios
import haxe.MainLoop;
import lime.system.CFFI;
#end

class Appodeal {

  public static function Init(gameID: String, adTypes: Array <AdType>, testing: Bool = false): Void {
    var types: Int = 0;
    #if ios
    initF = cpp.Lib.load("appodeal", "appodeal_init", 4);
    initF(gameID, types, testing, (e: String, d: String) -> Appodeal.OnAppodealStatus(e, d));
    inited = true;
    #end
  }

  public static function OnAppodealStatus(event: String, data: String): Void {
    @:keep
    MainLoop.runInMainThread(() -> dispatchEvent(event, data));
  }

  private static var _callback: Null<String->String->Void> = null;

  public static function SetCallback(callback: String->String->Void): Void {
    _callback = callback;
  }
  
  public static function dispatchEvent(event: String, message: String): Void  {
    if(_callback != null) _callback(event, message);
  }


}

CPP side:

#ifndef STATIC_LINK
#define IMPLEMENT_API
#endif

#if defined(HX_WINDOWS) || defined(HX_MACOS) || defined(HX_LINUX)
#define NEKO_COMPATIBLE
#endif

#include <hx/CFFI.h>
#include “Utils.h”
#include 

using namespace appodeal;

value * extCallback = NULL;

// TODO: make it extern
static void sendExternalEvent(const char *event, const char *data) {
  if (extCallback != NULL && val_is_function(*extCallback)) {
    val_call2(*extCallback, alloc_string(event), alloc_string(data));
  }
}

static void appodeal_init (value appId, value adTypes, value testing, value callback) {
  if (extCallback == NULL) extCallback = alloc_root();
  if (val_is_function(callback)) {
    *extCallback = callback;
    sendExternalEvent(“Init”, “Test”);
  } else {
    std::cout << “Appodeal CPP Callback is NOT a function!\n”;
  }
  InitAppodeal(val_string(appId), val_int(adTypes), val_bool(testing)); // ObjC code
}
DEFINE_PRIM (appodeal_init, 4);

The extension is still in progress, but you can also check the code here: