creating_android_modules.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. .. _doc_creating_android_modules:
  2. Creating Android modules
  3. ========================
  4. Introduction
  5. ------------
  6. Making video games portable is all fine and dandy, until mobile
  7. gaming monetization shows up.
  8. This area is complex, usually a mobile game that monetizes needs
  9. special connections to a server for things like:
  10. - Analytics
  11. - In-app purchases
  12. - Receipt validation
  13. - Install tracking
  14. - Ads
  15. - Video ads
  16. - Cross-promotion
  17. - In-game soft & hard currencies
  18. - Promo codes
  19. - A/B testing
  20. - Login
  21. - Cloud saves
  22. - Leaderboards and scores
  23. - User support & feedback
  24. - Posting to Facebook, Twitter, etc.
  25. - Push notifications
  26. On iOS, you can write a C++ module and take advantage of the C++/ObjC
  27. intercommunication.
  28. On Android, interfacing with C++ through JNI (Java Native Interface) isn't as convenient.
  29. Maybe REST?
  30. -----------
  31. Most of these APIs allow communication via REST/JSON APIs. Godot has
  32. great support for HTTP, HTTPS and JSON, so consider this as an option
  33. that works on every platform. Only write the code once and you are set
  34. to go.
  35. Android module
  36. --------------
  37. Writing an Android module is similar to :ref:`doc_custom_modules_in_c++`, but
  38. needs a few more steps.
  39. Make sure you are familiar with building your own :ref:`Android export templates <doc_compiling_for_android>`,
  40. as well as creating :ref:`doc_custom_modules_in_c++`.
  41. config.py
  42. ~~~~~~~~~
  43. In the config.py for the module, some extra functions are provided for
  44. convenience. First, it's often wise to detect if Android is the target platform
  45. being built for and only enable building in this case:
  46. .. code:: python
  47. def can_build(plat):
  48. return plat=="android"
  49. If more than one platform can be built (typical if implementing the
  50. module also for iOS), check manually for Android in the configure
  51. functions for Android (or other platform-specific) code:
  52. .. code:: python
  53. def can_build(plat):
  54. return plat=="android" or plat=="iphone"
  55. def configure(env):
  56. if env['platform'] == 'android':
  57. # android specific code
  58. Java singleton
  59. --------------
  60. An Android module will usually have a singleton class that will load it,
  61. this class inherits from ``Godot.SingletonBase``. Resource identifiers for
  62. any additional resources you have provided for the module will be in the
  63. ``com.godot.game.R`` class, so you'll likely want to import it.
  64. A singleton object template follows:
  65. .. code:: java
  66. package org.godotengine.godot;
  67. import android.app.Activity;
  68. import android.content.Intent;
  69. import com.godot.game.R;
  70. import javax.microedition.khronos.opengles.GL10;
  71. public class MySingleton extends Godot.SingletonBase {
  72. protected Activity appActivity;
  73. protected Context appContext;
  74. private int instanceId = 0;
  75. public int myFunction(String p_str) {
  76. // a function to bind
  77. return 1;
  78. }
  79. public void getInstanceId(int pInstanceId) {
  80. // You will need to call this method from Godot and pass in the get_instance_id().
  81. instanceId = pInstanceId;
  82. }
  83. static public Godot.SingletonBase initialize(Activity p_activity) {
  84. return new MySingleton(p_activity);
  85. }
  86. public MySingleton(Activity p_activity) {
  87. //register class name and functions to bind
  88. registerClass("MySingleton", new String[]
  89. {
  90. "myFunction",
  91. "getInstanceId"
  92. });
  93. this.appActivity = p_activity;
  94. this.appContext = appActivity.getApplicationContext();
  95. // you might want to try initializing your singleton here, but android
  96. // threads are weird and this runs in another thread, so to interact with Godot you usually have to do
  97. activity.runOnUiThread(new Runnable() {
  98. public void run() {
  99. //useful way to get config info from project.godot
  100. String key = GodotLib.getGlobal("plugin/api_key");
  101. //SDK.initializeHere();
  102. }
  103. });
  104. }
  105. // forwarded callbacks you can reimplement, as SDKs often need them
  106. protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {}
  107. protected void onMainRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {}
  108. protected void onMainPause() {}
  109. protected void onMainResume() {}
  110. protected void onMainDestroy() {}
  111. protected void onGLDrawFrame(GL10 gl) {}
  112. protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // singletons will always miss first onGLSurfaceChanged call
  113. }
  114. Calling back to Godot from Java is a little more difficult. The instance
  115. ID of the script must be known first, this is obtained by calling
  116. ``get_instance_ID()`` on the script. This returns an integer that can be
  117. passed to Java.
  118. From Java, use the ``calldeferred`` function to communicate back with Godot.
  119. Java will most likely run in a separate thread, so calls are deferred:
  120. .. code:: java
  121. GodotLib.calldeferred(<instanceid>, "<function>", new Object[]{param1,param2,etc});
  122. Add this singleton to the build of the project by adding the following
  123. to config.py:
  124. .. code:: python
  125. def can_build(plat):
  126. return plat=="android" or plat=="iphone"
  127. def configure(env):
  128. if env['platform'] == 'android':
  129. # will copy this to the java folder
  130. env.android_add_java_dir("Directory that contain MySingleton.java")
  131. AndroidManifest
  132. ---------------
  133. Some SDKs need custom values in AndroidManifest.xml. Permissions can be
  134. edited from the Godot exporter so there is no need to add those, but
  135. maybe other functionalities are needed.
  136. Create the custom chunk of android manifest and put it inside the
  137. module, add it like this:
  138. .. code:: python
  139. def can_build(plat):
  140. return plat=="android" or plat=="iphone"
  141. def configure(env):
  142. if env['platform'] == 'android':
  143. # will copy this to the java folder
  144. env.android_add_java_dir("Directory that contains MySingleton.java")
  145. env.android_add_to_manifest("AndroidManifestChunk.xml")
  146. Resources
  147. ---------
  148. In order to provide additional resources with your module you have to
  149. add something like this:
  150. .. code:: python
  151. def configure(env):
  152. if env['platform'] == 'android':
  153. # [...]
  154. env.android_add_res_dir("Directory that contains resource subdirectories (values, drawable, etc.)")
  155. Now you can refer to those resources by their id (``R.string.my_string``, and the like)
  156. by importing the ``com.godot.game.R`` class in your Java code.
  157. Assets
  158. ------
  159. Similarly, you can add any type of raw asset files to your app's asset directory like this:
  160. .. code:: python
  161. def configure(env):
  162. if env['platform'] == 'android':
  163. # [...]
  164. env.android_add_asset_dir("Directory that contains asset files for your app")
  165. Assets don't have resource ids, but can be read with their file name as streams of bytes with the help
  166. of the Android AssetManager class.
  167. SDK library
  168. -----------
  169. So, finally it's time to add the SDK library. The library can come in
  170. two flavors, a JAR file or an Android project for ant. JAR is the
  171. easiest to integrate, put it in the module directory and add it:
  172. .. code:: python
  173. def can_build(plat):
  174. return plat=="android" or plat=="iphone"
  175. def configure(env):
  176. if env['platform'] == 'android':
  177. # will copy this to the java folder
  178. env.android_add_java_dir("Directory that contains MySingleton.java")
  179. env.android_add_to_manifest("AndroidManifestChunk.xml")
  180. env.android_add_dependency("compile files('something_local.jar')") # if you have a jar, the path is relative to platform/android/java/gradlew, so it will start with ../../../modules/module_name/
  181. env.android_add_maven_repository("maven url") #add a maven url
  182. env.android_add_dependency("compile 'com.google.android.gms:play-services-ads:8'") #get dependency from maven repository
  183. SDK project
  184. -----------
  185. When this is an Android project, things usually get more complex. Copy
  186. the project folder inside the module directory and configure it:
  187. ::
  188. c:\godot\modules\mymodule\sdk-1.2> android -p . -t 15
  189. As of this writing, Godot uses minsdk 18 and target sdk 27. If this ever
  190. changes, it should be reflected in the manifest template:
  191. `AndroidManifest.xml.template <https://github.com/godotengine/godot/blob/3.1/platform/android/AndroidManifest.xml.template>`__
  192. Then, add the module folder to the project:
  193. .. code:: python
  194. def can_build(plat):
  195. return plat=="android" or plat=="iphone"
  196. def configure(env):
  197. if env['platform'] == 'android':
  198. # will copy this to the java folder
  199. env.android_module_file("MySingleton.java")
  200. env.android_module_manifest("AndroidManifestChunk.xml")
  201. env.android_module_source("sdk-1.2","")
  202. Building
  203. --------
  204. As you probably modify the contents of the module, and modify your .java
  205. inside the module, you need the module to be built with the rest of
  206. Godot, so compile android normally.
  207. ::
  208. c:\godot> scons p=android
  209. This will cause your module to be included, the .jar will be copied to
  210. the java folder, the .java will be copied to the sources folder, etc.
  211. Each time you modify the .java, scons must be called.
  212. Afterwards, continue the steps for compiling android :ref:`doc_compiling_for_android`.
  213. Using the module
  214. ~~~~~~~~~~~~~~~~
  215. To use the module from GDScript, first enable the singleton by adding
  216. the following line to project.godot:
  217. ::
  218. [android]
  219. modules="org/godotengine/godot/MySingleton"
  220. More than one singleton module can be enabled by separating with commas:
  221. ::
  222. [android]
  223. modules="org/godotengine/godot/MySingleton,org/godotengine/godot/MyOtherSingleton"
  224. Then request the singleton Java object from Globals like this:
  225. ::
  226. # in any file
  227. var singleton = null
  228. func _init():
  229. singleton = Globals.get_singleton("MySingleton")
  230. print(singleton.myFunction("Hello"))
  231. Troubleshooting
  232. ---------------
  233. Godot crashes upon load
  234. ~~~~~~~~~~~~~~~~~~~~~~~
  235. Check ``adb logcat`` for possible problems, then:
  236. - Make sure libgodot_android.so is in the ``libs/armeabi`` folder
  237. - Check that the methods used in the Java singleton only use simple
  238. Java datatypes, more complex ones are not supported.
  239. Future
  240. ------
  241. Godot has an experimental Java API Wrapper that allows to use the
  242. entire Java API from GDScript.
  243. It's simple to use and it's used like this:
  244. ::
  245. class = JavaClassWrapper.wrap(<javaclass as text>)
  246. This is most likely not functional yet, if you want to test it and help
  247. us make it work, contact us through the `developer mailing
  248. list <https://groups.google.com/forum/#!forum/godot-engine>`__.