plugins_for_ios.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. .. _doc_plugins_for_ios:
  2. Plugins for iOS
  3. ===============
  4. Godot provides StoreKit, GameCenter, iCloud services and other plugins.
  5. They are using same model of asynchronous calls explained below.
  6. ARKit and Camera access are also provided as plugins.
  7. Latest updates, documentation and source code can be found at `Godot iOS plugins repository <https://github.com/godotengine/godot-ios-plugins>`_
  8. Accessing plugin singletons
  9. ---------------------------
  10. To access plugin functionality, you first need to check that the plugin is
  11. exported and available by calling the `Engine.has_singleton()` function, which
  12. returns a registered singleton.
  13. Here's an example of how to do this in GDScript:
  14. ::
  15. var in_app_store
  16. var game_center
  17. func _ready():
  18. if Engine.has_singleton("InAppStore"):
  19. in_app_store = Engine.get_singleton("InAppStore")
  20. else:
  21. print("iOS IAP plugin is not available on this platform.")
  22. if Engine.has_singleton("GameCenter"):
  23. game_center = Engine.get_singleton("GameCenter")
  24. else:
  25. print("iOS Game Center plugin is not available on this platform.")
  26. Asynchronous methods
  27. --------------------
  28. When requesting an asynchronous operation, the method will look like
  29. this:
  30. ::
  31. Error purchase(Variant params);
  32. The parameter will usually be a Dictionary, with the information
  33. necessary to make the request, and the call will have two phases. First,
  34. the method will immediately return an Error value. If the Error is not
  35. 'OK', the call operation is completed, with an error probably caused
  36. locally (no internet connection, API incorrectly configured, etc). If
  37. the error value is 'OK', a response event will be produced and added to
  38. the 'pending events' queue. Example:
  39. ::
  40. func on_purchase_pressed():
  41. var result = InAppStore.purchase({ "product_id": "my_product" })
  42. if result == OK:
  43. animation.play("busy") # show the "waiting for response" animation
  44. else:
  45. show_error()
  46. # put this on a 1 second timer or something
  47. func check_events():
  48. while in_app_store.get_pending_event_count() > 0:
  49. var event = in_app_store.pop_pending_event()
  50. if event.type == "purchase":
  51. if event.result == "ok":
  52. show_success(event.product_id)
  53. else:
  54. show_error()
  55. Remember that when a call returns OK, the API will *always* produce an
  56. event through the pending_event interface, even if it's an error, or a
  57. network timeout, etc. You should be able to, for example, safely block
  58. the interface waiting for a reply from the server. If any of the APIs
  59. don't behave this way it should be treated as a bug.
  60. The pending event interface consists of two methods:
  61. - ``get_pending_event_count()``
  62. Returns the number of pending events on the queue.
  63. - ``Variant pop_pending_event()``
  64. Pops the first event from the queue and returns it.
  65. Store Kit
  66. ---------
  67. Implemented in `Godot iOS InAppStore plugin <https://github.com/godotengine/godot-ios-plugins/blob/master/plugins/inappstore/in_app_store.mm>`_.
  68. The Store Kit API is accessible through the ``InAppStore`` singleton.
  69. It is initialized automatically.
  70. The following methods are available and documented below:
  71. ::
  72. Error purchase(Variant params)
  73. Error request_product_info(Variant params)
  74. Error restore_purchases()
  75. void set_auto_finish_transaction(bool enable)
  76. void finish_transaction(String product_id)
  77. and the pending events interface:
  78. ::
  79. int get_pending_event_count()
  80. Variant pop_pending_event()
  81. ``purchase``
  82. ~~~~~~~~~~~~
  83. Purchases a product ID through the Store Kit API. You have to call ``finish_transaction(product_id)`` once you
  84. receive a successful response or call ``set_auto_finish_transaction(true)`` prior to calling ``purchase()``.
  85. These two methods ensure the transaction is completed.
  86. Parameters
  87. ^^^^^^^^^^
  88. Takes a dictionary as a parameter, with one field, ``product_id``, a
  89. string with your product ID. Example:
  90. ::
  91. var result = in_app_store.purchase({ "product_id": "my_product" })
  92. Response event
  93. ^^^^^^^^^^^^^^
  94. The response event will be a dictionary with the following fields:
  95. On error:
  96. ::
  97. {
  98. "type": "purchase",
  99. "result": "error",
  100. "product_id": "the product ID requested",
  101. }
  102. On success:
  103. ::
  104. {
  105. "type": "purchase",
  106. "result": "ok",
  107. "product_id": "the product ID requested",
  108. }
  109. ``request_product_info``
  110. ~~~~~~~~~~~~~~~~~~~~~~~~
  111. Requests the product info on a list of product IDs.
  112. Parameters
  113. ^^^^^^^^^^
  114. Takes a dictionary as a parameter, with a single ``product_ids`` key to which a
  115. string array of product IDs is assigned. Example:
  116. ::
  117. var result = in_app_store.request_product_info({ "product_ids": ["my_product1", "my_product2"] })
  118. Response event
  119. ^^^^^^^^^^^^^^
  120. The response event will be a dictionary with the following fields:
  121. ::
  122. {
  123. "type": "product_info",
  124. "result": "ok",
  125. "invalid_ids": [ list of requested IDs that were invalid ],
  126. "ids": [ list of IDs that were valid ],
  127. "titles": [ list of valid product titles (corresponds with list of valid IDs) ],
  128. "descriptions": [ list of valid product descriptions ] ,
  129. "prices": [ list of valid product prices ],
  130. "localized_prices": [ list of valid product localized prices ],
  131. }
  132. ``restore_purchases``
  133. ~~~~~~~~~~~~~~~~~~~~~
  134. Restores previously made purchases on user's account. This will create
  135. response events for each previously purchased product ID.
  136. Response event
  137. ^^^^^^^^^^^^^^
  138. The response events will be dictionaries with the following fields:
  139. ::
  140. {
  141. "type": "restore",
  142. "result": "ok",
  143. "product_id": "product ID of restored purchase",
  144. }
  145. ``set_auto_finish_transaction``
  146. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  147. If set to ``true``, once a purchase is successful, your purchase will be
  148. finalized automatically. Call this method prior to calling ``purchase()``.
  149. Parameters
  150. ^^^^^^^^^^
  151. Takes a boolean as a parameter which specifies if purchases should be
  152. automatically finalized. Example:
  153. ::
  154. in_app_store.set_auto_finish_transaction(true)
  155. ``finish_transaction``
  156. ~~~~~~~~~~~~~~~~~~~~~~
  157. If you don't want transactions to be automatically finalized, call this
  158. method after you receive a successful purchase response.
  159. Parameters
  160. ^^^^^^^^^^
  161. Takes a string ``product_id`` as an argument. ``product_id`` specifies what product to
  162. finalize the purchase on. Example:
  163. ::
  164. in_app_store.finish_transaction("my_product1")
  165. Game Center
  166. -----------
  167. Implemented in `Godot iOS GameCenter plugin <https://github.com/godotengine/godot-ios-plugins/blob/master/plugins/gamecenter/game_center.mm>`_.
  168. The Game Center API is available through the "GameCenter" singleton. It
  169. has the following methods:
  170. ::
  171. Error authenticate()
  172. bool is_authenticated()
  173. Error post_score(Variant score)
  174. Error award_achievement(Variant params)
  175. void reset_achievements()
  176. void request_achievements()
  177. void request_achievement_descriptions()
  178. Error show_game_center(Variant params)
  179. Error request_identity_verification_signature()
  180. and the pending events interface:
  181. ::
  182. int get_pending_event_count()
  183. Variant pop_pending_event()
  184. ``authenticate``
  185. ~~~~~~~~~~~~~~~~
  186. Authenticates a user in Game Center.
  187. Response event
  188. ^^^^^^^^^^^^^^
  189. The response event will be a dictionary with the following fields:
  190. On error:
  191. ::
  192. {
  193. "type": "authentication",
  194. "result": "error",
  195. "error_code": the value from NSError::code,
  196. "error_description": the value from NSError::localizedDescription,
  197. }
  198. On success:
  199. ::
  200. {
  201. "type": "authentication",
  202. "result": "ok",
  203. "player_id": the value from GKLocalPlayer::playerID,
  204. }
  205. ``post_score``
  206. ~~~~~~~~~~~~~~
  207. Posts a score to a Game Center leaderboard.
  208. Parameters
  209. ^^^^^^^^^^
  210. Takes a dictionary as a parameter, with two fields:
  211. - ``score`` a float number
  212. - ``category`` a string with the category name
  213. Example:
  214. ::
  215. var result = game_center.post_score({ "score": 100, "category": "my_leaderboard", })
  216. Response event
  217. ^^^^^^^^^^^^^^
  218. The response event will be a dictionary with the following fields:
  219. On error:
  220. ::
  221. {
  222. "type": "post_score",
  223. "result": "error",
  224. "error_code": the value from NSError::code,
  225. "error_description": the value from NSError::localizedDescription,
  226. }
  227. On success:
  228. ::
  229. {
  230. "type": "post_score",
  231. "result": "ok",
  232. }
  233. ``award_achievement``
  234. ~~~~~~~~~~~~~~~~~~~~~
  235. Modifies the progress of a Game Center achievement.
  236. Parameters
  237. ^^^^^^^^^^
  238. Takes a Dictionary as a parameter, with 3 fields:
  239. - ``name`` (string) the achievement name
  240. - ``progress`` (float) the achievement progress from 0.0 to 100.0
  241. (passed to ``GKAchievement::percentComplete``)
  242. - ``show_completion_banner`` (bool) whether Game Center should display
  243. an achievement banner at the top of the screen
  244. Example:
  245. ::
  246. var result = award_achievement({ "name": "hard_mode_completed", "progress": 6.1 })
  247. Response event
  248. ^^^^^^^^^^^^^^
  249. The response event will be a dictionary with the following fields:
  250. On error:
  251. ::
  252. {
  253. "type": "award_achievement",
  254. "result": "error",
  255. "error_code": the error code taken from NSError::code,
  256. }
  257. On success:
  258. ::
  259. {
  260. "type": "award_achievement",
  261. "result": "ok",
  262. }
  263. ``reset_achievements``
  264. ~~~~~~~~~~~~~~~~~~~~~~
  265. Clears all Game Center achievements. The function takes no parameters.
  266. Response event
  267. ^^^^^^^^^^^^^^
  268. The response event will be a dictionary with the following fields:
  269. On error:
  270. ::
  271. {
  272. "type": "reset_achievements",
  273. "result": "error",
  274. "error_code": the value from NSError::code,
  275. }
  276. On success:
  277. ::
  278. {
  279. "type": "reset_achievements",
  280. "result": "ok",
  281. }
  282. ``request_achievements``
  283. ~~~~~~~~~~~~~~~~~~~~~~~~
  284. Request all the Game Center achievements the player has made progress
  285. on. The function takes no parameters.
  286. Response event
  287. ^^^^^^^^^^^^^^
  288. The response event will be a dictionary with the following fields:
  289. On error:
  290. ::
  291. {
  292. "type": "achievements",
  293. "result": "error",
  294. "error_code": the value from NSError::code,
  295. }
  296. On success:
  297. ::
  298. {
  299. "type": "achievements",
  300. "result": "ok",
  301. "names": [ list of the name of each achievement ],
  302. "progress": [ list of the progress made on each achievement ],
  303. }
  304. ``request_achievement_descriptions``
  305. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  306. Request the descriptions of all existing Game Center achievements
  307. regardless of progress. The function takes no parameters.
  308. Response event
  309. ^^^^^^^^^^^^^^
  310. The response event will be a dictionary with the following fields:
  311. On error:
  312. ::
  313. {
  314. "type": "achievement_descriptions",
  315. "result": "error",
  316. "error_code": the value from NSError::code,
  317. }
  318. On success:
  319. ::
  320. {
  321. "type": "achievement_descriptions",
  322. "result": "ok",
  323. "names": [ list of the name of each achievement ],
  324. "titles": [ list of the title of each achievement ],
  325. "unachieved_descriptions": [ list of the description of each achievement when it is unachieved ],
  326. "achieved_descriptions": [ list of the description of each achievement when it is achieved ],
  327. "maximum_points": [ list of the points earned by completing each achievement ],
  328. "hidden": [ list of booleans indicating whether each achievement is initially visible ],
  329. "replayable": [ list of booleans indicating whether each achievement can be earned more than once ],
  330. }
  331. ``show_game_center``
  332. ~~~~~~~~~~~~~~~~~~~~
  333. Displays the built in Game Center overlay showing leaderboards,
  334. achievements, and challenges.
  335. Parameters
  336. ^^^^^^^^^^
  337. Takes a Dictionary as a parameter, with two fields:
  338. - ``view`` (string) (optional) the name of the view to present. Accepts
  339. "default", "leaderboards", "achievements", or "challenges". Defaults
  340. to "default".
  341. - ``leaderboard_name`` (string) (optional) the name of the leaderboard
  342. to present. Only used when "view" is "leaderboards" (or "default" is
  343. configured to show leaderboards). If not specified, Game Center will
  344. display the aggregate leaderboard.
  345. Examples:
  346. ::
  347. var result = show_game_center({ "view": "leaderboards", "leaderboard_name": "best_time_leaderboard" })
  348. var result = show_game_center({ "view": "achievements" })
  349. Response event
  350. ^^^^^^^^^^^^^^
  351. The response event will be a dictionary with the following fields:
  352. On close:
  353. ::
  354. {
  355. "type": "show_game_center",
  356. "result": "ok",
  357. }
  358. Multi-platform games
  359. --------------------
  360. When working on a multi-platform game, you won't always have the
  361. "GameCenter" singleton available (for example when running on PC or
  362. Android). Because the gdscript compiler looks up the singletons at
  363. compile time, you can't just query the singletons to see and use what
  364. you need inside a conditional block, you need to also define them as
  365. valid identifiers (local variable or class member). This is an example
  366. of how to work around this in a class:
  367. ::
  368. var GameCenter = null # define it as a class member
  369. func post_score(score):
  370. if GameCenter == null:
  371. return
  372. GameCenter.post_score({ "value": score, "category": "my_leaderboard" })
  373. func check_events():
  374. while GameCenter.get_pending_event_count() > 0:
  375. # do something with events here
  376. pass
  377. func _ready():
  378. # check if the singleton exists
  379. if Globals.has_singleton("GameCenter"):
  380. GameCenter = Globals.get_singleton("GameCenter")
  381. # connect your timer here to the "check_events" function