Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat
Making RevMob plugin, help with NDK build error - Gideros Forum

Making RevMob plugin, help with NDK build error

amaximovamaximov Member
edited April 2013 in Plugins
Hi, I am following the basic android plugin tutorial on AppcodingEasy and also using the AdMob plugin for reference to make a RevMob plugin. I have followed all steps including automatic building with NDK. However I am stuck when I try to build with NDK. I have copy pasted all ".h" files from Gideros installations directory and set them to build within Android.mk. Attached is a screenshot of the error I get and the zipped up file. Also attached is the zipped up eclipse project. I'd appreciate some help :)

Edit: I do not have great command prompt or file system knowledge but does ".." (Two dots) mean move up a directory?
Capture2.PNG
462 x 807 - 51K
Capture.PNG
1107 x 182 - 27K
zip
zip
Gideros Player.zip
4M

Comments

  • amaximovamaximov Member
    edited April 2013
    Setting up an identical NDK builder configuration with the ExamplePlugin project form appcodingeasy gives the same error.
  • Looks like it was an error in the path of the source file in Android.mk. Not sure how the example on appcodingeasy worked but I just had to rearrange my files a bit. I succesfully built armv7 and armv6 .so files and now I will start working more on actual development :)

    Likes: ar2rsawseen

    +1 -1 (+1 / -0 ) Share on Facebook
  • amaximovamaximov Member
    edited April 2013
    Hey @ar2rsawseen So I am working on banner ads right now and I want the ad remove itself when Gideros "stops". So I have a question, when are onStop, and onDestroy events called on the plugin class? I have a method to explicitly remove the banner(an android view) but I would like it to also get removed when I click the stop button for Gideros player in the IDE. Shouldn't the onStop event be called then? Seems like that method never gets called...

    Edit:With some debugging found that onStop actually gets called when you press the play button, after pressing the stop button. I feel like I should experiment some more before posting questions :)

    Likes: fxone

    +1 -1 (+1 / -0 ) Share on Facebook
  • ar2rsawseenar2rsawseen Maintainer
    @amaximov every post is welcome, even if you find the solution yourself after couple of minutes, because all of that will be indexed by search engines, and others may find solutions even faster :)

    About stop button, you probably mean the button when using Gideros player?

    For such purpose I usually use onPause and onResume events
  • Il just stick with onDestroy as onPause seems to also get called on screen locks and I don't want to do anything then.
  • amaximovamaximov Member
    edited April 2013
    Alright @ar2rsawseen I am getting more understanding of the Gideros plugin system but I have a question regarding events. While reading the Ultimate Guide to Gideros Studio at this location wihtin the book: https://docs.google.com/document/pub?id=149g_P1YlE4_6v_hHbFx3YAaYpdU0HoM70XJSLTE38ww#h.3r88ekovnmfe

    I saw this
    if (totalProgress >= 100) {
                            dispatchEvent("progressComplete", NULL, <a href="/profile/Progress%20Complete">@Progress Complete</a>);
                        }
    It looks like in the example the plugin works through Gideros -> C plugin -> C++ class. However since most ad sdk's have events such as onError and onAdRemove, is it possible to have those JAVA listeners somehow access the C++ class/plugin and tell IT to call an event? I already obviously know how to make the C plugin/class call Java methods but how about the other way around?

    Sorry if that is a very obvious question. I'm still a high school student and do not have all that much experience :)
  • amaximovamaximov Member
    edited April 2013
    Im looking at your notification plugin and I also have some questions. What is the purpose of having 2 .cpp files? Are those just different libs for notification and notification manager? Also in your NotificationClass file I seee
    public void onReceive(Context context, Intent intent) {
    		Bundle bundle = intent.getExtras();
    		int id = bundle.getInt("id");
    		JSONObject object = GNPersistent.get(context, "NotificationData", id+"");
    		if(object != null)
    		{
    			GNotification mBuilder = new GNotification();
    			mBuilder.id = id;
    			mBuilder.isScheduled = true;
    			try {
    				mBuilder.title = object.getString("title");
    				mBuilder.message = object.getString("message");
    				mBuilder.number = object.getInt("number");
    				mBuilder.sound = object.getString("sound");
    				mBuilder.soundPrefix = object.getString("soundPrefix");
    				mBuilder.mainClass = object.getString("mainClass");
    				mBuilder.icon = object.getInt("icon");
    				dispatch(context, mBuilder, false);
    			} catch (JSONException e) {}
    		}
     
    	}
    I am wondering if that piece "dispatch(context, mBuilder, false);" is what sends the event to be processed back by Lua code?

    Edit: On second thought I see dispatch as being a separate method that does "something else" I am very very new to native development so it would be a great help if you could help me communicate from JAVA and back to Lua via events. As I said in my last post, I saw hope you can dispatch events via a proxy through the C++ class but I have no clue how to do that from a JAVA class from a "listener" method that can be called anytime depending on various uncontrollable factors such as internet speed.
  • ar2rsawseenar2rsawseen Maintainer
    edited April 2013
    @amaximov thats quite good that you study those :)

    Yes dispatch there is something different in Notification plugin, the methods that you are looking for are prefixed as native.

    The multiple cpp files are to separate lua binding and Java/JNI stuff, so lua binding can be reused with other platforms, like IOS :)

    So lets take a look at GoogleBilling plugin and start from the start.

    in ggooglebilling.cpp, when creating GGoogleBilling instance, we are calling static method init of Java class and what we pass there is the pointer to our current GGoogleBilling instance like this:
    env->CallStaticVoidMethod(cls_, env->GetStaticMethodID(cls_, "init", "(J)V"), (jlong)this);
    On java part we receive it and store in sData like this:
    static public void init(long data)
    {
    	sData = data;
    	sInstance = new GGoogleBilling(sActivity.get());
    }
    Then if you notice, in GGoogleBilling.java there are methods defined like
    private static native void onBillingSupported(int responseCode, String type, long data);
    Native means this method will be called on the C part.

    So later in java code, when the specific event is received, this native method is called.
     <a href="/profile/Override">@Override</a>
    public void onBillingSupported(ResponseCode responseCode, String type)
    {
        if (sData != 0)
            GGoogleBilling.onBillingSupported(responseCode.ordinal(), type, sData);
    }
    And we are also passing sData, which was a pointer of our C class.

    Then on the C part, we receive this call like this:
    void Java_com_giderosmobile_android_plugins_googlebilling_GGoogleBilling_onBillingSupported(JNIEnv *env, jclass clz, jint responseCode, jstring type, jlong data)
    {
    	((GGoogleBilling*)data)->onBillingSupported(responseCode, type);
    }
    As you see, we are casting our pointer back to class instance and calling specific instance method.

    Inside this method we enqueue the event to Gideros:
    void onBillingSupported(jint responseCode, jstring jproductType)
    {
    	JNIEnv *env = g_getJNIEnv();
     
    	const char *productType = jproductType ? env->GetStringUTFChars(jproductType, NULL) : NULL;
     
    	ggooglebilling_CheckBillingSupportedCompleteEvent *event = (ggooglebilling_CheckBillingSupportedCompleteEvent*)gevent_CreateEventStruct1(
    		sizeof(ggooglebilling_CheckBillingSupportedCompleteEvent),
    		offsetof(ggooglebilling_CheckBillingSupportedCompleteEvent, productType), productType);
     
    	event->responseCode = responseCode;
     
    	if (jproductType)
    		env->ReleaseStringUTFChars(jproductType, productType);
     
    	gevent_EnqueueEvent(gid_, callback_s, GGOOGLEBILLING_CHECK_BILLING_SUPPORTED_COMPLETE_EVENT, event, 1, this);
    }
    We are using the event structure we defined in ggooglebilling.h which we use to pass event data. As you see, passing strings are a little bit more complicated and we use Gideros internal structure to handle it:
    gevent_CreateEventStruct1 for single string
    gevent_CreateEventStruct2 for two strings
    gevent_CreateEventStruct3 for three strings

    After that we simply enqueue event by calling:
    gevent_EnqueueEvent(gid_, callback_s, GGOOGLEBILLING_CHECK_BILLING_SUPPORTED_COMPLETE_EVENT, event, 1, this);
    where gid_ is a unique Gideros internal ID used to deal with instances and events. We got it in the construct by calling
    gid_ = g_NextId();
    Second param callback_s is a signature of static method to be called upon dispatch, we then handle it in same class, by calling none static method and using
    callbackList_.dispatchEvent(type, event);
    callbackList_ is an internal Gideros property, so it's just what you need to do :)

    GGOOGLEBILLING_CHECK_BILLING_SUPPORTED_COMPLETE_EVENT is an id of event, thats why we have them enumed in ggooglebilling.h

    event is the event data/structure we created earlier

    Number 1 tells to Gideros event system that free() function should be called on event pointer after dispatching it.

    And the last argument this, is basically an additional data to pass to event callback (similar like it is in Lua Gideros part) so we can cast instance from static callback method.

    Last things to do is to handle that on Lua part, thus inside googlebillingbinder.cpp where all the binding is done, there is a dispatchEvent(int type, void *event) method, which basically creates Event object in lua, adds the provided information from event structure and dispatches it.

    The one question that might remain is how come, if we enqueue event in ggooglebilling.cpp we receive something inside googlebillingbinder.cpp?

    Because inside googlebillingbinder.cpp in constructor of GoogleBilling we called
    ggooglebilling_addCallback(callback_s, this);
    Which basically as we see in ggooglebilling.cpp adds this instance, that we passed to that internal Gideros structure callbackList_ which then dispatched event to all subscribed methods.
    g_id addCallback(gevent_Callback callback, void *udata)
    {
    	return callbackList_.addCallback(callback, udata);
    }

    I know it's a lot to take in, so sure start slowly and you can ask any questions :)

    Likes: fxone

    +1 -1 (+1 / -0 ) Share on Facebook
  • @ar2rsawseen wow what a great tutorial. This information should be preserved instead of drowned on forums, why dont you add a new article on docs? :)

    Likes: fxone

    have fun with our games~
    http://www.nightspade.com
    +1 -1 (+1 / -0 ) Share on Facebook
  • ar2rsawseenar2rsawseen Maintainer
    Oh yes, it is bookmarked and will be added :)
  • Thanks soo much ar2rsawseen. I'm very new to C++ but I think I can manage getting a grip of this eventually. I'll keep working on it!
Sign In or Register to comment.