android_parser 2.4.1 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/ci.yml +26 -0
- data/.gitignore +2 -1
- data/.rspec +3 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +9 -17
- data/README.md +98 -75
- data/Rakefile +5 -39
- data/android_parser.gemspec +26 -58
- data/lib/android/apk.rb +7 -3
- data/lib/android/axml_parser.rb +5 -2
- data/lib/android/axml_writer.rb +2 -0
- data/lib/android/dex/access_flag.rb +2 -1
- data/lib/android/dex/dex_object.rb +6 -5
- data/lib/android/dex/info.rb +3 -1
- data/lib/android/dex/utils.rb +5 -3
- data/lib/android/dex.rb +3 -1
- data/lib/android/layout.rb +5 -4
- data/lib/android/manifest.rb +213 -47
- data/lib/android/resource.rb +18 -6
- data/lib/android/utils.rb +1 -0
- data/lib/android_parser.rb +10 -0
- data/lib/ruby_apk.rb +4 -8
- metadata +49 -55
- data/.travis.yml +0 -5
- data/Gemfile.lock +0 -92
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Android
|
3
4
|
class Dex
|
@@ -16,7 +17,7 @@ module Android
|
|
16
17
|
parse()
|
17
18
|
@size = @parsing_off
|
18
19
|
end
|
19
|
-
|
20
|
+
|
20
21
|
# returns symbol keys
|
21
22
|
# @return [Array<Symbol>] header key
|
22
23
|
def symbols
|
@@ -31,7 +32,7 @@ module Android
|
|
31
32
|
|
32
33
|
# @return [String]
|
33
34
|
def inspect
|
34
|
-
str = "<#{self.class}\n"
|
35
|
+
str = "<#{self.class}\n".dup
|
35
36
|
@params.each do |key,val|
|
36
37
|
str.concat " #{key}: #{val}\n"
|
37
38
|
end
|
@@ -82,7 +83,7 @@ module Android
|
|
82
83
|
value
|
83
84
|
end
|
84
85
|
# read various values from data buffer as array
|
85
|
-
# @param [Symbol] type
|
86
|
+
# @param [Symbol] type
|
86
87
|
# @param [Integer] size num of data
|
87
88
|
# @return [Array] value array
|
88
89
|
def read_value_array(type, size)
|
@@ -263,7 +264,7 @@ module Android
|
|
263
264
|
# @return bytes
|
264
265
|
# @note this method for DexObject#read_class_array (private method)
|
265
266
|
def self.size
|
266
|
-
2 * 2 + 4
|
267
|
+
2 * 2 + 4
|
267
268
|
end
|
268
269
|
private
|
269
270
|
def parse
|
@@ -280,7 +281,7 @@ module Android
|
|
280
281
|
# @return bytes
|
281
282
|
# @note this method for DexObject#read_class_array (private method)
|
282
283
|
def self.size
|
283
|
-
2 * 2 + 4
|
284
|
+
2 * 2 + 4
|
284
285
|
end
|
285
286
|
def parse
|
286
287
|
@params[:class_idx] = read_value(:ushort)
|
data/lib/android/dex/info.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'dex_object'
|
2
4
|
|
3
5
|
module Android
|
@@ -32,7 +34,7 @@ module Android
|
|
32
34
|
end
|
33
35
|
def super_class
|
34
36
|
if @class_def[:superclass_idx] != NO_INDEX
|
35
|
-
@super_class = @dex.type_resolve(@class_def[:superclass_idx])
|
37
|
+
@super_class = @dex.type_resolve(@class_def[:superclass_idx])
|
36
38
|
else
|
37
39
|
nil
|
38
40
|
end
|
data/lib/android/dex/utils.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Android
|
2
4
|
class Dex
|
3
5
|
class << self
|
4
6
|
# parse uleb128(unsigned integer) data
|
5
7
|
# @param [String] data target byte data
|
6
|
-
# @param [Integer] offset
|
8
|
+
# @param [Integer] offset
|
7
9
|
# @return [Integer, Integer] parsed value and parsed byte length
|
8
10
|
# @see http://en.wikipedia.org/wiki/LEB128
|
9
11
|
def uleb128(data, offset=0)
|
@@ -19,7 +21,7 @@ module Android
|
|
19
21
|
end
|
20
22
|
# parse uleb128 + 1 data
|
21
23
|
# @param [String] data target byte data
|
22
|
-
# @param [Integer] offset
|
24
|
+
# @param [Integer] offset
|
23
25
|
# @return [Integer, Integer] parsed value and parsed byte length
|
24
26
|
def uleb128p1(data, offset=0)
|
25
27
|
ret, len = self.uleb128(data, offset)
|
@@ -27,7 +29,7 @@ module Android
|
|
27
29
|
end
|
28
30
|
# parse sleb128(signed integer) data
|
29
31
|
# @param [String] data target byte data
|
30
|
-
# @param [Integer] offset
|
32
|
+
# @param [Integer] offset
|
31
33
|
# @return [Integer, Integer] parsed value and parsed byte length
|
32
34
|
def sleb128(data, offset=0)
|
33
35
|
result = 0
|
data/lib/android/dex.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'dex/dex_object'
|
2
4
|
require_relative 'dex/info'
|
3
5
|
require_relative 'dex/access_flag'
|
@@ -36,7 +38,7 @@ module Android
|
|
36
38
|
|
37
39
|
|
38
40
|
# @private
|
39
|
-
TYPE_DESCRIPTOR = {
|
41
|
+
TYPE_DESCRIPTOR = {
|
40
42
|
'V' => 'void',
|
41
43
|
'Z' => 'boolean',
|
42
44
|
'B' => 'byte',
|
data/lib/android/layout.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'android_parser'
|
3
4
|
require 'rexml/document'
|
4
5
|
|
5
6
|
module Android
|
@@ -8,7 +9,7 @@ module Android
|
|
8
9
|
def self.collect_layouts(apk)
|
9
10
|
targets = apk.find {|name, data| name =~ /^res\/layout\/*/ }
|
10
11
|
ret = {}
|
11
|
-
targets.each do |path|
|
12
|
+
targets.each do |path|
|
12
13
|
data = apk.file(path)
|
13
14
|
data.force_encoding(Encoding::ASCII_8BIT)
|
14
15
|
ret[path] = nil
|
@@ -34,7 +35,7 @@ module Android
|
|
34
35
|
|
35
36
|
# @return [String] xml string
|
36
37
|
def to_xml(indent=4)
|
37
|
-
xml = ''
|
38
|
+
xml = ''.dup
|
38
39
|
formatter = REXML::Formatters::Pretty.new(indent)
|
39
40
|
formatter.write(@doc.root, xml)
|
40
41
|
xml
|
data/lib/android/manifest.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rexml/document'
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module Android
|
4
5
|
# parsed AndroidManifest.xml class
|
@@ -33,33 +34,46 @@ module Android
|
|
33
34
|
# @return [REXML::Element]
|
34
35
|
attr_reader :elem
|
35
36
|
|
36
|
-
|
37
37
|
# @param [REXML::Element] elem target element
|
38
38
|
# @raise [ArgumentError] when elem is invalid.
|
39
39
|
def initialize(elem)
|
40
40
|
raise ArgumentError unless Component.valid?(elem)
|
41
|
+
|
41
42
|
@elem = elem
|
42
43
|
@type = elem.name
|
43
44
|
@name = elem.attributes['name']
|
44
45
|
@icon_id = elem.attributes['icon']
|
45
46
|
|
46
|
-
@intent_filters =
|
47
|
-
|
48
|
-
|
49
|
-
intent_filters = []
|
50
|
-
filters.elements.each do |filter|
|
51
|
-
next unless IntentFilter.valid?(filter)
|
47
|
+
@intent_filters = parse_intent_filters
|
48
|
+
@metas = parse_metas
|
49
|
+
end
|
52
50
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
51
|
+
private
|
52
|
+
|
53
|
+
def parse_intent_filters
|
54
|
+
intent_filters = []
|
55
|
+
return intent_filters if @elem.elements['intent-filter'].nil?
|
56
|
+
|
57
|
+
@elem.each_element('intent-filter') do |filter|
|
58
|
+
next if filter&.elements&.empty?
|
59
|
+
next unless IntentFilter.valid?(filter)
|
60
|
+
|
61
|
+
intent_filter = IntentFilter.new(filter)
|
62
|
+
intent_filters << intent_filter unless intent_filter.empty?
|
57
63
|
end
|
58
64
|
|
59
|
-
|
60
|
-
|
61
|
-
|
65
|
+
intent_filters
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_metas
|
69
|
+
metas = []
|
70
|
+
return metas if @elem.elements['meta-data'].nil?
|
71
|
+
|
72
|
+
@elem.each_element('meta-data') do |e|
|
73
|
+
metas << Meta.new(e)
|
62
74
|
end
|
75
|
+
|
76
|
+
metas
|
63
77
|
end
|
64
78
|
end
|
65
79
|
|
@@ -73,17 +87,18 @@ module Android
|
|
73
87
|
false
|
74
88
|
end
|
75
89
|
|
90
|
+
# @return whether this instance is the launcher activity.
|
76
91
|
def launcher_activity?
|
77
|
-
intent_filters.
|
78
|
-
|
92
|
+
intent_filters.any? do |intent_filter|
|
93
|
+
intent_filter.exist?('android.intent.category.LAUNCHER')
|
79
94
|
end
|
80
95
|
end
|
81
96
|
|
82
97
|
# @return whether this instance is the default main launcher activity.
|
83
98
|
def default_launcher_activity?
|
84
99
|
intent_filters.any? do |intent_filter|
|
85
|
-
intent_filter.
|
86
|
-
|
100
|
+
intent_filter.exist?('android.intent.category.LAUNCHER') &&
|
101
|
+
intent_filter.exist?('android.intent.category.DEFAULT')
|
87
102
|
end
|
88
103
|
end
|
89
104
|
end
|
@@ -116,41 +131,129 @@ module Android
|
|
116
131
|
end
|
117
132
|
|
118
133
|
# intent-filter element in components
|
119
|
-
|
120
|
-
# filter types
|
134
|
+
class IntentFilter
|
135
|
+
# filter types (action is required, category and data are optional)
|
121
136
|
TYPES = ['action', 'category', 'data']
|
122
137
|
|
138
|
+
# browsable of category
|
139
|
+
CATEGORY_BROWSABLE = 'android.intent.category.BROWSABLE'
|
140
|
+
|
123
141
|
# the element is valid IntentFilter element or not
|
124
142
|
# @param [REXML::Element] elem xml element
|
125
143
|
# @return [Boolean]
|
126
|
-
def self.valid?(
|
127
|
-
|
144
|
+
def self.valid?(filter)
|
145
|
+
filter&.elements&.any? do |elem|
|
146
|
+
TYPES.include?(elem&.name&.downcase)
|
147
|
+
end
|
128
148
|
rescue => e
|
129
149
|
false
|
130
150
|
end
|
131
151
|
|
132
|
-
#
|
133
|
-
|
134
|
-
# @return [IntentFilter::
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
152
|
+
# @return [IntentFilter::Action] intent-filter actions
|
153
|
+
attr_reader :actions
|
154
|
+
# @return [IntentFilter::Category] intent-filter categories
|
155
|
+
attr_reader :categories
|
156
|
+
# @return [IntentFilter::Data] intent-filter data
|
157
|
+
attr_reader :data
|
158
|
+
# @return [IntentFilter::Data] intent-filter data
|
159
|
+
attr_reader :activity
|
160
|
+
|
161
|
+
def initialize(filter)
|
162
|
+
@activity = filter.parent
|
163
|
+
@actions = []
|
164
|
+
@categories = []
|
165
|
+
@data = []
|
166
|
+
|
167
|
+
filter.elements.each do |element|
|
168
|
+
type = element.name.downcase
|
169
|
+
next unless TYPES.include?(type)
|
170
|
+
|
171
|
+
case type
|
172
|
+
when 'action'
|
173
|
+
@actions << Action.new(element)
|
174
|
+
when 'category'
|
175
|
+
@categories << Category.new(element)
|
176
|
+
when 'data'
|
177
|
+
@data << Data.new(element)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns true if self contains no [IntentFilter::Action] elements.
|
183
|
+
# @return [Boolean]
|
184
|
+
def empty?
|
185
|
+
@actions.empty?
|
186
|
+
end
|
187
|
+
|
188
|
+
def exist?(name, type: nil)
|
189
|
+
if type.to_s.empty? && !name.start_with?('android.intent.')
|
190
|
+
raise 'Fill type or use correct name'
|
146
191
|
end
|
192
|
+
|
193
|
+
type ||= name.split('.')[2]
|
194
|
+
raise 'Not found type' unless TYPES.include?(type)
|
195
|
+
|
196
|
+
method_name = case type
|
197
|
+
when 'action'
|
198
|
+
:actions
|
199
|
+
when 'category'
|
200
|
+
:categories
|
201
|
+
when 'data'
|
202
|
+
:data
|
203
|
+
end
|
204
|
+
|
205
|
+
values = send(method_name).select { |e| e.name == name }
|
206
|
+
values.empty? ? false : values #(values.size == 1 ? values.first : values)
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return [Array<String>] all data elements
|
210
|
+
# @note return empty array when the manifest include no http or https scheme of data
|
211
|
+
# @since 2.5.0
|
212
|
+
def deep_links
|
213
|
+
return unless deep_links?
|
214
|
+
|
215
|
+
data.select {|d| !d.host.nil? }
|
216
|
+
.map { |d| d.host }
|
217
|
+
.uniq
|
218
|
+
end
|
219
|
+
|
220
|
+
# the deep links exists with http or https in data element or not
|
221
|
+
# @return [Boolean]
|
222
|
+
# @since 2.5.0
|
223
|
+
def deep_links?
|
224
|
+
browsable? && data.any? { |d| ['http', 'https'].include?(d.scheme) }
|
225
|
+
end
|
226
|
+
|
227
|
+
# @return [Array<String>] all data elements
|
228
|
+
# @note return empty array when the manifest not include http or https scheme(s) of data
|
229
|
+
# @since 2.5.0
|
230
|
+
def schemes
|
231
|
+
return unless schemes?
|
232
|
+
|
233
|
+
data.select {|d| !d.scheme.nil? && !['http', 'https'].include?(d.scheme) }
|
234
|
+
.map { |d| d.scheme }
|
235
|
+
.uniq
|
236
|
+
end
|
237
|
+
|
238
|
+
# the deep links exists with non-http or non-https in data element or not
|
239
|
+
# @return [Boolean]
|
240
|
+
# @since 2.5.0
|
241
|
+
def schemes?
|
242
|
+
browsable? && data.any? { |d| !['http', 'https'].include?(d.scheme) }
|
243
|
+
end
|
244
|
+
|
245
|
+
# the browsable category vaild or not
|
246
|
+
# @return [Boolean]
|
247
|
+
# @since 2.5.0
|
248
|
+
def browsable?
|
249
|
+
exist?(CATEGORY_BROWSABLE)
|
147
250
|
end
|
148
251
|
|
149
252
|
# intent-filter action class
|
150
253
|
class Action
|
151
|
-
|
254
|
+
# @return [String] action name of intent-filter
|
152
255
|
attr_reader :name
|
153
|
-
|
256
|
+
# @return [String] action type of intent-filter
|
154
257
|
attr_reader :type
|
155
258
|
|
156
259
|
def initialize(elem)
|
@@ -161,9 +264,9 @@ module Android
|
|
161
264
|
|
162
265
|
# intent-filter category class
|
163
266
|
class Category
|
164
|
-
|
267
|
+
# @return [String] category name of intent-filter
|
165
268
|
attr_reader :name
|
166
|
-
|
269
|
+
# @return [String] category type of intent-filter
|
167
270
|
attr_reader :type
|
168
271
|
|
169
272
|
def initialize(elem)
|
@@ -237,11 +340,15 @@ module Android
|
|
237
340
|
# @return [Array<String>] permission names
|
238
341
|
# @note return empty array when the manifest includes no use-parmission element
|
239
342
|
def use_permissions
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
343
|
+
manifest_values('/manifest/uses-permission')
|
344
|
+
end
|
345
|
+
|
346
|
+
# used features array
|
347
|
+
# @return [Array<String>] features names
|
348
|
+
# @note return empty array when the manifest includes no use-features element
|
349
|
+
# @since 2.5.0
|
350
|
+
def use_features
|
351
|
+
manifest_values('/manifest/uses-feature')
|
245
352
|
end
|
246
353
|
|
247
354
|
# Returns the manifest's application element or nil, if there isn't any.
|
@@ -277,6 +384,45 @@ module Android
|
|
277
384
|
activities
|
278
385
|
end
|
279
386
|
|
387
|
+
# @return [Array<Android::Manifest::Component>] all services in the apk
|
388
|
+
# @note return empty array when the manifest include no services
|
389
|
+
# @since 2.5.0
|
390
|
+
def services
|
391
|
+
components.select { |c| c.type == 'service' }
|
392
|
+
end
|
393
|
+
|
394
|
+
# @return [Array<String>] all deep link host and schemes in intent filters
|
395
|
+
# @note return empty array when the manifest include no http or https scheme of data
|
396
|
+
# @since 2.5.0
|
397
|
+
def deep_links
|
398
|
+
activities.each_with_object([]) do |activity, obj|
|
399
|
+
intent_filters = activity.intent_filters
|
400
|
+
next if intent_filters.empty?
|
401
|
+
|
402
|
+
intent_filters.each do |filter|
|
403
|
+
next unless filter.deep_links?
|
404
|
+
|
405
|
+
obj << filter.deep_links
|
406
|
+
end
|
407
|
+
end.flatten.uniq
|
408
|
+
end
|
409
|
+
|
410
|
+
# @return [Array<String>] all schemes in intent filters
|
411
|
+
# @note return empty array when the manifest not include http or https scheme(s) of data
|
412
|
+
# @since 2.5.0
|
413
|
+
def schemes
|
414
|
+
activities.each_with_object([]) do |activity, obj|
|
415
|
+
intent_filters = activity.intent_filters
|
416
|
+
next if intent_filters.empty?
|
417
|
+
|
418
|
+
intent_filters.each do |filter|
|
419
|
+
next unless filter.schemes?
|
420
|
+
|
421
|
+
obj << filter.schemes
|
422
|
+
end
|
423
|
+
end.flatten.uniq
|
424
|
+
end
|
425
|
+
|
280
426
|
# @return [Array<Android::Manifest::Activity&ActivityAlias>] all activities that are launchers in the apk
|
281
427
|
# @note return empty array when the manifest include no activities
|
282
428
|
def launcher_activities
|
@@ -311,7 +457,17 @@ module Android
|
|
311
457
|
|
312
458
|
# @return [Integer] minSdkVersion in uses element
|
313
459
|
def min_sdk_ver
|
314
|
-
@doc.elements['/manifest/uses-sdk']
|
460
|
+
@doc.elements['/manifest/uses-sdk']
|
461
|
+
.attributes['minSdkVersion']
|
462
|
+
.to_i
|
463
|
+
end
|
464
|
+
|
465
|
+
# @return [Integer] targetSdkVersion in uses element
|
466
|
+
# @since 2.5.0
|
467
|
+
def target_sdk_version
|
468
|
+
@doc.elements['/manifest/uses-sdk']
|
469
|
+
.attributes['targetSdkVersion']
|
470
|
+
.to_i
|
315
471
|
end
|
316
472
|
|
317
473
|
# application label
|
@@ -324,7 +480,7 @@ module Android
|
|
324
480
|
if label.nil?
|
325
481
|
# application element has no label attributes.
|
326
482
|
# so looking for activites that has label attribute.
|
327
|
-
activities = @doc.elements['/manifest/application'].find{|e| e.name == 'activity' && !e.attributes['label'].nil? }
|
483
|
+
activities = @doc.elements['/manifest/application'].find{ |e| e.name == 'activity' && !e.attributes['label'].nil? }
|
328
484
|
label = activities.nil? ? nil : activities.first.attributes['label']
|
329
485
|
end
|
330
486
|
unless @rsc.nil?
|
@@ -346,5 +502,15 @@ module Android
|
|
346
502
|
formatter.write(@doc.root, xml)
|
347
503
|
xml
|
348
504
|
end
|
505
|
+
|
506
|
+
private
|
507
|
+
|
508
|
+
def manifest_values(path, key = 'name')
|
509
|
+
values = []
|
510
|
+
@doc.each_element(path) do |elem|
|
511
|
+
values << elem.attributes[key]
|
512
|
+
end
|
513
|
+
values.uniq
|
514
|
+
end
|
349
515
|
end
|
350
516
|
end
|
data/lib/android/resource.rb
CHANGED
@@ -239,6 +239,7 @@ module Android
|
|
239
239
|
|
240
240
|
def res_types
|
241
241
|
end
|
242
|
+
|
242
243
|
def find_res_string(key, opts={})
|
243
244
|
unless opts[:lang].nil?
|
244
245
|
string = @res_strings_lang[opts[:lang]]
|
@@ -354,12 +355,7 @@ module Android
|
|
354
355
|
@types[type_id('string')].each do |type|
|
355
356
|
str_hash = {}
|
356
357
|
type.entry_count.times do |i|
|
357
|
-
|
358
|
-
if entry.nil?
|
359
|
-
str_hash[i] = nil
|
360
|
-
else
|
361
|
-
str_hash[i] = @global_string_pool.strings[type[i].val.data]
|
362
|
-
end
|
358
|
+
str_hash[i] = lookup_string_value(type, i)
|
363
359
|
end
|
364
360
|
lang = type.config.locale_lang
|
365
361
|
contry = type.config.locale_contry
|
@@ -374,6 +370,20 @@ module Android
|
|
374
370
|
end
|
375
371
|
private :extract_res_strings
|
376
372
|
|
373
|
+
def lookup_string_value(type, index)
|
374
|
+
entry = type[index]
|
375
|
+
return nil if entry.nil?
|
376
|
+
|
377
|
+
if entry.val.data_type == ResValue::TYPE_REFERENCE
|
378
|
+
# this assumes that the value references another string resource, i.e. we're ignoring the type id of the reference
|
379
|
+
reference_id = entry.val.data & 0xffff
|
380
|
+
lookup_string_value(type, reference_id)
|
381
|
+
else
|
382
|
+
@global_string_pool.strings[entry.val.data]
|
383
|
+
end
|
384
|
+
end
|
385
|
+
private :lookup_string_value
|
386
|
+
|
377
387
|
def inspect
|
378
388
|
"<ResTablePackage offset:%#08x, size:%#x, name:\"%s\">" % [@offset, @size, @name]
|
379
389
|
end
|
@@ -522,6 +532,8 @@ module Android
|
|
522
532
|
end
|
523
533
|
|
524
534
|
class ResValue < Chunk
|
535
|
+
TYPE_REFERENCE = 0x01
|
536
|
+
|
525
537
|
attr_reader :size, :data_type, :data
|
526
538
|
def parse
|
527
539
|
@size = read_int16
|
data/lib/android/utils.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'android/apk'
|
4
|
+
require_relative 'android/manifest'
|
5
|
+
require_relative 'android/axml_parser'
|
6
|
+
require_relative 'android/axml_writer'
|
7
|
+
require_relative 'android/dex'
|
8
|
+
require_relative 'android/resource'
|
9
|
+
require_relative 'android/utils'
|
10
|
+
require_relative 'android/layout'
|
data/lib/ruby_apk.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
require_relative 'android/dex'
|
6
|
-
require_relative 'android/resource'
|
7
|
-
require_relative 'android/utils'
|
8
|
-
require_relative 'android/layout'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Compatible with older versions
|
4
|
+
require File.dirname(__FILE__) + '/android_parser'
|