@@ -8,9 +8,12 @@ import options = require("../common/options");
88import constants = require( "../constants" ) ;
99import hostInfo = require( "../common/host-info" ) ;
1010import helpers = require( "../common/helpers" ) ;
11+ import fs = require( "fs" ) ;
12+ import os = require( "os" ) ;
1113
1214class AndroidProjectService implements IPlatformProjectService {
1315 private SUPPORTED_TARGETS = [ "android-17" , "android-18" , "android-19" , "android-21" ] ;
16+ private static METADATA_DIRNAME = "__metadata" ;
1417 private targetApi : string ;
1518
1619 constructor ( private $androidEmulatorServices : Mobile . IEmulatorPlatformServices ,
@@ -118,19 +121,134 @@ class AndroidProjectService implements IPlatformProjectService {
118121 return assetsDirectory ;
119122
120123 } ) . future < string > ( ) ( ) ;
121- }
124+ }
125+
126+ private updateMetadata ( projectRoot : string ) : void {
127+ var projMetadataDir = path . join ( projectRoot , "assets" , "metadata" ) ;
128+ var libsmetadataDir = path . join ( projectRoot , "../../lib" , this . platformData . normalizedPlatformName , AndroidProjectService . METADATA_DIRNAME ) ;
129+ shell . cp ( "-f" , path . join ( libsmetadataDir , "*.dat" ) , projMetadataDir ) ;
130+ }
131+
132+ private generateMetadata ( projectRoot : string ) : void {
133+ var metadataGeneratorPath = path . join ( __dirname , "../../resources/tools/metadata-generator.jar" ) ;
134+ var libsFolder = path . join ( projectRoot , "../../lib" , this . platformData . normalizedPlatformName ) ;
135+ var metadataDirName = AndroidProjectService . METADATA_DIRNAME ;
136+ var outDir = path . join ( libsFolder , metadataDirName ) ;
137+ this . $fs . ensureDirectoryExists ( outDir ) . wait ( ) ;
138+
139+ shell . cp ( "-f" , path . join ( __dirname , "../../resources/tools/android.jar" ) , libsFolder ) ;
140+ shell . cp ( "-f" , path . join ( __dirname , "../../resources/tools/android-support-v4.jar" ) , libsFolder ) ;
141+ shell . cp ( "-f" , path . join ( projectRoot , "libs/*.jar" ) , libsFolder ) ;
142+
143+ this . spawn ( 'java' , [ '-jar' , metadataGeneratorPath , libsFolder , outDir ] ) . wait ( ) ;
144+ }
122145
123146 public buildProject ( projectRoot : string ) : IFuture < void > {
124147 return ( ( ) => {
125148 var buildConfiguration = options . release ? "release" : "debug" ;
126- var args = this . getAntArgs ( buildConfiguration , projectRoot ) ;
127- this . spawn ( 'ant' , args ) . wait ( ) ;
149+ var args = this . getAntArgs ( buildConfiguration , projectRoot ) ;
150+ var argsSaved = this . getAntArgs ( buildConfiguration , projectRoot ) ;
151+ this . spawn ( 'ant' , args ) . wait ( ) ;
152+ this . generateMetadata ( projectRoot ) ;
153+ this . updateMetadata ( projectRoot ) ;
154+ // build the project again in order to include the newly generated metadata
155+ this . spawn ( 'ant' , argsSaved ) . wait ( ) ;
128156 } ) . future < void > ( ) ( ) ;
129157 }
130158
131159 public isPlatformPrepared ( projectRoot : string ) : IFuture < boolean > {
132160 return this . $fs . exists ( path . join ( projectRoot , "assets" , constants . APP_FOLDER_NAME ) ) ;
133- }
161+ }
162+
163+ private generateBuildFile ( projDir : string , targetSdk : string ) : void {
164+ this . $logger . info ( "Generate build.xml for %s" , projDir ) ;
165+ var cmd = util . format ( "android update project -p %s --target %s --subprojects" , projDir , targetSdk ) ;
166+ this . $childProcess . exec ( cmd ) . wait ( ) ;
167+ }
168+
169+ private parseProjectProperties ( projDir : string , destDir : string ) : void {
170+ var projProp = path . join ( projDir , "project.properties" ) ;
171+
172+ if ( ! this . $fs . exists ( projProp ) . wait ( ) ) {
173+ this . $logger . warn ( "File %s does not exist" , projProp ) ;
174+ return ;
175+ }
176+
177+ var lines = this . $fs . readText ( projProp , "utf-8" ) . wait ( ) . split ( os . EOL ) ;
178+
179+ var regEx = / a n d r o i d \. l i b r a r y \. r e f e r e n c e \. ( \d + ) = ( .* ) / ;
180+ lines . forEach ( elem => {
181+ var match = elem . match ( regEx ) ;
182+ if ( match ) {
183+ var libRef : ILibRef = { idx : parseInt ( match [ 1 ] ) , path : match [ 2 ] . trim ( ) } ;
184+ libRef . adjustedPath = this . $fs . isRelativePath ( libRef . path ) ? path . join ( projDir , libRef . path ) : libRef . path ;
185+ this . parseProjectProperties ( libRef . adjustedPath , destDir ) ;
186+ }
187+ } ) ;
188+
189+ this . $logger . info ( "Copying %s" , projDir ) ;
190+ shell . cp ( "-Rf" , projDir , destDir ) ;
191+
192+ var targetDir = path . join ( destDir , path . basename ( projDir ) ) ;
193+ // TODO: parametrize targetSdk
194+ var targetSdk = "android-17" ;
195+ this . generateBuildFile ( targetDir , targetSdk ) ;
196+ }
197+
198+ private getProjectReferences ( projDir : string ) : ILibRef [ ] {
199+ var projProp = path . join ( projDir , "project.properties" ) ;
200+
201+ var lines = this . $fs . readText ( projProp , "utf-8" ) . wait ( ) . split ( os . EOL ) ;
202+
203+ var refs : ILibRef [ ] = [ ] ;
204+
205+ var regEx = / a n d r o i d \. l i b r a r y \. r e f e r e n c e \. ( \d + ) = ( .* ) / ;
206+ lines . forEach ( elem => {
207+ var match = elem . match ( regEx ) ;
208+ if ( match ) {
209+ var libRef : ILibRef = { idx : parseInt ( match [ 1 ] ) , path : match [ 2 ] } ;
210+ libRef . adjustedPath = path . join ( projDir , libRef . path ) ;
211+ refs . push ( libRef ) ;
212+ }
213+ } ) ;
214+
215+ return refs ;
216+ }
217+
218+ private updateProjectReferences ( projDir : string , libraryPath : string ) : void {
219+ var refs = this . getProjectReferences ( projDir ) ;
220+ var maxIdx = refs . length > 0 ? _ . max ( refs , r => r . idx ) . idx : 0 ;
221+
222+ var relLibDir = path . relative ( projDir , libraryPath ) . split ( "\\" ) . join ( "/" ) ;
223+
224+ var libRefExists = _ . any ( refs , r => path . normalize ( r . path ) === path . normalize ( relLibDir ) ) ;
225+
226+ if ( ! libRefExists ) {
227+ var projRef = util . format ( "%sandroid.library.reference.%d=%s" , os . EOL , maxIdx + 1 , relLibDir ) ;
228+ var projProp = path . join ( projDir , "project.properties" ) ;
229+ fs . appendFileSync ( projProp , projRef , { encoding : "utf-8" } ) ;
230+ }
231+ }
232+
233+ public addLibrary ( platformData : IPlatformData , libraryPath : string ) : IFuture < void > {
234+ return ( ( ) => {
235+ var name = path . basename ( libraryPath ) ;
236+ var projDir = this . $projectData . projectDir ;
237+ var targetPath = path . join ( projDir , "lib" , platformData . normalizedPlatformName ) ;
238+ this . $fs . ensureDirectoryExists ( targetPath ) . wait ( ) ;
239+
240+ this . parseProjectProperties ( libraryPath , targetPath ) ;
241+
242+ shell . cp ( "-f" , path . join ( libraryPath , "*.jar" ) , targetPath ) ;
243+ var projectLibsDir = path . join ( platformData . projectRoot , "libs" ) ;
244+ this . $fs . ensureDirectoryExists ( projectLibsDir ) . wait ( ) ;
245+ shell . cp ( "-f" , path . join ( libraryPath , "*.jar" ) , projectLibsDir ) ;
246+
247+ var targetLibPath = path . join ( targetPath , path . basename ( libraryPath ) ) ;
248+
249+ this . updateProjectReferences ( platformData . projectRoot , targetLibPath ) ;
250+ } ) . future < void > ( ) ( ) ;
251+ }
134252
135253 public getFrameworkFilesExtensions ( ) : string [ ] {
136254 return [ ".jar" , ".dat" ] ;
@@ -325,4 +443,4 @@ class AndroidProjectService implements IPlatformProjectService {
325443 } ) . future < void > ( ) ( ) ;
326444 }
327445}
328- $injector . register ( "androidProjectService" , AndroidProjectService ) ;
446+ $injector . register ( "androidProjectService" , AndroidProjectService ) ;
0 commit comments