├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── admob-lib
├── admob.gd
└── icon.png
├── admob-plugin
├── .gitignore
├── .idea
│ ├── .name
│ ├── codeStyles
│ │ └── Project.xml
│ ├── compiler.xml
│ ├── gradle.xml
│ ├── jarRepositories.xml
│ ├── misc.xml
│ └── vcs.xml
├── .project
├── .settings
│ └── org.eclipse.buildship.core.prefs
├── app
│ ├── .classpath
│ ├── .gitignore
│ ├── .project
│ ├── .settings
│ │ └── org.eclipse.buildship.core.prefs
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── shinnil
│ │ │ └── godot
│ │ │ └── plugin
│ │ │ └── android
│ │ │ └── godotadmob
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ └── res
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ └── ic_launcher_background.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── test
│ │ └── java
│ │ └── shinnil
│ │ └── godot
│ │ └── plugin
│ │ └── android
│ │ └── godotadmob
│ │ └── ExampleUnitTest.java
├── build.gradle
├── godot-lib.release
│ ├── .gitignore
│ ├── .project
│ ├── .settings
│ │ └── org.eclipse.buildship.core.prefs
│ ├── build.gradle
│ └── put-godot-lib.release.aar.here
├── godotadmob
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── shinnil
│ │ │ └── godot
│ │ │ └── plugin
│ │ │ └── android
│ │ │ └── godotadmob
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── shinnil
│ │ │ └── godot
│ │ │ └── plugin
│ │ │ └── android
│ │ │ └── godotadmob
│ │ │ ├── Banner.java
│ │ │ ├── CMP.java
│ │ │ ├── GodotAdMob.java
│ │ │ ├── GodotRewardedVideo.java
│ │ │ ├── Interstitial.java
│ │ │ ├── RewardedInterstitial.java
│ │ │ └── RewardedVideo.java
│ │ └── test
│ │ └── java
│ │ └── shinnil
│ │ └── godot
│ │ └── plugin
│ │ └── android
│ │ └── godotadmob
│ │ └── ExampleUnitTest.java
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── version.gradle
├── config
└── GodotAdMob.gdap
├── demo
├── admob-lib
│ ├── admob.gd
│ └── icon.png
├── export_presets.cfg
├── icon.png
├── main.gd
├── main.tscn
└── project.godot
├── images
├── properties.png
├── search_node.png
└── signals.png
├── issue_template.md
├── showcase.md
└── tools
└── package_build.sh
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | #github: [Shin-NiL]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | #patreon: # Replace with a single Patreon username
5 | #open_collective: # Replace with a single Open Collective username
6 | ko_fi: shinnil
7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | #liberapay: # Replace with a single Liberapay username
10 | #issuehunt: # Replace with a single IssueHunt username
11 | #otechie: # Replace with a single Otechie username
12 | # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 | custom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=3MJE3M4FMJYGN&lc=BR&item_name=Shin%2dNiL%27s%20Github&item_number=Github¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted']
14 |
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | .DS_Store
3 | *.import
4 | .import
5 | .mono
6 | .idea
7 | *.o
8 | demo/android
9 | tools/releases
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Shin-NiL
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GodotAdMob
2 |
3 | This is an Android AdMob plugin for Godot Engine (https://github.com/okamstudio/godot) 3.2.2 or higher. For Godot < 3.2 or iOS support you can use the [old module](https://github.com/kloder-games/godot-admob).
4 |
5 | Currently, this plugin supports:
6 | - Banner
7 | - Interstitial
8 | - Rewarded Video
9 | - [Rewarded Interstitial](https://developers.google.com/admob/android/rewarded-interstitial)
10 |
11 | ## Setup
12 |
13 | ### Video Guide
14 | Our friend *dQuigz* created a [nice video tutorial on how to use this plugin](https://youtu.be/0a6EvlNgLL0).
15 |
16 | ### Text Instructions
17 | - Configure, install and enable the "Android Custom Template" for your project, just follow the [official documentation](https://docs.godotengine.org/en/stable/getting_started/workflow/export/android_custom_build.html);
18 | - go to the [release tab](https://github.com/Shin-NiL/Godot-Android-AdMob-Plugin/releases), choose a version and download the respective ```GodotAdMobPlugin-x.x.x.zip``` package;
19 | - extract the content of the ```admob-plugin``` directory (```GodotAdmob.gdap``` and ```GodotAdmob.release.aar``` from the zip package) inside the ```res://android/plugins``` directory on your Godot project.
20 | - extract the ```admob-lib``` directory (from the zip package) inside the ```res://``` directory on your Godot project.
21 | - on the Project -> Export... -> Android -> Options ->
22 | - Permissions: check the permissions for _Access Network State_ and _Internet_
23 | - Custom Template: check the _Use Custom Build_
24 | - Plugins: check the _Godot Ad Mob_ (this plugin)
25 | - edit the file ```res://android/build/AndroidManifest.xml``` to add your App ID as described [here](https://developers.google.com/admob/android/quick-start#update_your_androidmanifestxml). For the demo project, for example, you should use:
26 | ```
27 |
30 | ```
31 | One good place to add this metadata is just below these lines, inside of the **application** tag:
32 | ```
33 |
34 | ...
35 |
36 |
37 |
38 |
39 | Here
40 |
41 | ```
42 | - To avoid the mergeDex error, enable the multidex support. Edit the file ```res://android/build/build.gradle``` and insert the line `multiDexEnabled = true` inside the `android` => `defaultConfig`:
43 | ```
44 | android {
45 | defaultConfig {
46 | ...
47 | multiDexEnabled = true
48 | ...
49 | }
50 | }
51 | ```
52 |
53 |
54 | **NOTE**: everytime you install a new version of the Android Build Template this step must be done again, as the ```AndroidManifest.xml``` file will be overriden.
55 |
56 |
57 | Now you'll be able to add an AdMob Node to your scene (**only one node should be added per scene**)
58 |
59 | 
60 |
61 | Edit its properties
62 |
63 | 
64 |
65 | And connect its signals
66 |
67 | 
68 |
69 | ## Sample Code
70 |
71 | In the demo directory you'll find a working sample project where you can see how the things works on the scripting side.
72 |
73 | __REMEMBER__: You still need to configure the project as described in the "Setup" section to be able to run the demo project.
74 |
75 | ## Showcase
76 |
77 | Does this plugin really work? Yes sir! You can see a list of published games [here](showcase.md).
78 |
79 |
80 | ## Donations
81 |
82 | Was this project useful for you? Wanna make a donation? These are the options:
83 |
84 | ### Paypal
85 |
86 | My [Paypal donation link](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=3MJE3M4FMJYGN&lc=BR&item_name=Shin%2dNiL%27s%20Github&item_number=Github¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)
87 |
88 | ### Brave Browser
89 | If you're a Brave browser user, please consider donating some BATs ;)
90 |
91 |
92 | ## API Reference
93 |
94 | ### Properties
95 | ```python
96 | # If true use your real ad, if false use test ads. Make sure to only set it to true with your published apk, otherwise you can be banned by Google
97 | # type bool, default false
98 | is_real
99 |
100 | # If true, displays banner on the top of the screen, if false displays on the bottom
101 | # type bool, default true
102 | banner_on_top
103 |
104 | # The banner size constants
105 | # Valid values are: "ADAPTIVE_BANNER", "SMART_BANNER", "BANNER", "LARGE_BANNER", "MEDIUM_RECTANGLE", "FULL_BANNER", "LEADERBOARD"
106 | banner_size
107 |
108 | # Your app banner ad ID
109 | # type String, optional
110 | banner_id
111 |
112 | # Your app interstitial ad ID
113 | # type String, optional
114 | interstitial_id
115 |
116 | # Your app rewarded video ad ID
117 | # type String, optional
118 | rewarded_id
119 |
120 | # Your app rewarded interstitial ad ID
121 | # type String, optional
122 | rewarded_interstitial_id
123 |
124 | # If true, set the ads to children directed. If true, max_ad_content_rate will be ignored (your max_ad_content_rate would can not be other than "G")
125 | # type bool, default false
126 | child_directed
127 |
128 | # If ads should be personalized. In the European Economic Area, GDPR requires ad personalization to be opt-in.
129 | # type bool, default true
130 | is_personalized
131 |
132 | # Its value must be "G", "PG", "T" or "MA". If the rating of your app in Play Console and your config of max_ad_content_rate in AdMob are not matched, your app can be banned by Google
133 | # type String, default G
134 | max_ad_content_rate
135 |
136 | # If true, ads should be displayed after consent verification (calling method request_consent_info_update())
137 | ads_using_consent
138 |
139 | # True for testing purpose only
140 | # False for production environment
141 | testing_consent
142 | ```
143 |
144 | ### Methods
145 | ```python
146 |
147 | # Initialize AdMob on a background thread for optimization
148 | initialize_on_background_thread()
149 |
150 | # Load the banner (and show inmediatly)
151 | load_banner()
152 |
153 | # Load the interstitial ad
154 | load_interstitial()
155 |
156 | # Load the rewarded video ad
157 | load_rewarded_video()
158 |
159 | # Load the rewarded interstitial ad
160 | load_rewarded_interstitial()
161 |
162 | # Show the banner ad
163 | show_banner()
164 |
165 | # Hide the banner ad
166 | hide_banner()
167 |
168 | # Move banner after loaded
169 | move_banner(on_top: bool)
170 |
171 | # Show the interstitial ad
172 | show_interstitial()
173 |
174 | # Show the rewarded video ad
175 | show_rewarded_video()
176 |
177 | # Show the rewarded interstitial ad
178 | show_rewarded_interstitial()
179 |
180 | # Check if the interstitial ad is loaded
181 | # @return bool true if is loaded
182 | is_interstitial_loaded()
183 |
184 | # Check if the rewarded video ad is loaded
185 | # @return bool true if is loaded
186 | is_rewarded_video_loaded()
187 |
188 | # Check if the rewarded interstitial ad is loaded
189 | # @return bool true if is loaded
190 | is_rewarded_interstitial_loaded()
191 |
192 | # Resize the banner (useful when the orientation changes for example)
193 | banner_resize()
194 |
195 | # Get the current banner dimension
196 | # @return Vector2 (width, height)
197 | get_banner_dimension()
198 |
199 | # Verify consent status
200 | request_consent_info_update()
201 |
202 | # Reset consent status
203 | # Should by called only for testing purpose OR 'if you decide to remove the UMP SDK completely from your project.'
204 | # See: https://developers.google.com/admob/android/privacy#reset_consent_state
205 | reset_consent()
206 |
207 | ```
208 | ### Signals
209 | ```python
210 | # AdMob Background Initialization Success
211 | admob_initialized
212 |
213 | # Banner ad was loaded with success
214 | banner_loaded
215 |
216 | # Banner ad has failed to load
217 | # @param int error_code the error code
218 | banner_failed_to_load(error_code)
219 |
220 | # Interstitial ad was loaded with success
221 | interstitial_loaded
222 |
223 | # Interstitial ad was opened
224 | interstitial_opened
225 |
226 | # Interstitial ad was closed
227 | interstitial_closed
228 |
229 | # Interstitial ad has failed to load
230 | # @param int error_code the error code
231 | interstitial_failed_to_load(error_code)
232 |
233 | # Interstitial ad has been clicked
234 | interstitial_clicked
235 |
236 | # The user has provided an interstitial impression.
237 | interstitial_impression
238 |
239 | # Rewarded video ad was loaded with success
240 | rewarded_video_loaded
241 |
242 | # Rewarded video ad was opened
243 | rewarded_video_opened
244 |
245 | # Rewarded video ad was closed
246 | rewarded_video_closed
247 |
248 | # Rewarded video ad has failed to load
249 | # @param int error_code the error code
250 | rewarded_video_failed_to_load(error_code)
251 |
252 | # Rewarded interstitial ad was loaded with success
253 | rewarded_interstitial_loaded
254 |
255 | # Rewarded interstitial ad was opened
256 | rewarded_interstitial_opened
257 |
258 | # Rewarded interstitial ad was closed
259 | rewarded_interstitial_closed
260 |
261 | # Rewarded interstitial ad has failed to load
262 | # @param int error_code the error code
263 | rewarded_interstitial_failed_to_load(error_code)
264 |
265 | # Rewarded interstitial ad has failed to show
266 | # @param int error_code the error code
267 | rewarded_interstitial_failed_to_show(error_code)
268 |
269 | # Rewarded video/interstitial ad was watched and will reward the user
270 | # @param String currency The reward item description, ex: coin
271 | # @param int amount The reward item amount
272 | rewarded(currency, amount)
273 |
274 | # Rewarded video was clicked
275 | rewarded_clicked
276 |
277 | # The user has given an impression for a rewarded video.
278 | rewarded_impression
279 |
280 | # Good for nothing. Only used for debug information.
281 | consent_info_update_success
282 |
283 | # Error on consent verification
284 | consent_info_update_failure(error_code, error_message)
285 |
286 | # Now you can show ads to user
287 | consent_app_can_request_ad(consent_status)
288 | ```
289 |
290 | ## Compiling the Plugin (optional)
291 |
292 | If you want to compile the plugin by yourself, it's very easy:
293 | 1. Clone this repository;
294 | 2. Checkout the desired version;
295 | 3. Download the AAR library for Android plugin from the official Godot website;
296 | 4. Copy the downloaded AAR file into the `admob-plugin/godot-lib.release/` directory and rename it to `godot-lib.release.aar`;
297 | 5. Configure the demo project according to the "Setup" instructions. Install the "Android Custom Template" for the demo project. This generates the required build configuration.
298 | 6. Using command line go to the `admob-plugin/` directory;
299 | 7. Run `gradlew build`.
300 |
301 | If everything goes fine, you'll find the `.aar` files at `admob-plugin/godotadmob/build/outputs/aar/`.
302 |
303 | ## Troubleshooting
304 |
305 | * First of all, please make sure you're able to compile the custom build for Android without the AdMob plugin, this way we can isolate the cause of the issue.
306 |
307 | * Using logcat for Android is the best way to troubleshoot most issues. You can filter Godot only messages with logcat using the command:
308 | ```
309 | adb logcat -s godot
310 | ```
311 | * _AdMob Java Singleton not found_:
312 | 1. this plugin is Android only, so the AdMob Java singleton will only exists on the Android platform. In other words, you will be able to run it on an Android device (or emulator) only, it will not work on editor or on another platform;
313 | 2. make sure you checked the _Use Custom Build_ and _Godot Ad Mob_ options in the export window.
314 |
315 | * App is crashing at startup: use the `logcat` to check what's happening. It can be caused for many different reasons, if you forgot to or not configure correctly you App ID on the `AndroidManifest.xml`, for example, your app will crash.
316 |
317 | * Error code 3 (_ERROR_CODE_NO_FILL_) is a common issue with Admob, but out of the scope to this plugin. Here's the description on the API page: [ERROR_CODE_NO_FILL: The ad request was successful, but no ad was returned due to lack of ad inventory.](https://developers.google.com/android/reference/com/google/android/gms/ads/AdRequest.html#ERROR_CODE_NO_FILL)
318 |
319 | * Any other error code: you can find more information about the error codes [here](https://support.google.com/admob/thread/3494603). Please don't open issues on this repository asking for help about that, as we can't provide any, sorry.
320 |
321 | * Banner sizes: [Adaptive Banners](https://developers.google.com/admob/android/banner/adaptive) and [Smart Banners](https://developers.google.com/admob/android/banner/smart) uses dynamic banner sizes, the [other options](https://developers.google.com/admob/android/banner) uses fixed sizes, please check its respectives documentation for more details. Smart banners are deprecated and may not work properly.
322 |
323 | ## Optimize AdMob
324 |
325 | To prevent ["Application Not Responding" (ANR)](https://developer.android.com/topic/performance/vitals/anr) issues, you can follow some of the optimization strategies mentioned below.
326 |
327 | Before making any method calls to load ads, call `initialize_on_background_thread()` to initialize AdMob. The signal `admob_initialized` will be triggered, indicating that the initialization was successful.
328 |
329 | Alternatively, you can update your manifest with the optimization flag `OPTIMIZE_INITIALIZATION` to improve initialization without using a background thread.
330 |
331 | You can also use the `OPTIMIZE_AD_LOADING` flag to improve ad loading performance.
332 |
333 | Learn more at [Optimize initialization and ad loading (Beta)](https://developers.google.com/admob/android/optimize-initialization).
334 |
335 |
336 | ## References
337 |
338 | Based on the works of:
339 | * https://github.com/Mavhod/GodotAdmob
340 | * https://github.com/kloder-games/godot-admob
341 |
342 | ## License
343 |
344 | MIT license
345 |
--------------------------------------------------------------------------------
/admob-lib/admob.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | class_name AdMob, "res://admob-lib/icon.png"
4 |
5 | # signals
6 | signal admob_initialized
7 |
8 | signal banner_loaded
9 | signal banner_failed_to_load(error_code)
10 | signal interstitial_failed_to_load(error_code)
11 | signal interstitial_loaded
12 | signal interstitial_opened
13 | signal interstitial_closed
14 | signal interstitial_clicked
15 | signal interstitial_impression
16 | signal rewarded_video_opened
17 | signal rewarded_video_loaded
18 | signal rewarded_video_closed
19 | signal rewarded_video_failed_to_load(error_code)
20 | signal rewarded_interstitial_opened
21 | signal rewarded_interstitial_loaded
22 | signal rewarded_interstitial_closed
23 | signal rewarded_interstitial_failed_to_load(error_code)
24 | signal rewarded_interstitial_failed_to_show(error_code)
25 | signal rewarded(currency, amount)
26 | signal rewarded_clicked
27 | signal rewarded_impression
28 |
29 | signal consent_info_update_success
30 | signal consent_info_update_failure(error_code, error_message)
31 | signal consent_app_can_request_ad(consent_status)
32 |
33 |
34 | # properties
35 | export var is_real:bool setget is_real_set
36 | export var banner_on_top:bool = true
37 | # SMART_BANNER is deprecated
38 | export(String, "ADAPTIVE_BANNER", "SMART_BANNER", "BANNER", "LARGE_BANNER", "MEDIUM_RECTANGLE", "FULL_BANNER", "LEADERBOARD") var banner_size = "ADAPTIVE_BANNER"
39 | export var banner_id:String
40 | export var interstitial_id:String
41 | export var rewarded_id:String
42 | export var rewarded_interstitial_id:String
43 | export var child_directed:bool = false setget child_directed_set
44 | export var is_personalized:bool = true setget is_personalized_set
45 | export(String, "G", "PG", "T", "MA") var max_ad_content_rate = "G" setget max_ad_content_rate_set
46 |
47 | # Testing consent flag
48 | export var ads_using_consent:bool setget ads_using_consent
49 | export var testing_consent:bool setget testing_consent_set
50 |
51 |
52 | # "private" properties
53 | var _admob_singleton = null
54 | var _is_interstitial_loaded:bool = false
55 | var _is_rewarded_video_loaded:bool = false
56 | var _is_rewarded_interstitial_loaded:bool = false
57 |
58 |
59 | func _enter_tree():
60 | if not init():
61 | print("AdMob Java Singleton not found. This plugin will only work on Android")
62 |
63 | # setters
64 | func is_real_set(new_val) -> void:
65 | is_real = new_val
66 | # warning-ignore:return_value_discarded
67 | init()
68 |
69 | func testing_consent_set(new_val) -> void:
70 | testing_consent = new_val
71 |
72 | func ads_using_consent(new_val) -> void:
73 | ads_using_consent = new_val
74 |
75 | func child_directed_set(new_val) -> void:
76 | child_directed = new_val
77 | # warning-ignore:return_value_discarded
78 | init()
79 |
80 | func is_personalized_set(new_val) -> void:
81 | is_personalized = new_val
82 | # warning-ignore:return_value_discarded
83 | init()
84 |
85 | func max_ad_content_rate_set(new_val) -> void:
86 | if new_val != "G" and new_val != "PG" \
87 | and new_val != "T" and new_val != "MA":
88 |
89 | max_ad_content_rate = "G"
90 | print("Invalid max_ad_content_rate, using 'G'")
91 | else:
92 | max_ad_content_rate = new_val
93 | init()
94 |
95 |
96 | # initialization
97 | func init() -> bool:
98 | if(Engine.has_singleton("GodotAdMob")):
99 | _admob_singleton = Engine.get_singleton("GodotAdMob")
100 |
101 | # check if one signal is already connected
102 | if not _admob_singleton.is_connected("on_admob_ad_loaded", self, "_on_admob_ad_loaded"):
103 | connect_signals()
104 |
105 | _admob_singleton.initWithContentRating(
106 | is_real,
107 | child_directed,
108 | is_personalized,
109 | max_ad_content_rate
110 | )
111 | return true
112 | return false
113 |
114 | # connect the AdMob Java signals
115 | func connect_signals() -> void:
116 | _admob_singleton.connect("on_admob_initialized", self, "_on_admob_initialized")
117 |
118 | _admob_singleton.connect("on_admob_ad_loaded", self, "_on_admob_ad_loaded")
119 | _admob_singleton.connect("on_admob_banner_failed_to_load", self, "_on_admob_banner_failed_to_load")
120 | _admob_singleton.connect("on_interstitial_failed_to_load", self, "_on_interstitial_failed_to_load")
121 | _admob_singleton.connect("on_interstitial_opened", self, "_on_interstitial_opened")
122 | _admob_singleton.connect("on_interstitial_loaded", self, "_on_interstitial_loaded")
123 | _admob_singleton.connect("on_interstitial_close", self, "_on_interstitial_close")
124 | _admob_singleton.connect("on_interstitial_clicked", self, "_on_interstitial_clicked")
125 | _admob_singleton.connect("on_interstitial_impression", self, "_on_interstitial_impression")
126 | _admob_singleton.connect("on_rewarded_video_ad_loaded", self, "_on_rewarded_video_ad_loaded")
127 | _admob_singleton.connect("on_rewarded_video_ad_opened", self, "_on_rewarded_video_ad_opened")
128 | _admob_singleton.connect("on_rewarded_video_ad_closed", self, "_on_rewarded_video_ad_closed")
129 | _admob_singleton.connect("on_rewarded_video_ad_failed_to_load", self, "_on_rewarded_video_ad_failed_to_load")
130 | _admob_singleton.connect("on_rewarded_interstitial_ad_loaded", self, "_on_rewarded_interstitial_ad_loaded")
131 | _admob_singleton.connect("on_rewarded_interstitial_ad_opened", self, "_on_rewarded_interstitial_ad_opened")
132 | _admob_singleton.connect("on_rewarded_interstitial_ad_closed", self, "_on_rewarded_interstitial_ad_closed")
133 | _admob_singleton.connect("on_rewarded_interstitial_ad_failed_to_load", self, "_on_rewarded_interstitial_ad_failed_to_load")
134 | _admob_singleton.connect("on_rewarded_interstitial_ad_failed_to_show", self, "_on_rewarded_interstitial_ad_failed_to_show")
135 | _admob_singleton.connect("on_rewarded", self, "_on_rewarded")
136 | _admob_singleton.connect("on_rewarded_clicked", self, "_on_rewarded_clicked")
137 | _admob_singleton.connect("on_rewarded_impression", self, "_on_rewarded_impression")
138 |
139 | _admob_singleton.connect("on_consent_info_update_success", self, "_on_consent_info_update_success")
140 | _admob_singleton.connect("on_consent_info_update_failure", self, "_on_consent_info_update_failure")
141 | _admob_singleton.connect("on_app_can_request_ads", self, "_on_app_can_request_ads")
142 |
143 |
144 | # initialize
145 | func initialize_on_background_thread() -> void:
146 | if _admob_singleton != null:
147 | _admob_singleton.initializeOnBackgroundThread()
148 |
149 | # load
150 |
151 | func load_banner() -> void:
152 | if _admob_singleton != null:
153 | _admob_singleton.loadBanner(banner_id, banner_on_top, banner_size)
154 |
155 | func load_interstitial() -> void:
156 | if _admob_singleton != null:
157 | _admob_singleton.loadInterstitial(interstitial_id)
158 |
159 | func is_interstitial_loaded() -> bool:
160 | if _admob_singleton != null:
161 | return _is_interstitial_loaded
162 | return false
163 |
164 | func load_rewarded_video() -> void:
165 | if _admob_singleton != null:
166 | _admob_singleton.loadRewardedVideo(rewarded_id)
167 |
168 | func is_rewarded_video_loaded() -> bool:
169 | if _admob_singleton != null:
170 | return _is_rewarded_video_loaded
171 | return false
172 |
173 | func load_rewarded_interstitial() -> void:
174 | if _admob_singleton != null:
175 | _admob_singleton.loadRewardedInterstitial(rewarded_interstitial_id)
176 |
177 | func is_rewarded_interstitial_loaded() -> bool:
178 | if _admob_singleton != null:
179 | return _is_rewarded_interstitial_loaded
180 | return false
181 |
182 | # show / hide
183 |
184 | func show_banner() -> void:
185 | if _admob_singleton != null:
186 | _admob_singleton.showBanner()
187 |
188 | func hide_banner() -> void:
189 | if _admob_singleton != null:
190 | _admob_singleton.hideBanner()
191 |
192 | func move_banner(on_top: bool) -> void:
193 | if _admob_singleton != null:
194 | banner_on_top = on_top
195 | _admob_singleton.move(banner_on_top)
196 |
197 | func show_interstitial() -> void:
198 | if _admob_singleton != null:
199 | _admob_singleton.showInterstitial()
200 | _is_interstitial_loaded = false
201 |
202 | func show_rewarded_video() -> void:
203 | if _admob_singleton != null:
204 | _admob_singleton.showRewardedVideo()
205 | _is_rewarded_video_loaded = false
206 |
207 | func show_rewarded_interstitial() -> void:
208 | if _admob_singleton != null:
209 | _admob_singleton.showRewardedInterstitial()
210 | _is_rewarded_interstitial_loaded = false
211 |
212 | # resize
213 |
214 | func banner_resize() -> void:
215 | if _admob_singleton != null:
216 | _admob_singleton.resize()
217 |
218 | # dimension
219 | func get_banner_dimension() -> Vector2:
220 | if _admob_singleton != null:
221 | return Vector2(_admob_singleton.getBannerWidth(), _admob_singleton.getBannerHeight())
222 | return Vector2()
223 |
224 | func request_consent_info_update() -> void:
225 | if _admob_singleton != null:
226 | _admob_singleton.requestConsentInfoUpdate(testing_consent)
227 |
228 | func reset_consent() -> void:
229 | if _admob_singleton != null:
230 | _admob_singleton.resetConsentInformation()
231 |
232 | # callbacks
233 |
234 | func _on_admob_initialized() -> void:
235 | emit_signal("admob_initialized")
236 |
237 | func _on_admob_ad_loaded() -> void:
238 | emit_signal("banner_loaded")
239 |
240 | func _on_admob_banner_failed_to_load(error_code:int) -> void:
241 | emit_signal("banner_failed_to_load", error_code)
242 |
243 | func _on_interstitial_failed_to_load(error_code:int) -> void:
244 | _is_interstitial_loaded = false
245 | emit_signal("interstitial_failed_to_load", error_code)
246 |
247 | func _on_interstitial_opened() -> void:
248 | emit_signal("interstitial_opened")
249 |
250 | func _on_interstitial_loaded() -> void:
251 | _is_interstitial_loaded = true
252 | emit_signal("interstitial_loaded")
253 |
254 | func _on_interstitial_close() -> void:
255 | emit_signal("interstitial_closed")
256 |
257 | func _on_interstitial_clicked() -> void:
258 | emit_signal("interstitial_clicked")
259 |
260 | func _on_interstitial_impression() -> void:
261 | emit_signal("interstitial_impression")
262 |
263 | func _on_rewarded_video_ad_loaded() -> void:
264 | _is_rewarded_video_loaded = true
265 | emit_signal("rewarded_video_loaded")
266 |
267 | func _on_rewarded_video_ad_opened() -> void:
268 | emit_signal("rewarded_video_opened")
269 |
270 | func _on_rewarded_video_ad_closed() -> void:
271 | emit_signal("rewarded_video_closed")
272 |
273 | func _on_rewarded_video_ad_failed_to_load(error_code:int) -> void:
274 | _is_rewarded_video_loaded = false
275 | emit_signal("rewarded_video_failed_to_load", error_code)
276 |
277 | func _on_rewarded_interstitial_ad_opened() -> void:
278 | emit_signal("rewarded_interstitial_opened")
279 |
280 | func _on_rewarded_interstitial_ad_loaded() -> void:
281 | _is_rewarded_interstitial_loaded = true
282 | emit_signal("rewarded_interstitial_loaded")
283 |
284 | func _on_rewarded_interstitial_ad_closed() -> void:
285 | emit_signal("rewarded_interstitial_closed")
286 |
287 | func _on_rewarded_interstitial_ad_failed_to_load(error_code:int) -> void:
288 | _is_rewarded_interstitial_loaded = false
289 | emit_signal("rewarded_interstitial_failed_to_load", error_code)
290 |
291 | func _on_rewarded_interstitial_ad_failed_to_show(error_code:int) -> void:
292 | _is_rewarded_interstitial_loaded = false
293 | emit_signal("rewarded_interstitial_failed_to_show", error_code)
294 |
295 | func _on_rewarded(currency:String, amount:int) -> void:
296 | emit_signal("rewarded", currency, amount)
297 |
298 | func _on_rewarded_clicked() -> void:
299 | emit_signal("rewarded_clicked")
300 |
301 | func _on_rewarded_impression() -> void:
302 | emit_signal("rewarded_impression")
303 |
304 | func _on_consent_info_update_success() -> void:
305 | emit_signal("consent_info_update_success")
306 |
307 | func _on_consent_info_update_failure(error_code:int, error_message:String) -> void:
308 | emit_signal("consent_info_update_failure", error_code, error_message)
309 |
310 | func _on_app_can_request_ads(consent_status:int) -> void:
311 | emit_signal("consent_app_can_request_ad", consent_status)
312 |
--------------------------------------------------------------------------------
/admob-lib/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-lib/icon.png
--------------------------------------------------------------------------------
/admob-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | local.properties
4 | .DS_Store
5 | /build
6 | /captures
7 | .externalNativeBuild
8 | .cxx
9 | *.aar
--------------------------------------------------------------------------------
/admob-plugin/.idea/.name:
--------------------------------------------------------------------------------
1 | GodotAdMob
--------------------------------------------------------------------------------
/admob-plugin/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | xmlns:android
14 |
15 | ^$
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | xmlns:.*
25 |
26 | ^$
27 |
28 |
29 | BY_NAME
30 |
31 |
32 |
33 |
34 |
35 |
36 | .*:id
37 |
38 | http://schemas.android.com/apk/res/android
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | .*:name
48 |
49 | http://schemas.android.com/apk/res/android
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | name
59 |
60 | ^$
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | style
70 |
71 | ^$
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | .*
81 |
82 | ^$
83 |
84 |
85 | BY_NAME
86 |
87 |
88 |
89 |
90 |
91 |
92 | .*
93 |
94 | http://schemas.android.com/apk/res/android
95 |
96 |
97 | ANDROID_ATTRIBUTE_ORDER
98 |
99 |
100 |
101 |
102 |
103 |
104 | .*
105 |
106 | .*
107 |
108 |
109 | BY_NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/admob-plugin/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/admob-plugin/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
21 |
22 |
--------------------------------------------------------------------------------
/admob-plugin/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/admob-plugin/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/admob-plugin/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/admob-plugin/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | GodotAdmob
4 | Project admob-plugin created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.buildship.core.gradleprojectbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.buildship.core.gradleprojectnature
16 |
17 |
18 |
19 | 1659094184453
20 |
21 | 30
22 |
23 | org.eclipse.core.resources.regexFilterMatcher
24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/admob-plugin/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | arguments=
2 | auto.sync=false
3 | build.scans.enabled=false
4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
5 | connection.project.dir=
6 | eclipse.preferences.version=1
7 | gradle.user.home=
8 | java.home=C\:/Program Files/Java/jdk1.8.0_151
9 | jvm.arguments=
10 | offline.mode=false
11 | override.workspace.settings=true
12 | show.console.view=true
13 | show.executions.view=true
14 |
--------------------------------------------------------------------------------
/admob-plugin/app/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/admob-plugin/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/admob-plugin/app/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | app
4 | Project app created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.buildship.core.gradleprojectbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.buildship.core.gradleprojectnature
22 |
23 |
24 |
25 | 1659094184463
26 |
27 | 30
28 |
29 | org.eclipse.core.resources.regexFilterMatcher
30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/admob-plugin/app/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | arguments=
2 | auto.sync=false
3 | build.scans.enabled=false
4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3))
5 | connection.project.dir=..
6 | eclipse.preferences.version=1
7 | gradle.user.home=
8 | java.home=C\:/Program Files/Java/jdk1.8.0_151
9 | jvm.arguments=
10 | offline.mode=false
11 | override.workspace.settings=true
12 | show.console.view=true
13 | show.executions.view=true
14 |
--------------------------------------------------------------------------------
/admob-plugin/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdk versions.compileSdk
5 | buildToolsVersion versions.buildTools
6 |
7 | defaultConfig {
8 | applicationId "shinnil.godot.plugin.android.godotadmob"
9 | minSdkVersion versions.minSdk
10 | targetSdkVersion versions.targetSdk
11 | versionCode pluginVersionCode
12 | versionName pluginVersionName
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(dir: 'libs', include: ['*.jar'])
28 |
29 | implementation "androidx.appcompat:appcompat:${appcompatVersion}"
30 | testImplementation 'junit:junit:4.13.2'
31 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
32 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
33 | }
34 |
--------------------------------------------------------------------------------
/admob-plugin/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/androidTest/java/shinnil/godot/plugin/android/godotadmob/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("shinnil.godot.plugin.android.godotadmob", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 |
7 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GodotAdMob
3 |
4 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/admob-plugin/app/src/test/java/shinnil/godot/plugin/android/godotadmob/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/admob-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | // TODO: Copy config.gradle from the build template of a specific Godot version.
3 | apply from: "../demo/android/build/config.gradle"
4 | apply from: 'version.gradle'
5 |
6 | buildscript {
7 | apply from: "../demo/android/build/config.gradle"
8 |
9 | repositories {
10 | google()
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | classpath "com.android.tools.build:gradle:${versions.androidGradlePlugin}"
16 |
17 |
18 | // NOTE: Do not place your application dependencies here; they belong
19 | // in the individual module build.gradle files
20 | }
21 | }
22 |
23 | allprojects {
24 | repositories {
25 | google()
26 | mavenCentral()
27 | }
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/admob-plugin/godot-lib.release/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/admob-plugin/godot-lib.release/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | godot-lib.release
4 | Project godot-lib.release created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.buildship.core.gradleprojectbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.buildship.core.gradleprojectnature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/admob-plugin/godot-lib.release/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | arguments=
2 | auto.sync=false
3 | build.scans.enabled=false
4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.3))
5 | connection.project.dir=..
6 | eclipse.preferences.version=1
7 | gradle.user.home=
8 | java.home=C\:/Program Files/Java/jdk1.8.0_151
9 | jvm.arguments=
10 | offline.mode=false
11 | override.workspace.settings=true
12 | show.console.view=true
13 | show.executions.view=true
14 |
--------------------------------------------------------------------------------
/admob-plugin/godot-lib.release/build.gradle:
--------------------------------------------------------------------------------
1 | configurations.maybeCreate("default")
2 | artifacts.add("default", file('godot-lib.release.aar'))
--------------------------------------------------------------------------------
/admob-plugin/godot-lib.release/put-godot-lib.release.aar.here:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/godot-lib.release/put-godot-lib.release.aar.here
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | }
4 |
5 | android {
6 | compileSdk versions.compileSdk
7 | buildToolsVersion versions.buildTools
8 |
9 | defaultConfig {
10 | minSdkVersion versions.minSdk
11 | targetSdkVersion versions.targetSdk
12 | versionCode pluginVersionCode
13 | versionName pluginVersionName
14 |
15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16 | consumerProguardFiles 'consumer-rules.pro'
17 | }
18 |
19 | libraryVariants.all { variant ->
20 | variant.outputs.all { output ->
21 | output.outputFileName = "GodotAdMob.$pluginVersionName.${variant.name}.aar"
22 | }
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 |
32 | }
33 |
34 | dependencies {
35 | implementation fileTree(dir: 'libs', include: ['*.jar'])
36 |
37 | compileOnly project(':godot-lib.release')
38 | implementation "com.google.android.gms:play-services-ads:${playServicesAdsVersion}"
39 |
40 | implementation "androidx.appcompat:appcompat:${appcompatVersion}"
41 | testImplementation 'junit:junit:4.13.2'
42 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
44 |
45 | implementation 'com.google.android.ump:user-messaging-platform:2.0.0'
46 | }
47 |
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/godotadmob/consumer-rules.pro
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/androidTest/java/shinnil/godot/plugin/android/godotadmob/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.content.Context;
4 |
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 |
8 | import androidx.test.ext.junit.runners.AndroidJUnit4;
9 | import androidx.test.platform.app.InstrumentationRegistry;
10 |
11 | import static org.junit.Assert.assertEquals;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 |
25 | assertEquals("shinnil.godot.plugin.android.godotadmob.test", appContext.getPackageName());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/java/shinnil/godot/plugin/android/godotadmob/Banner.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Color;
5 | import android.util.DisplayMetrics;
6 | import android.util.Log;
7 | import android.view.Display;
8 | import android.view.Gravity;
9 | import android.view.View;
10 | import android.widget.FrameLayout;
11 |
12 | import androidx.annotation.NonNull;
13 |
14 | import com.google.android.gms.ads.AdListener;
15 | import com.google.android.gms.ads.AdRequest;
16 | import com.google.android.gms.ads.AdSize;
17 | import com.google.android.gms.ads.AdView;
18 | import com.google.android.gms.ads.LoadAdError;
19 |
20 | interface BannerListener {
21 | void onBannerLoaded();
22 | void onBannerFailedToLoad(int errorCode);
23 | }
24 |
25 | public class Banner {
26 | private AdView adView = null; // Banner view
27 | private final FrameLayout layout;
28 | private FrameLayout.LayoutParams adParams = null;
29 | private final AdRequest adRequest;
30 | private final Activity activity;
31 | private final String bannerSize;
32 |
33 |
34 | public Banner(final String id, final AdRequest adRequest, final Activity activity, final BannerListener defaultBannerListener, final boolean isOnTop, final FrameLayout layout, final String bannerSize) {
35 | this.activity = activity;
36 | this.layout = layout;
37 | this.adRequest = adRequest;
38 | this.bannerSize = bannerSize;
39 |
40 | AddBanner(id, (isOnTop ? Gravity.TOP : Gravity.BOTTOM), getAdSize(bannerSize), new AdListener() {
41 | @Override
42 | public void onAdLoaded() {
43 | Log.w("godot", "AdMob: onAdLoaded: banner");
44 | defaultBannerListener.onBannerLoaded();
45 | }
46 |
47 | @Override
48 | public void onAdFailedToLoad(@NonNull LoadAdError adError) {
49 | Log.w("godot", "AdMob: onAdFailedToLoad. errorCode: " + adError.getCode());
50 | defaultBannerListener.onBannerFailedToLoad(adError.getCode());
51 | }
52 | });
53 | }
54 |
55 | public void show() {
56 | if (adView == null) {
57 | Log.w("w", "AdMob: showBanner - banner not loaded");
58 | return;
59 | }
60 |
61 | if (adView.getVisibility() == View.VISIBLE) {
62 | return;
63 | }
64 |
65 | adView.setVisibility(View.VISIBLE);
66 | adView.resume();
67 | Log.d("godot", "AdMob: Show Banner");
68 | }
69 |
70 | public void move(final boolean isOnTop)
71 | {
72 | if (layout == null || adView == null || adParams == null) {
73 | return;
74 | }
75 |
76 | layout.removeView(adView); // Remove the old view
77 |
78 | AdListener adListener = adView.getAdListener();
79 | String id = adView.getAdUnitId();
80 | AddBanner(id, (isOnTop ? Gravity.TOP : Gravity.BOTTOM), adView.getAdSize(), adListener);
81 |
82 | Log.d("godot", "AdMob: Banner Moved");
83 | }
84 |
85 | public void resize() {
86 | if (layout == null || adView == null || adParams == null) {
87 | return;
88 | }
89 |
90 | layout.removeView(adView); // Remove the old view
91 |
92 | AdListener adListener = adView.getAdListener();
93 | String id = adView.getAdUnitId();
94 | AddBanner(id, adParams.gravity, getAdSize(bannerSize), adListener);
95 |
96 | Log.d("godot", "AdMob: Banner Resized");
97 | }
98 |
99 | private void AddBanner(final String id, final int gravity, final AdSize size, final AdListener listener) {
100 | adParams = new FrameLayout.LayoutParams(
101 | FrameLayout.LayoutParams.MATCH_PARENT,
102 | FrameLayout.LayoutParams.WRAP_CONTENT
103 | );
104 | adParams.gravity = gravity;
105 |
106 | // Create new view & set old params
107 | adView = new AdView(activity);
108 | adView.setAdUnitId(id);
109 | adView.setBackgroundColor(Color.TRANSPARENT);
110 | adView.setAdSize(size);
111 | adView.setAdListener(listener);
112 |
113 | // Add to layout and load ad
114 | layout.addView(adView, adParams);
115 |
116 | // Request
117 | adView.loadAd(adRequest);
118 | }
119 |
120 | public void remove() {
121 | if (adView != null) {
122 | layout.removeView(adView); // Remove the old view
123 | }
124 | }
125 |
126 | public void hide() {
127 | if (adView.getVisibility() == View.GONE) return;
128 | adView.setVisibility(View.GONE);
129 | adView.pause();
130 | Log.d("godot", "AdMob: Hide Banner");
131 | }
132 |
133 | private AdSize getAdaptiveAdSize() {
134 | // Determine the screen width (less decorations) to use for the ad width.
135 | Display display = activity.getWindowManager().getDefaultDisplay();
136 | DisplayMetrics outMetrics = new DisplayMetrics();
137 | display.getMetrics(outMetrics);
138 |
139 | float widthPixels = outMetrics.widthPixels;
140 | float density = outMetrics.density;
141 |
142 | int adWidth = (int) (widthPixels / density);
143 |
144 | // Get adaptive ad size and return for setting on the ad view.
145 | return AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(activity, adWidth);
146 | }
147 |
148 | private AdSize getAdSize(final String bannerSize) {
149 | switch (bannerSize) {
150 | case "SMART_BANNER":
151 | //noinspection deprecation
152 | return AdSize.SMART_BANNER;
153 | case "BANNER":
154 | return AdSize.BANNER;
155 | case "LARGE_BANNER":
156 | return AdSize.LARGE_BANNER;
157 | case "MEDIUM_RECTANGLE":
158 | return AdSize.MEDIUM_RECTANGLE;
159 | case "FULL_BANNER":
160 | return AdSize.FULL_BANNER;
161 | case "LEADERBOARD":
162 | return AdSize.LEADERBOARD;
163 | default:
164 | return getAdaptiveAdSize();
165 | }
166 | }
167 |
168 | public int getWidth() {
169 | return getAdSize(bannerSize).getWidthInPixels(activity);
170 | }
171 |
172 | public int getHeight() {
173 | return getAdSize(bannerSize).getHeightInPixels(activity);
174 | }
175 |
176 |
177 | }
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/java/shinnil/godot/plugin/android/godotadmob/CMP.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.Nullable;
8 |
9 | import com.google.android.gms.ads.AdRequest;
10 | import com.google.android.gms.ads.MobileAds;
11 | import com.google.android.ump.ConsentDebugSettings;
12 | import com.google.android.ump.ConsentForm;
13 | import com.google.android.ump.ConsentInformation;
14 | import com.google.android.ump.ConsentRequestParameters;
15 | import com.google.android.ump.FormError;
16 | import com.google.android.ump.UserMessagingPlatform;
17 |
18 | import org.godotengine.godot.GodotLib;
19 |
20 | interface CMPListener {
21 | void onConsentInfoUpdateSuccess();
22 | void onConsentInfoUpdateFailure(int errorCode, String errorMessage);
23 |
24 | void onAppCanRequestAds(int consentStatus);
25 | }
26 |
27 | public class CMP {
28 | private ConsentInformation consentInformation;
29 | private ConsentForm consentForm;
30 |
31 | private final Activity activity;
32 | private final CMPListener defaultCMPListener;
33 |
34 | public CMP(Activity activity,
35 | final boolean testingConsent,
36 | final String testingDeviceId,
37 | CMPListener defaultCMPListener) {
38 | this.activity = activity;
39 | this.defaultCMPListener = defaultCMPListener;
40 |
41 | consentInformation = UserMessagingPlatform.getConsentInformation(this.activity);
42 |
43 | // Set tag for under age of consent. false means users are not under
44 | // age.
45 | ConsentRequestParameters params = new ConsentRequestParameters
46 | .Builder()
47 | .setTagForUnderAgeOfConsent(false)
48 | .build();
49 |
50 | Log.w("godot", "Consent status: " +
51 | String.valueOf(consentInformation.getConsentStatus()));
52 |
53 | if(testingConsent) {
54 |
55 | ConsentDebugSettings debugSettings = new ConsentDebugSettings.Builder(this.activity)
56 | .setDebugGeography(ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_EEA)
57 | .addTestDeviceHashedId(testingDeviceId)
58 | .build();
59 |
60 | params = new ConsentRequestParameters
61 | .Builder()
62 | .setConsentDebugSettings(debugSettings)
63 | .build();
64 |
65 | Log.w("godot", "Consent status: " +
66 | String.valueOf(consentInformation.getConsentStatus()));
67 | }
68 |
69 | consentInformation.requestConsentInfoUpdate(
70 | this.activity,
71 | params,
72 | new ConsentInformation.OnConsentInfoUpdateSuccessListener() {
73 | @Override
74 | public void onConsentInfoUpdateSuccess() {
75 | // The consent information state was updated.
76 | // You are now ready to check if a form is available.
77 | Log.w("godot", "AdMob: onConsentInfoUpdateSuccess");
78 |
79 | defaultCMPListener.onConsentInfoUpdateSuccess();
80 |
81 | if (consentInformation.isConsentFormAvailable()) {
82 | Log.w("godot", "AdMob: Consent information available.");
83 | loadForm();
84 | }else{
85 | Log.w("godot", "AdMob: No consent information.");
86 | Log.w("godot", "Consent status: " +
87 | String.valueOf(consentInformation.getConsentStatus()));
88 |
89 | if(ConsentInformation.ConsentStatus.NOT_REQUIRED ==
90 | consentInformation.getConsentStatus()){
91 | defaultCMPListener.onAppCanRequestAds(consentInformation.getConsentStatus());
92 | }
93 | }
94 | }
95 | },
96 | new ConsentInformation.OnConsentInfoUpdateFailureListener() {
97 | @Override
98 | public void onConsentInfoUpdateFailure(FormError formError) {
99 | // Handle the error.
100 | Log.w("godot", "AdMob: onConsentInfoUpdateFailure: "
101 | + formError.getErrorCode()
102 | + " - "
103 | + formError.getMessage()
104 | );
105 | defaultCMPListener.onConsentInfoUpdateFailure(formError.getErrorCode(),
106 | formError.getMessage());
107 | }
108 | });
109 | }
110 |
111 | public void resetConsentInformation(){
112 | if(consentInformation != null) {
113 | consentInformation.reset();
114 | }
115 | }
116 |
117 | public void loadForm() {
118 | // Loads a consent form. Must be called on the main thread.
119 | UserMessagingPlatform.loadConsentForm(
120 | this.activity,
121 | new UserMessagingPlatform.OnConsentFormLoadSuccessListener() {
122 | @Override
123 | public void onConsentFormLoadSuccess(ConsentForm consentForm) {
124 | CMP.this.consentForm = consentForm;
125 | Log.w("godot", "AdMob: onConsentFormLoadSuccess");
126 | if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.REQUIRED) {
127 | consentForm.show(
128 | CMP.this.activity,
129 | new ConsentForm.OnConsentFormDismissedListener() {
130 | @Override
131 | public void onConsentFormDismissed(@Nullable FormError formError) {
132 | if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED) {
133 | // App can start requesting ads.
134 | Log.w("godot", "AdMob: App can start requesting ads.");
135 | defaultCMPListener.onAppCanRequestAds(consentInformation.getConsentStatus());
136 | }
137 |
138 | // Handle dismissal by reloading form.
139 | loadForm();
140 | }
141 | });
142 | }else if(consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED){
143 | Log.w("godot", "AdMob: App can start requesting ads.");
144 | defaultCMPListener.onAppCanRequestAds(consentInformation.getConsentStatus());
145 | }
146 | }
147 | },
148 | new UserMessagingPlatform.OnConsentFormLoadFailureListener() {
149 | @Override
150 | public void onConsentFormLoadFailure(FormError formError) {
151 | // Handle the error.
152 | Log.w("godot", "AdMob: onConsentInfoUpdateFailure: "
153 | + formError.getErrorCode()
154 | + " - "
155 | + formError.getMessage()
156 | );
157 | }
158 | }
159 | );
160 | }
161 |
162 | }
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/java/shinnil/godot/plugin/android/godotadmob/GodotAdMob.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import static com.google.android.gms.ads.RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE;
4 |
5 | import android.annotation.SuppressLint;
6 | import android.app.Activity;
7 | import android.os.Bundle;
8 | import android.provider.Settings;
9 | import android.util.Log;
10 | import android.view.View;
11 | import android.widget.FrameLayout;
12 |
13 | import androidx.annotation.NonNull;
14 | import androidx.collection.ArraySet;
15 |
16 | import com.google.ads.mediation.admob.AdMobAdapter;
17 | import com.google.android.gms.ads.AdRequest;
18 | import com.google.android.gms.ads.MobileAds;
19 | import com.google.android.gms.ads.RequestConfiguration;
20 | import com.google.android.gms.ads.initialization.InitializationStatus;
21 | import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
22 |
23 | import org.godotengine.godot.Godot;
24 | import org.godotengine.godot.GodotLib;
25 | import org.godotengine.godot.plugin.GodotPlugin;
26 | import org.godotengine.godot.plugin.SignalInfo;
27 | import org.godotengine.godot.plugin.UsedByGodot;
28 |
29 | import java.security.MessageDigest;
30 | import java.security.NoSuchAlgorithmException;
31 | import java.util.Arrays;
32 | import java.util.List;
33 | import java.util.Locale;
34 | import java.util.Set;
35 |
36 | @SuppressWarnings("unused")
37 | public class GodotAdMob extends GodotPlugin {
38 | private final Activity activity; // The main activity of the game
39 |
40 | private boolean isReal = false; // Store if is real or not
41 | private boolean isForChildDirectedTreatment = false; // Store if is children directed treatment desired
42 | private boolean isPersonalized = true; // ads are personalized by default, GDPR compliance within the European Economic Area may require you to disable personalization.
43 | private String maxAdContentRating = ""; // Store maxAdContentRating ("G", "PG", "T" or "MA")
44 | private Bundle extras = null;
45 |
46 | private FrameLayout layout = null; // Store the layout
47 |
48 | private RewardedVideo rewardedVideo = null; // Rewarded Video object
49 | private RewardedInterstitial rewardedInterstitial = null; // Rewarded Interstitial object
50 | private Interstitial interstitial = null; // Interstitial object
51 | private Banner banner = null; // Banner object
52 | private CMP cmp; // Google Consent Management Platform (CMP)
53 |
54 |
55 | public GodotAdMob(Godot godot) {
56 | super(godot);
57 | this.activity = getActivity();
58 | }
59 |
60 | // create and add a new layout to Godot
61 | @Override
62 | public View onMainCreate(Activity activity) {
63 | layout = new FrameLayout(activity);
64 | return layout;
65 | }
66 |
67 | @NonNull
68 | @Override
69 | public String getPluginName() {
70 | return "GodotAdMob";
71 | }
72 |
73 | @NonNull
74 | @Override
75 | public Set getPluginSignals() {
76 | Set signals = new ArraySet<>();
77 |
78 | signals.add(new SignalInfo("on_admob_initialized"));
79 |
80 | signals.add(new SignalInfo("on_admob_ad_loaded"));
81 | signals.add(new SignalInfo("on_admob_banner_failed_to_load", Integer.class));
82 |
83 | signals.add(new SignalInfo("on_interstitial_loaded"));
84 | signals.add(new SignalInfo("on_interstitial_failed_to_load", Integer.class));
85 | signals.add(new SignalInfo("on_interstitial_close"));
86 | signals.add(new SignalInfo("on_interstitial_opened"));
87 | signals.add(new SignalInfo("on_interstitial_clicked"));
88 | signals.add(new SignalInfo("on_interstitial_impression"));
89 |
90 | signals.add(new SignalInfo("on_rewarded_video_ad_closed"));
91 | signals.add(new SignalInfo("on_rewarded_video_ad_failed_to_load", Integer.class));
92 | signals.add(new SignalInfo("on_rewarded_video_ad_loaded"));
93 | signals.add(new SignalInfo("on_rewarded_video_ad_opened"));
94 |
95 | signals.add(new SignalInfo("on_rewarded_interstitial_ad_loaded"));
96 | signals.add(new SignalInfo("on_rewarded_interstitial_ad_opened"));
97 | signals.add(new SignalInfo("on_rewarded_interstitial_ad_closed"));
98 | signals.add(new SignalInfo("on_rewarded_interstitial_ad_failed_to_load", Integer.class));
99 | signals.add(new SignalInfo("on_rewarded_interstitial_ad_failed_to_show", Integer.class));
100 |
101 | signals.add(new SignalInfo("on_rewarded", String.class, Integer.class));
102 | signals.add(new SignalInfo("on_rewarded_clicked"));
103 | signals.add(new SignalInfo("on_rewarded_impression"));
104 |
105 | signals.add(new SignalInfo("on_consent_info_update_success"));
106 | signals.add(
107 | new SignalInfo("on_consent_info_update_failure",
108 | Integer.class, String.class));
109 | signals.add(new SignalInfo("on_app_can_request_ads", Integer.class));
110 |
111 | return signals;
112 | }
113 |
114 | /* Init
115 | * ********************************************************************** */
116 |
117 | /**
118 | * Prepare for work with AdMob
119 | *
120 | * @param isReal Tell if the environment is for real or test
121 | */
122 | @UsedByGodot
123 | public void init(boolean isReal) {
124 | this.initWithContentRating(isReal, false, true, "");
125 | }
126 |
127 | /**
128 | * Init with content rating additional options
129 | *
130 | * @param isReal Tell if the environment is for real or test
131 | * @param isForChildDirectedTreatment Target audience is children.
132 | * @param isPersonalized If ads should be personalized or not.
133 | * GDPR compliance within the European Economic Area requires that you
134 | * disable ad personalization if the user does not wish to opt into
135 | * ad personalization.
136 | * @param maxAdContentRating must be "G", "PG", "T" or "MA"
137 | */
138 | @UsedByGodot
139 | public void initWithContentRating(
140 | boolean isReal,
141 | boolean isForChildDirectedTreatment,
142 | boolean isPersonalized,
143 | String maxAdContentRating) {
144 |
145 | this.isReal = isReal;
146 | this.isForChildDirectedTreatment = isForChildDirectedTreatment;
147 | this.isPersonalized = isPersonalized;
148 | this.maxAdContentRating = maxAdContentRating;
149 |
150 | this.setRequestConfigurations();
151 |
152 | if (!isPersonalized) {
153 | // https://developers.google.com/admob/android/eu-consent#forward_consent_to_the_google_mobile_ads_sdk
154 | if (extras == null) {
155 | extras = new Bundle();
156 | }
157 | extras.putString("npa", "1");
158 | }
159 |
160 | Log.d("godot", "AdMob: init with content rating options");
161 | }
162 |
163 |
164 | private void setRequestConfigurations() {
165 | if (!this.isReal) {
166 | List testDeviceIds = Arrays.asList(AdRequest.DEVICE_ID_EMULATOR, getAdMobDeviceId());
167 | RequestConfiguration requestConfiguration = MobileAds.getRequestConfiguration()
168 | .toBuilder()
169 | .setTestDeviceIds(testDeviceIds)
170 | .build();
171 | MobileAds.setRequestConfiguration(requestConfiguration);
172 | }
173 |
174 | if (this.isForChildDirectedTreatment) {
175 | RequestConfiguration requestConfiguration = MobileAds.getRequestConfiguration()
176 | .toBuilder()
177 | .setTagForChildDirectedTreatment(TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE)
178 | .build();
179 | MobileAds.setRequestConfiguration(requestConfiguration);
180 | }
181 |
182 | // StringEquality false positive
183 | //noinspection StringEquality
184 | if (this.maxAdContentRating != null && this.maxAdContentRating != "") {
185 | RequestConfiguration requestConfiguration = MobileAds.getRequestConfiguration()
186 | .toBuilder()
187 | .setMaxAdContentRating(this.maxAdContentRating)
188 | .build();
189 | MobileAds.setRequestConfiguration(requestConfiguration);
190 | }
191 | }
192 |
193 |
194 | /**
195 | * Returns AdRequest object constructed considering the extras.
196 | *
197 | * @return AdRequest object
198 | */
199 | private AdRequest getAdRequest() {
200 | AdRequest.Builder adBuilder = new AdRequest.Builder();
201 | AdRequest adRequest;
202 | if (!this.isForChildDirectedTreatment && extras != null) {
203 | adBuilder.addNetworkExtrasBundle(AdMobAdapter.class, extras);
204 | }
205 |
206 | adRequest = adBuilder.build();
207 | return adRequest;
208 | }
209 |
210 | /**
211 | * To Initializes AdMob on a background thread to improve performance.
212 | */
213 | @UsedByGodot
214 | public void initializeOnBackgroundThread() {
215 | new Thread(() -> {
216 | MobileAds.initialize(activity, new OnInitializationCompleteListener() {
217 | @Override
218 | public void onInitializationComplete(InitializationStatus initializationStatus) {
219 | emitSignal("on_admob_initialized");
220 | }
221 | });
222 | }).start();
223 | }
224 |
225 | /* Rewarded Video
226 | * ********************************************************************** */
227 |
228 | /**
229 | * Load a Rewarded Video
230 | *
231 | * @param id AdMod Rewarded video ID
232 | */
233 | @UsedByGodot
234 | public void loadRewardedVideo(final String id) {
235 | activity.runOnUiThread(() -> {
236 | rewardedVideo = new RewardedVideo(activity, new RewardedVideoListener() {
237 | @Override
238 | public void onRewardedVideoLoaded() {
239 | emitSignal("on_rewarded_video_ad_loaded");
240 | }
241 |
242 | @Override
243 | public void onRewardedVideoFailedToLoad(int errorCode) {
244 | emitSignal("on_rewarded_video_ad_failed_to_load", errorCode);
245 | }
246 |
247 | @Override
248 | public void onRewardedVideoOpened() {
249 | emitSignal("on_rewarded_video_ad_opened");
250 | }
251 |
252 | @Override
253 | public void onRewardedVideoClosed() {
254 | emitSignal("on_rewarded_video_ad_closed");
255 | }
256 |
257 | @Override
258 | public void onRewarded(String type, int amount) {
259 | emitSignal("on_rewarded", type, amount);
260 | }
261 |
262 | @Override
263 | public void onRewardedClicked() {
264 | emitSignal("on_rewarded_clicked");
265 | }
266 |
267 | @Override
268 | public void onRewardedAdImpression() {
269 | emitSignal("on_rewarded_impression");
270 | }
271 | });
272 | rewardedVideo.load(id, getAdRequest());
273 | });
274 | }
275 |
276 | /**
277 | * Show a Rewarded Video
278 | */
279 | @UsedByGodot
280 | public void showRewardedVideo() {
281 | activity.runOnUiThread(() -> {
282 | if (rewardedVideo == null) {
283 | return;
284 | }
285 | rewardedVideo.show();
286 | });
287 | }
288 |
289 | /* Rewarded Interstitial
290 | * ********************************************************************** */
291 |
292 | /**
293 | * Load a Rewarded Interstitial
294 | *
295 | * @param id AdMod Rewarded interstitial ID
296 | */
297 | @UsedByGodot
298 | public void loadRewardedInterstitial(final String id) {
299 | activity.runOnUiThread(() -> {
300 | rewardedInterstitial = new RewardedInterstitial(activity, new RewardedInterstitialListener() {
301 | @Override
302 | public void onRewardedInterstitialLoaded() {
303 | emitSignal("on_rewarded_interstitial_ad_loaded");
304 | }
305 |
306 | @Override
307 | public void onRewardedInterstitialOpened() {
308 | emitSignal("on_rewarded_interstitial_ad_opened");
309 | }
310 |
311 | @Override
312 | public void onRewardedInterstitialClosed() {
313 | emitSignal("on_rewarded_interstitial_ad_closed");
314 | }
315 |
316 | @Override
317 | public void onRewardedInterstitialFailedToLoad(int errorCode) {
318 | emitSignal("on_rewarded_interstitial_ad_failed_to_load", errorCode);
319 | }
320 |
321 | @Override
322 | public void onRewardedInterstitialFailedToShow(int errorCode) {
323 | emitSignal("on_rewarded_interstitial_ad_failed_to_show", errorCode);
324 | }
325 |
326 | @Override
327 | public void onRewarded(String type, int amount) {
328 | emitSignal("on_rewarded", type, amount);
329 | }
330 |
331 | @Override
332 | public void onRewardedClicked() {
333 | emitSignal("on_rewarded_clicked");
334 | }
335 |
336 | @Override
337 | public void onRewardedAdImpression() {
338 | emitSignal("on_rewarded_impression");
339 | }
340 | });
341 | rewardedInterstitial.load(id, getAdRequest());
342 | });
343 | }
344 |
345 | /**
346 | * Show a Rewarded Interstitial
347 | */
348 | @UsedByGodot
349 | public void showRewardedInterstitial() {
350 | activity.runOnUiThread(() -> {
351 | if (rewardedInterstitial == null) {
352 | return;
353 | }
354 | rewardedInterstitial.show();
355 | });
356 | }
357 |
358 |
359 | /* Banner
360 | * ********************************************************************** */
361 |
362 | /**
363 | * Load a banner
364 | *
365 | * @param id AdMod Banner ID
366 | * @param isOnTop To made the banner top or bottom
367 | */
368 | @UsedByGodot
369 | public void loadBanner(final String id, final boolean isOnTop, final String bannerSize) {
370 | activity.runOnUiThread(() -> {
371 | if (banner != null) banner.remove();
372 | banner = new Banner(id, getAdRequest(), activity, new BannerListener() {
373 | @Override
374 | public void onBannerLoaded() {
375 | emitSignal("on_admob_ad_loaded");
376 | }
377 |
378 | @Override
379 | public void onBannerFailedToLoad(int errorCode) {
380 | emitSignal("on_admob_banner_failed_to_load", errorCode);
381 | }
382 | }, isOnTop, layout, bannerSize);
383 | });
384 | }
385 |
386 | /**
387 | * Show the banner
388 | */
389 | @UsedByGodot
390 | public void showBanner() {
391 | activity.runOnUiThread(() -> {
392 | if (banner != null) {
393 | banner.show();
394 | }
395 | });
396 | }
397 |
398 | /**
399 | * Resize the banner
400 | * @param isOnTop To made the banner top or bottom
401 | */
402 | @UsedByGodot
403 | public void move(final boolean isOnTop) {
404 | activity.runOnUiThread(() -> {
405 | if (banner != null) {
406 | banner.move(isOnTop);
407 | }
408 | });
409 | }
410 |
411 | /**
412 | * Resize the banner
413 | */
414 | @UsedByGodot
415 | public void resize() {
416 | activity.runOnUiThread(() -> {
417 | if (banner != null) {
418 | banner.resize();
419 | }
420 | });
421 | }
422 |
423 |
424 | /**
425 | * Hide the banner
426 | */
427 | @UsedByGodot
428 | public void hideBanner() {
429 | activity.runOnUiThread(() -> {
430 | if (banner != null) {
431 | banner.hide();
432 | }
433 | });
434 | }
435 |
436 | /**
437 | * Get the banner width
438 | *
439 | * @return int Banner width
440 | */
441 | @UsedByGodot
442 | public int getBannerWidth() {
443 | if (banner != null) {
444 | return banner.getWidth();
445 | }
446 | return 0;
447 | }
448 |
449 | /**
450 | * Get the banner height
451 | *
452 | * @return int Banner height
453 | */
454 | @UsedByGodot
455 | public int getBannerHeight() {
456 | if (banner != null) {
457 | return banner.getHeight();
458 | }
459 | return 0;
460 | }
461 |
462 | /* Interstitial
463 | * ********************************************************************** */
464 |
465 | /**
466 | * Load a interstitial
467 | *
468 | * @param id AdMod Interstitial ID
469 | */
470 | @UsedByGodot
471 | public void loadInterstitial(final String id) {
472 | activity.runOnUiThread(() -> interstitial = new Interstitial(id, getAdRequest(), activity, new InterstitialListener() {
473 | @Override
474 | public void onInterstitialLoaded() {
475 | emitSignal("on_interstitial_loaded");
476 | }
477 |
478 | @Override
479 | public void onInterstitialFailedToLoad(int errorCode) {
480 | emitSignal("on_interstitial_failed_to_load", errorCode);
481 | }
482 |
483 | @Override
484 | public void onInterstitialOpened() {
485 | // Not Implemented
486 | emitSignal("on_interstitial_opened");
487 | }
488 |
489 | @Override
490 | public void onInterstitialClosed() {
491 | emitSignal("on_interstitial_close");
492 | }
493 |
494 | @Override
495 | public void onInterstitialClicked() {
496 | emitSignal("on_interstitial_clicked");
497 | }
498 |
499 | @Override
500 | public void onInterstitialImpression() {
501 | emitSignal("on_interstitial_impression");
502 | }
503 | }));
504 | }
505 |
506 | /**
507 | * Show the interstitial
508 | */
509 | @UsedByGodot
510 | public void showInterstitial() {
511 | activity.runOnUiThread(() -> {
512 | if (interstitial != null) {
513 | interstitial.show();
514 | }
515 | });
516 | }
517 |
518 | /* ConsentInformation
519 | * ********************************************************************** */
520 | @UsedByGodot
521 | public void requestConsentInfoUpdate(final boolean testingConsent){
522 |
523 | activity.runOnUiThread(() -> cmp = new CMP(activity,
524 | testingConsent,
525 | testingConsent ? getAdMobDeviceId() : "",
526 | new CMPListener() {
527 | @Override
528 | public void onConsentInfoUpdateSuccess() {
529 | emitSignal("on_consent_info_update_success");
530 | }
531 |
532 | @Override
533 | public void onConsentInfoUpdateFailure(int errorCode, String errorMessage) {
534 | emitSignal("on_consent_info_update_failure", errorCode, errorMessage);
535 | }
536 |
537 | @Override
538 | public void onAppCanRequestAds(int consentStatus) {
539 | emitSignal("on_app_can_request_ads", consentStatus);
540 | }
541 | }));
542 | }
543 |
544 | @UsedByGodot
545 | public void resetConsentInformation(){
546 | Log.w("godot", "Removing consent: ");
547 | if(cmp != null) {
548 | cmp.resetConsentInformation();
549 | }
550 | }
551 |
552 | /* Utils
553 | * ********************************************************************** */
554 |
555 | /**
556 | * Generate MD5 for the deviceID
557 | *
558 | * @param s The string to generate de MD5
559 | * @return String The MD5 generated
560 | */
561 | private String md5(final String s) {
562 | try {
563 | // Create MD5 Hash
564 | MessageDigest digest = MessageDigest.getInstance("MD5");
565 | digest.update(s.getBytes());
566 | byte[] messageDigest = digest.digest();
567 |
568 | // Create Hex String
569 | StringBuilder hexString = new StringBuilder();
570 | for (int i = 0; i < messageDigest.length; i++) {
571 | String h = Integer.toHexString(0xFF & messageDigest[i]);
572 | while (h.length() < 2) h = "0" + h;
573 | hexString.append(h);
574 | }
575 | return hexString.toString();
576 | } catch (NoSuchAlgorithmException e) {
577 | //Logger.logStackTrace(TAG,e);
578 | }
579 | return "";
580 | }
581 |
582 | /**
583 | * Get the Device ID for AdMob
584 | *
585 | * @return String Device ID
586 | */
587 | private String getAdMobDeviceId() {
588 | @SuppressLint("HardwareIds") String android_id = Settings.Secure.getString(activity.getContentResolver(), Settings.Secure.ANDROID_ID);
589 | String deviceId = md5(android_id).toUpperCase(Locale.US);
590 | return deviceId;
591 | }
592 |
593 | }
594 |
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/java/shinnil/godot/plugin/android/godotadmob/GodotRewardedVideo.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 |
6 | import androidx.annotation.NonNull;
7 |
8 | import com.google.android.gms.ads.AdError;
9 | import com.google.android.gms.ads.AdRequest;
10 | import com.google.android.gms.ads.FullScreenContentCallback;
11 | import com.google.android.gms.ads.LoadAdError;
12 | import com.google.android.gms.ads.MobileAds;
13 | import com.google.android.gms.ads.rewarded.RewardedAd;
14 | import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback;
15 |
16 | import org.godotengine.godot.GodotLib;
17 |
18 |
19 | public class GodotRewardedVideo {
20 | private RewardedAd rewardedAd = null;
21 | private int instanceId;
22 | private Activity activity;
23 |
24 | public void init(Activity activity, final int instanceId) {
25 | this.activity = activity;
26 | this.instanceId = instanceId;
27 | MobileAds.initialize(activity);
28 | }
29 |
30 | public boolean isLoaded() {
31 | return rewardedAd != null;
32 | }
33 |
34 | public void load(final String id, AdRequest adRequest) {
35 |
36 | RewardedAd.load(activity, id, adRequest, new RewardedAdLoadCallback() {
37 | @Override
38 | public void onAdLoaded(@NonNull RewardedAd rewardedAd) {
39 | super.onAdLoaded(rewardedAd);
40 | setAd(rewardedAd);
41 | Log.w("godot", "AdMob: onAdLoaded");
42 | GodotLib.calldeferred(instanceId, "_on_rewarded_video_ad_loaded", new Object[]{});
43 | }
44 |
45 | @Override
46 | public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
47 | super.onAdFailedToLoad(loadAdError);
48 | // safety
49 | setAd(null);
50 | Log.w("godot", "AdMob: onAdFailedToLoad. errorCode: " + loadAdError.getCode());
51 | GodotLib.calldeferred(instanceId, "_on_rewarded_video_ad_failed_to_load", new Object[]{loadAdError.getCode()});
52 | }
53 | });
54 | }
55 |
56 | public void show() {
57 | if (rewardedAd != null) {
58 | rewardedAd.show(activity, rewardItem -> {
59 | Log.w("godot", "AdMob: "
60 | + String.format(" onRewarded! currency: %s amount: %d", rewardItem.getType(), rewardItem.getAmount()));
61 | GodotLib.calldeferred(instanceId, "_on_rewarded",
62 | new Object[]{rewardItem.getType(), rewardItem.getAmount()});
63 | });
64 | }
65 | }
66 |
67 | private void setAd(RewardedAd rewardedAd) {
68 | // Avoid memory leaks.
69 | if (this.rewardedAd != null)
70 | this.rewardedAd.setFullScreenContentCallback(null);
71 | if (rewardedAd != null) {
72 | rewardedAd.setFullScreenContentCallback(new FullScreenContentCallback() {
73 | @Override
74 | public void onAdClicked() {
75 | super.onAdClicked();
76 | Log.w("godot", "AdMob: onAdClicked");
77 | GodotLib.calldeferred(instanceId, "_on_rewarded_clicked", new Object[]{});
78 | }
79 |
80 | @Override
81 | public void onAdDismissedFullScreenContent() {
82 | super.onAdDismissedFullScreenContent();
83 | // TODO: Test if new video ads are loaded
84 | // setAd(null);
85 | // RewardedAd.load(activity, id, adRequest, rewardedAdLoadCallback);
86 | Log.w("godot", "AdMob: onAdDismissedFullScreenContent");
87 | GodotLib.calldeferred(instanceId, "_on_rewarded_video_ad_closed", new Object[]{});
88 | }
89 |
90 | @Override
91 | public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
92 | super.onAdFailedToShowFullScreenContent(adError);
93 | Log.w("godot", "AdMob: onAdFailedToShowFullScreenContent");
94 | GodotLib.calldeferred(instanceId, "_on_rewarded_video_ad_failed_to_load", new Object[]{adError.getCode()});
95 | }
96 |
97 | @Override
98 | public void onAdImpression() {
99 | super.onAdImpression();
100 | Log.w("godot", "AdMob: onAdImpression");
101 | GodotLib.calldeferred(instanceId, "_on_rewarded_impression", new Object[]{});
102 | }
103 |
104 | @Override
105 | public void onAdShowedFullScreenContent() {
106 | super.onAdShowedFullScreenContent();
107 | Log.w("godot", "AdMob: onAdShowedFullScreenContent");
108 | GodotLib.calldeferred(instanceId, "_on_rewarded_video_ad_opened", new Object[]{});
109 | }
110 | });
111 | }
112 | this.rewardedAd = rewardedAd;
113 | }
114 | }
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/java/shinnil/godot/plugin/android/godotadmob/Interstitial.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 |
6 | import androidx.annotation.NonNull;
7 |
8 | import com.google.android.gms.ads.AdError;
9 | import com.google.android.gms.ads.AdRequest;
10 | import com.google.android.gms.ads.FullScreenContentCallback;
11 | import com.google.android.gms.ads.LoadAdError;
12 | import com.google.android.gms.ads.interstitial.InterstitialAd;
13 | import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback;
14 |
15 | interface InterstitialListener {
16 | void onInterstitialLoaded();
17 | void onInterstitialFailedToLoad(int errorCode);
18 | void onInterstitialOpened();
19 | void onInterstitialClosed();
20 | // new
21 | void onInterstitialClicked();
22 | void onInterstitialImpression();
23 | }
24 |
25 | public class Interstitial {
26 | private final String id;
27 | private final AdRequest adRequest;
28 | private InterstitialAd interstitialAd = null; // Interstitial object
29 | private final Activity activity;
30 | private final InterstitialListener defaultInterstitialListener;
31 |
32 | public Interstitial(final String id, final AdRequest adRequest, final Activity activity, final InterstitialListener defaultInterstitialListener) {
33 | this.activity = activity;
34 | this.id = id;
35 | this.adRequest = adRequest;
36 | this.defaultInterstitialListener = defaultInterstitialListener;
37 | load();
38 | }
39 |
40 | public void show() {
41 | if (interstitialAd != null) {
42 | interstitialAd.show(activity);
43 | } else {
44 | Log.w("w", "AdMob: showInterstitial - interstitial not loaded");
45 | }
46 | }
47 |
48 | public boolean isLoaded() {
49 | return interstitialAd != null;
50 | }
51 |
52 | private void setAd(InterstitialAd interstitialAd) {
53 | if (interstitialAd == this.interstitialAd)
54 | return;
55 | // Avoid memory leaks
56 | if (this.interstitialAd != null) {
57 | this.interstitialAd.setFullScreenContentCallback(null);
58 | this.interstitialAd.setOnPaidEventListener(null);
59 | }
60 | if (interstitialAd != null) {
61 | interstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() {
62 | @Override
63 | public void onAdClicked() {
64 | super.onAdClicked();
65 | Log.w("godot", "AdMob: onAdClicked()");
66 | defaultInterstitialListener.onInterstitialClicked();
67 | }
68 |
69 | @Override
70 | public void onAdDismissedFullScreenContent() {
71 | super.onAdDismissedFullScreenContent();
72 | // TODO: Test if new video ads are loaded
73 | setAd(null);
74 | Log.w("godot", "AdMob: onAdDismissedFullScreenContent");
75 | defaultInterstitialListener.onInterstitialClosed();
76 | load();
77 | }
78 |
79 | @Override
80 | public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
81 | super.onAdFailedToShowFullScreenContent(adError);
82 | Log.w("godot", "AdMob: onAdFailedToShowFullScreenContent");
83 | defaultInterstitialListener.onInterstitialFailedToLoad(adError.getCode());
84 | }
85 |
86 | @Override
87 | public void onAdShowedFullScreenContent() {
88 | super.onAdShowedFullScreenContent();
89 | Log.w("godot", "AdMob: onAdShowedFullScreenContent");
90 | defaultInterstitialListener.onInterstitialOpened();
91 | }
92 |
93 | @Override
94 | public void onAdImpression() {
95 | super.onAdImpression();
96 | Log.w("godot", "AdMob: onAdImpression");
97 | defaultInterstitialListener.onInterstitialImpression();
98 | }
99 | });
100 | }
101 | this.interstitialAd = interstitialAd;
102 | }
103 |
104 | private void load() {
105 | InterstitialAd.load(activity, id, adRequest, new InterstitialAdLoadCallback() {
106 | @Override
107 | public void onAdLoaded(@NonNull InterstitialAd interstitialAd) {
108 | super.onAdLoaded(interstitialAd);
109 | setAd(interstitialAd);
110 | Log.w("godot", "AdMob: onAdLoaded: interstitial");
111 | defaultInterstitialListener.onInterstitialLoaded();
112 | }
113 |
114 | @Override
115 | public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
116 | super.onAdFailedToLoad(loadAdError);
117 | // safety
118 | setAd(null);
119 | Log.w("godot", "AdMob: onAdFailedToLoad(int errorCode) - error code: " + loadAdError.getCode());
120 | defaultInterstitialListener.onInterstitialFailedToLoad(loadAdError.getCode());
121 | }
122 | });
123 | }
124 | }
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/java/shinnil/godot/plugin/android/godotadmob/RewardedInterstitial.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 |
6 | import androidx.annotation.NonNull;
7 |
8 | import com.google.android.gms.ads.AdError;
9 | import com.google.android.gms.ads.AdRequest;
10 | import com.google.android.gms.ads.FullScreenContentCallback;
11 | import com.google.android.gms.ads.LoadAdError;
12 | import com.google.android.gms.ads.MobileAds;
13 | import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd;
14 | import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback;
15 |
16 | interface RewardedInterstitialListener {
17 | void onRewardedInterstitialLoaded();
18 | void onRewardedInterstitialOpened();
19 | void onRewardedInterstitialClosed();
20 | void onRewardedInterstitialFailedToLoad(int errorCode);
21 | void onRewardedInterstitialFailedToShow(int errorCode);
22 | void onRewarded(String type, int amount);
23 | void onRewardedClicked();
24 | void onRewardedAdImpression();
25 | }
26 |
27 | public class RewardedInterstitial {
28 | private RewardedInterstitialAd rewardedAd = null;
29 | private final Activity activity;
30 | private final RewardedInterstitialListener defaultRewardedInterstitialListener;
31 |
32 | public RewardedInterstitial(Activity activity, final RewardedInterstitialListener defaultRewardedInterstitialListener) {
33 | this.activity = activity;
34 | this.defaultRewardedInterstitialListener = defaultRewardedInterstitialListener;
35 | MobileAds.initialize(activity);
36 | }
37 |
38 | public boolean isLoaded() {
39 | return rewardedAd != null;
40 | }
41 |
42 | public void load(final String id, AdRequest adRequest) {
43 |
44 | RewardedInterstitialAd.load(activity, id, adRequest, new RewardedInterstitialAdLoadCallback() {
45 | @Override
46 | public void onAdLoaded(@NonNull RewardedInterstitialAd rewardedAd) {
47 | super.onAdLoaded(rewardedAd);
48 | setAd(rewardedAd);
49 | Log.w("godot", "AdMob: onAdLoaded: rewarded interstitial");
50 | defaultRewardedInterstitialListener.onRewardedInterstitialLoaded();
51 | }
52 |
53 | @Override
54 | public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
55 | super.onAdFailedToLoad(loadAdError);
56 | // safety
57 | setAd(null);
58 | Log.w("godot", "AdMob: onAdFailedToLoad. errorCode: " + loadAdError.getCode());
59 | defaultRewardedInterstitialListener.onRewardedInterstitialFailedToLoad(loadAdError.getCode());
60 | }
61 | });
62 | }
63 |
64 | public void show() {
65 | if (rewardedAd != null) {
66 | rewardedAd.show(activity, rewardItem -> {
67 | Log.w("godot", "AdMob: "
68 | + String.format(" onRewarded! currency: %s amount: %d", rewardItem.getType(), rewardItem.getAmount()));
69 | defaultRewardedInterstitialListener.onRewarded(rewardItem.getType(), rewardItem.getAmount());
70 | });
71 | }
72 | }
73 |
74 | private void setAd(RewardedInterstitialAd rewardedAd) {
75 | // Avoid memory leaks.
76 | if (this.rewardedAd != null)
77 | this.rewardedAd.setFullScreenContentCallback(null);
78 | if (rewardedAd != null) {
79 | rewardedAd.setFullScreenContentCallback(new FullScreenContentCallback() {
80 | @Override
81 | public void onAdClicked() {
82 | super.onAdClicked();
83 | Log.w("godot", "AdMob: onAdClicked");
84 | defaultRewardedInterstitialListener.onRewardedClicked();
85 | }
86 |
87 | @Override
88 | public void onAdDismissedFullScreenContent() {
89 | super.onAdDismissedFullScreenContent();
90 | // TODO: Test if new video ads are loaded
91 | // setAd(null);
92 | // RewardedAd.load(activity, id, adRequest, rewardedAdLoadCallback);
93 | Log.w("godot", "AdMob: onAdDismissedFullScreenContent");
94 | defaultRewardedInterstitialListener.onRewardedInterstitialClosed();
95 | }
96 |
97 | @Override
98 | public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
99 | super.onAdFailedToShowFullScreenContent(adError);
100 | Log.w("godot", "AdMob: onAdFailedToShowFullScreenContent");
101 | defaultRewardedInterstitialListener.onRewardedInterstitialFailedToShow(adError.getCode());
102 | }
103 |
104 | @Override
105 | public void onAdImpression() {
106 | super.onAdImpression();
107 | Log.w("godot", "AdMob: onAdImpression");
108 | defaultRewardedInterstitialListener.onRewardedAdImpression();
109 | }
110 |
111 | @Override
112 | public void onAdShowedFullScreenContent() {
113 | super.onAdShowedFullScreenContent();
114 | Log.w("godot", "AdMob: onAdShowedFullScreenContent");
115 | defaultRewardedInterstitialListener.onRewardedInterstitialOpened();
116 | }
117 | });
118 | }
119 | this.rewardedAd = rewardedAd;
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/main/java/shinnil/godot/plugin/android/godotadmob/RewardedVideo.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 |
6 | import androidx.annotation.NonNull;
7 |
8 | import com.google.android.gms.ads.AdError;
9 | import com.google.android.gms.ads.AdRequest;
10 | import com.google.android.gms.ads.FullScreenContentCallback;
11 | import com.google.android.gms.ads.LoadAdError;
12 | import com.google.android.gms.ads.MobileAds;
13 | import com.google.android.gms.ads.rewarded.RewardedAd;
14 | import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback;
15 |
16 | interface RewardedVideoListener {
17 | void onRewardedVideoLoaded();
18 | void onRewardedVideoFailedToLoad(int errorCode);
19 | void onRewardedVideoOpened();
20 | void onRewardedVideoClosed();
21 | void onRewarded(String type, int amount);
22 | /* Removed in GMS Ads SDK version 19 or 20.
23 | void onRewardedVideoStarted();
24 | void onRewardedVideoCompleted();
25 | */
26 | // new
27 | void onRewardedClicked();
28 | void onRewardedAdImpression();
29 | }
30 |
31 | public class RewardedVideo {
32 | private RewardedAd rewardedAd = null;
33 | private final Activity activity;
34 | private final RewardedVideoListener defaultRewardedVideoListener;
35 |
36 | public RewardedVideo(Activity activity, final RewardedVideoListener defaultRewardedVideoListener) {
37 | this.activity = activity;
38 | this.defaultRewardedVideoListener = defaultRewardedVideoListener;
39 | MobileAds.initialize(activity);
40 | }
41 |
42 | public boolean isLoaded() {
43 | return rewardedAd != null;
44 | }
45 |
46 | public void load(final String id, AdRequest adRequest) {
47 |
48 | RewardedAd.load(activity, id, adRequest, new RewardedAdLoadCallback() {
49 | @Override
50 | public void onAdLoaded(@NonNull RewardedAd rewardedAd) {
51 | super.onAdLoaded(rewardedAd);
52 | setAd(rewardedAd);
53 | Log.w("godot", "AdMob: onAdLoaded: rewarded video");
54 | defaultRewardedVideoListener.onRewardedVideoLoaded();
55 | }
56 |
57 | @Override
58 | public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
59 | super.onAdFailedToLoad(loadAdError);
60 | // safety
61 | setAd(null);
62 | Log.w("godot", "AdMob: onAdFailedToLoad. errorCode: " + loadAdError.getCode());
63 | defaultRewardedVideoListener.onRewardedVideoFailedToLoad(loadAdError.getCode());
64 | }
65 | });
66 | }
67 |
68 | public void show() {
69 | if (rewardedAd != null) {
70 | rewardedAd.show(activity, rewardItem -> {
71 | Log.w("godot", "AdMob: "
72 | + String.format(" onRewarded! currency: %s amount: %d", rewardItem.getType(), rewardItem.getAmount()));
73 | defaultRewardedVideoListener.onRewarded(rewardItem.getType(), rewardItem.getAmount());
74 | });
75 | }
76 | }
77 |
78 | private void setAd(RewardedAd rewardedAd) {
79 | // Avoid memory leaks.
80 | if (this.rewardedAd != null)
81 | this.rewardedAd.setFullScreenContentCallback(null);
82 | if (rewardedAd != null) {
83 | rewardedAd.setFullScreenContentCallback(new FullScreenContentCallback() {
84 | @Override
85 | public void onAdClicked() {
86 | super.onAdClicked();
87 | Log.w("godot", "AdMob: onAdClicked");
88 | defaultRewardedVideoListener.onRewardedClicked();
89 | }
90 |
91 | @Override
92 | public void onAdDismissedFullScreenContent() {
93 | super.onAdDismissedFullScreenContent();
94 | // TODO: Test if new video ads are loaded
95 | // setAd(null);
96 | // RewardedAd.load(activity, id, adRequest, rewardedAdLoadCallback);
97 | Log.w("godot", "AdMob: onAdDismissedFullScreenContent");
98 | defaultRewardedVideoListener.onRewardedVideoClosed();
99 | }
100 |
101 | @Override
102 | public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
103 | super.onAdFailedToShowFullScreenContent(adError);
104 | Log.w("godot", "AdMob: onAdFailedToShowFullScreenContent");
105 | defaultRewardedVideoListener.onRewardedVideoFailedToLoad(adError.getCode());
106 | }
107 |
108 | @Override
109 | public void onAdImpression() {
110 | super.onAdImpression();
111 | Log.w("godot", "AdMob: onAdImpression");
112 | defaultRewardedVideoListener.onRewardedAdImpression();
113 | }
114 |
115 | @Override
116 | public void onAdShowedFullScreenContent() {
117 | super.onAdShowedFullScreenContent();
118 | Log.w("godot", "AdMob: onAdShowedFullScreenContent");
119 | defaultRewardedVideoListener.onRewardedVideoOpened();
120 | }
121 | });
122 | }
123 | this.rewardedAd = rewardedAd;
124 | }
125 | }
--------------------------------------------------------------------------------
/admob-plugin/godotadmob/src/test/java/shinnil/godot/plugin/android/godotadmob/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package shinnil.godot.plugin.android.godotadmob;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/admob-plugin/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 |
--------------------------------------------------------------------------------
/admob-plugin/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/admob-plugin/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/admob-plugin/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/admob-plugin/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/admob-plugin/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/admob-plugin/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='GodotAdMob'
2 | include ':app', ':godot-lib.release'
3 | include ':godotadmob'
4 |
--------------------------------------------------------------------------------
/admob-plugin/version.gradle:
--------------------------------------------------------------------------------
1 | ext.pluginVersionCode = 8
2 | ext.pluginVersionName = "6.2.0"
3 | ext.playServicesAdsVersion = "22.2.0"
4 | ext.appcompatVersion = "1.5.1"
5 |
--------------------------------------------------------------------------------
/config/GodotAdMob.gdap:
--------------------------------------------------------------------------------
1 | [config]
2 |
3 | name="GodotAdMob"
4 | binary_type="local"
5 | binary="GodotAdMob.6.2.0.release.aar"
6 |
7 | [dependencies]
8 |
9 | remote=["com.google.android.gms:play-services-ads:22.2.0", "androidx.appcompat:appcompat:1.5.1"]
10 |
--------------------------------------------------------------------------------
/demo/admob-lib/admob.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | class_name AdMob, "res://admob-lib/icon.png"
4 |
5 | # signals
6 | signal banner_loaded
7 | signal banner_failed_to_load(error_code)
8 | signal interstitial_failed_to_load(error_code)
9 | signal interstitial_loaded
10 | signal interstitial_opened
11 | signal interstitial_closed
12 | signal interstitial_clicked
13 | signal interstitial_impression
14 | signal rewarded_video_opened
15 | signal rewarded_video_loaded
16 | signal rewarded_video_closed
17 | signal rewarded_video_failed_to_load(error_code)
18 | signal rewarded_interstitial_opened
19 | signal rewarded_interstitial_loaded
20 | signal rewarded_interstitial_closed
21 | signal rewarded_interstitial_failed_to_load(error_code)
22 | signal rewarded_interstitial_failed_to_show(error_code)
23 | signal rewarded(currency, amount)
24 | signal rewarded_clicked
25 | signal rewarded_impression
26 |
27 | signal consent_info_update_success
28 | signal consent_info_update_failure(error_code, error_message)
29 | signal consent_app_can_request_ad(consent_status)
30 |
31 |
32 | # properties
33 | export var is_real:bool setget is_real_set
34 | export var banner_on_top:bool = true
35 | # SMART_BANNER is deprecated
36 | export(String, "ADAPTIVE_BANNER", "SMART_BANNER", "BANNER", "LARGE_BANNER", "MEDIUM_RECTANGLE", "FULL_BANNER", "LEADERBOARD") var banner_size = "ADAPTIVE_BANNER"
37 | export var banner_id:String
38 | export var interstitial_id:String
39 | export var rewarded_id:String
40 | export var rewarded_interstitial_id:String
41 | export var child_directed:bool = false setget child_directed_set
42 | export var is_personalized:bool = true setget is_personalized_set
43 | export(String, "G", "PG", "T", "MA") var max_ad_content_rate = "G" setget max_ad_content_rate_set
44 |
45 | # Testing consent flag
46 | export var ads_using_consent:bool setget ads_using_consent
47 | export var testing_consent:bool setget testing_consent_set
48 |
49 |
50 | # "private" properties
51 | var _admob_singleton = null
52 | var _is_interstitial_loaded:bool = false
53 | var _is_rewarded_video_loaded:bool = false
54 | var _is_rewarded_interstitial_loaded:bool = false
55 |
56 |
57 | func _enter_tree():
58 | if not init():
59 | print("AdMob Java Singleton not found. This plugin will only work on Android")
60 |
61 | # setters
62 | func is_real_set(new_val) -> void:
63 | is_real = new_val
64 | # warning-ignore:return_value_discarded
65 | init()
66 |
67 | func testing_consent_set(new_val) -> void:
68 | testing_consent = new_val
69 |
70 | func ads_using_consent(new_val) -> void:
71 | ads_using_consent = new_val
72 |
73 | func child_directed_set(new_val) -> void:
74 | child_directed = new_val
75 | # warning-ignore:return_value_discarded
76 | init()
77 |
78 | func is_personalized_set(new_val) -> void:
79 | is_personalized = new_val
80 | # warning-ignore:return_value_discarded
81 | init()
82 |
83 | func max_ad_content_rate_set(new_val) -> void:
84 | if new_val != "G" and new_val != "PG" \
85 | and new_val != "T" and new_val != "MA":
86 |
87 | max_ad_content_rate = "G"
88 | print("Invalid max_ad_content_rate, using 'G'")
89 | else:
90 | max_ad_content_rate = new_val
91 | init()
92 |
93 |
94 | # initialization
95 | func init() -> bool:
96 | if(Engine.has_singleton("GodotAdMob")):
97 | _admob_singleton = Engine.get_singleton("GodotAdMob")
98 |
99 | # check if one signal is already connected
100 | if not _admob_singleton.is_connected("on_admob_ad_loaded", self, "_on_admob_ad_loaded"):
101 | connect_signals()
102 |
103 | _admob_singleton.initWithContentRating(
104 | is_real,
105 | child_directed,
106 | is_personalized,
107 | max_ad_content_rate
108 | )
109 | return true
110 | return false
111 |
112 | # connect the AdMob Java signals
113 | func connect_signals() -> void:
114 | _admob_singleton.connect("on_admob_ad_loaded", self, "_on_admob_ad_loaded")
115 | _admob_singleton.connect("on_admob_banner_failed_to_load", self, "_on_admob_banner_failed_to_load")
116 | _admob_singleton.connect("on_interstitial_failed_to_load", self, "_on_interstitial_failed_to_load")
117 | _admob_singleton.connect("on_interstitial_opened", self, "_on_interstitial_opened")
118 | _admob_singleton.connect("on_interstitial_loaded", self, "_on_interstitial_loaded")
119 | _admob_singleton.connect("on_interstitial_close", self, "_on_interstitial_close")
120 | _admob_singleton.connect("on_interstitial_clicked", self, "_on_interstitial_clicked")
121 | _admob_singleton.connect("on_interstitial_impression", self, "_on_interstitial_impression")
122 | _admob_singleton.connect("on_rewarded_video_ad_loaded", self, "_on_rewarded_video_ad_loaded")
123 | _admob_singleton.connect("on_rewarded_video_ad_opened", self, "_on_rewarded_video_ad_opened")
124 | _admob_singleton.connect("on_rewarded_video_ad_closed", self, "_on_rewarded_video_ad_closed")
125 | _admob_singleton.connect("on_rewarded_video_ad_failed_to_load", self, "_on_rewarded_video_ad_failed_to_load")
126 | _admob_singleton.connect("on_rewarded_interstitial_ad_loaded", self, "_on_rewarded_interstitial_ad_loaded")
127 | _admob_singleton.connect("on_rewarded_interstitial_ad_opened", self, "_on_rewarded_interstitial_ad_opened")
128 | _admob_singleton.connect("on_rewarded_interstitial_ad_closed", self, "_on_rewarded_interstitial_ad_closed")
129 | _admob_singleton.connect("on_rewarded_interstitial_ad_failed_to_load", self, "_on_rewarded_interstitial_ad_failed_to_load")
130 | _admob_singleton.connect("on_rewarded_interstitial_ad_failed_to_show", self, "_on_rewarded_interstitial_ad_failed_to_show")
131 | _admob_singleton.connect("on_rewarded", self, "_on_rewarded")
132 | _admob_singleton.connect("on_rewarded_clicked", self, "_on_rewarded_clicked")
133 | _admob_singleton.connect("on_rewarded_impression", self, "_on_rewarded_impression")
134 |
135 | _admob_singleton.connect("on_consent_info_update_success", self, "_on_consent_info_update_success")
136 | _admob_singleton.connect("on_consent_info_update_failure", self, "_on_consent_info_update_failure")
137 | _admob_singleton.connect("on_app_can_request_ads", self, "_on_app_can_request_ads")
138 |
139 | # load
140 |
141 | func load_banner() -> void:
142 | if _admob_singleton != null:
143 | _admob_singleton.loadBanner(banner_id, banner_on_top, banner_size)
144 |
145 | func load_interstitial() -> void:
146 | if _admob_singleton != null:
147 | _admob_singleton.loadInterstitial(interstitial_id)
148 |
149 | func is_interstitial_loaded() -> bool:
150 | if _admob_singleton != null:
151 | return _is_interstitial_loaded
152 | return false
153 |
154 | func load_rewarded_video() -> void:
155 | if _admob_singleton != null:
156 | _admob_singleton.loadRewardedVideo(rewarded_id)
157 |
158 | func is_rewarded_video_loaded() -> bool:
159 | if _admob_singleton != null:
160 | return _is_rewarded_video_loaded
161 | return false
162 |
163 | func load_rewarded_interstitial() -> void:
164 | if _admob_singleton != null:
165 | _admob_singleton.loadRewardedInterstitial(rewarded_interstitial_id)
166 |
167 | func is_rewarded_interstitial_loaded() -> bool:
168 | if _admob_singleton != null:
169 | return _is_rewarded_interstitial_loaded
170 | return false
171 |
172 | # show / hide
173 |
174 | func show_banner() -> void:
175 | if _admob_singleton != null:
176 | _admob_singleton.showBanner()
177 |
178 | func hide_banner() -> void:
179 | if _admob_singleton != null:
180 | _admob_singleton.hideBanner()
181 |
182 | func move_banner(on_top: bool) -> void:
183 | if _admob_singleton != null:
184 | banner_on_top = on_top
185 | _admob_singleton.move(banner_on_top)
186 |
187 | func show_interstitial() -> void:
188 | if _admob_singleton != null:
189 | _admob_singleton.showInterstitial()
190 | _is_interstitial_loaded = false
191 |
192 | func show_rewarded_video() -> void:
193 | if _admob_singleton != null:
194 | _admob_singleton.showRewardedVideo()
195 | _is_rewarded_video_loaded = false
196 |
197 | func show_rewarded_interstitial() -> void:
198 | if _admob_singleton != null:
199 | _admob_singleton.showRewardedInterstitial()
200 | _is_rewarded_interstitial_loaded = false
201 |
202 | # resize
203 |
204 | func banner_resize() -> void:
205 | if _admob_singleton != null:
206 | _admob_singleton.resize()
207 |
208 | # dimension
209 | func get_banner_dimension() -> Vector2:
210 | if _admob_singleton != null:
211 | return Vector2(_admob_singleton.getBannerWidth(), _admob_singleton.getBannerHeight())
212 | return Vector2()
213 |
214 | func request_consent_info_update() -> void:
215 | if _admob_singleton != null:
216 | _admob_singleton.requestConsentInfoUpdate(testing_consent)
217 |
218 | func reset_consent() -> void:
219 | if _admob_singleton != null:
220 | _admob_singleton.resetConsentInformation()
221 |
222 | # callbacks
223 |
224 | func _on_admob_ad_loaded() -> void:
225 | emit_signal("banner_loaded")
226 |
227 | func _on_admob_banner_failed_to_load(error_code:int) -> void:
228 | emit_signal("banner_failed_to_load", error_code)
229 |
230 | func _on_interstitial_failed_to_load(error_code:int) -> void:
231 | _is_interstitial_loaded = false
232 | emit_signal("interstitial_failed_to_load", error_code)
233 |
234 | func _on_interstitial_opened() -> void:
235 | emit_signal("interstitial_opened")
236 |
237 | func _on_interstitial_loaded() -> void:
238 | _is_interstitial_loaded = true
239 | emit_signal("interstitial_loaded")
240 |
241 | func _on_interstitial_close() -> void:
242 | emit_signal("interstitial_closed")
243 |
244 | func _on_interstitial_clicked() -> void:
245 | emit_signal("interstitial_clicked")
246 |
247 | func _on_interstitial_impression() -> void:
248 | emit_signal("interstitial_impression")
249 |
250 | func _on_rewarded_video_ad_loaded() -> void:
251 | _is_rewarded_video_loaded = true
252 | emit_signal("rewarded_video_loaded")
253 |
254 | func _on_rewarded_video_ad_opened() -> void:
255 | emit_signal("rewarded_video_opened")
256 |
257 | func _on_rewarded_video_ad_closed() -> void:
258 | emit_signal("rewarded_video_closed")
259 |
260 | func _on_rewarded_video_ad_failed_to_load(error_code:int) -> void:
261 | _is_rewarded_video_loaded = false
262 | emit_signal("rewarded_video_failed_to_load", error_code)
263 |
264 | func _on_rewarded_interstitial_ad_opened() -> void:
265 | emit_signal("rewarded_interstitial_opened")
266 |
267 | func _on_rewarded_interstitial_ad_loaded() -> void:
268 | _is_rewarded_interstitial_loaded = true
269 | emit_signal("rewarded_interstitial_loaded")
270 |
271 | func _on_rewarded_interstitial_ad_closed() -> void:
272 | emit_signal("rewarded_interstitial_closed")
273 |
274 | func _on_rewarded_interstitial_ad_failed_to_load(error_code:int) -> void:
275 | _is_rewarded_interstitial_loaded = false
276 | emit_signal("rewarded_interstitial_failed_to_load", error_code)
277 |
278 | func _on_rewarded_interstitial_ad_failed_to_show(error_code:int) -> void:
279 | _is_rewarded_interstitial_loaded = false
280 | emit_signal("rewarded_interstitial_failed_to_show", error_code)
281 |
282 | func _on_rewarded(currency:String, amount:int) -> void:
283 | emit_signal("rewarded", currency, amount)
284 |
285 | func _on_rewarded_clicked() -> void:
286 | emit_signal("rewarded_clicked")
287 |
288 | func _on_rewarded_impression() -> void:
289 | emit_signal("rewarded_impression")
290 |
291 | func _on_consent_info_update_success() -> void:
292 | emit_signal("consent_info_update_success")
293 |
294 | func _on_consent_info_update_failure(error_code:int, error_message:String) -> void:
295 | emit_signal("consent_info_update_failure", error_code, error_message)
296 |
297 | func _on_app_can_request_ads(consent_status:int) -> void:
298 | emit_signal("consent_app_can_request_ad", consent_status)
299 |
--------------------------------------------------------------------------------
/demo/admob-lib/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/demo/admob-lib/icon.png
--------------------------------------------------------------------------------
/demo/export_presets.cfg:
--------------------------------------------------------------------------------
1 | [preset.0]
2 |
3 | name="Android"
4 | platform="Android"
5 | runnable=true
6 | custom_features=""
7 | export_filter="all_resources"
8 | include_filter=""
9 | exclude_filter=""
10 | export_path=""
11 | script_export_mode=1
12 | script_encryption_key=""
13 |
14 | [preset.0.options]
15 |
16 | custom_template/debug=""
17 | custom_template/release=""
18 | custom_build/use_custom_build=true
19 | custom_build/export_format=0
20 | custom_build/min_sdk=""
21 | custom_build/target_sdk=""
22 | plugins/GodotAdMob=true
23 | architectures/armeabi-v7a=true
24 | architectures/arm64-v8a=true
25 | architectures/x86=true
26 | architectures/x86_64=true
27 | keystore/debug=""
28 | keystore/debug_user=""
29 | keystore/debug_password=""
30 | keystore/release=""
31 | keystore/release_user=""
32 | keystore/release_password=""
33 | one_click_deploy/clear_previous_install=true
34 | version/code=1
35 | version/name="1.0"
36 | package/unique_name="org.godotengine.$genname"
37 | package/name=""
38 | package/signed=true
39 | package/classify_as_game=true
40 | package/retain_data_on_uninstall=false
41 | package/exclude_from_recents=false
42 | launcher_icons/main_192x192=""
43 | launcher_icons/adaptive_foreground_432x432=""
44 | launcher_icons/adaptive_background_432x432=""
45 | graphics/opengl_debug=false
46 | xr_features/xr_mode=0
47 | xr_features/hand_tracking=0
48 | xr_features/hand_tracking_frequency=0
49 | xr_features/passthrough=0
50 | screen/immersive_mode=true
51 | screen/support_small=true
52 | screen/support_normal=true
53 | screen/support_large=true
54 | screen/support_xlarge=true
55 | user_data_backup/allow=false
56 | command_line/extra_args=""
57 | apk_expansion/enable=false
58 | apk_expansion/SALT=""
59 | apk_expansion/public_key=""
60 | permissions/custom_permissions=PoolStringArray( "com.google.android.gms.permission.AD_ID" )
61 | permissions/access_checkin_properties=false
62 | permissions/access_coarse_location=false
63 | permissions/access_fine_location=false
64 | permissions/access_location_extra_commands=false
65 | permissions/access_mock_location=false
66 | permissions/access_network_state=true
67 | permissions/access_surface_flinger=false
68 | permissions/access_wifi_state=false
69 | permissions/account_manager=false
70 | permissions/add_voicemail=false
71 | permissions/authenticate_accounts=false
72 | permissions/battery_stats=false
73 | permissions/bind_accessibility_service=false
74 | permissions/bind_appwidget=false
75 | permissions/bind_device_admin=false
76 | permissions/bind_input_method=false
77 | permissions/bind_nfc_service=false
78 | permissions/bind_notification_listener_service=false
79 | permissions/bind_print_service=false
80 | permissions/bind_remoteviews=false
81 | permissions/bind_text_service=false
82 | permissions/bind_vpn_service=false
83 | permissions/bind_wallpaper=false
84 | permissions/bluetooth=false
85 | permissions/bluetooth_admin=false
86 | permissions/bluetooth_privileged=false
87 | permissions/brick=false
88 | permissions/broadcast_package_removed=false
89 | permissions/broadcast_sms=false
90 | permissions/broadcast_sticky=false
91 | permissions/broadcast_wap_push=false
92 | permissions/call_phone=false
93 | permissions/call_privileged=false
94 | permissions/camera=false
95 | permissions/capture_audio_output=false
96 | permissions/capture_secure_video_output=false
97 | permissions/capture_video_output=false
98 | permissions/change_component_enabled_state=false
99 | permissions/change_configuration=false
100 | permissions/change_network_state=false
101 | permissions/change_wifi_multicast_state=false
102 | permissions/change_wifi_state=false
103 | permissions/clear_app_cache=false
104 | permissions/clear_app_user_data=false
105 | permissions/control_location_updates=false
106 | permissions/delete_cache_files=false
107 | permissions/delete_packages=false
108 | permissions/device_power=false
109 | permissions/diagnostic=false
110 | permissions/disable_keyguard=false
111 | permissions/dump=false
112 | permissions/expand_status_bar=false
113 | permissions/factory_test=false
114 | permissions/flashlight=false
115 | permissions/force_back=false
116 | permissions/get_accounts=false
117 | permissions/get_package_size=false
118 | permissions/get_tasks=false
119 | permissions/get_top_activity_info=false
120 | permissions/global_search=false
121 | permissions/hardware_test=false
122 | permissions/inject_events=false
123 | permissions/install_location_provider=false
124 | permissions/install_packages=false
125 | permissions/install_shortcut=false
126 | permissions/internal_system_window=false
127 | permissions/internet=true
128 | permissions/kill_background_processes=false
129 | permissions/location_hardware=false
130 | permissions/manage_accounts=false
131 | permissions/manage_app_tokens=false
132 | permissions/manage_documents=false
133 | permissions/manage_external_storage=false
134 | permissions/master_clear=false
135 | permissions/media_content_control=false
136 | permissions/modify_audio_settings=false
137 | permissions/modify_phone_state=false
138 | permissions/mount_format_filesystems=false
139 | permissions/mount_unmount_filesystems=false
140 | permissions/nfc=false
141 | permissions/persistent_activity=false
142 | permissions/process_outgoing_calls=false
143 | permissions/read_calendar=false
144 | permissions/read_call_log=false
145 | permissions/read_contacts=false
146 | permissions/read_external_storage=false
147 | permissions/read_frame_buffer=false
148 | permissions/read_history_bookmarks=false
149 | permissions/read_input_state=false
150 | permissions/read_logs=false
151 | permissions/read_phone_state=false
152 | permissions/read_profile=false
153 | permissions/read_sms=false
154 | permissions/read_social_stream=false
155 | permissions/read_sync_settings=false
156 | permissions/read_sync_stats=false
157 | permissions/read_user_dictionary=false
158 | permissions/reboot=false
159 | permissions/receive_boot_completed=false
160 | permissions/receive_mms=false
161 | permissions/receive_sms=false
162 | permissions/receive_wap_push=false
163 | permissions/record_audio=false
164 | permissions/reorder_tasks=false
165 | permissions/restart_packages=false
166 | permissions/send_respond_via_message=false
167 | permissions/send_sms=false
168 | permissions/set_activity_watcher=false
169 | permissions/set_alarm=false
170 | permissions/set_always_finish=false
171 | permissions/set_animation_scale=false
172 | permissions/set_debug_app=false
173 | permissions/set_orientation=false
174 | permissions/set_pointer_speed=false
175 | permissions/set_preferred_applications=false
176 | permissions/set_process_limit=false
177 | permissions/set_time=false
178 | permissions/set_time_zone=false
179 | permissions/set_wallpaper=false
180 | permissions/set_wallpaper_hints=false
181 | permissions/signal_persistent_processes=false
182 | permissions/status_bar=false
183 | permissions/subscribed_feeds_read=false
184 | permissions/subscribed_feeds_write=false
185 | permissions/system_alert_window=false
186 | permissions/transmit_ir=false
187 | permissions/uninstall_shortcut=false
188 | permissions/update_device_stats=false
189 | permissions/use_credentials=false
190 | permissions/use_sip=false
191 | permissions/vibrate=false
192 | permissions/wake_lock=false
193 | permissions/write_apn_settings=false
194 | permissions/write_calendar=false
195 | permissions/write_call_log=false
196 | permissions/write_contacts=false
197 | permissions/write_external_storage=false
198 | permissions/write_gservices=false
199 | permissions/write_history_bookmarks=false
200 | permissions/write_profile=false
201 | permissions/write_secure_settings=false
202 | permissions/write_settings=false
203 | permissions/write_sms=false
204 | permissions/write_social_stream=false
205 | permissions/write_sync_settings=false
206 | permissions/write_user_dictionary=false
207 |
--------------------------------------------------------------------------------
/demo/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/demo/icon.png
--------------------------------------------------------------------------------
/demo/main.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | onready var admob = $AdMob
4 | onready var debug_out = $CanvasLayer/DebugOut
5 |
6 | func _ready():
7 |
8 | if not admob.ads_using_consent:
9 | print('Ads without consent verification')
10 | loadAds()
11 | else:
12 | print('Ads with consent')
13 | # warning-ignore:return_value_discarded
14 | get_tree().connect("screen_resized", self, "_on_resize")
15 |
16 | func loadAds() -> void:
17 | admob.load_banner()
18 | admob.load_interstitial()
19 | admob.load_rewarded_video()
20 | admob.load_rewarded_interstitial()
21 |
22 | # buttons callbacks
23 | func _on_BtnReload_pressed() -> void:
24 | loadAds()
25 |
26 | func _on_BtnBanner_toggled(button_pressed):
27 | if button_pressed: admob.show_banner()
28 | else: admob.hide_banner()
29 |
30 | func _on_BtnBannerMove_toggled(button_pressed: bool) -> void:
31 | admob.move_banner(button_pressed)
32 | $"CanvasLayer/BtnBannerResize".disabled = true
33 | $"CanvasLayer/BtnBanner".disabled = true
34 | $"CanvasLayer/BtnBannerMove".disabled = true
35 |
36 | func _on_BtnBannerResize_pressed() -> void:
37 | admob.banner_resize()
38 |
39 | func _on_BtnInterstitial_pressed():
40 | debug_out.text = debug_out.text + "Interstitial loaded before shown = " + str(admob.is_interstitial_loaded()) +"\n"
41 | admob.show_interstitial()
42 | debug_out.text = debug_out.text + "Interstitial loaded after shown = " + str(admob.is_interstitial_loaded()) +"\n"
43 |
44 | func _on_BtnRewardedVideo_pressed():
45 | debug_out.text = debug_out.text + "Rewarded loaded before shown = " + str(admob.is_rewarded_video_loaded()) +"\n"
46 | admob.show_rewarded_video()
47 | debug_out.text = debug_out.text + "Rewarded loaded after shown = " + str(admob.is_rewarded_video_loaded()) +"\n"
48 |
49 | func _on_BtnRewardedInterstitial_pressed() -> void:
50 | debug_out.text = debug_out.text + "Rewarded interstitial loaded before shown = " + str(admob.is_rewarded_interstitial_loaded()) +"\n"
51 | admob.show_rewarded_interstitial()
52 | debug_out.text = debug_out.text + "Rewarded interstitial loaded after shown = " + str(admob.is_rewarded_interstitial_loaded()) +"\n"
53 |
54 | # AdMob callbacks
55 | func _on_resize():
56 | debug_out.text = debug_out.text + "Banner resized\n"
57 | admob.banner_resize()
58 |
59 | func _on_AdMob_banner_failed_to_load(error_code):
60 | debug_out.text = debug_out.text + "Banner failed to load: Error code " + str(error_code) + "\n"
61 |
62 | func _on_AdMob_banner_loaded():
63 | $"CanvasLayer/BtnBannerResize".disabled = false
64 | $"CanvasLayer/BtnBanner".disabled = false
65 | $"CanvasLayer/BtnBannerMove".disabled = false
66 | debug_out.text = debug_out.text + "Banner loaded\n"
67 | debug_out.text = debug_out.text + "Banner size = " + str(admob.get_banner_dimension()) + "\n"
68 |
69 | func _on_AdMob_interstitial_opened():
70 | debug_out.text = debug_out.text + "Interstitial opened\n"
71 |
72 | func _on_AdMob_interstitial_loaded():
73 | $"CanvasLayer/BtnInterstitial".disabled = false
74 | debug_out.text = debug_out.text + "Interstitial loaded\n"
75 |
76 | func _on_AdMob_interstitial_clicked():
77 | debug_out.text = debug_out.text + "Interstitial clicked\n"
78 |
79 | func _on_AdMob_interstitial_closed():
80 | debug_out.text = debug_out.text + "Interstitial closed\n"
81 | $"CanvasLayer/BtnInterstitial".disabled = false
82 |
83 | func _on_AdMob_interstitial_failed_to_load(error_code):
84 | debug_out.text = debug_out.text + "Interstitial failed to load: Error code " + str(error_code) + "\n"
85 |
86 | func _on_AdMob_interstitial_impression():
87 | debug_out.text = debug_out.text + "Interstitial impression\n"
88 |
89 | func _on_AdMob_network_error():
90 | debug_out.text = debug_out.text + "Network error\n"
91 |
92 | func _on_AdMob_rewarded(currency, amount):
93 | debug_out.text = debug_out.text + "Rewarded watched, currency: " + str(currency) + " amount:"+ str(amount)+ "\n"
94 |
95 | func _on_AdMob_rewarded_clicked():
96 | debug_out.text = debug_out.text + "Rewarded clicked\n"
97 |
98 | func _on_AdMob_rewarded_impression():
99 | debug_out.text = debug_out.text + "Rewarded impression\n"
100 |
101 | func _on_AdMob_rewarded_video_closed():
102 | debug_out.text = debug_out.text + "Rewarded video closed\n"
103 | $"CanvasLayer/BtnRewardedVideo".disabled = true
104 | admob.load_rewarded_video()
105 |
106 | func _on_AdMob_rewarded_video_failed_to_load(error_code):
107 | debug_out.text = debug_out.text + "Rewarded video failed to load: Error code " + str(error_code) + "\n"
108 |
109 | func _on_AdMob_rewarded_video_loaded():
110 | $"CanvasLayer/BtnRewardedVideo".disabled = false
111 | debug_out.text = debug_out.text + "Rewarded video loaded\n"
112 |
113 | func _on_AdMob_rewarded_video_opened():
114 | debug_out.text = debug_out.text + "Rewarded video opened\n"
115 |
116 | func _on_AdMob_rewarded_interstitial_loaded() -> void:
117 | $CanvasLayer/BtnRewardedInterstitial.disabled = false
118 | debug_out.text = debug_out.text + "Rewarded interstitial loaded\n"
119 |
120 | func _on_AdMob_rewarded_interstitial_opened() -> void:
121 | debug_out.text = debug_out.text + "Rewarded interstitial opened\n"
122 |
123 | func _on_AdMob_rewarded_interstitial_closed() -> void:
124 | debug_out.text = debug_out.text + "Rewarded interstitial closed\n"
125 | $CanvasLayer/BtnRewardedInterstitial.disabled = true
126 | admob.load_rewarded_interstitial()
127 |
128 | func _on_AdMob_rewarded_interstitial_failed_to_load(error_code) -> void:
129 | debug_out.text = debug_out.text + "Rewarded interstitial failed to load: Error code " + str(error_code) + "\n"
130 |
131 | func _on_AdMob_rewarded_interstitial_failed_to_show(error_code) -> void:
132 | debug_out.text = debug_out.text + "Rewarded interstitial failed to show: Error code " + str(error_code) + "\n"
133 |
134 | func _on_BtnRequestConsentInfoUpdate_pressed():
135 | debug_out.text = debug_out.text + "Request Consent\n"
136 | admob.request_consent_info_update()
137 |
138 |
139 |
140 | func _on_BtnResetConsent_pressed():
141 | debug_out.text = debug_out.text + "RESET Consent\n"
142 | admob.reset_consent()
143 |
144 |
145 | func _on_AdMob_consent_app_can_request_ad(consent_status):
146 | debug_out.text = debug_out.text + 'App can start requesting ads.'
147 | print('App can start requesting ads.')
148 | loadAds()
149 |
150 | func _on_AdMob_consent_info_update_failure(error_code, error_message):
151 | debug_out.text = debug_out.text + 'Consent failure: ' + "(" + str(error_code) + "," + error_message + ")"
152 |
153 |
154 | func _on_AdMob_consent_info_update_success():
155 | debug_out.text = debug_out.text + '_on_AdMob_consent_info_update_success'
156 |
--------------------------------------------------------------------------------
/demo/main.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=2]
2 |
3 | [ext_resource path="res://main.gd" type="Script" id=1]
4 | [ext_resource path="res://admob-lib/admob.gd" type="Script" id=2]
5 |
6 | [node name="Node2D" type="Node2D"]
7 | script = ExtResource( 1 )
8 | __meta__ = {
9 | "__editor_plugin_screen__": "3D"
10 | }
11 |
12 | [node name="CanvasLayer" type="CanvasLayer" parent="."]
13 |
14 | [node name="DebugOut" type="RichTextLabel" parent="CanvasLayer"]
15 | anchor_left = 0.5
16 | anchor_top = 0.5
17 | anchor_right = 0.5
18 | anchor_bottom = 0.5
19 | margin_left = -75.0
20 | margin_top = 120.0
21 | margin_right = 305.0
22 | margin_bottom = 208.0
23 | text = "
24 | "
25 | scroll_following = true
26 |
27 | [node name="BtnReload" type="Button" parent="CanvasLayer"]
28 | anchor_left = 0.5
29 | anchor_top = 0.5
30 | anchor_right = 0.5
31 | anchor_bottom = 0.5
32 | margin_left = -291.0
33 | margin_top = -217.0
34 | margin_right = -213.0
35 | margin_bottom = -142.0
36 | text = "Reload"
37 | __meta__ = {
38 | "_edit_use_anchors_": false
39 | }
40 |
41 | [node name="BtnInterstitial" type="Button" parent="CanvasLayer"]
42 | anchor_left = 0.5
43 | anchor_top = 0.5
44 | anchor_right = 0.5
45 | anchor_bottom = 0.5
46 | margin_left = -75.0
47 | margin_top = -166.077
48 | margin_right = 75.0
49 | margin_bottom = -91.0766
50 | disabled = true
51 | text = "Show Interstitial"
52 |
53 | [node name="BtnBannerResize" type="Button" parent="CanvasLayer"]
54 | anchor_left = 0.5
55 | anchor_top = 0.5
56 | anchor_right = 0.5
57 | anchor_bottom = 0.5
58 | margin_left = -251.0
59 | margin_top = -65.6294
60 | margin_right = -101.0
61 | margin_bottom = 9.37061
62 | disabled = true
63 | text = "Resize Banner"
64 |
65 | [node name="BtnRequestConsentInfoUpdate" type="Button" parent="CanvasLayer"]
66 | anchor_left = 0.5
67 | anchor_top = 0.5
68 | anchor_right = 0.5
69 | anchor_bottom = 0.5
70 | margin_left = -251.0
71 | margin_top = 31.0
72 | margin_right = -101.0
73 | margin_bottom = 106.0
74 | text = "Request Consent"
75 |
76 | [node name="BtnResetConsent" type="Button" parent="CanvasLayer"]
77 | anchor_left = 0.5
78 | anchor_top = 0.5
79 | anchor_right = 0.5
80 | anchor_bottom = 0.5
81 | margin_left = -251.0
82 | margin_top = 120.0
83 | margin_right = -101.0
84 | margin_bottom = 195.0
85 | text = "Reset Consent"
86 |
87 | [node name="BtnBanner" type="Button" parent="CanvasLayer"]
88 | anchor_left = 0.5
89 | anchor_top = 0.5
90 | anchor_right = 0.5
91 | anchor_bottom = 0.5
92 | margin_left = -75.0
93 | margin_top = -65.6294
94 | margin_right = 75.0
95 | margin_bottom = 9.37061
96 | disabled = true
97 | toggle_mode = true
98 | text = "Show/Hide Banner"
99 |
100 | [node name="BtnBannerMove" type="Button" parent="CanvasLayer"]
101 | anchor_left = 0.5
102 | anchor_top = 0.5
103 | anchor_right = 0.5
104 | anchor_bottom = 0.5
105 | margin_left = 103.0
106 | margin_top = -65.6294
107 | margin_right = 253.0
108 | margin_bottom = 9.37061
109 | disabled = true
110 | toggle_mode = true
111 | text = "Move Banner"
112 |
113 | [node name="BtnRewardedVideo" type="Button" parent="CanvasLayer"]
114 | anchor_left = 0.5
115 | anchor_top = 0.5
116 | anchor_right = 0.5
117 | anchor_bottom = 0.5
118 | margin_left = -75.0
119 | margin_top = 31.0654
120 | margin_right = 76.0
121 | margin_bottom = 106.065
122 | disabled = true
123 | text = "Show Rewarded Video"
124 |
125 | [node name="BtnRewardedInterstitial" type="Button" parent="CanvasLayer"]
126 | anchor_left = 0.5
127 | anchor_top = 0.5
128 | anchor_right = 0.5
129 | anchor_bottom = 0.5
130 | margin_left = 103.0
131 | margin_top = 31.0
132 | margin_right = 254.0
133 | margin_bottom = 106.0
134 | disabled = true
135 | text = "Show Rewarded Interstitial"
136 |
137 | [node name="AdMob" type="Node" parent="."]
138 | script = ExtResource( 2 )
139 | __meta__ = {
140 | "_editor_description_": ""
141 | }
142 | banner_id = "ca-app-pub-3940256099942544/6300978111"
143 | interstitial_id = "ca-app-pub-3940256099942544/1033173712"
144 | rewarded_id = "ca-app-pub-3940256099942544/5224354917"
145 | rewarded_interstitial_id = "ca-app-pub-3940256099942544/5354046379"
146 | is_personalized = false
147 |
148 | [connection signal="pressed" from="CanvasLayer/BtnReload" to="." method="_on_BtnReload_pressed"]
149 | [connection signal="pressed" from="CanvasLayer/BtnInterstitial" to="." method="_on_BtnInterstitial_pressed"]
150 | [connection signal="pressed" from="CanvasLayer/BtnBannerResize" to="." method="_on_BtnBannerResize_pressed"]
151 | [connection signal="pressed" from="CanvasLayer/BtnRequestConsentInfoUpdate" to="." method="_on_BtnRequestConsentInfoUpdate_pressed"]
152 | [connection signal="pressed" from="CanvasLayer/BtnResetConsent" to="." method="_on_BtnResetConsent_pressed"]
153 | [connection signal="toggled" from="CanvasLayer/BtnBanner" to="." method="_on_BtnBanner_toggled"]
154 | [connection signal="toggled" from="CanvasLayer/BtnBannerMove" to="." method="_on_BtnBannerMove_toggled"]
155 | [connection signal="pressed" from="CanvasLayer/BtnRewardedVideo" to="." method="_on_BtnRewardedVideo_pressed"]
156 | [connection signal="pressed" from="CanvasLayer/BtnRewardedInterstitial" to="." method="_on_BtnRewardedInterstitial_pressed"]
157 | [connection signal="banner_failed_to_load" from="AdMob" to="." method="_on_AdMob_banner_failed_to_load"]
158 | [connection signal="banner_loaded" from="AdMob" to="." method="_on_AdMob_banner_loaded"]
159 | [connection signal="consent_app_can_request_ad" from="AdMob" to="." method="_on_AdMob_consent_app_can_request_ad"]
160 | [connection signal="consent_info_update_failure" from="AdMob" to="." method="_on_AdMob_consent_info_update_failure"]
161 | [connection signal="consent_info_update_success" from="AdMob" to="." method="_on_AdMob_consent_info_update_success"]
162 | [connection signal="interstitial_clicked" from="AdMob" to="." method="_on_AdMob_interstitial_clicked"]
163 | [connection signal="interstitial_closed" from="AdMob" to="." method="_on_AdMob_interstitial_closed"]
164 | [connection signal="interstitial_failed_to_load" from="AdMob" to="." method="_on_AdMob_interstitial_failed_to_load"]
165 | [connection signal="interstitial_impression" from="AdMob" to="." method="_on_AdMob_interstitial_impression"]
166 | [connection signal="interstitial_loaded" from="AdMob" to="." method="_on_AdMob_interstitial_loaded"]
167 | [connection signal="interstitial_opened" from="AdMob" to="." method="_on_AdMob_interstitial_opened"]
168 | [connection signal="rewarded" from="AdMob" to="." method="_on_AdMob_rewarded"]
169 | [connection signal="rewarded_clicked" from="AdMob" to="." method="_on_AdMob_rewarded_clicked"]
170 | [connection signal="rewarded_impression" from="AdMob" to="." method="_on_AdMob_rewarded_impression"]
171 | [connection signal="rewarded_interstitial_closed" from="AdMob" to="." method="_on_AdMob_rewarded_interstitial_closed"]
172 | [connection signal="rewarded_interstitial_failed_to_load" from="AdMob" to="." method="_on_AdMob_rewarded_interstitial_failed_to_load"]
173 | [connection signal="rewarded_interstitial_failed_to_show" from="AdMob" to="." method="_on_AdMob_rewarded_interstitial_failed_to_show"]
174 | [connection signal="rewarded_interstitial_loaded" from="AdMob" to="." method="_on_AdMob_rewarded_interstitial_loaded"]
175 | [connection signal="rewarded_interstitial_opened" from="AdMob" to="." method="_on_AdMob_rewarded_interstitial_opened"]
176 | [connection signal="rewarded_video_closed" from="AdMob" to="." method="_on_AdMob_rewarded_video_closed"]
177 | [connection signal="rewarded_video_failed_to_load" from="AdMob" to="." method="_on_AdMob_rewarded_video_failed_to_load"]
178 | [connection signal="rewarded_video_loaded" from="AdMob" to="." method="_on_AdMob_rewarded_video_loaded"]
179 | [connection signal="rewarded_video_opened" from="AdMob" to="." method="_on_AdMob_rewarded_video_opened"]
180 |
--------------------------------------------------------------------------------
/demo/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=4
10 |
11 | _global_script_classes=[ {
12 | "base": "Node",
13 | "class": "AdMob",
14 | "language": "GDScript",
15 | "path": "res://admob-lib/admob.gd"
16 | } ]
17 | _global_script_class_icons={
18 | "AdMob": "res://admob-lib/icon.png"
19 | }
20 |
21 | [application]
22 |
23 | config/name="AdMob Plugin Test"
24 | run/main_scene="res://main.tscn"
25 | config/icon="res://icon.png"
26 |
27 | [display]
28 |
29 | window/size/width=640
30 | window/size/height=480
31 | window/handheld/orientation="sensor"
32 | window/stretch/mode="2d"
33 | window/stretch/aspect="keep_height"
34 |
35 | [editor_plugins]
36 |
37 | enabled=PoolStringArray( )
38 |
39 | [rendering]
40 |
41 | quality/driver/driver_name="GLES2"
42 | vram_compression/import_etc=true
43 |
--------------------------------------------------------------------------------
/images/properties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/images/properties.png
--------------------------------------------------------------------------------
/images/search_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/images/search_node.png
--------------------------------------------------------------------------------
/images/signals.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shin-NiL/Godot-Android-Admob-Plugin/459293ea8be1c64a88b4307a82c5514401327408/images/signals.png
--------------------------------------------------------------------------------
/issue_template.md:
--------------------------------------------------------------------------------
1 | **Godot version:**
2 |
3 | **AdMob Plugin version:**
4 |
5 | **Issue description:**
6 |
7 |
8 |
--------------------------------------------------------------------------------
/showcase.md:
--------------------------------------------------------------------------------
1 | # Showcase
2 | I've created this file because I love to see what people create using this plugin ;)
3 |
4 | If you like to add your game in this list open an issue or send me a pull request with the link and title of your published game.
5 |
6 | ## List of Published Games using this Plugin
7 |
8 | - [12345 Rotors - Puzzle Game](https://play.google.com/store/apps/details?id=com.ross.numbergame12345)
9 | - [Ball Square](https://play.google.com/store/apps/details?id=com.mani.ballandsquare&hl=en_US)
10 | - [Ball Toss](https://play.google.com/store/apps/details?id=com.EGFABT.Ball_Toss)
11 | - [Block Runner](https://play.google.com/store/apps/details?id=org.godotengine.blockrunner)
12 | - [Bomber Pilot](https://play.google.com/store/apps/details?id=org.ohyaiamheregames.bomberpilot)
13 | - [Bomber Pilot 2](https://play.google.com/store/apps/details?id=org.ohyaiamheregames.bomberpilottwo)
14 | - [Break Bacteria](https://play.google.com/store/apps/details?id=com.turkicgames.breakbacteria)
15 | - [Cars On Tracks](https://play.google.com/store/apps/details?id=org.Introsflexion.CarsOnTracks)
16 | - [DeathGuy](https://play.google.com/store/apps/details?id=org.amdotblacksheep.deathguy)
17 | - [Dirtfall - Vacuum Cleaning Simulator](https://play.google.com/store/apps/details?id=com.goldspark.cleaner.dirtfall)
18 | - [Dogecoin: The Video Game](https://play.google.com/store/apps/details?id=org.dtgames.dodecoingame)
19 | - [Domino Trail](https://play.google.com/store/apps/details?id=org.losyk.dominotrail)
20 | - [Flappy Unicorn](https://play.google.com/store/apps/details?id=com.dtgames.flappyunicorn)
21 | - [Future Funk Soccer Racing](https://play.google.com/store/apps/details?id=org.godotengine.cargame)
22 | - [Galaxy Fights - Space Shooter](https://play.google.com/store/apps/details?id=com.landapp.games.shooter)
23 | - [Help Luigi!](https://play.google.com/store/apps/details?id=com.bananaonfire.helpluigi)
24 | - [HoverFlow - Endless Driver](https://play.google.com/store/apps/details?id=godot.pizzajuggler.hoverflow)
25 | - [iDrink – Drinking Game 🍻](https://play.google.com/store/apps/details?id=com.garfsapps.umgole)
26 | - [Inline](https://play.google.com/store/apps/details?id=com.loustak.inline)
27 | - [Ionitron - ion magnet puzzle game](https://play.google.com/store/apps/details?id=godot.pizzajuggler.ionitron)
28 | - [Landbox](https://play.google.com/store/apps/details?id=org.hideckies.landbox)
29 | - [Life Is Not The End](https://play.google.com/store/apps/details?id=org.godotengine.lifeisnottheend)
30 | - [Logikal](https://play.google.com/store/apps/details?id=org.khgames.logikal)
31 | - [Mad Crab Grab](https://play.google.com/store/apps/details?id=org.godotengine.madcrabgrab)
32 | - [No Rush - Puzzle/Platformer Game](https://play.google.com/store/apps/details?id=org.turkmenh.norush)
33 | - [Office Kiss Game](https://play.google.com/store/apps/details?id=org.godotengine.secretkisses)
34 | - [Piranha Escape](https://play.google.com/store/apps/details?id=com.bitmagine.piranhaescape)
35 | - [Plane in a Cavern](https://play.google.com/store/apps/details?id=org.kanataexe.tappytheplane)
36 | - [Push Puzzle](https://play.google.com/store/apps/details?id=push.puzzle.sokoban)
37 | - [Reverse Babylon](https://play.google.com/store/apps/details?id=com.PlastilinLepim.babylon)
38 | - [Rush: Endless Arcade](https://play.google.com/store/apps/details?id=org.haruntrkmn.rush)
39 | - [SLID - Letter Sliding Puzzle](https://play.google.com/store/apps/details?id=com.kamofa.slid)
40 | - [Space Flex](https://play.google.com/store/apps/details?id=com.gachitech.space_flex)
41 | - [SpeedSnake](https://play.google.com/store/apps/details?id=com.mosscrow.speedsnake)
42 | - [Spin Mania](https://play.google.com/store/apps/details?id=com.kalzcoat.spinmania)
43 | - [TriHard](https://play.google.com/store/apps/details?id=org.dtgames.trihard)
44 | - [Turzzle](https://play.google.com/store/apps/details?id=com.bananaonfire.turzzle)
45 | - [Walls of Stone - Puzzle Game](https://play.google.com/store/apps/details?id=dev.mintstudios.wos)
46 | - [Warzone 2 - Top down shooter](https://play.google.com/store/apps/details?id=com.raptor.inc)
47 | - [WoW Death Roll Simulator](https://play.google.com/store/apps/details?id=ch.jackfruit.deathrollsimulator)
48 | - [Zeptris](https://play.google.com/store/apps/details?id=net.wynoo.zeptris)
49 | - [Zig-Zag](https://play.google.com/store/apps/details?id=org.kanataexe.zigzag)
50 | - [Zone Crush - A Match 3 Game 2020](https://play.google.com/store/apps/details?id=com.GamesForLife.ZoneCrush)
51 |
--------------------------------------------------------------------------------
/tools/package_build.sh:
--------------------------------------------------------------------------------
1 | #!bin/bash
2 |
3 | RELEASES_DIR="releases"
4 | VERSION_DIR="$RELEASES_DIR/$1"
5 | PLUGIN_DIR="$RELEASES_DIR/$1/admob-plugin"
6 |
7 | if [[ ! -e $RELEASES_DIR ]]; then
8 | mkdir -p $RELEASES_DIR
9 | fi
10 |
11 | mkdir -p $PLUGIN_DIR
12 | cp -r ../admob-lib $VERSION_DIR
13 | cp ../config/GodotAdmob.gdap ../admob-plugin/godotadmob/build/outputs/aar/GodotAdMob.${1}.release.aar $PLUGIN_DIR
14 |
15 | cd $VERSION_DIR
16 | zip -r "../GodotAdmobPlugin-${1}.zip" .
17 |
--------------------------------------------------------------------------------