OSDN Git Service

RUBY_ENGINE is not defined in old Ruby
[sharp4k/CUTEn.git] / tools / cuten_app.rake
1 if not defined? APP_NAME
2   abort "Please require me after defining APP_NAME"
3 end
4
5 require 'pathname'
6 require 'rexml/document'
7
8 module Project# {{{
9   module_function
10   def xml
11     @xml ||= REXML::Document.new File.read('AndroidManifest.xml')
12   end
13
14   def package
15     xml.root.attributes['package']
16   end
17
18   MAIN_ACTIVITY_XPATH = '/manifest/application/activity[intent-filter/action[@android:name="android.intent.action.MAIN"]]'
19   def main_activity
20     if e = REXML::XPath.first(xml, MAIN_ACTIVITY_XPATH)
21       name = e.attributes['android:name'].gsub(/^\./, '')
22       package + '.' + name
23     end
24   end
25
26   API_LEVEL_XPATH = '/manifest/uses-sdk[@android:minSdkVersion]'
27   def api_level
28     if e = REXML::XPath.first(xml, API_LEVEL_XPATH)
29       e.attributes['android:minSdkVersion'].to_i
30     end
31   end
32
33   def output_dir
34     Pathname.new 'bin'
35   end
36
37   def class_output_dir
38     output_dir.join 'classes'
39   end
40
41   def res_output_dir
42     output_dir.join 'res'
43   end
44
45   def gen_dir
46     Pathname.new 'gen'
47   end
48
49   def src_dir
50     Pathname.new 'src'
51   end
52
53   def res_dir
54     Pathname.new 'res'
55   end
56
57   def res_apk_file
58     output_dir.join "#{APP_NAME}.ap_"
59   end
60
61   def asset_dir
62     Pathname.new 'assets'
63   end
64
65   def manifest_output_file
66     output_dir.join 'AndroidManifest.xml'
67   end
68
69   def dex_output_file
70     output_dir.join 'classes.dex'
71   end
72
73   def apk_unaligned_file
74     output_dir.join "#{APP_NAME}-debug-unaligned.apk"
75   end
76
77   def apk_aligned_file
78     output_dir.join "#{APP_NAME}-debug.apk"
79   end
80 end# }}}
81
82 module AndroidSdk# {{{
83   module_function
84
85   @android_home = Pathname.new ENV['ANDROID_HOME']
86
87   def detect_platforms
88     @platforms = {}
89     platforms.entries.each do |e|
90       path = platforms.join e
91       if path.directory?
92         prop = path.join 'source.properties'
93         if prop.file? and prop.readable?
94           prop.open do |f|
95             f.readlines.each do |line|
96               line.chomp!
97               if m = line.match(/\AAndroidVersion\.ApiLevel=(\d+)\z/)
98                 $stderr.puts "Detected platform api_level=#{m[1]} at #{path.to_s}"
99                 @platforms[m[1].to_i] = path
100               end
101             end
102           end
103         end
104       end
105     end
106   end
107
108   def platform_tools
109     @android_home.join 'platform-tools'
110   end
111
112   def platforms
113     @android_home.join 'platforms'
114   end
115
116   def platform
117     if @platforms.has_key? Project.api_level
118       @platforms[Project.api_level]
119     else
120       raise "Platform not found!: api_level=#{Project.api_level}"
121     end
122   end
123
124   def tools
125     @android_home.join 'tools'
126   end
127
128   def aapt
129     platform_tools.join 'aapt'
130   end
131
132   def dx
133     platform_tools.join 'dx'
134   end
135
136   def adb
137     platform_tools.join 'adb'
138   end
139
140   def apkbuilder
141     tools.join 'apkbuilder'
142   end
143
144   def zipalign
145     tools.join 'zipalign'
146   end
147
148   def android_jar
149     platform.join 'android.jar'
150   end
151
152   def annotations_jar
153     tools.join 'support', 'annotations.jar'
154   end
155
156   def classpath
157     lib_file = Pathname.new('.').parent.join('jar', 'CUTEnLib.jar')
158     [
159       Project.class_output_dir.to_s,
160       annotations_jar.to_s,
161       lib_file.to_s,
162     ].join(':')
163   end
164 end# }}}
165 AndroidSdk.detect_platforms
166
167 task :default => 'apk:aligned'
168
169 directory Project.class_output_dir.to_s
170 directory Project.res_output_dir.to_s
171 directory Project.gen_dir.to_s
172 file Project.manifest_output_file.to_s => [Project.output_dir] do
173   cp 'AndroidManifest.xml', Project.manifest_output_file.to_s
174 end
175 desc 'Prepare directories'
176 task :prepare => [
177   Project.class_output_dir.to_s,
178   Project.res_output_dir.to_s,
179   Project.gen_dir.to_s,
180   Project.manifest_output_file.to_s,
181 ]
182
183 desc 'Generate BuildConfig.java'
184 task :buildconfig => [:prepare] do
185   require 'erb'
186   class BuildConfigGenerator
187     attr_reader :package, :debug
188     def initialize(package, debug)
189       @package = package
190       @debug = debug
191     end
192
193     erb = ERB.new <<-EOS
194 /** Automatically generated file. DO NOT MODIFY */
195 package <%= package %>;
196
197 public final class BuildConfig {
198     public final static boolean DEBUG = <%= debug %>;
199 }
200     EOS
201     erb.def_method self, 'generate'
202   end
203
204   pkg = Project.package
205   Project.gen_dir.join(*pkg.split('.')).join('BuildConfig.java').open('w') do |f|
206     f.puts BuildConfigGenerator.new(pkg, true).generate
207   end
208 end
209
210 namespace :r do
211   desc 'Generate R.java'
212   task :generate => [:prepare] do
213     cmd = [
214       AndroidSdk.aapt.to_s, 'package',
215       '-f', '-m',
216       '-M', Project.manifest_output_file.to_s,
217       '-S', Project.res_dir.to_s,
218       '-I', AndroidSdk.android_jar.to_s,
219       '-J', Project.gen_dir.to_s,
220       '--generate-dependencies',
221     ]
222     sh *cmd
223   end
224 end
225
226 desc 'Compile Java sources'
227 task :javac => ['r:generate', :buildconfig] do
228   cmd = [
229     'javac', '-d', Project.class_output_dir.to_s,
230     '-classpath', AndroidSdk.classpath,
231     '-sourcepath', [Project.src_dir.to_s, Project.gen_dir.to_s].join(':'),
232     '-target', '1.5',
233     '-bootclasspath', AndroidSdk.android_jar.to_s,
234     '-encoding', 'UTF-8',
235     '-g',
236     '-source', '1.5',
237   ]
238
239   main = Project.main_activity
240   main_file = main && main.split('.').join(File::Separator) + '.java'
241   Project.src_dir.find do |path|
242     if path.file? and path.extname == '.java'
243       if main_file and path.to_s.end_with? main_file
244         $stderr.puts "#{path.to_s}: excluding main activity"
245       else
246         cmd.push path.to_s
247       end
248     end
249   end
250   Project.gen_dir.find do |path|
251     if path.file? and path.extname == '.java'
252       cmd.push path.to_s
253     end
254   end
255   sh *cmd
256 end
257
258 desc 'Convert to dex format'
259 task :dx => [:javac] do
260   cmd = [
261     AndroidSdk.dx.to_s, '--dex',
262     '--output', Project.dex_output_file.to_s,
263     Project.class_output_dir.to_s,
264     AndroidSdk.annotations_jar.to_s
265   ]
266   sh *cmd
267 end
268
269 namespace :r do
270   desc 'Crunch resources'
271   task :crunch => 'r:generate' do
272     cmd = [
273       AndroidSdk.aapt.to_s, 'crunch',
274       '-S', Project.res_dir.to_s,
275       '-C', Project.res_output_dir.to_s,
276     ]
277     sh *cmd
278   end
279
280   desc 'Package resources'
281   task :package => 'r:crunch' do
282     cmd = [
283       AndroidSdk.aapt.to_s, 'package',
284       '--no-crunch', '-f', '--debug-mode', '--auto-add-overlay',
285       '-M', Project.manifest_output_file.to_s,
286       '-S', Project.res_output_dir.to_s,
287       '-S', Project.res_dir.to_s,
288       '-I', AndroidSdk.android_jar.to_s,
289       '-F', Project.res_apk_file.to_s,
290       '--generate-dependencies',
291     ]
292     if Project.asset_dir.directory?
293       cmd.push *['-A', Project.asset_dir.to_s]
294     end
295     sh *cmd
296   end
297 end
298
299 namespace :apk do
300   desc 'Generate unaligned apk'
301   task :unaligned => [:dx, 'r:package'] do
302     if defined? RUBY_ENGINE and RUBY_ENGINE == 'jruby'
303       require_relative 'cuten_app_jruby_helper'
304       SdkLib.apkbuilder Project.apk_unaligned_file.to_s, Project.res_apk_file.to_s, Project.dex_output_file.to_s
305     else
306       # XXX: apkbuilder is deprecated
307       cmd = [
308         AndroidSdk.apkbuilder.to_s,
309         Project.apk_unaligned_file.to_s,
310         '-d', '-u',
311         '-z', Project.res_apk_file.to_s,
312         '-f', Project.dex_output_file.to_s,
313       ]
314       sh *cmd
315     end
316   end
317
318   desc 'Generate apk'
319   task :aligned => 'apk:unaligned' do
320     cmd = [
321       AndroidSdk.zipalign.to_s,
322       '-f', '4',
323       Project.apk_unaligned_file.to_s,
324       Project.apk_aligned_file.to_s,
325     ]
326     sh *cmd
327   end
328
329   desc 'Push apk to /sdcard'
330   task :push => 'apk:aligned' do
331     fname = 'MainClass.txt'
332     if File.file? fname
333       class_name = open(fname) { |f| f.gets.chomp }
334       sh AndroidSdk.adb.to_s, 'shell', 'rm /sdcard/*.apk'
335       sh AndroidSdk.adb.to_s, 'push', Project.apk_aligned_file.to_s, "/sdcard/#{class_name}.apk"
336     else
337       abort "#{fname} not found!"
338     end
339   end
340 end
341
342 desc 'Clean'
343 task :clean do
344   rm_rf [Project.output_dir.to_s, Project.gen_dir.to_s]
345 end