How to create a C++ class that accept callback function in Javascript?

Hi,

I would like to use this ImagePicker with Cocos2d-JS v3.11.1.

However, the JSB is not working in the newer version.
I try to regenerate the JSB but got error on the ImagePickerDelegate.
I think there are some issue on the ImagePickerDelegate implementation.

I have modified the ImagePicker to return a texture2d and image data string which working with Cocos2d-JS v3.8.1.

The current usage in Javascript is

		var delegator = new cc.ImagePickerDelegate();
		delegator.didFinishPickingWithResult = function(texture2d, imageDataString)
		{
			self.processPic(texture2d, imageDataString);
		};

		var picker = cc.ImagePicker.getInstance();
		picker.pickImage(delegator);

I would like to modify the code without using the delegate.

		var picker = cc.ImagePicker.getInstance();
		picker.didFinishPickingWithResult = function(texture2d, imageDataString)
		{
			self.processPic(texture2d, imageDataString);
		};
		picker.pickImage();

How can i create the C++ function that accept callback like this?

@zhangxm
Can you please give me so guide on this?

Thank you.

I am not familiar with JSB, @pandamicro do you have any suggestion?

@zhangxm

Thank you for your reply.

How about on C++ implementation that accept callback function with 2 variables - a texture2d and a string?

What did you mean? I am not sure if you need std::function.

@zhangxm

Yes, i trying to use std::function after study other class.

I success generated the JSB by adding ImagePicker into the class of tools/tojs/cocos2dx_extension.ini
The ImagePicker success to open gallery on Android but callback is not call.

var picker = cc.ImagePicker.getInstance();
			picker.didFinishPickingWithResult(function(texture, imageData)
			{
cc.log("callback in");
				self.processPic(texture, imageData);
			});
			picker.pickImage();

ImagePicker.h

#ifndef __ImagePicker__
#define __ImagePicker__

#include <string>
#include <functional>
#include "platform/CCPlatformMacros.h"
#include "renderer/CCTexture2D.h"

NS_CC_BEGIN

class Texture2D;

class CC_DLL ImagePicker
{
public:
    ImagePicker();
    static ImagePicker *getInstance();
    
    void pickImage();
    void finishImage(Texture2D *image, std::string imageString);
    void didFinishPickingWithResult(const std::function<void(Texture2D *, std::string)>& callback);
private :
    std::function<void(Texture2D *, std::string)> _ImagePickerCallback;
};

NS_CC_END

ImagePicker.cpp

#include "ImagePicker.h"
#include "ImagePickerImpl.h"

NS_CC_BEGIN

static ImagePicker* sharedPicker = nullptr;

ImagePicker::ImagePicker()
:_ImagePickerCallback(nullptr)
{
}

ImagePicker* ImagePicker::getInstance(){
    if(sharedPicker == nullptr){
        sharedPicker = new ImagePicker();
    }
    return sharedPicker;
}

void ImagePicker::pickImage() {
    ImagePickerImpl::openImage();
}

void ImagePicker::finishImage(Texture2D *image, std::string imageString)
{
    sharedPicker->_ImagePickerCallback(image, imageString);
}

void ImagePicker::didFinishPickingWithResult(const std::function<void(Texture2D *, std::string)>& callback)
{
    _ImagePickerCallback = callback;
}

NS_CC_END

Is there anything wrong i doing?

Thank you.

binding generator can not binding std::function, let’s ask @pandamicro how to do manual binding.

@zhangxm

Thank for your clarification.
This is a big problem as there is no good and updated document about JSB.

Waiting @pandamicro for the manual binding guide.

Hi @Zinitter

Actually std::function can be bound in JSB to a lambda function, can you show me the code in auto bindings for didFinishPickingWithResult ?

@pandamicro

Thank you for your reply.

jsb_cocos2dx_extension.hpp

extern JSClass  *jsb_cocos2d_ImagePicker_class;
extern JSObject *jsb_cocos2d_ImagePicker_prototype;

