admob_android/
lib.rs

1use crossbow_android::{error::*, jni::JavaVM, plugin::*};
2use std::sync::Arc;
3
4pub struct AdMobPlugin {
5    singleton: Arc<JniSingleton>,
6    vm: Arc<JavaVM>,
7}
8
9impl CrossbowPlugin for AdMobPlugin {
10    fn from_java_vm(vm: Arc<JavaVM>) -> Result<Self>
11    where
12        Self: Sized,
13    {
14        let singleton = get_jni_singleton(Self::get_plugin_name()).ok_or_else(|| {
15            AndroidError::SingletonNotRegistered(Self::get_plugin_name().to_owned())
16        })?;
17        Ok(Self { singleton, vm })
18    }
19
20    fn get_plugin_name() -> &'static str {
21        "CrossbowAdMob"
22    }
23
24    fn get_receiver(&self) -> &Receiver<Signal> {
25        self.singleton.get_receiver()
26    }
27}
28
29impl AdMobPlugin {
30    // TODO: Make async API
31    // pub async fn initialize_async<S>(
32    //     &self,
33    //     is_for_child_directed_treatment: bool,
34    //     max_ad_content_rating: S,
35    //     is_real: bool,
36    //     is_test_europe_user_consent: bool,
37    // ) -> Result<()>
38    // where
39    //     S: AsRef<str>,
40    // {
41    //     self.initialize(
42    //         is_for_child_directed_treatment,
43    //         max_ad_content_rating,
44    //         is_real,
45    //         is_test_europe_user_consent,
46    //     )?;
47    //     // loop {
48    //     //     self.get_receiver().recv().await?;
49    //     // }
50    //     Ok(())
51    // }
52
53    // TODO: Fix initialization_complete Signal not being sent
54    pub fn initialize<S>(
55        &self,
56        is_for_child_directed_treatment: bool,
57        max_ad_content_rating: S,
58        is_real: bool,
59        is_test_europe_user_consent: bool,
60    ) -> Result<()>
61    where
62        S: AsRef<str>,
63    {
64        let jnienv = self.vm.attach_current_thread_as_daemon()?;
65        let g_str = jnienv.new_string(max_ad_content_rating)?;
66        self.singleton.call_method(
67            &jnienv,
68            "initialize",
69            &[
70                is_for_child_directed_treatment.into(),
71                g_str.into(),
72                is_real.into(),
73                is_test_europe_user_consent.into(),
74            ],
75        )?;
76        jnienv.exception_check()?;
77        Ok(())
78    }
79
80    pub fn is_initialized(&self) -> Result<bool> {
81        let jnienv = self.vm.attach_current_thread_as_daemon()?;
82        let val = self
83            .singleton
84            .call_method(&jnienv, "getIsInitialized", &[])?;
85        Ok(val.z()?)
86    }
87
88    pub fn load_interstitial(&self, ad_id: &str) -> Result<()> {
89        let jnienv = self.vm.attach_current_thread_as_daemon()?;
90        let ad_id = jnienv.new_string(ad_id.to_string())?;
91        self.singleton
92            .call_method(&jnienv, "loadInterstitial", &[ad_id.into()])?;
93        jnienv.exception_check()?;
94        Ok(())
95    }
96
97    pub fn is_interstitial_loaded(&self) -> Result<bool> {
98        let jnienv = self.vm.attach_current_thread_as_daemon()?;
99        let val = self
100            .singleton
101            .call_method(&jnienv, "getIsInterstitialLoaded", &[])?;
102        Ok(val.z()?)
103    }
104
105    pub fn show_interstitial(&self) -> Result<()> {
106        let jnienv = self.vm.attach_current_thread_as_daemon()?;
107        self.singleton
108            .call_method(&jnienv, "showInterstitial", &[])?;
109        jnienv.exception_check()?;
110        Ok(())
111    }
112
113    pub fn request_user_consent(&self) -> Result<()> {
114        let jnienv = self.vm.attach_current_thread_as_daemon()?;
115        self.singleton
116            .call_method(&jnienv, "requestUserConsent", &[])?;
117        jnienv.exception_check()?;
118        Ok(())
119    }
120
121    pub fn reset_consent_state(&self) -> Result<()> {
122        let jnienv = self.vm.attach_current_thread_as_daemon()?;
123        self.singleton
124            .call_method(&jnienv, "resetConsentState", &[])?;
125        jnienv.exception_check()?;
126        Ok(())
127    }
128
129    pub fn load_banner<S>(
130        &self,
131        ad_unit_id: S,
132        position: i32,
133        size: BannerSize,
134        show_instantly: bool,
135        respect_safe_area: bool,
136    ) -> Result<()>
137    where
138        S: AsRef<str>,
139    {
140        let jnienv = self.vm.attach_current_thread_as_daemon()?;
141        let ad_unit_id = jnienv.new_string(ad_unit_id)?;
142        let size = jnienv.new_string(size.to_string())?;
143        self.singleton.call_method(
144            &jnienv,
145            "loadBanner",
146            &[
147                ad_unit_id.into(),
148                position.into(),
149                size.into(),
150                show_instantly.into(),
151                respect_safe_area.into(),
152            ],
153        )?;
154        jnienv.exception_check()?;
155        Ok(())
156    }
157
158    pub fn is_banner_loaded(&self) -> Result<bool> {
159        let jnienv = self.vm.attach_current_thread_as_daemon()?;
160        let val = self
161            .singleton
162            .call_method(&jnienv, "getIsBannerLoaded", &[])?;
163        Ok(val.z()?)
164    }
165
166    pub fn destroy_banner(&self) -> Result<()> {
167        let jnienv = self.vm.attach_current_thread_as_daemon()?;
168        self.singleton.call_method(&jnienv, "destroyBanner", &[])?;
169        jnienv.exception_check()?;
170        Ok(())
171    }
172
173    pub fn show_banner(&self) -> Result<()> {
174        let jnienv = self.vm.attach_current_thread_as_daemon()?;
175        self.singleton.call_method(&jnienv, "showBanner", &[])?;
176        jnienv.exception_check()?;
177        Ok(())
178    }
179
180    pub fn hide_banner(&self) -> Result<()> {
181        let jnienv = self.vm.attach_current_thread_as_daemon()?;
182        self.singleton.call_method(&jnienv, "hideBanner", &[])?;
183        jnienv.exception_check()?;
184        Ok(())
185    }
186
187    pub fn banner_width(&self) -> Result<i32> {
188        let jnienv = self.vm.attach_current_thread_as_daemon()?;
189        let val = self.singleton.call_method(&jnienv, "getBannerWidth", &[])?;
190        Ok(val.i()?)
191    }
192
193    pub fn banner_height(&self) -> Result<i32> {
194        let jnienv = self.vm.attach_current_thread_as_daemon()?;
195        let val = self
196            .singleton
197            .call_method(&jnienv, "getBannerHeight", &[])?;
198        Ok(val.i()?)
199    }
200
201    pub fn banner_width_in_pixels(&self) -> Result<i32> {
202        let jnienv = self.vm.attach_current_thread_as_daemon()?;
203        let val = self
204            .singleton
205            .call_method(&jnienv, "getBannerWidthInPixels", &[])?;
206        Ok(val.i()?)
207    }
208
209    pub fn banner_height_in_pixels(&self) -> Result<i32> {
210        let jnienv = self.vm.attach_current_thread_as_daemon()?;
211        let val = self
212            .singleton
213            .call_method(&jnienv, "getBannerHeightInPixels", &[])?;
214        Ok(val.i()?)
215    }
216
217    pub fn load_rewarded<S>(&self, ad_unit_id: S) -> Result<()>
218    where
219        S: AsRef<str>,
220    {
221        let jnienv = self.vm.attach_current_thread_as_daemon()?;
222        let ad_unit_id = jnienv.new_string(ad_unit_id)?;
223        self.singleton
224            .call_method(&jnienv, "loadRewarded", &[ad_unit_id.into()])?;
225        jnienv.exception_check()?;
226        Ok(())
227    }
228
229    pub fn is_rewarded_loaded(&self) -> Result<bool> {
230        let jnienv = self.vm.attach_current_thread_as_daemon()?;
231        let val = self
232            .singleton
233            .call_method(&jnienv, "getIsRewardedLoaded", &[])?;
234        Ok(val.z()?)
235    }
236
237    pub fn show_rewarded(&self) -> Result<()> {
238        let jnienv = self.vm.attach_current_thread_as_daemon()?;
239        self.singleton.call_method(&jnienv, "showRewarded", &[])?;
240        jnienv.exception_check()?;
241        Ok(())
242    }
243
244    pub fn load_rewarded_interstitial<S>(&self, ad_unit_id: S) -> Result<()>
245    where
246        S: AsRef<str>,
247    {
248        let jnienv = self.vm.attach_current_thread_as_daemon()?;
249        let ad_unit_id = jnienv.new_string(ad_unit_id)?;
250        self.singleton
251            .call_method(&jnienv, "loadRewardedInterstitial", &[ad_unit_id.into()])?;
252        jnienv.exception_check()?;
253        Ok(())
254    }
255
256    pub fn is_rewarded_interstitial_loaded(&self) -> Result<bool> {
257        let jnienv = self.vm.attach_current_thread_as_daemon()?;
258        let val = self
259            .singleton
260            .call_method(&jnienv, "getIsRewardedInterstitialLoaded", &[])?;
261        Ok(val.z()?)
262    }
263
264    pub fn show_rewarded_interstitial(&self) -> Result<()> {
265        let jnienv = self.vm.attach_current_thread_as_daemon()?;
266        self.singleton
267            .call_method(&jnienv, "showRewardedInterstitial", &[])?;
268        jnienv.exception_check()?;
269        Ok(())
270    }
271}
272
273#[derive(Clone, Copy, Default)]
274pub enum BannerSize {
275    Banner,
276    LargeBanner,
277    MediumRectangle,
278    FullBanner,
279    Leaderboard,
280    Adaptive,
281    #[default]
282    SmartBanner,
283}
284
285impl ToString for BannerSize {
286    fn to_string(&self) -> String {
287        match self {
288            Self::Banner => "BANNER".to_string(),
289            Self::LargeBanner => "LARGE_BANNER".to_string(),
290            Self::MediumRectangle => "MEDIUM_RECTANGLE".to_string(),
291            Self::FullBanner => "FULL_BANNER".to_string(),
292            Self::Leaderboard => "LEADERBOARD".to_string(),
293            Self::Adaptive => "ADAPTIVE".to_string(),
294            Self::SmartBanner => "SMART_BANNER".to_string(),
295        }
296    }
297}