android_manifest/
lib.rs

1#[macro_use]
2extern crate yaserde_derive;
3
4mod action;
5mod activity;
6mod activity_alias;
7mod application;
8mod attribute_list;
9mod category;
10mod compatible_screens;
11mod data;
12pub mod error;
13mod grant_uri_permission;
14mod instrumentation;
15mod intent_filter;
16mod layout;
17mod manifest;
18mod meta_data;
19mod path_permission;
20mod permission;
21mod permission_group;
22mod permission_tree;
23mod profileable;
24mod provider;
25mod queries;
26mod receiver;
27mod resources;
28mod service;
29mod supports_gl_texture;
30mod supports_screens;
31mod ui_options;
32mod uses_configuration;
33mod uses_feature;
34mod uses_library;
35mod uses_native_library;
36mod uses_permission;
37mod uses_permission_sdk_23;
38mod uses_sdk;
39mod var_or_bool;
40
41pub use action::*;
42pub use activity::*;
43pub use activity_alias::*;
44pub use application::*;
45pub use attribute_list::*;
46pub use category::*;
47pub use compatible_screens::*;
48pub use data::*;
49use error::{Error, Result};
50pub use grant_uri_permission::*;
51pub use instrumentation::*;
52pub use intent_filter::*;
53pub use layout::*;
54pub use manifest::*;
55pub use meta_data::*;
56pub use path_permission::*;
57pub use permission::*;
58pub use permission_group::*;
59pub use permission_tree::*;
60pub use profileable::*;
61pub use provider::*;
62pub use queries::*;
63pub use receiver::*;
64pub use resources::*;
65pub use service::*;
66pub use supports_gl_texture::*;
67pub use supports_screens::*;
68pub use ui_options::*;
69pub use uses_configuration::*;
70pub use uses_feature::*;
71pub use uses_library::*;
72pub use uses_native_library::UsesNativeLibrary;
73pub use uses_permission::*;
74pub use uses_permission_sdk_23::*;
75pub use uses_sdk::*;
76pub use var_or_bool::*;
77
78/// Deserialize an instance of type [`AndroidManifest`](crate::AndroidManifest) from a
79/// string of XML text.
80pub fn from_str(s: &str) -> Result<AndroidManifest> {
81    yaserde::de::from_str(s).map_err(Error::FailedToDeserialize)
82}
83
84/// Deserialize an instance of type [`AndroidManifest`](crate::AndroidManifest) from an IO
85/// stream of XML text.
86pub fn from_reader<R: std::io::Read>(reader: R) -> Result<AndroidManifest> {
87    yaserde::de::from_reader(reader).map_err(Error::FailedToDeserialize)
88}
89
90/// Serialize the given [`AndroidManifest`](crate::AndroidManifest) structure as a String
91/// of XML text.
92pub fn to_string(manifest: &AndroidManifest) -> Result<String> {
93    yaserde::ser::to_string(manifest).map_err(Error::FailedToSerialize)
94}
95
96/// Serialize the given [`AndroidManifest`](crate::AndroidManifest) structure as a
97/// pretty-printed String of XML text.
98pub fn to_string_pretty(manifest: &AndroidManifest) -> Result<String> {
99    let config = yaserde::ser::Config {
100        perform_indent: true,
101        write_document_declaration: true,
102        indent_string: None,
103    };
104    yaserde::ser::to_string_with_config(manifest, &config).map_err(Error::FailedToSerialize)
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn test_complex_manifest_deserialize() {
113        let given_xml = r#"<?xml version="1.0" encoding="utf-8"?>
114    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
115              package="org.domokit.gcm"
116              android:versionCode="4"
117              android:versionName="0.0.4">
118        <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
119        <uses-permission android:name="android.permission.INTERNET" />
120
121        <uses-permission android:name="android.permission.WAKE_LOCK" />
122        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
123
124        <permission android:name="org.domokit.gcm.permission.C2D_MESSAGE"
125            android:protectionLevel="signature" />
126        <uses-permission android:name="org.domokit.gcm.permission.C2D_MESSAGE" />
127
128        <application android:label="gcm" android:name="org.domokit.sky.shell.SkyApplication" android:usesCleartextTraffic="${usesCleartextTraffic}">
129            <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
130                      android:hardwareAccelerated="true"
131                      android:launchMode="singleTask"
132                      android:name="org.domokit.sky.shell.SkyActivity"
133                      android:theme="@android:style/Theme.Black.NoTitleBar">
134                <intent-filter>
135                    <action android:name="android.intent.action.MAIN" />
136                    <category android:name="android.intent.category.LAUNCHER" />
137                </intent-filter>
138            </activity>
139            <service
140                android:name="org.domokit.sky.shell.UpdateService"
141                android:exported="false"
142                android:process=":remote"/>
143            <receiver
144                android:name="com.google.android.gms.gcm.GcmReceiver"
145                android:exported="true"
146                android:permission="com.google.android.c2dm.permission.SEND" >
147                <intent-filter>
148                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
149                    <category android:name="org.domokit.sky.shell" />
150                </intent-filter>
151            </receiver>
152            <service
153                android:name="org.domokit.gcm.GcmListenerService"
154                android:exported="false" >
155                <intent-filter>
156                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
157                </intent-filter>
158            </service>
159            <service
160                android:name="org.domokit.gcm.InstanceIDListenerService"
161                android:exported="false">
162                <intent-filter>
163                    <action android:name="com.google.android.gms.iid.InstanceID"/>
164                </intent-filter>
165            </service>
166            <service
167                android:name="org.domokit.gcm.RegistrationIntentService"
168                android:exported="false">
169            </service>
170        </application>
171    </manifest>"#;
172        let expected_manifest = AndroidManifest {
173            package: "org.domokit.gcm".to_string(),
174            version_code: Some(4),
175            version_name: Some("0.0.4".to_string()),
176            application: Application {
177                label: Some(StringResourceOrString::string("gcm")),
178                name: Some("org.domokit.sky.shell.SkyApplication".to_string()),
179                uses_cleartext_traffic: Some("${usesCleartextTraffic}".into()),
180                activity: vec![Activity {
181                    config_changes: AttributeList::from_vec(vec![
182                        ConfigChanges::Orientation,
183                        ConfigChanges::KeyboardHidden,
184                        ConfigChanges::Keyboard,
185                        ConfigChanges::ScreenSize,
186                    ]),
187                    hardware_accelerated: Some(true.into()),
188                    launch_mode: Some(LaunchMode::SingleTask),
189                    name: "org.domokit.sky.shell.SkyActivity".to_string(),
190                    theme: Some(StyleResource::new(
191                        "Theme.Black.NoTitleBar",
192                        Some("android".to_string()),
193                    )),
194                    intent_filter: vec![IntentFilter {
195                        action: vec![Action {
196                            name: Some("android.intent.action.MAIN".to_string()),
197                        }],
198                        category: vec![Category {
199                            name: Some("android.intent.category.LAUNCHER".to_string()),
200                        }],
201                        ..Default::default()
202                    }],
203                    ..Default::default()
204                }],
205                service: vec![
206                    Service {
207                        exported: Some(false.into()),
208                        name: "org.domokit.sky.shell.UpdateService".to_string(),
209                        process: Some(":remote".to_string()),
210                        ..Default::default()
211                    },
212                    Service {
213                        exported: Some(false.into()),
214                        name: "org.domokit.gcm.GcmListenerService".to_string(),
215                        intent_filter: vec![IntentFilter {
216                            action: vec![Action {
217                                name: Some("com.google.android.c2dm.intent.RECEIVE".to_string()),
218                            }],
219                            ..Default::default()
220                        }],
221                        ..Default::default()
222                    },
223                    Service {
224                        exported: Some(false.into()),
225                        name: "org.domokit.gcm.InstanceIDListenerService".to_string(),
226                        intent_filter: vec![IntentFilter {
227                            action: vec![Action {
228                                name: Some("com.google.android.gms.iid.InstanceID".to_string()),
229                            }],
230                            ..Default::default()
231                        }],
232                        ..Default::default()
233                    },
234                    Service {
235                        exported: Some(false.into()),
236                        name: "org.domokit.gcm.RegistrationIntentService".to_string(),
237                        ..Default::default()
238                    },
239                ],
240                receiver: vec![Receiver {
241                    exported: Some(true.into()),
242                    name: "com.google.android.gms.gcm.GcmReceiver".to_string(),
243                    permission: Some("com.google.android.c2dm.permission.SEND".to_string()),
244                    intent_filter: vec![IntentFilter {
245                        action: vec![Action {
246                            name: Some("com.google.android.c2dm.intent.RECEIVE".to_string()),
247                        }],
248                        category: vec![Category {
249                            name: Some("org.domokit.sky.shell".to_string()),
250                        }],
251                        ..Default::default()
252                    }],
253                    ..Default::default()
254                }],
255                ..Default::default()
256            },
257            uses_sdk: Some(UsesSdk {
258                min_sdk_version: Some(14),
259                target_sdk_version: Some(21),
260                ..Default::default()
261            }),
262            permission: vec![Permission {
263                name: Some("org.domokit.gcm.permission.C2D_MESSAGE".to_string()),
264                protection_level: Some(ProtectionLevel::Signature),
265                ..Default::default()
266            }],
267            uses_permission: vec![
268                UsesPermission {
269                    name: Some("android.permission.INTERNET".to_string()),
270                    ..Default::default()
271                },
272                UsesPermission {
273                    name: Some("android.permission.WAKE_LOCK".to_string()),
274                    ..Default::default()
275                },
276                UsesPermission {
277                    name: Some("com.google.android.c2dm.permission.RECEIVE".to_string()),
278                    ..Default::default()
279                },
280                UsesPermission {
281                    name: Some("org.domokit.gcm.permission.C2D_MESSAGE".to_string()),
282                    ..Default::default()
283                },
284            ],
285            ..Default::default()
286        };
287        let deserialized_xml_manifest: AndroidManifest = from_str(given_xml).unwrap();
288        assert_eq!(expected_manifest, deserialized_xml_manifest);
289        let serialized_toml_manifest = toml::to_string_pretty(&deserialized_xml_manifest).unwrap();
290        let deserialized_toml_manifest: AndroidManifest =
291            toml::from_str(&serialized_toml_manifest).unwrap();
292        assert_eq!(deserialized_xml_manifest, deserialized_toml_manifest);
293    }
294}