1 if not defined? APP_NAME
2 abort "Please require me after defining APP_NAME"
6 require 'rexml/document'
11 @xml ||= REXML::Document.new File.read('AndroidManifest.xml')
15 xml.root.attributes['package']
18 MAIN_ACTIVITY_XPATH = '/manifest/application/activity[intent-filter/action[@android:name="android.intent.action.MAIN"]]'
20 if e = REXML::XPath.first(xml, MAIN_ACTIVITY_XPATH)
21 name = e.attributes['android:name'].gsub(/^\./, '')
26 API_LEVEL_XPATH = '/manifest/uses-sdk[@android:minSdkVersion]'
28 if e = REXML::XPath.first(xml, API_LEVEL_XPATH)
29 e.attributes['android:minSdkVersion'].to_i
38 output_dir.join 'classes'
58 output_dir.join "#{APP_NAME}.ap_"
65 def manifest_output_file
66 output_dir.join 'AndroidManifest.xml'
70 output_dir.join 'classes.dex'
73 def apk_unaligned_file
74 output_dir.join "#{APP_NAME}-debug-unaligned.apk"
78 output_dir.join "#{APP_NAME}-debug.apk"
82 module AndroidSdk# {{{
85 @android_home = Pathname.new ENV['ANDROID_HOME']
89 platforms.entries.each do |e|
90 path = platforms.join e
92 prop = path.join 'source.properties'
93 if prop.file? and prop.readable?
95 f.readlines.each do |line|
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
109 @android_home.join 'platform-tools'
113 @android_home.join 'platforms'
117 if @platforms.has_key? Project.api_level
118 @platforms[Project.api_level]
120 raise "Platform not found!: api_level=#{Project.api_level}"
125 @android_home.join 'tools'
129 platform_tools.join 'aapt'
133 platform_tools.join 'dx'
137 platform_tools.join 'adb'
141 tools.join 'apkbuilder'
145 tools.join 'zipalign'
149 platform.join 'android.jar'
153 tools.join 'support', 'annotations.jar'
157 lib_file = Pathname.new('.').parent.join('jar', 'CUTEnLib.jar')
159 Project.class_output_dir.to_s,
160 annotations_jar.to_s,
165 AndroidSdk.detect_platforms
167 task :default => 'apk:aligned'
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
175 desc 'Prepare directories'
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,
183 desc 'Generate BuildConfig.java'
184 task :buildconfig => [:prepare] do
186 class BuildConfigGenerator
187 attr_reader :package, :debug
188 def initialize(package, debug)
194 /** Automatically generated file. DO NOT MODIFY */
195 package <%= package %>;
197 public final class BuildConfig {
198 public final static boolean DEBUG = <%= debug %>;
201 erb.def_method self, 'generate'
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
211 desc 'Generate R.java'
212 task :generate => [:prepare] do
214 AndroidSdk.aapt.to_s, 'package',
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',
226 desc 'Compile Java sources'
227 task :javac => ['r:generate', :buildconfig] do
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(':'),
233 '-bootclasspath', AndroidSdk.android_jar.to_s,
234 '-encoding', 'UTF-8',
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"
250 Project.gen_dir.find do |path|
251 if path.file? and path.extname == '.java'
258 desc 'Convert to dex format'
259 task :dx => [:javac] do
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
270 desc 'Crunch resources'
271 task :crunch => 'r:generate' do
273 AndroidSdk.aapt.to_s, 'crunch',
274 '-S', Project.res_dir.to_s,
275 '-C', Project.res_output_dir.to_s,
280 desc 'Package resources'
281 task :package => 'r:crunch' do
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',
292 if Project.asset_dir.directory?
293 cmd.push *['-A', Project.asset_dir.to_s]
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
306 # XXX: apkbuilder is deprecated
308 AndroidSdk.apkbuilder.to_s,
309 Project.apk_unaligned_file.to_s,
311 '-z', Project.res_apk_file.to_s,
312 '-f', Project.dex_output_file.to_s,
319 task :aligned => 'apk:unaligned' do
321 AndroidSdk.zipalign.to_s,
323 Project.apk_unaligned_file.to_s,
324 Project.apk_aligned_file.to_s,
329 desc 'Push apk to /sdcard'
330 task :push => 'apk:aligned' do
331 fname = 'MainClass.txt'
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"
337 abort "#{fname} not found!"
344 rm_rf [Project.output_dir.to_s, Project.gen_dir.to_s]