play_billing/
lib.rs

1use crossbow_android::{error::*, jni::JavaVM, plugin::*};
2use std::sync::Arc;
3
4pub struct PlayBillingPlugin {
5    singleton: Arc<JniSingleton>,
6    vm: Arc<JavaVM>,
7}
8
9impl CrossbowPlugin for PlayBillingPlugin {
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        "CrossbowPlayBilling"
22    }
23
24    fn get_receiver(&self) -> &Receiver<Signal> {
25        self.singleton.get_receiver()
26    }
27}
28
29impl PlayBillingPlugin {
30    pub fn start_connection(&self) -> Result<()> {
31        let jnienv = self.vm.attach_current_thread_as_daemon()?;
32        self.singleton
33            .call_method(&jnienv, "startConnection", &[])?;
34        jnienv.exception_check()?;
35        Ok(())
36    }
37
38    pub fn end_connection(&self) -> Result<()> {
39        let jnienv = self.vm.attach_current_thread_as_daemon()?;
40        self.singleton.call_method(&jnienv, "endConnection", &[])?;
41        jnienv.exception_check()?;
42        Ok(())
43    }
44
45    pub fn is_ready(&self) -> Result<bool> {
46        let jnienv = self.vm.attach_current_thread_as_daemon()?;
47        let res = self.singleton.call_method(&jnienv, "isReady", &[])?;
48        jnienv.exception_check()?;
49        Ok(res.z()?)
50    }
51
52    pub fn get_connection_state(&self) -> Result<i32> {
53        let jnienv = self.vm.attach_current_thread_as_daemon()?;
54        let res = self
55            .singleton
56            .call_method(&jnienv, "getConnectionState", &[])?;
57        jnienv.exception_check()?;
58        Ok(res.i()?)
59    }
60
61    pub fn query_purchases<S>(&self, purchase_type: S) -> Result<()>
62    where
63        S: AsRef<str>,
64    {
65        let jnienv = self.vm.attach_current_thread_as_daemon()?;
66        let purchase_type_str = jnienv.new_string(purchase_type)?;
67        self.singleton
68            .call_method(&jnienv, "queryPurchases", &[purchase_type_str.into()])?;
69        jnienv.exception_check()?;
70        Ok(())
71    }
72
73    pub fn query_sku_details<S>(&self, sku_list: &[S], sku_type: S) -> Result<()>
74    where
75        S: AsRef<str>,
76    {
77        let jnienv = self.vm.attach_current_thread_as_daemon()?;
78        let empty_str = jnienv.new_string("")?;
79        let string_array =
80            jnienv.new_object_array(sku_list.len() as i32, "java/lang/String", empty_str)?;
81        for (index, id) in sku_list.iter().enumerate() {
82            let id_str = jnienv.new_string(id)?;
83            jnienv.set_object_array_element(string_array, index as i32, id_str)?;
84        }
85        let sku_type_str = jnienv.new_string(sku_type)?;
86        self.singleton.call_method(
87            &jnienv,
88            "querySkuDetails",
89            &[string_array.into(), sku_type_str.into()],
90        )?;
91        jnienv.exception_check()?;
92        Ok(())
93    }
94
95    pub fn acknowledge_purchase<S>(&self, purchase_token: S) -> Result<()>
96    where
97        S: AsRef<str>,
98    {
99        let jnienv = self.vm.attach_current_thread_as_daemon()?;
100        let purchase_token_str = jnienv.new_string(purchase_token)?;
101        self.singleton
102            .call_method(&jnienv, "acknowledgePurchase", &[purchase_token_str.into()])?;
103        jnienv.exception_check()?;
104        Ok(())
105    }
106
107    pub fn consume_purchase<S>(&self, purchase_token: S) -> Result<()>
108    where
109        S: AsRef<str>,
110    {
111        let jnienv = self.vm.attach_current_thread_as_daemon()?;
112        let purchase_token_str = jnienv.new_string(purchase_token)?;
113        self.singleton
114            .call_method(&jnienv, "consumePurchase", &[purchase_token_str.into()])?;
115        jnienv.exception_check()?;
116        Ok(())
117    }
118
119    pub fn confirm_price_change<S>(&self, sku: S) -> Result<JniRustType>
120    where
121        S: AsRef<str>,
122    {
123        let jnienv = self.vm.attach_current_thread_as_daemon()?;
124        let sku_str = jnienv.new_string(sku)?;
125        let res = self
126            .singleton
127            .call_method(&jnienv, "confirmPriceChange", &[sku_str.into()])?;
128        jnienv.exception_check()?;
129        Ok(JniRustType::from_jobject(&jnienv, res.l()?)?)
130    }
131
132    pub fn purchase<S>(&self, sku: S) -> Result<JniRustType>
133    where
134        S: AsRef<str>,
135    {
136        let jnienv = self.vm.attach_current_thread_as_daemon()?;
137        let sku_str = jnienv.new_string(sku)?;
138        let res = self
139            .singleton
140            .call_method(&jnienv, "purchase", &[sku_str.into()])?;
141        jnienv.exception_check()?;
142        Ok(JniRustType::from_jobject(&jnienv, res.l()?)?)
143    }
144
145    pub fn update_subscription<S>(
146        &self,
147        old_token: S,
148        sku: S,
149        proration_mode: i32,
150    ) -> Result<JniRustType>
151    where
152        S: AsRef<str>,
153    {
154        let jnienv = self.vm.attach_current_thread_as_daemon()?;
155        let old_token_str = jnienv.new_string(old_token)?;
156        let sku_str = jnienv.new_string(sku)?;
157        let res = self.singleton.call_method(
158            &jnienv,
159            "updateSubscription",
160            &[old_token_str.into(), sku_str.into(), proration_mode.into()],
161        )?;
162        jnienv.exception_check()?;
163        Ok(JniRustType::from_jobject(&jnienv, res.l()?)?)
164    }
165
166    pub fn set_obfuscated_account_id<S>(&self, account_id: S) -> Result<()>
167    where
168        S: AsRef<str>,
169    {
170        let jnienv = self.vm.attach_current_thread_as_daemon()?;
171        let account_id_str = jnienv.new_string(account_id)?;
172        self.singleton
173            .call_method(&jnienv, "setObfuscatedAccountId", &[account_id_str.into()])?;
174        jnienv.exception_check()?;
175        Ok(())
176    }
177
178    pub fn set_obfuscated_profile_id<S>(&self, profile_id: S) -> Result<()>
179    where
180        S: AsRef<str>,
181    {
182        let jnienv = self.vm.attach_current_thread_as_daemon()?;
183        let profile_id_str = jnienv.new_string(profile_id)?;
184        self.singleton
185            .call_method(&jnienv, "setObfuscatedProfileId", &[profile_id_str.into()])?;
186        jnienv.exception_check()?;
187        Ok(())
188    }
189}