nitg/android: add a deeper folder to generated project
[nit.git] / src / android_platform.nit
1 # This file is part of NIT ( http://www.nitlanguage.org )t
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Compile program for the Android platform
18 module android_platform
19
20 import platform
21 import abstract_compiler
22
23 redef class ToolContext
24 redef fun platform_from_name(name)
25 do
26 if name == "android" then return new AndroidPlatform
27 return super
28 end
29
30 fun exec_and_check(args: Array[String])
31 do
32 var prog = args.first
33 args.remove_at 0
34
35 # Is the wanted program available?
36 var proc_which = new IProcess.from_a("which", [prog])
37 proc_which.wait
38 var res = proc_which.status
39 if res != 0 then
40 print "Android project error: executable \"{prog}\" not found"
41 exit 1
42 end
43
44 # Execute the wanted program
45 var proc = new Process.from_a(prog, args)
46 proc.wait
47 res = proc.status
48 if res != 0 then
49 print "Android project error: execution of \"{prog} {args.join(" ")}\" failed"
50 exit 1
51 end
52 end
53 end
54
55 class AndroidPlatform
56 super Platform
57
58 redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext)
59 end
60
61 class AndroidToolchain
62 super MakefileToolchain
63
64 var android_project_root: String
65
66 redef fun compile_dir
67 do
68 var normal_compile_dir = super
69 android_project_root = normal_compile_dir
70 return "{normal_compile_dir}/jni/nit_compile/"
71 end
72
73 redef fun write_files(compiler, compile_dir, cfiles)
74 do
75 var app_name = compiler.mainmodule.name
76 var app_package = "org.nitlanguage.{app_name}"
77 var app_version = "0.1"
78
79 var args = ["android", "-s", "create", "project", "--name", app_name,
80 "--target", "android-10", "--path", android_project_root,
81 "--package", app_package, "--activity", app_name]
82 toolcontext.exec_and_check(args)
83
84 # create compile_dir
85 var dir = "{android_project_root}/jni/"
86 if not dir.file_exists then dir.mkdir
87
88 dir = compile_dir
89 if not dir.file_exists then dir.mkdir
90
91 # compile normal C files
92 super(compiler, compile_dir, cfiles)
93
94 # Gather extra C files generated elsewhere than in super
95 for f in compiler.extern_bodies do
96 if f isa ExternCFile then cfiles.add(f.filename.basename(""))
97 end
98
99 ## Generate delagating makefile
100 dir = "{android_project_root}/jni/"
101 var file = new OFStream.open("{dir}/Android.mk")
102 file.write """
103 include $(call all-subdir-makefiles)
104 """
105 file.close
106
107 ### generate makefile into "{compile_dir}/Android.mk"
108 dir = compile_dir
109 file = new OFStream.open("{dir}/Android.mk")
110 file.write """
111 LOCAL_PATH := $(call my-dir)
112 include $(CLEAR_VARS)
113
114 LOCAL_CFLAGS := -D ANDROID
115 LOCAL_MODULE := main
116 LOCAL_SRC_FILES := \\
117 {{{cfiles.join(" \\\n")}}}
118 LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM -lz
119 LOCAL_STATIC_LIBRARIES := android_native_app_glue
120
121 include $(BUILD_SHARED_LIBRARY)
122
123 $(call import-module,android/native_app_glue)
124 """
125 file.close
126
127 ### generate AndroidManifest.xml
128 dir = android_project_root
129 file = new OFStream.open("{dir}/AndroidManifest.xml")
130 file.write """<?xml version="1.0" encoding="utf-8"?>
131 <!-- BEGIN_INCLUDE(manifest) -->
132 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
133 package="{{{app_package}}}"
134 android:versionCode="1"
135 android:versionName="{{{app_version}}}"
136 android:debuggable="true">
137
138 <!-- This is the platform API where NativeActivity was introduced. -->
139 <uses-sdk android:minSdkVersion="9" />
140
141 <!-- This .apk has no Java code itself, so set hasCode to false. -->
142 <application android:label="@string/app_name" android:hasCode="false" android:debuggable="true">
143
144 <!-- Our activity is the built-in NativeActivity framework class.
145 This will take care of integrating with our NDK code. -->
146 <activity android:name="android.app.NativeActivity"
147 android:label="@string/app_name"
148 android:configChanges="orientation|keyboardHidden">
149 <!-- Tell NativeActivity the name of or .so -->
150 <meta-data android:name=\"{{{app_package}}}\"
151 android:value=\"{{{app_name}}}\" />
152 <intent-filter>
153 <action android:name="android.intent.action.MAIN" />
154 <category android:name="android.intent.category.LAUNCHER" />
155 </intent-filter>
156 </activity>
157 </application>
158
159 </manifest>
160 <!-- END_INCLUDE(manifest) -->
161 """
162 file.close
163
164 ### generate res/values/strings.xml
165 dir = "{android_project_root}/res/"
166 if not dir.file_exists then dir.mkdir
167 dir = "{dir}/values/"
168 if not dir.file_exists then dir.mkdir
169 file = new OFStream.open("{dir}/strings.xml")
170 file.write """<?xml version="1.0" encoding="utf-8"?>
171 <resources>
172 <string name="app_name">{{{app_name}}}</string>
173 </resources>"""
174 file.close
175 end
176
177 redef fun write_makefile(compiler, compile_dir, cfiles)
178 do
179 # Do nothing, already done in `write_files`
180 end
181
182 redef fun compile_c_code(compiler, compile_dir)
183 do
184 # Compile C code (and thus Nit)
185 toolcontext.exec_and_check(["ndk-build", "-s", "-j", "4", "-C", android_project_root])
186
187 # Generate the apk
188 toolcontext.exec_and_check(["ant", "-q", "debug", "-f", android_project_root+"/build.xml"])
189 end
190 end