Cocos2dx has already created a layer of C++ codes which
- are called by Java/OC when certain app lifecycle events should be coped with in game, e.g. appWillEnterBackground,
- can call methods provided in JavaByteCodes(.class)/ObjcFramework.
In order to do IAP and GameCentre related development for iOS in JS, we'll be using the 2nd feature to call an existing Objc method which contains a param of a "CompletionHandlerType", by "properly associating type systems in C++ & Objc", to be specific, the important problem is just "how to represent an Objc completion handler in C++".
To practice, the only good reference by 2018-12-24 is provided by this CocosCreator manual, which suggests that among the two directions
"#1 JavaScript calls C++ function", and
"#2 C++ calls JavaScript function"
, we should try #1 first.
#1 JavaScript calls C++ function
#1.1 Writes the C++ function to be called
What is NOT mentioned explicitly by the CocosCreator manual for JSB2.0 is that such C++ functions should be "static without any namespace/class", that is, like a Clang built static/shared lib, e.g. a "*.a"/"*.so" file for Unix.
bool foo(se::State& s)
{
...
...
}
SE_BIND_FUNC(foo) // Binding a JS function as an example
#1.2 Specifying the namespace/class for encapsulation
However in real applications it's terrible to not use any namespace/class, therefore the "static functions without any namespace/class" are often wrapped in a so called "bridge file", which calls the underlying namespace/class rich implementations.
// Params of type "char const * const" don't need be freed.
// TODO: Invoke a specified JS global function.
return true;
}
You might wonder how the underlying "SE_DECLARE_FUNC" and "SE_BIND_FUNC" work. When "invitation_send" is first declared in "invitation_bridge.hpp", you actually only declares the function named "invitation_send##Registry(...)", whose param list is shown in detail below.
That said, when the JavaScript codes try to invoke "invitation_send". it actually invokes "invitation_send##Registry(...)" which will convert the long list of params into a single "se:State& s" param for you to handle in that simplified function "invitation_send(se:State& s)" which is only declard and defined in "invitation_bridge.cpp", i.e. unseen by the JavaScript codes. The convertion part is highlighted below.
#1.3 Registering the "C++ registry functions" to the "JavaScript engine _globalObject"
The "C++ registry functions" are not yet recognized by the "JavaScript engine", until we invoke "register_MyGame_Invitation()".
auto cls = se::Class::create("Invitation", ns, nullptr, nullptr);
/*
A call in JavaScript codes "MyGame.Invitation.send" will call "invitation_send##Registry" declared in "invitation_bridge.h", see the screenshot of MACROs above.
This "register_MyGame_Invitation" will finally be called with param "ScriptEngine::getInstance()->_globalObj", but with CocosCreator JSB2.0 you don't directly relate them together, instead you can use "ScriptEngine::getInstance()->addRegisterCallback(register_MyGame_Invitation)" to accomplish the job.