bool js_cocos2dx_extension_ImagePicker_constructor(JSContext *cx, uint32_t argc, jsval *vp);
void js_cocos2dx_extension_ImagePicker_finalize(JSContext *cx, JSObject *obj);
void js_register_cocos2dx_extension_ImagePicker(JSContext *cx, JS::HandleObject global);
void register_all_cocos2dx_extension(JSContext* cx, JS::HandleObject obj);
bool js_cocos2dx_extension_ImagePicker_pickImage(JSContext *cx, uint32_t argc, jsval *vp);
bool js_cocos2dx_extension_ImagePicker_finishImage(JSContext *cx, uint32_t argc, jsval *vp);
bool js_cocos2dx_extension_ImagePicker_didFinishPickingWithResult(JSContext *cx, uint32_t argc, jsval *vp);
bool js_cocos2dx_extension_ImagePicker_getInstance(JSContext *cx, uint32_t argc, jsval *vp);
bool js_cocos2dx_extension_ImagePicker_ImagePicker(JSContext *cx, uint32_t argc, jsval *vp);

jsb_cocos2dx_extension.cpp

JSClass  *jsb_cocos2d_ImagePicker_class;
JSObject *jsb_cocos2d_ImagePicker_prototype;

bool js_cocos2dx_extension_ImagePicker_pickImage(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    cocos2d::ImagePicker* cobj = (cocos2d::ImagePicker *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_cocos2dx_extension_ImagePicker_pickImage : Invalid Native Object");
    if (argc == 0) {
        cobj->pickImage();
        args.rval().setUndefined();
        return true;
    }

    JS_ReportError(cx, "js_cocos2dx_extension_ImagePicker_pickImage : wrong number of arguments: %d, was expecting %d", argc, 0);
    return false;
}
bool js_cocos2dx_extension_ImagePicker_finishImage(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    bool ok = true;
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    cocos2d::ImagePicker* cobj = (cocos2d::ImagePicker *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_cocos2dx_extension_ImagePicker_finishImage : Invalid Native Object");
    if (argc == 2) {
        cocos2d::Texture2D* arg0 = nullptr;
        std::string arg1;
        do {
            if (args.get(0).isNull()) { arg0 = nullptr; break; }
            if (!args.get(0).isObject()) { ok = false; break; }
            js_proxy_t *jsProxy;
            JS::RootedObject tmpObj(cx, args.get(0).toObjectOrNull());
            jsProxy = jsb_get_js_proxy(tmpObj);
            arg0 = (cocos2d::Texture2D*)(jsProxy ? jsProxy->ptr : NULL);
            JSB_PRECONDITION2( arg0, cx, false, "Invalid Native Object");
        } while (0);
        ok &= jsval_to_std_string(cx, args.get(1), &arg1);
        JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_extension_ImagePicker_finishImage : Error processing arguments");
        cobj->finishImage(arg0, arg1);
        args.rval().setUndefined();
        return true;
    }

    JS_ReportError(cx, "js_cocos2dx_extension_ImagePicker_finishImage : wrong number of arguments: %d, was expecting %d", argc, 2);
    return false;
}
bool js_cocos2dx_extension_ImagePicker_didFinishPickingWithResult(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    bool ok = true;
    JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
    js_proxy_t *proxy = jsb_get_js_proxy(obj);
    cocos2d::ImagePicker* cobj = (cocos2d::ImagePicker *)(proxy ? proxy->ptr : NULL);
    JSB_PRECONDITION2( cobj, cx, false, "js_cocos2dx_extension_ImagePicker_didFinishPickingWithResult : Invalid Native Object");
    if (argc == 1) {
        std::function<void (cocos2d::Texture2D *, std::basic_string<char>)> arg0;
        do {
		    if(JS_TypeOfValue(cx, args.get(0)) == JSTYPE_FUNCTION)
		    {
		        JS::RootedObject jstarget(cx, args.thisv().toObjectOrNull());
		        std::shared_ptr<JSFunctionWrapper> func(new JSFunctionWrapper(cx, jstarget, args.get(0), args.thisv()));
		        auto lambda = [=](cocos2d::Texture2D* larg0, std::basic_string<char> larg1) -> void {
		            JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
		            jsval largv[2];
		            if (larg0) {
		            largv[0] = OBJECT_TO_JSVAL(js_get_or_create_jsobject<cocos2d::Texture2D>(cx, (cocos2d::Texture2D*)larg0));
		        } else {
		            largv[0] = JSVAL_NULL;
		        };
		            largv[1] = std_string_to_jsval(cx, larg1);
		            JS::RootedValue rval(cx);
		            bool succeed = func->invoke(2, &largv[0], &rval);
		            if (!succeed && JS_IsExceptionPending(cx)) {
		                JS_ReportPendingException(cx);
		            }
		        };
		        arg0 = lambda;
		    }
		    else
		    {
		        arg0 = nullptr;
		    }
		} while(0)
		;
        JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_extension_ImagePicker_didFinishPickingWithResult : Error processing arguments");
        cobj->didFinishPickingWithResult(arg0);
        args.rval().setUndefined();
        return true;
    }

    JS_ReportError(cx, "js_cocos2dx_extension_ImagePicker_didFinishPickingWithResult : wrong number of arguments: %d, was expecting %d", argc, 1);
    return false;
}
bool js_cocos2dx_extension_ImagePicker_getInstance(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    if (argc == 0) {

        cocos2d::ImagePicker* ret = cocos2d::ImagePicker::getInstance();
        jsval jsret = JSVAL_NULL;
        if (ret) {
        jsret = OBJECT_TO_JSVAL(js_get_or_create_jsobject<cocos2d::ImagePicker>(cx, (cocos2d::ImagePicker*)ret));
    } else {
        jsret = JSVAL_NULL;
    };
        args.rval().set(jsret);
        return true;
    }
    JS_ReportError(cx, "js_cocos2dx_extension_ImagePicker_getInstance : wrong number of arguments");
    return false;
}

bool js_cocos2dx_extension_ImagePicker_constructor(JSContext *cx, uint32_t argc, jsval *vp)
{
    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
    bool ok = true;
    cocos2d::ImagePicker* cobj = new (std::nothrow) cocos2d::ImagePicker();

    js_type_class_t *typeClass = js_get_type_from_native<cocos2d::ImagePicker>(cobj);

    // link the native object with the javascript object
    JS::RootedObject jsobj(cx, jsb_create_weak_jsobject(cx, cobj, typeClass, "cocos2d::ImagePicker"));
    args.rval().set(OBJECT_TO_JSVAL(jsobj));
    if (JS_HasProperty(cx, jsobj, "_ctor", &ok) && ok)
        ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(jsobj), "_ctor", args);
    return true;
}


void js_cocos2d_ImagePicker_finalize(JSFreeOp *fop, JSObject *obj) {
    CCLOGINFO("jsbindings: finalizing JS object %p (ImagePicker)", obj);
    js_proxy_t* nproxy;
    js_proxy_t* jsproxy;
    JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
    JS::RootedObject jsobj(cx, obj);
    jsproxy = jsb_get_js_proxy(jsobj);
    if (jsproxy) {
        cocos2d::ImagePicker *nobj = static_cast<cocos2d::ImagePicker *>(jsproxy->ptr);
        nproxy = jsb_get_native_proxy(jsproxy->ptr);

        if (nobj) {
            jsb_remove_proxy(nproxy, jsproxy);
            delete nobj;
        }
        else
            jsb_remove_proxy(nullptr, jsproxy);
    }
}
void js_register_cocos2dx_extension_ImagePicker(JSContext *cx, JS::HandleObject global) {
    jsb_cocos2d_ImagePicker_class = (JSClass *)calloc(1, sizeof(JSClass));
    jsb_cocos2d_ImagePicker_class->name = "ImagePicker";
    jsb_cocos2d_ImagePicker_class->addProperty = JS_PropertyStub;
    jsb_cocos2d_ImagePicker_class->delProperty = JS_DeletePropertyStub;
    jsb_cocos2d_ImagePicker_class->getProperty = JS_PropertyStub;
    jsb_cocos2d_ImagePicker_class->setProperty = JS_StrictPropertyStub;
    jsb_cocos2d_ImagePicker_class->enumerate = JS_EnumerateStub;
    jsb_cocos2d_ImagePicker_class->resolve = JS_ResolveStub;
    jsb_cocos2d_ImagePicker_class->convert = JS_ConvertStub;
    jsb_cocos2d_ImagePicker_class->finalize = js_cocos2d_ImagePicker_finalize;
    jsb_cocos2d_ImagePicker_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);

    static JSPropertySpec properties[] = {
        JS_PS_END
    };

    static JSFunctionSpec funcs[] = {
        JS_FN("pickImage", js_cocos2dx_extension_ImagePicker_pickImage, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
        JS_FN("finishImage", js_cocos2dx_extension_ImagePicker_finishImage, 2, JSPROP_PERMANENT | JSPROP_ENUMERATE),
        JS_FN("didFinishPickingWithResult", js_cocos2dx_extension_ImagePicker_didFinishPickingWithResult, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE),
        JS_FS_END
    };

    static JSFunctionSpec st_funcs[] = {
        JS_FN("getInstance", js_cocos2dx_extension_ImagePicker_getInstance, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE),
        JS_FS_END
    };

    jsb_cocos2d_ImagePicker_prototype = JS_InitClass(
        cx, global,
        JS::NullPtr(),
        jsb_cocos2d_ImagePicker_class,
        js_cocos2dx_extension_ImagePicker_constructor, 0, // constructor
        properties,
        funcs,
        NULL, // no static properties
        st_funcs);

    JS::RootedObject proto(cx, jsb_cocos2d_ImagePicker_prototype);
    JS::RootedValue className(cx, std_string_to_jsval(cx, "ImagePicker"));
    JS_SetProperty(cx, proto, "_className", className);
    JS_SetProperty(cx, proto, "__nativeObj", JS::TrueHandleValue);
    JS_SetProperty(cx, proto, "__is_ref", JS::FalseHandleValue);
    // add the proto and JSClass to the type->js info hash table
    jsb_register_class<cocos2d::ImagePicker>(cx, jsb_cocos2d_ImagePicker_class, proto, JS::NullPtr());
}

The bindings seems ok, can you set a break point in the lambda function of js_cocos2dx_extension_ImagePicker_didFinishPickingWithResult, and another break point in ImagePicker::finishImage. Then check out wether they are all invoked during callback

1 Like

@pandamicro

How can i set breakpoint in the code?

Using this std::abort()?

@pandamicro

I’m compile using Android Studio 2.1.2 with
compileSdkVersion 22
buildToolsVersion “22.0.1”

I found that i override onActivityResult on AppActivity for other library.

There is also onActivityResult on org/cocos2dx/lib/Cocos2dxImagePicker.java.

But after i comment out onActivityResult on AppActivity, app crash after finish execute Cocos2dxImagePicker.java function.

public static void openImage() {
Log.d(“myTag”, “Cocos2dxImagePicker openImage”);
if(!initialized) {
initialized = true;
Cocos2dxHelper.addOnActivityResultListener(new Cocos2dxImagePicker());
}

    Intent intent = new Intent();
    intent.setType("image/*");
    intent.setAction(Intent.ACTION_GET_CONTENT);
          
    Cocos2dxHelper.getActivity().startActivityForResult(intent, IMAGE_PICKER_ACTIVITY);
}

@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data)
{
    if (requestCode != IMAGE_PICKER_ACTIVITY)
        return false;
    if (resultCode == Activity.RESULT_OK) {
        Log.d("myTag", "Cocos2dxImagePicker onActivityResult RESULT_OK1");
        Uri imageUri = data.getData();  
        try {
            Log.d("myTag", "Cocos2dxImagePicker onActivityResult RESULT_OK2");
            InputStream is = Cocos2dxHelper.getActivity().getContentResolver().openInputStream(imageUri);
            ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
            int bufferSize = 10240;
            byte[] buffer = new byte[bufferSize];

            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                byteBuffer.write(buffer, 0, len);
            }
            
            is.close();

            String imageBase64 = Base64.encodeBytes(byteBuffer.toByteArray());

            ImagePickerResult(byteBuffer.toByteArray(), imageBase64);
            Log.d("myTag", "Cocos2dxImagePicker onActivityResult RESULT_OK3");
            return true;
        } catch (Exception e) {
            Log.d("myTag", "Cocos2dxImagePicker onActivityResult RESULT_OK3 e:"+e.toString());
            //logger.info("Just a stack trace, nothing to worry about", e);

        }
    }

    ImagePickerResult(null, null);
    return false;
}

