BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.struct;
30 |
31 | /**
32 | * A Chunk is just a piece of memory split into two parts, a header and a body.
33 | * The exact structure of the header and the body of a given Chunk is determined by its type.
34 | *
35 | * chunk header struct.
36 | * struct ResChunk_header {
37 | * uint16_t type;
38 | * uint16_t headerSize;
39 | * uint32_t size;
40 | * }
41 | *
42 | */
43 | public class ChunkHeader {
44 |
45 | // Type identifier for this chunk. The meaning of this value depends
46 | // on the containing chunk.
47 | private int chunkType;
48 |
49 | // Size of the chunk header (in bytes). Adding this value to
50 | // the address of the chunk allows you to find its associated data
51 | // (if any).
52 | private int headerSize;
53 |
54 | // Total size of this chunk (in bytes). This is the chunkSize plus
55 | // the size of any data associated with the chunk. Adding this value
56 | // to the chunk allows you to completely skip its contents (including
57 | // any child chunks). If this value is the same as chunkSize, there is
58 | // no data associated with the chunk.
59 | private long chunkSize;
60 |
61 | public ChunkHeader(int chunkType, int headerSize, long chunkSize) {
62 | this.chunkType = chunkType;
63 | this.headerSize = headerSize;
64 | this.chunkSize = chunkSize;
65 | }
66 |
67 | public int getBodySize() {
68 | return (int) (this.chunkSize - this.headerSize);
69 | }
70 |
71 | public int getChunkType() {
72 | return chunkType;
73 | }
74 |
75 | public void setChunkType(int chunkType) {
76 | this.chunkType = chunkType;
77 | }
78 |
79 | public int getHeaderSize() {
80 | return headerSize;
81 | }
82 |
83 | public void setHeaderSize(int headerSize) {
84 | this.headerSize = headerSize;
85 | }
86 |
87 | public long getChunkSize() {
88 | return chunkSize;
89 | }
90 |
91 | public void setChunkSize(long chunkSize) {
92 | this.chunkSize = chunkSize;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/jaredrummler/apkparser/sample/fragments/AppListFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package com.jaredrummler.apkparser.sample.fragments;
19 |
20 | import android.app.ListFragment;
21 | import android.content.pm.PackageInfo;
22 | import android.content.pm.PackageManager;
23 | import android.os.AsyncTask;
24 | import android.os.Bundle;
25 | import android.os.Parcelable;
26 | import android.view.View;
27 | import android.widget.AdapterView;
28 |
29 | import com.jaredrummler.apkparser.sample.adapters.AppListAdapter;
30 | import com.jaredrummler.apkparser.sample.dialogs.AppDialog;
31 | import com.jaredrummler.apkparser.sample.util.AppNames;
32 |
33 | import java.util.ArrayList;
34 | import java.util.Collections;
35 | import java.util.Comparator;
36 | import java.util.List;
37 |
38 | public class AppListFragment extends ListFragment implements AdapterView.OnItemClickListener {
39 |
40 | private final ArrayList installedPackages = new ArrayList<>();
41 | private Parcelable listState;
42 |
43 | @Override public void onViewCreated(View view, Bundle savedInstanceState) {
44 | super.onViewCreated(view, savedInstanceState);
45 | if (savedInstanceState != null) {
46 | ArrayList packages = savedInstanceState.getParcelableArrayList("packages");
47 | if (packages != null && !packages.isEmpty()) {
48 | installedPackages.addAll(packages);
49 | }
50 | listState = savedInstanceState.getParcelable("state");
51 | }
52 | new AppLoader().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
53 | getListView().setOnItemClickListener(this);
54 | }
55 |
56 | @Override public void onSaveInstanceState(Bundle outState) {
57 | super.onSaveInstanceState(outState);
58 | outState.putParcelableArrayList("packages", installedPackages);
59 | outState.putParcelable("state", getListView().onSaveInstanceState());
60 | }
61 |
62 | @Override public void onItemClick(AdapterView> parent, View view, int position, long id) {
63 | AppDialog.show(getActivity(), installedPackages.get(position));
64 | }
65 |
66 | private final class AppLoader extends AsyncTask> {
67 |
68 | @Override protected List doInBackground(Void... params) {
69 | if (installedPackages.isEmpty()) {
70 | final PackageManager pm = getActivity().getPackageManager();
71 | installedPackages.addAll(pm.getInstalledPackages(0));
72 | Collections.sort(installedPackages, new Comparator() {
73 |
74 | @Override public int compare(PackageInfo lhs, PackageInfo rhs) {
75 | return AppNames.getLabel(pm, lhs).compareToIgnoreCase(AppNames.getLabel(pm, rhs));
76 | }
77 | });
78 | }
79 | return installedPackages;
80 | }
81 |
82 | @Override protected void onPostExecute(List apps) {
83 | setListAdapter(new AppListAdapter(getActivity(), apps));
84 | getListView().setFastScrollEnabled(true);
85 | if (listState != null) {
86 | getListView().onRestoreInstanceState(listState);
87 | listState = null;
88 | }
89 | }
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/utils/xml/XmlEscaper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.utils.xml;
30 |
31 | /**
32 | * Utils method to escape xml string, copied from apache commons lang3
33 | */
34 | public class XmlEscaper {
35 |
36 | /**
37 | * Escapes the characters in a {@code String} using XML entities.
38 | */
39 | public static String escapeXml10(String input) {
40 | return ESCAPE_XML10.translate(input);
41 | }
42 |
43 | public static final CharSequenceTranslator ESCAPE_XML10 =
44 | new AggregateTranslator(
45 | new LookupTranslator(EntityArrays.BASIC_ESCAPE()),
46 | new LookupTranslator(EntityArrays.APOS_ESCAPE()),
47 | new LookupTranslator(
48 | new String[][]{
49 | {"\u0000", ""},
50 | {"\u0001", ""},
51 | {"\u0002", ""},
52 | {"\u0003", ""},
53 | {"\u0004", ""},
54 | {"\u0005", ""},
55 | {"\u0006", ""},
56 | {"\u0007", ""},
57 | {"\u0008", ""},
58 | {"\u000b", ""},
59 | {"\u000c", ""},
60 | {"\u000e", ""},
61 | {"\u000f", ""},
62 | {"\u0010", ""},
63 | {"\u0011", ""},
64 | {"\u0012", ""},
65 | {"\u0013", ""},
66 | {"\u0014", ""},
67 | {"\u0015", ""},
68 | {"\u0016", ""},
69 | {"\u0017", ""},
70 | {"\u0018", ""},
71 | {"\u0019", ""},
72 | {"\u001a", ""},
73 | {"\u001b", ""},
74 | {"\u001c", ""},
75 | {"\u001d", ""},
76 | {"\u001e", ""},
77 | {"\u001f", ""},
78 | {"\ufffe", ""},
79 | {"\uffff", ""}
80 | }),
81 | NumericEntityEscaper.between(0x7f, 0x84),
82 | NumericEntityEscaper.between(0x86, 0x9f),
83 | new UnicodeUnpairedSurrogateRemover()
84 | );
85 | }
86 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/struct/resource/ResourceEntry.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.struct.resource;
30 |
31 | import com.jaredrummler.apkparser.struct.ResourceEntity;
32 |
33 | import java.util.Locale;
34 |
35 | public class ResourceEntry {
36 |
37 | // Number of bytes in this structure. uint16_t
38 | private int size;
39 |
40 | // If set, this is a complex entry, holding a set of name/value
41 | // mappings. It is followed by an array of ResTable_map structures.
42 | public static final int FLAG_COMPLEX = 0x0001;
43 | // If set, this resource has been declared public, so libraries
44 | // are allowed to reference it.
45 | public static final int FLAG_PUBLIC = 0x0002;
46 | // uint16_t
47 | private int flags;
48 |
49 | // Reference into ResTable_package::keyStrings identifying this entry.
50 | //public long keyRef;
51 |
52 | private String key;
53 |
54 | // the resvalue following this resource entry.
55 | private ResourceEntity value;
56 |
57 | public String toStringValue(ResourceTable resourceTable, Locale locale) {
58 | if (value != null) {
59 | return value.toStringValue(resourceTable, locale);
60 | } else {
61 | return "null";
62 | }
63 | }
64 |
65 | public int getSize() {
66 | return size;
67 | }
68 |
69 | public void setSize(int size) {
70 | this.size = size;
71 | }
72 |
73 | public int getFlags() {
74 | return flags;
75 | }
76 |
77 | public void setFlags(int flags) {
78 | this.flags = flags;
79 | }
80 |
81 | public String getKey() {
82 | return key;
83 | }
84 |
85 | public void setKey(String key) {
86 | this.key = key;
87 | }
88 |
89 | public ResourceEntity getValue() {
90 | return value;
91 | }
92 |
93 | public void setValue(ResourceEntity value) {
94 | this.value = value;
95 | }
96 |
97 | @Override public String toString() {
98 | return "ResourceEntry{" + "size=" + size + ", flags=" + flags + ", key='" + key + '\'' +
99 | ", value=" + value + '}';
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/struct/resource/TypeHeader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.struct.resource;
30 |
31 | import com.jaredrummler.apkparser.struct.ChunkHeader;
32 |
33 | public class TypeHeader extends ChunkHeader {
34 |
35 | public static final long NO_ENTRY = 0xFFFFFFFFL;
36 |
37 | // The type identifier this chunk is holding. Type IDs start at 1 (corresponding to the value
38 | // of the type bits in a resource identifier). 0 is invalid.
39 | // uint8_t
40 | private short id;
41 |
42 | // Must be 0. uint8_t
43 | private short res0;
44 | // Must be 0. uint16_t
45 | private int res1;
46 |
47 | // Number of uint32_t entry indices that follow. uint32
48 | private long entryCount;
49 |
50 | // Offset from header where ResTable_entry data starts.uint32_t
51 | private long entriesStart;
52 |
53 | // Configuration this collection of entries is designed for.
54 | private ResTableConfig config;
55 |
56 | public TypeHeader(int chunkType, int headerSize, long chunkSize) {
57 | super(chunkType, headerSize, chunkSize);
58 | }
59 |
60 | public short getId() {
61 | return id;
62 | }
63 |
64 | public void setId(short id) {
65 | this.id = id;
66 | }
67 |
68 | public short getRes0() {
69 | return res0;
70 | }
71 |
72 | public void setRes0(short res0) {
73 | this.res0 = res0;
74 | }
75 |
76 | public int getRes1() {
77 | return res1;
78 | }
79 |
80 | public void setRes1(int res1) {
81 | this.res1 = res1;
82 | }
83 |
84 | public long getEntryCount() {
85 | return entryCount;
86 | }
87 |
88 | public void setEntryCount(long entryCount) {
89 | this.entryCount = entryCount;
90 | }
91 |
92 | public long getEntriesStart() {
93 | return entriesStart;
94 | }
95 |
96 | public void setEntriesStart(long entriesStart) {
97 | this.entriesStart = entriesStart;
98 | }
99 |
100 | public ResTableConfig getConfig() {
101 | return config;
102 | }
103 |
104 | public void setConfig(ResTableConfig config) {
105 | this.config = config;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/utils/xml/LookupTranslator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.utils.xml;
30 |
31 | import java.io.IOException;
32 | import java.io.Writer;
33 | import java.util.HashMap;
34 |
35 | /**
36 | * Translates a value using a lookup table.
37 | */
38 | class LookupTranslator extends CharSequenceTranslator {
39 |
40 | private final HashMap lookupMap;
41 | private final int shortest;
42 | private final int longest;
43 |
44 | /**
45 | * Define the lookup table to be used in translation
46 | *
47 | * Note that, as of Lang 3.1, the key to the lookup table is converted to a
48 | * java.lang.String, while the value remains as a java.lang.CharSequence.
49 | * This is because we need the key to support hashCode and equals(Object),
50 | * allowing it to be the key for a HashMap. See LANG-882.
51 | *
52 | * @param lookup
53 | * CharSequence[][] table of size [*][2]
54 | */
55 | public LookupTranslator(final CharSequence[]... lookup) {
56 | lookupMap = new HashMap<>();
57 | int _shortest = Integer.MAX_VALUE;
58 | int _longest = 0;
59 | if (lookup != null) {
60 | for (final CharSequence[] seq : lookup) {
61 | this.lookupMap.put(seq[0].toString(), seq[1]);
62 | final int sz = seq[0].length();
63 | if (sz < _shortest) {
64 | _shortest = sz;
65 | }
66 | if (sz > _longest) {
67 | _longest = sz;
68 | }
69 | }
70 | }
71 | shortest = _shortest;
72 | longest = _longest;
73 | }
74 |
75 | @Override public int translate(final CharSequence input, final int index, final Writer out)
76 | throws IOException {
77 | int max = longest;
78 | if (index + longest > input.length()) {
79 | max = input.length() - index;
80 | }
81 | // descend so as to get a greedy algorithm
82 | for (int i = max; i >= shortest; i--) {
83 | final CharSequence subSeq = input.subSequence(index, index + i);
84 | final CharSequence result = lookupMap.get(subSeq.toString());
85 | if (result != null) {
86 | out.write(result.toString());
87 | return i;
88 | }
89 | }
90 | return 0;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # APK Parser [](https://maven-badges.herokuapp.com/maven-central/com.jaredrummler/apk-parser) [](LICENSE.txt) [](https://twitter.com/jrummy16)
2 |
3 | #### Features
4 | * Retrieve basic apk metas, such as title, icon, package name, version, etc.
5 | * Parse and convert binary xml file to text
6 | * Classes from dex file
7 | * Get certificate metas and verify apk signature
8 |
9 | 
10 |
11 | #### Get apk-parser
12 | Download [the latest AAR](https://repo1.maven.org/maven2/com/jaredrummler/apk-parser/1.0.2/apk-parser-1.0.2.aar) or grab via Gradle:
13 |
14 | ```groovy
15 | compile 'com.jaredrummler:apk-parser:1.0.2'
16 | ```
17 |
18 | #### Usage
19 | The easiest way is to use the ApkParser class, which contains convenient methods to get AndroidManifest.xml, apk meta infos, etc.
20 | #####1. Apk meta info
21 | ApkMeta contains name(label), packageName, version, sdk, used features, etc.
22 | ```java
23 | PackageManager pm = getPackageManager();
24 | ApplicationInfo appInfo = pm.getApplicationInfo("com.facebook.katana", 0);
25 | ApkParser apkParser = ApkParser.create(appInfo);
26 | ApkMeta meta = apkParser.getApkMeta();
27 | String packageName = meta.packageName;
28 | long versionCode = meta.versionCode;
29 | List usesFeatures = meta.usesFeatures;
30 | List requestedPermissions = meta.usesPermissions;
31 | ```
32 | #####2. Get binary xml and manifest xml file
33 | ```java
34 | ApplicationInfo appInfo = getPackageManager().getApplicationInfo("some.package.name", 0);
35 | ApkParser apkParser = ApkParser.create(appInfo);
36 | String readableAndroidManifest = apkParser.getManifestXml();
37 | String xml = apkParser.transBinaryXml("res/layout/activity_main.xml");
38 | ```
39 | #####3. Get dex classes
40 | ```java
41 | ApplicationInfo appInfo = getPackageManager().getApplicationInfo("com.instagram.android", 0);
42 | ApkParser apkParser = ApkParser.create(appInfo);
43 | List dexFiles = apkParser.getDexInfos(); // if size > 1 then app is using multidex
44 | for (DexInfo dexInfo : dexFiles) {
45 | DexClass[] dexClasses = dexInfo.classes;
46 | DexHeader dexHeader = dexInfo.header;
47 | }
48 | ```
49 |
50 | #####4. Get certificate and verify apk signature
51 | ```java
52 | ApplicationInfo appInfo = getPackageManager().getApplicationInfo("com.instagram.android", 0);
53 | ApkParser apkParser = ApkParser.create(appInfo);
54 | if (apkParser.verifyApk() == ApkParser.ApkSignStatus.SIGNED) {
55 | System.out.println(apkParser.getCertificateMeta().signAlgorithm);
56 | }
57 | ```
58 |
59 | #####5. Get intent-filters from apk manifest:
60 | ```java
61 | ApkParser parser = ApkParser.create(getPackageManager(), "com.android.settings");
62 | AndroidManifest androidManifest = parser.getAndroidManifest();
63 | for (AndroidComponent component : androidManifest.getComponents()) {
64 | if (!component.intentFilters.isEmpty()) {
65 | for (IntentFilter intentFilter : component.intentFilters) {
66 | // Got an intent filter for activity/service/provider/receiver.
67 | }
68 | }
69 | }
70 | ```
71 |
72 | #####6. Locales
73 | Apk may return different infos(title, icon, etc.) for different region and language, which is
74 | determined by Locales.
75 | If the locale is not set, the "en_US" locale(Locale.US) is used. You can set the
76 | locale like this:
77 | ```java
78 | ApkParser apkParser = ApkParser.create(filePath);
79 | apkParser.setPreferredLocale(Locale.SIMPLIFIED_CHINESE);
80 | ApkMeta apkMeta = apkParser.getApkMeta();
81 | ```
82 | The PreferredLocale parameter work for getApkMeta, getManifestXml, and other binary xmls.
83 | Apk parser will find best match languages with locale you specified.
84 |
85 | If locale is set to null, ApkParser will not translate resource tag, just give the resource id.
86 | For example, apk title will be '@string/app_name' instead of 'WeChat'.
87 |
88 | ___
89 |
90 | APK Parser is based on [CaoQianLi's apk-parser](https://github.com/CaoQianLi/apk-parser)
91 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/jaredrummler/apkparser/sample/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package com.jaredrummler.apkparser.sample.activities;
19 |
20 | import android.app.ProgressDialog;
21 | import android.content.Intent;
22 | import android.content.pm.PackageInfo;
23 | import android.os.AsyncTask;
24 | import android.os.Bundle;
25 | import android.os.Looper;
26 | import android.support.v7.app.AppCompatActivity;
27 | import android.widget.Toast;
28 |
29 | import com.jaredrummler.apkparser.ApkParser;
30 | import com.jaredrummler.apkparser.model.DexInfo;
31 | import com.jaredrummler.apkparser.sample.dialogs.XmlListDialog;
32 | import com.jaredrummler.apkparser.sample.fragments.AppListFragment;
33 | import com.jaredrummler.apkparser.sample.interfaces.ApkParserSample;
34 | import com.jaredrummler.apkparser.sample.util.Helper;
35 |
36 | import java.io.IOException;
37 | import java.text.NumberFormat;
38 | import java.util.List;
39 |
40 | public class MainActivity extends AppCompatActivity implements ApkParserSample {
41 |
42 | @Override protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | if (savedInstanceState == null) {
45 | getFragmentManager()
46 | .beginTransaction()
47 | .add(android.R.id.content, new AppListFragment())
48 | .commit();
49 | }
50 | }
51 |
52 | @Override public void openXmlFile(PackageInfo app, String xml) {
53 | Intent intent = new Intent(this, XmlSourceViewerActivity.class);
54 | intent.putExtra("app", app);
55 | intent.putExtra("xml", xml);
56 | startActivity(intent);
57 | }
58 |
59 | @Override public void listXmlFiles(final PackageInfo app) {
60 | final ProgressDialog pd = new ProgressDialog(this);
61 | pd.setMessage("Please wait...");
62 | pd.show();
63 |
64 | new AsyncTask() {
65 |
66 | @Override protected String[] doInBackground(Void... params) {
67 | return Helper.getXmlFiles(app.applicationInfo.sourceDir);
68 | }
69 |
70 | @Override protected void onPostExecute(String[] items) {
71 | pd.dismiss();
72 | if (!isFinishing()) {
73 | XmlListDialog.show(MainActivity.this, app, items);
74 | }
75 | }
76 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
77 | }
78 |
79 | @Override public void showMethodCount(final PackageInfo app) {
80 | new Thread(new Runnable() {
81 |
82 | @Override public void run() {
83 | ApkParser parser = ApkParser.create(app);
84 | try {
85 | List dexInfos = parser.getDexInfos();
86 | int methodCount = 0;
87 | for (DexInfo dexInfo : dexInfos) {
88 | methodCount += dexInfo.header.methodIdsSize;
89 | }
90 | String message = NumberFormat.getNumberInstance().format(methodCount);
91 | toast(message, Toast.LENGTH_SHORT);
92 | } catch (IOException e) {
93 | toast(e.getMessage(), Toast.LENGTH_LONG);
94 | } finally {
95 | parser.close();
96 | }
97 | }
98 | }).start();
99 | }
100 |
101 | private void toast(final String message, final int length) {
102 | if (Looper.myLooper() == Looper.getMainLooper()) {
103 | Toast.makeText(getApplicationContext(), message, length).show();
104 | } else {
105 | runOnUiThread(new Runnable() {
106 |
107 | @Override public void run() {
108 | Toast.makeText(getApplicationContext(), message, length).show();
109 | }
110 | });
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/struct/resource/PackageHeader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.struct.resource;
30 |
31 | import com.jaredrummler.apkparser.struct.ChunkHeader;
32 |
33 | public class PackageHeader extends ChunkHeader {
34 |
35 | // If this is a base package, its ID. ResourcePackage IDs start at 1 (corresponding to the value of
36 | // the package bits in a resource identifier). 0 means this is not a base package.
37 | // uint32_t
38 | private long id;
39 |
40 | // Actual name of this package, -terminated.
41 | // char16_t name[128]
42 | private String name;
43 |
44 | // Offset to a ResStringPool_header defining the resource type symbol table.
45 | // If zero, this package is inheriting from another base package (overriding specific values in it).
46 | // uinit 32
47 | private long typeStrings;
48 |
49 | // Last index into typeStrings that is for public use by others.
50 | // uint32_t
51 | private long lastPublicType;
52 |
53 | // Offset to a ResStringPool_header defining the resource
54 | // key symbol table. If zero, this package is inheriting from
55 | // another base package (overriding specific values in it).
56 | // uint32_t
57 | private long keyStrings;
58 |
59 | // Last index into keyStrings that is for public use by others.
60 | // uint32_t
61 | private long lastPublicKey;
62 |
63 | public PackageHeader(int chunkType, int headerSize, long chunkSize) {
64 | super(chunkType, headerSize, chunkSize);
65 | }
66 |
67 | public long getId() {
68 | return id;
69 | }
70 |
71 | public void setId(long id) {
72 | this.id = id;
73 | }
74 |
75 | public String getName() {
76 | return name;
77 | }
78 |
79 | public void setName(String name) {
80 | this.name = name;
81 | }
82 |
83 | public long getTypeStrings() {
84 | return typeStrings;
85 | }
86 |
87 | public void setTypeStrings(long typeStrings) {
88 | this.typeStrings = typeStrings;
89 | }
90 |
91 | public long getLastPublicType() {
92 | return lastPublicType;
93 | }
94 |
95 | public void setLastPublicType(long lastPublicType) {
96 | this.lastPublicType = lastPublicType;
97 | }
98 |
99 | public long getKeyStrings() {
100 | return keyStrings;
101 | }
102 |
103 | public void setKeyStrings(long keyStrings) {
104 | this.keyStrings = keyStrings;
105 | }
106 |
107 | public long getLastPublicKey() {
108 | return lastPublicKey;
109 | }
110 |
111 | public void setLastPublicKey(long lastPublicKey) {
112 | this.lastPublicKey = lastPublicKey;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/struct/xml/Attribute.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.struct.xml;
30 |
31 | import android.util.SparseArray;
32 |
33 | import com.jaredrummler.apkparser.struct.ResourceEntity;
34 | import com.jaredrummler.apkparser.struct.resource.ResourceTable;
35 | import com.jaredrummler.apkparser.utils.ResourceLoader;
36 |
37 | import java.util.Locale;
38 |
39 | public class Attribute {
40 |
41 | private String namespace;
42 | private String name;
43 | // The original raw string value of this
44 | private String rawValue;
45 | // Processed typed value of this
46 | private ResourceEntity typedValue;
47 | // the final value as string
48 | private String value;
49 |
50 | public String toStringValue(ResourceTable resourceTable, Locale locale) {
51 | if (rawValue != null) {
52 | return rawValue;
53 | } else if (typedValue != null) {
54 | return typedValue.toStringValue(resourceTable, locale);
55 | } else {
56 | // something happen;
57 | return "";
58 | }
59 | }
60 |
61 | /**
62 | * These are attribute resource constants for the platform; as found in android.R.attr
63 | */
64 | public static class AttrIds {
65 |
66 | private static final SparseArray IDS = ResourceLoader.loadSystemAttrIds();
67 |
68 | public static String getString(long id) {
69 | String value = IDS.get((int) id);
70 | if (value == null) {
71 | value = "AttrId:0x" + Long.toHexString(id);
72 | }
73 | return value;
74 | }
75 |
76 | }
77 |
78 | public String getNamespace() {
79 | return namespace;
80 | }
81 |
82 | public void setNamespace(String namespace) {
83 | this.namespace = namespace;
84 | }
85 |
86 | public String getName() {
87 | return name;
88 | }
89 |
90 | public void setName(String name) {
91 | this.name = name;
92 | }
93 |
94 | public String getRawValue() {
95 | return rawValue;
96 | }
97 |
98 | public void setRawValue(String rawValue) {
99 | this.rawValue = rawValue;
100 | }
101 |
102 | public ResourceEntity getTypedValue() {
103 | return typedValue;
104 | }
105 |
106 | public void setTypedValue(ResourceEntity typedValue) {
107 | this.typedValue = typedValue;
108 | }
109 |
110 | public String getValue() {
111 | return value;
112 | }
113 |
114 | public void setValue(String value) {
115 | this.value = value;
116 | }
117 |
118 | @Override public String toString() {
119 | return "Attribute{" + "name='" + name + '\'' + ", namespace='" + namespace + '\'' + '}';
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/parser/XmlNamespaces.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.parser;
30 |
31 | import com.jaredrummler.apkparser.struct.xml.XmlNamespaceEndTag;
32 | import com.jaredrummler.apkparser.struct.xml.XmlNamespaceStartTag;
33 |
34 | import java.util.ArrayList;
35 | import java.util.Collections;
36 | import java.util.List;
37 |
38 | class XmlNamespaces {
39 |
40 | private final List namespaces = new ArrayList<>();
41 | private final List newNamespaces = new ArrayList<>();
42 |
43 | public void addNamespace(XmlNamespaceStartTag tag) {
44 | XmlNamespace namespace = new XmlNamespace(tag.getPrefix(), tag.getUri());
45 | namespaces.add(namespace);
46 | newNamespaces.add(namespace);
47 | }
48 |
49 | public void removeNamespace(XmlNamespaceEndTag tag) {
50 | XmlNamespace namespace = new XmlNamespace(tag.getPrefix(), tag.getUri());
51 | namespaces.remove(namespace);
52 | newNamespaces.remove(namespace);
53 | }
54 |
55 | public String getPrefixViaUri(String uri) {
56 | if (uri == null) {
57 | return null;
58 | }
59 | for (XmlNamespace namespace : namespaces) {
60 | if (namespace.uri.equals(uri)) {
61 | return namespace.prefix;
62 | }
63 | }
64 | return null;
65 | }
66 |
67 | public List consumeNameSpaces() {
68 | if (!newNamespaces.isEmpty()) {
69 | List xmlNamespaces = new ArrayList<>();
70 | xmlNamespaces.addAll(newNamespaces);
71 | newNamespaces.clear();
72 | return xmlNamespaces;
73 | } else {
74 | return Collections.emptyList();
75 | }
76 | }
77 |
78 | public static class XmlNamespace {
79 |
80 | final String prefix;
81 | final String uri;
82 |
83 | private XmlNamespace(String prefix, String uri) {
84 | this.prefix = prefix;
85 | this.uri = uri;
86 | }
87 |
88 | @Override public boolean equals(Object o) {
89 | if (this == o) return true;
90 | if (o == null || getClass() != o.getClass()) return false;
91 |
92 | XmlNamespace namespace = (XmlNamespace) o;
93 |
94 | if (prefix == null && namespace.prefix != null) return false;
95 | if (uri == null && namespace.uri != null) return false;
96 | if (prefix != null && !prefix.equals(namespace.prefix)) return false;
97 | if (uri != null && !uri.equals(namespace.uri)) return false;
98 |
99 | return true;
100 | }
101 |
102 | @Override public int hashCode() {
103 | int result = prefix.hashCode();
104 | result = 31 * result + uri.hashCode();
105 | return result;
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/struct/resource/ResourcePackage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.struct.resource;
30 |
31 | import com.jaredrummler.apkparser.struct.StringPool;
32 |
33 | import java.util.ArrayList;
34 | import java.util.HashMap;
35 | import java.util.List;
36 | import java.util.Map;
37 |
38 | public class ResourcePackage {
39 |
40 | // the packageName
41 | private String name;
42 | private short id;
43 | // contains the names of the types of the Resources defined in the ResourcePackage
44 | private StringPool typeStringPool;
45 | // contains the names (keys) of the Resources defined in the ResourcePackage.
46 | private StringPool keyStringPool;
47 |
48 | public ResourcePackage(PackageHeader header) {
49 | this.name = header.getName();
50 | this.id = (short) header.getId();
51 | }
52 |
53 | private Map typeSpecMap = new HashMap<>();
54 |
55 | private Map> typesMap = new HashMap<>();
56 |
57 | public void addTypeSpec(TypeSpec typeSpec) {
58 | this.typeSpecMap.put(typeSpec.getId(), typeSpec);
59 | }
60 |
61 | public TypeSpec getTypeSpec(Short id) {
62 | return this.typeSpecMap.get(id);
63 | }
64 |
65 | public void addType(Type type) {
66 | List types = this.typesMap.get(type.getId());
67 | if (types == null) {
68 | types = new ArrayList<>();
69 | this.typesMap.put(type.getId(), types);
70 | }
71 | types.add(type);
72 | }
73 |
74 | public List getTypes(Short id) {
75 | return this.typesMap.get(id);
76 | }
77 |
78 | public String getName() {
79 | return name;
80 | }
81 |
82 | public void setName(String name) {
83 | this.name = name;
84 | }
85 |
86 | public short getId() {
87 | return id;
88 | }
89 |
90 | public void setId(short id) {
91 | this.id = id;
92 | }
93 |
94 | public StringPool getTypeStringPool() {
95 | return typeStringPool;
96 | }
97 |
98 | public void setTypeStringPool(StringPool typeStringPool) {
99 | this.typeStringPool = typeStringPool;
100 | }
101 |
102 | public StringPool getKeyStringPool() {
103 | return keyStringPool;
104 | }
105 |
106 | public void setKeyStringPool(StringPool keyStringPool) {
107 | this.keyStringPool = keyStringPool;
108 | }
109 |
110 | public Map getTypeSpecMap() {
111 | return typeSpecMap;
112 | }
113 |
114 | public void setTypeSpecMap(Map typeSpecMap) {
115 | this.typeSpecMap = typeSpecMap;
116 | }
117 |
118 | public Map> getTypesMap() {
119 | return typesMap;
120 | }
121 |
122 | public void setTypesMap(Map> typesMap) {
123 | this.typesMap = typesMap;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/model/DexClass.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.model;
30 |
31 | import com.jaredrummler.apkparser.struct.dex.DexClassStruct;
32 |
33 | public class DexClass {
34 |
35 | public static Builder newDexClass() {
36 | return new Builder();
37 | }
38 |
39 | public final String classType;
40 | public final String superClass;
41 | public final int accessFlags;
42 |
43 | private DexClass(Builder builder) {
44 | this.classType = builder.classType;
45 | this.superClass = builder.superClass;
46 | this.accessFlags = builder.accessFlags;
47 | }
48 |
49 | public String getPackageName() {
50 | String packageName = classType;
51 | if (packageName.length() > 0) {
52 | if (packageName.charAt(0) == 'L') {
53 | packageName = packageName.substring(1);
54 | }
55 | }
56 | if (packageName.length() > 0) {
57 | int idx = classType.lastIndexOf('/');
58 | if (idx > 0) {
59 | packageName = packageName.substring(0, classType.lastIndexOf('/') - 1);
60 | } else if (packageName.charAt(packageName.length() - 1) == ';') {
61 | packageName = packageName.substring(0, packageName.length() - 1);
62 | }
63 | }
64 | return packageName.replace('/', '.');
65 | }
66 |
67 | public boolean isInterface() {
68 | return (accessFlags & DexClassStruct.ACC_INTERFACE) != 0;
69 | }
70 |
71 | public boolean isEnum() {
72 | return (accessFlags & DexClassStruct.ACC_ENUM) != 0;
73 | }
74 |
75 | public boolean isAnnotation() {
76 | return (accessFlags & DexClassStruct.ACC_ANNOTATION) != 0;
77 | }
78 |
79 | public boolean isPublic() {
80 | return (accessFlags & DexClassStruct.ACC_PUBLIC) != 0;
81 | }
82 |
83 | public boolean isProtected() {
84 | return (accessFlags & DexClassStruct.ACC_PROTECTED) != 0;
85 | }
86 |
87 | public boolean isStatic() {
88 | return (accessFlags & DexClassStruct.ACC_STATIC) != 0;
89 | }
90 |
91 | @Override public String toString() {
92 | return classType;
93 | }
94 |
95 | public static final class Builder {
96 |
97 | private String classType;
98 | private String superClass;
99 | private int accessFlags;
100 |
101 | private Builder() {
102 | }
103 |
104 | public DexClass build() {
105 | return new DexClass(this);
106 | }
107 |
108 | public Builder classType(String classType) {
109 | this.classType = classType;
110 | return this;
111 | }
112 |
113 | public Builder superClass(String superClass) {
114 | this.superClass = superClass;
115 | return this;
116 | }
117 |
118 | public Builder accessFlags(int accessFlags) {
119 | this.accessFlags = accessFlags;
120 | return this;
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/parser/CertificateParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.parser;
30 |
31 | import com.jaredrummler.apkparser.model.CertificateMeta;
32 | import com.jaredrummler.apkparser.utils.Utils;
33 |
34 | import java.io.BufferedInputStream;
35 | import java.io.IOException;
36 | import java.io.InputStream;
37 | import java.math.BigInteger;
38 | import java.nio.charset.Charset;
39 | import java.security.MessageDigest;
40 | import java.security.NoSuchAlgorithmException;
41 |
42 | import javax.security.cert.CertificateException;
43 | import javax.security.cert.X509Certificate;
44 |
45 | public class CertificateParser {
46 |
47 | private final InputStream in;
48 |
49 | public CertificateParser(InputStream in) {
50 | this.in = new BufferedInputStream(in);
51 | }
52 |
53 | public CertificateMeta parse() throws IOException, CertificateException {
54 | X509Certificate certificate = X509Certificate.getInstance(Utils.toByteArray(in));
55 | CertificateMeta.Builder builder = CertificateMeta.newCertificateMeta();
56 | byte[] bytes = certificate.getEncoded();
57 | String certMd5 = md5Digest(bytes);
58 | String publicKeyString = byteToHexString(bytes);
59 | String certBase64Md5 = md5Digest(publicKeyString);
60 | builder.data(bytes);
61 | builder.certBase64Md5(certBase64Md5);
62 | builder.certMd5(certMd5);
63 | builder.startDate(certificate.getNotBefore());
64 | builder.endDate(certificate.getNotAfter());
65 | builder.signAlgorithm(certificate.getSigAlgName());
66 | builder.signAlgorithmOID(certificate.getSigAlgOID());
67 | return builder.build();
68 | }
69 |
70 | private String md5Digest(byte[] input) throws IOException {
71 | MessageDigest digest = getDigest("MD5");
72 | digest.update(input);
73 | return getHexString(digest.digest());
74 | }
75 |
76 | private String md5Digest(String input) throws IOException {
77 | MessageDigest digest = getDigest("MD5");
78 | digest.update(input.getBytes(Charset.forName("UTF-8")));
79 | return getHexString(digest.digest());
80 | }
81 |
82 | private String byteToHexString(byte[] bArray) {
83 | StringBuilder sb = new StringBuilder(bArray.length);
84 | String sTemp;
85 | for (byte aBArray : bArray) {
86 | sTemp = Integer.toHexString(0xFF & (char) aBArray);
87 | if (sTemp.length() < 2) {
88 | sb.append(0);
89 | }
90 | sb.append(sTemp.toUpperCase());
91 | }
92 | return sb.toString();
93 | }
94 |
95 | private String getHexString(byte[] digest) {
96 | BigInteger bi = new BigInteger(1, digest);
97 | return String.format("%032x", bi);
98 | }
99 |
100 | private MessageDigest getDigest(String algorithm) {
101 | try {
102 | return MessageDigest.getInstance(algorithm);
103 | } catch (NoSuchAlgorithmException e) {
104 | throw new RuntimeException(e);
105 | }
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/parser/XmlTranslator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.parser;
30 |
31 | import com.jaredrummler.apkparser.struct.xml.*;
32 | import com.jaredrummler.apkparser.utils.xml.XmlEscaper;
33 |
34 | import java.util.List;
35 |
36 | public class XmlTranslator implements XmlStreamer {
37 |
38 | private StringBuilder sb = new StringBuilder("\n");
39 | private XmlNamespaces namespaces = new XmlNamespaces();
40 | private boolean isLastStartTag;
41 | private int shift;
42 |
43 | @Override public void onStartTag(XmlNodeStartTag xmlNodeStartTag) {
44 | if (isLastStartTag) {
45 | sb.append(">\n");
46 | }
47 | appendShift(shift++);
48 | sb.append('<');
49 | if (xmlNodeStartTag.getNamespace() != null) {
50 | String prefix = namespaces.getPrefixViaUri(xmlNodeStartTag.getNamespace());
51 | if (prefix != null) {
52 | sb.append(prefix).append(':');
53 | } else {
54 | sb.append(xmlNodeStartTag.getNamespace()).append(':');
55 | }
56 | }
57 | sb.append(xmlNodeStartTag.getName());
58 |
59 | List nps = namespaces.consumeNameSpaces();
60 | if (!nps.isEmpty()) {
61 | for (XmlNamespaces.XmlNamespace np : nps) {
62 | sb.append(" xmlns:")
63 | .append(np.prefix)
64 | .append("=\"")
65 | .append(np.uri)
66 | .append("\"");
67 | }
68 | }
69 | isLastStartTag = true;
70 |
71 | for (Attribute attribute : xmlNodeStartTag.getAttributes().value()) {
72 | onAttribute(attribute);
73 | }
74 | }
75 |
76 | private void onAttribute(Attribute attribute) {
77 | sb.append(' ');
78 | String namespace = this.namespaces.getPrefixViaUri(attribute.getNamespace());
79 | if (namespace == null) {
80 | namespace = attribute.getNamespace();
81 | }
82 | if (namespace != null && !namespace.isEmpty()) {
83 | sb.append(namespace).append(':');
84 | }
85 | String escapedFinalValue = XmlEscaper.escapeXml10(attribute.getValue());
86 | sb.append(attribute.getName()).append('=').append('"')
87 | .append(escapedFinalValue).append('"');
88 | }
89 |
90 | @Override public void onEndTag(XmlNodeEndTag xmlNodeEndTag) {
91 | --shift;
92 | if (isLastStartTag) {
93 | sb.append(" />\n");
94 | } else {
95 | appendShift(shift);
96 | sb.append("");
97 | if (xmlNodeEndTag.getNamespace() != null) {
98 | sb.append(xmlNodeEndTag.getNamespace()).append(':');
99 | }
100 | sb.append(xmlNodeEndTag.getName());
101 | sb.append(">\n");
102 | }
103 | isLastStartTag = false;
104 | }
105 |
106 | @Override public void onCData(XmlCData xmlCData) {
107 | appendShift(shift);
108 | sb.append(xmlCData.getValue()).append('\n');
109 | isLastStartTag = false;
110 | }
111 |
112 | @Override public void onNamespaceStart(XmlNamespaceStartTag tag) {
113 | this.namespaces.addNamespace(tag);
114 | }
115 |
116 | @Override public void onNamespaceEnd(XmlNamespaceEndTag tag) {
117 | this.namespaces.removeNamespace(tag);
118 | }
119 |
120 | private void appendShift(int shift) {
121 | for (int i = 0; i < shift; i++) {
122 | sb.append('\t');
123 | }
124 | }
125 |
126 | public String getXml() {
127 | return sb.toString();
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/utils/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.utils;
30 |
31 | import java.io.ByteArrayOutputStream;
32 | import java.io.IOException;
33 | import java.io.InputStream;
34 | import java.util.Iterator;
35 | import java.util.zip.ZipEntry;
36 | import java.util.zip.ZipFile;
37 |
38 | public class Utils {
39 |
40 | public static byte[] toByteArray(InputStream in) throws IOException {
41 | try {
42 | byte[] buf = new byte[1024];
43 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
44 | int len;
45 | while ((len = in.read(buf)) != -1) {
46 | bos.write(buf, 0, len);
47 | }
48 | try {
49 | return bos.toByteArray();
50 | } finally {
51 | bos.close();
52 | }
53 | } finally {
54 | in.close();
55 | }
56 | }
57 |
58 | public static ZipEntry getEntry(ZipFile zf, String path) {
59 | return zf.getEntry(path);
60 | }
61 |
62 | /**
63 | * Copied fom commons StringUtils
64 | *
65 | * Joins the elements of the provided {@code Iterable} into a single String containing the
66 | * provided elements.
67 | */
68 | public static String join(final Iterable> iterable, final String separator) {
69 | if (iterable == null) {
70 | return null;
71 | }
72 | return join(iterable.iterator(), separator);
73 | }
74 |
75 | /**
76 | * Copied fom commons StringUtils
77 | */
78 | public static String join(final Iterator> iterator, final String separator) {
79 |
80 | // handle null, zero and one elements before building a buffer
81 | if (iterator == null) {
82 | return null;
83 | }
84 | if (!iterator.hasNext()) {
85 | return "";
86 | }
87 | final Object first = iterator.next();
88 | if (!iterator.hasNext()) {
89 | return first == null ? null : first.toString();
90 | }
91 |
92 | // two or more elements
93 | final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
94 | if (first != null) {
95 | buf.append(first);
96 | }
97 |
98 | while (iterator.hasNext()) {
99 | if (separator != null) {
100 | buf.append(separator);
101 | }
102 | final Object obj = iterator.next();
103 | if (obj != null) {
104 | buf.append(obj);
105 | }
106 | }
107 | return buf.toString();
108 | }
109 |
110 | public static boolean isNumeric(final CharSequence cs) {
111 | if (isEmpty(cs)) {
112 | return false;
113 | }
114 | final int sz = cs.length();
115 | for (int i = 0; i < sz; i++) {
116 | if (!Character.isDigit(cs.charAt(i))) {
117 | return false;
118 | }
119 | }
120 | return true;
121 | }
122 |
123 | public static boolean isEmpty(final CharSequence cs) {
124 | return cs == null || cs.length() == 0;
125 | }
126 |
127 | public static String substringBefore(final String str, final String separator) {
128 | if (Utils.isEmpty(str) || separator == null) {
129 | return str;
130 | }
131 | if (separator.isEmpty()) {
132 | return "";
133 | }
134 | final int pos = str.indexOf(separator);
135 | if (pos == -1) {
136 | return str;
137 | }
138 | return str.substring(0, pos);
139 | }
140 |
141 | public static boolean equals(Object a, Object b) {
142 | return (a == null) ? (b == null) : a.equals(b);
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/library/src/main/java/com/jaredrummler/apkparser/parser/ApkMetaTranslator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015, Jared Rummler
3 | * Copyright (c) 2015, Liu Dong
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * * Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of the nor the
14 | * names of its contributors may be used to endorse or promote products
15 | * derived from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | package com.jaredrummler.apkparser.parser;
30 |
31 | import com.jaredrummler.apkparser.model.ApkMeta;
32 | import com.jaredrummler.apkparser.model.GlEsVersion;
33 | import com.jaredrummler.apkparser.model.Permission;
34 | import com.jaredrummler.apkparser.model.UseFeature;
35 | import com.jaredrummler.apkparser.struct.xml.*;
36 |
37 | public class ApkMetaTranslator implements XmlStreamer {
38 |
39 | private final ApkMeta.Builder builder = ApkMeta.newApkMeta();
40 |
41 | @Override public void onStartTag(XmlNodeStartTag xmlNodeStartTag) {
42 | Attributes attributes = xmlNodeStartTag.getAttributes();
43 | switch (xmlNodeStartTag.getName()) {
44 | case "application":
45 | builder.label(attributes.get("label"));
46 | builder.icon(attributes.get("icon"));
47 | break;
48 | case "manifest":
49 | builder.packageName(attributes.get("package"));
50 | builder.versionName(attributes.get("versionName"));
51 | builder.versionCode(attributes.getLong("versionCode"));
52 | String installLocation = attributes.get("installLocation");
53 | if (installLocation != null) {
54 | builder.installLocation(installLocation);
55 | }
56 | break;
57 | case "uses-sdk":
58 | builder.minSdkVersion(attributes.get("minSdkVersion"));
59 | builder.targetSdkVersion(attributes.get("targetSdkVersion"));
60 | builder.maxSdkVersion(attributes.get("maxSdkVersion"));
61 | break;
62 | case "supports-screens":
63 | builder.anyDensity(attributes.getBoolean("anyDensity", false));
64 | builder.smallScreens(attributes.getBoolean("smallScreens", false));
65 | builder.normalScreens(attributes.getBoolean("normalScreens", false));
66 | builder.largeScreens(attributes.getBoolean("largeScreens", false));
67 | break;
68 | case "uses-feature":
69 | String name = attributes.get("name");
70 | boolean required = attributes.getBoolean("required", false);
71 | if (name != null) {
72 | builder.addUseFeatures(new UseFeature(name, required));
73 | } else {
74 | Integer gl = attributes.getInt("glEsVersion");
75 | if (gl != null) {
76 | builder.glEsVersion(new GlEsVersion(gl >> 16, gl & 0xffff, required));
77 | }
78 | }
79 | break;
80 | case "uses-permission":
81 | builder.addUsesPermission(attributes.get("name"));
82 | break;
83 | case "permission":
84 | builder.addPermission(Permission.newPermission()
85 | .name(attributes.get("name"))
86 | .label(attributes.get("label"))
87 | .icon(attributes.get("icon"))
88 | .group(attributes.get("group"))
89 | .description(attributes.get("description"))
90 | .protectionLevel(attributes.get("android:protectionLevel"))
91 | .build());
92 | break;
93 | case "meta-data":
94 | builder.addMetaData(attributes.get("name"), attributes.get("value"));
95 | break;
96 | }
97 | }
98 |
99 | @Override public void onEndTag(XmlNodeEndTag xmlNodeEndTag) {
100 | }
101 |
102 | @Override public void onCData(XmlCData xmlCData) {
103 | }
104 |
105 | @Override public void onNamespaceStart(XmlNamespaceStartTag tag) {
106 | }
107 |
108 | @Override public void onNamespaceEnd(XmlNamespaceEndTag tag) {
109 | }
110 |
111 | public ApkMeta getApkMeta() {
112 | return builder.build();
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------