@@ -31,7 +31,10 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
31
31
private $mobileHelper : Mobile . IMobileHelper ,
32
32
private $injector : IInjector ,
33
33
private $pluginVariablesService : IPluginVariablesService ,
34
- private $deviceAppDataFactory : Mobile . IDeviceAppDataFactory ) {
34
+ private $deviceAppDataFactory : Mobile . IDeviceAppDataFactory ,
35
+ private $devicePlatformsConstants : Mobile . IDevicePlatformsConstants ,
36
+ private $projectTemplatesService : IProjectTemplatesService ,
37
+ private $xmlValidator : IXmlValidator ) {
35
38
super ( $fs , $projectData , $projectDataService ) ;
36
39
this . _androidProjectPropertiesManagers = Object . create ( null ) ;
37
40
}
@@ -253,7 +256,52 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
253
256
}
254
257
255
258
public prepareProject ( ) : IFuture < void > {
256
- return Future . fromResult ( ) ;
259
+ return ( ( ) => {
260
+ let resDestinationDir = this . getAppResourcesDestinationDirectoryPath ( ) . wait ( ) ;
261
+ let androidManifestPath = path . join ( resDestinationDir , this . platformData . configurationFileName ) ;
262
+
263
+ // In case the file is not correct, looks like we are still using the default AndroidManifest.xml from runtime and the current file (in res dir)
264
+ // should be merged with it.
265
+ if ( this . isAndroidManifestFileCorrect ( androidManifestPath ) . wait ( ) ) {
266
+ // Delete the AndroidManifest.xml file from res directory as the runtime will consider it as addition to the one in src/main and will try to merge them.
267
+ // However now they are the same file.
268
+ this . $fs . deleteFile ( androidManifestPath ) . wait ( ) ;
269
+ }
270
+ } ) . future < void > ( ) ( ) ;
271
+ }
272
+
273
+ public ensureConfigurationFileInAppResources ( ) : IFuture < void > {
274
+ return ( ( ) => {
275
+ let originalAndroidManifestFilePath = path . join ( this . $projectData . appResourcesDirectoryPath , this . $devicePlatformsConstants . Android , this . platformData . configurationFileName ) ,
276
+ hasAndroidManifestInAppResources = this . $fs . exists ( originalAndroidManifestFilePath ) . wait ( ) ,
277
+ shouldExtractDefaultManifest = ! hasAndroidManifestInAppResources ,
278
+ isAndroidManifestBackedUp = false ;
279
+
280
+ if ( hasAndroidManifestInAppResources ) {
281
+ let isFileCorrect = this . isAndroidManifestFileCorrect ( originalAndroidManifestFilePath ) . wait ( ) ;
282
+ if ( ! isFileCorrect ) {
283
+ shouldExtractDefaultManifest = true ;
284
+ isAndroidManifestBackedUp = true ;
285
+ this . backupOriginalAndroidManifest ( originalAndroidManifestFilePath ) . wait ( ) ;
286
+ }
287
+ }
288
+
289
+ // In case we should extract the manifest from default template, but for some reason we cannot, break the execution,
290
+ // so the original file from Android runtime will be used.
291
+ if ( shouldExtractDefaultManifest && ! this . extractAndroidManifestFromDefaultTemplate ( originalAndroidManifestFilePath ) . wait ( ) ) {
292
+ // now revert back
293
+ this . revertBackupOfOriginalAndroidManifest ( originalAndroidManifestFilePath ) . wait ( ) ;
294
+ return ;
295
+ }
296
+
297
+ if ( isAndroidManifestBackedUp ) {
298
+ this . $logger . warn ( `Your ${ this . platformData . configurationFileName } in app/App_Resources/Android will be replaced by the default one from hello-world template.` ) ;
299
+ this . $logger . printMarkdown ( `The original file will be moved to \`${ this . configurationFileBackupName } \`. Merge it **manually** with the new \`${ this . platformData . configurationFileName } \` in your app/App_Resources/Android.` ) ;
300
+ }
301
+
302
+ // Overwrite the AndroidManifest from runtime.
303
+ this . $fs . copyFile ( originalAndroidManifestFilePath , this . platformData . configurationFilePath ) . wait ( ) ;
304
+ } ) . future < void > ( ) ( ) ;
257
305
}
258
306
259
307
public prepareAppResources ( appResourcesDirectoryPath : string ) : IFuture < void > {
@@ -275,7 +323,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
275
323
}
276
324
277
325
public processConfigurationFilesFromAppResources ( ) : IFuture < void > {
278
- return Future . fromResult ( ) ;
326
+ return this . ensureConfigurationFileInAppResources ( ) ;
279
327
}
280
328
281
329
private processResourcesFromPlugin ( pluginData : IPluginData , pluginPlatformsFolderPath : string ) : IFuture < void > {
@@ -462,5 +510,69 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
462
510
463
511
} ) . future < void > ( ) ( ) ;
464
512
}
513
+
514
+ private isAndroidManifestFileCorrect ( pathToAndroidManifest : string ) : IFuture < boolean > {
515
+ return ( ( ) : boolean => {
516
+ try {
517
+ // Check if the AndroidManifest in app/App_Resouces is the correct one
518
+ // Use a real magic to detect if this is the correct file, by checking some mandatory strings.
519
+ let fileContent = this . $fs . readText ( pathToAndroidManifest ) . wait ( ) ,
520
+ isFileCorrect = ! ! ( ~ fileContent . indexOf ( "android:minSdkVersion" ) && ~ fileContent . indexOf ( "android:targetSdkVersion" )
521
+ && ~ fileContent . indexOf ( "uses-permission" ) && ~ fileContent . indexOf ( "<application" )
522
+ && ~ fileContent . indexOf ( "<activity" ) && ~ fileContent . indexOf ( "<intent-filter>" )
523
+ && ~ fileContent . indexOf ( "android.intent.action.MAIN" ) && ~ fileContent . indexOf ( "com.tns.ErrorReportActivity" )
524
+ && ~ fileContent . indexOf ( "android:versionCode" )
525
+ && ! this . $xmlValidator . getXmlFileErrors ( pathToAndroidManifest ) . wait ( ) ) ;
526
+
527
+ this . $logger . trace ( `Existing ${ this . platformData . configurationFileName } is ${ isFileCorrect ? "" : "NOT " } correct.` ) ;
528
+ return isFileCorrect ;
529
+ } catch ( err ) {
530
+ this . $logger . trace ( `Error while checking ${ pathToAndroidManifest } : ` , err ) ;
531
+ return false ;
532
+ }
533
+ } ) . future < boolean > ( ) ( ) ;
534
+ }
535
+
536
+ private get configurationFileBackupName ( ) : string {
537
+ return this . platformData . configurationFileName + ".backup" ;
538
+ }
539
+
540
+ private backupOriginalAndroidManifest ( originalAndroidManifestFilePath : string ) : IFuture < void > {
541
+ return ( ( ) => {
542
+ let newPathForOriginalManifest = path . join ( path . dirname ( originalAndroidManifestFilePath ) , this . configurationFileBackupName ) ;
543
+ shell . mv ( originalAndroidManifestFilePath , newPathForOriginalManifest ) ;
544
+ } ) . future < void > ( ) ( ) ;
545
+ }
546
+
547
+ private revertBackupOfOriginalAndroidManifest ( originalAndroidManifestFilePath : string ) : IFuture < void > {
548
+ return ( ( ) => {
549
+ let pathToBackupFile = path . join ( path . dirname ( originalAndroidManifestFilePath ) , this . configurationFileBackupName ) ;
550
+ if ( this . $fs . exists ( pathToBackupFile ) . wait ( ) ) {
551
+ this . $logger . trace ( `Could not extract ${ this . platformData . configurationFileName } from default template. Reverting the change of your app/App_Resources/${ this . platformData . configurationFileName } .` ) ;
552
+ shell . mv ( pathToBackupFile , originalAndroidManifestFilePath ) ;
553
+ }
554
+ } ) . future < void > ( ) ( ) ;
555
+ }
556
+
557
+ private extractAndroidManifestFromDefaultTemplate ( originalAndroidManifestFilePath : string ) : IFuture < boolean > {
558
+ return ( ( ) : boolean => {
559
+ let defaultTemplatePath = this . $projectTemplatesService . defaultTemplatePath . wait ( ) ;
560
+ let templateAndroidManifest = path . join ( defaultTemplatePath , constants . APP_RESOURCES_FOLDER_NAME , this . $devicePlatformsConstants . Android , this . platformData . configurationFileName ) ;
561
+ if ( this . $fs . exists ( templateAndroidManifest ) . wait ( ) ) {
562
+ this . $logger . trace ( `${ originalAndroidManifestFilePath } is missing. Upgrading the source of the project with one from the new project template. Copy ${ templateAndroidManifest } to ${ originalAndroidManifestFilePath } ` ) ;
563
+ try {
564
+ this . $fs . copyFile ( templateAndroidManifest , originalAndroidManifestFilePath ) . wait ( ) ;
565
+ } catch ( e ) {
566
+ this . $logger . trace ( `Copying template's ${ this . platformData . configurationFileName } failed. ` , e ) ;
567
+ return false ;
568
+ }
569
+ } else {
570
+ this . $logger . trace ( `${ originalAndroidManifestFilePath } is missing but the template ${ templateAndroidManifest } is missing too, can not upgrade ${ this . platformData . configurationFileName } .` ) ;
571
+ return false ;
572
+ }
573
+
574
+ return true ;
575
+ } ) . future < boolean > ( ) ( ) ;
576
+ }
465
577
}
466
578
$injector . register ( "androidProjectService" , AndroidProjectService ) ;
0 commit comments