App crash after Log.d("myTag", "Cocos2dxImagePicker onActivityResult RESULT_OK3");

07-14 13:49:19.787 17519-17519/com.zinitt.Zinitt D/Cocos2dxActivity: onResume()
07-14 13:49:19.817 17519-17519/com.zinitt.Zinitt D/Cocos2dxActivity: onWindowFocusChanged() hasFocus=true
07-14 13:49:19.837 17519-17553/com.zinitt.Zinitt W/dalvikvm: JNI WARNING: threadid=14 using env from threadid=1 (GetStringUTFChars)
07-14 13:49:19.837 17519-17553/com.zinitt.Zinitt W/dalvikvm:              in Lorg/cocos2dx/lib/Cocos2dxRenderer;.nativeRender:()V (GetStringUTFChars)
07-14 13:49:19.837 17519-17553/com.zinitt.Zinitt I/dalvikvm: "GLThread 838" prio=5 tid=14 NATIVE
07-14 13:49:19.837 17519-17553/com.zinitt.Zinitt I/dalvikvm:   | group="main" sCount=0 dsCount=0 obj=0x4364b3e8 self=0x7839ad40
07-14 13:49:19.837 17519-17553/com.zinitt.Zinitt I/dalvikvm:   | sysTid=17553 nice=0 sched=0/0 cgrp=apps handle=2017474936
07-14 13:49:19.837 17519-17553/com.zinitt.Zinitt I/dalvikvm:   | state=R schedstat=( 7642395183 2294348060 14149 ) utm=645 stm=119 core=2
07-14 13:49:19.847 17519-17519/com.zinitt.Zinitt I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@435eef18 time:9151438
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #00  pc 0000132e  /system/lib/libcorkscrew.so (unwind_backtrace_thread+29)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #01  pc 00063502  /system/lib/libdvm.so (dvmDumpNativeStack(DebugOutputTarget const*, int)+33)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #02  pc 000574e8  /system/lib/libdvm.so (dvmDumpThreadEx(DebugOutputTarget const*, Thread*, bool)+395)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #03  pc 00057556  /system/lib/libdvm.so (dvmDumpThread(Thread*, bool)+25)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #04  pc 0003b65c  /system/lib/libdvm.so
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #05  pc 0003ed62  /system/lib/libdvm.so
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #06  pc 0162837c  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so (_JNIEnv::GetStringUTFChars(_jstring*, unsigned char*)+48)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #07  pc 01875e34  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #08  pc 01876420  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #09  pc 010397bc  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so (std::function<void ()>::operator()() const+60)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #10  pc 01ba3600  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so (cocos2d::Scheduler::update(float)+1532)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #11  pc 01b5f5a8  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so (cocos2d::Director::drawScene()+160)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #12  pc 01b63a4c  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so (cocos2d::DisplayLinkDirector::mainLoop()+136)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #13  pc 009ad37c  /data/app-lib/com.zinitt.Zinitt-1/libcocos2djs.so (Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender+40)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #14  pc 0002034c  /system/lib/libdvm.so (dvmPlatformInvoke+112)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #15  pc 00050fce  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+397)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #16  pc 000297e0  /system/lib/libdvm.so
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #17  pc 00030c6c  /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #18  pc 0002e304  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #19  pc 00063430  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+335)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #20  pc 00063454  /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+19)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #21  pc 00058132  /system/lib/libdvm.so
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #22  pc 0000d248  /system/lib/libc.so (__thread_entry+72)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:   #23  pc 0000d3e0  /system/lib/libc.so (pthread_create+240)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:     at org.cocos2dx.lib.Cocos2dxRenderer.nativeRender(Native Method)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:     at org.cocos2dx.lib.Cocos2dxRenderer.onDrawFrame(Cocos2dxRenderer.java:104)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1523)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt I/dalvikvm:     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt E/dalvikvm: VM aborting
07-14 13:49:19.857 17519-17553/com.zinitt.Zinitt A/libc: Fatal signal 6 (SIGABRT) at 0x0000446f (code=-6), thread 17553 (Thread-838)

Update :
I have test the code in iOS simulator, it working fine.
So i think there is problem on the Android Java reading image or returning result.

@pandamicro @zhangxm

I have solved the problem.

The crash on Android is caused by JNI WARNING: threadid=14 using env from threadid=1 (GetStringUTFChars)

    Director::getInstance()->getScheduler()->performFunctionInCocosThread([image, imageData, env]
    {
         const char *nativeString = env->GetStringUTFChars(string, JNI_FALSE);
    }

So put any env related code outisde performFunctionInCocosThread solve the problem.

However, i have some questions about JSB.

1.When the auto JSB generated, i found that it create jsb_cocos2dx_extension_auto_api.js in auto/api folder.

How can i separate the ImagePicker api and how can i include them?
I would like to let other users manual integrate the code.

2.How can i change cc to jsb as prefix, for example, cc.ImagePicker.getInstance() to jsb.ImagePicker.getInstance()? I found this in the jsb_cocos2dx_extension_auto.cpp. Do I just need to change the cc to jsb after separate the code?

void register_all_cocos2dx_extension(JSContext* cx, JS::HandleObject obj) {
    // Get the ns
    JS::RootedObject ns(cx);
    get_or_create_js_obj(cx, obj, "cc", &ns);

3.The current ImagePicker using static ImagePicker* sharedPicker = nullptr; which have no constructor and all sharing the same instance. There are some implementations usage need to use getInstance, ImagePicker::getInstance()->finishImage(texture, imageString);

I can’t use var picker = new cc.ImagePicker.getInstance() but var picker = cc.ImagePicker.getInstance().
Would without using new and sharing instance caused memory issue? I would follow this style to create other JSB if no problem.

Sorry for long questions as i trying to learn JSB and want to follow good practice.

Thank you.

1 Like

Glad you solved the problem, sorry I haven’t got much time today to follow the thread

They are useless, they just tell you what API was generated, you don’t need them

It’s not recommended to directly modify auto bindings code, you can make a separated ini file to bind your own classes, setup target_namespace to jsb will give you jsb.ImagePicker.

It’s actually irrelevant with JSB. Singletons are well known to be memory leak, because developers will never destroy it. Personally, I think singleton have its own use case, I wouldn’t mind to make ImagePicker singleton, actually device control APIs are often easy to make as singletons. But stay warning when you try to create a singleton, if there is better choice, do not use it. Personal opinion …

1 Like

@pandamicro

Thank you for taking time to answer my questions.

I can see the singleton class is easier to create as i still not familiar with the C++.

But i would like to create the class that can gain benefit from Cocos engine memory handling.
Memory leak is a big issue.

I want to create more plugin that not come with Cocos engine.

  1. Camera to take picture
  2. Backup jsb.sqlite and choose any backup to restore.

Should i follow this ImagePicker class or any base template for reference?

May be it can be used with the future Cocos Plugin Manager.

Thank you.

You are welcome~

All depends on your use cases, to benefit from our Reference counting system, you can inherit cocos2d::Ref class, then use retain / release / autorelease to manage its life cycle.

@pandamicro

You mean use retain / release / autorelease in C++ code?

Yes, if you’d like to use Reference counting system, then control the reference count manually is obligated.

1 Like

Thank you for your guide.

Hi, Zinitter
Could you share your code in “ImagePickerImpl.cpp” file?
Thank you.