@@ -31,7 +31,10 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
3131 private $mobileHelper : Mobile . IMobileHelper ,
3232 private $injector : IInjector ,
3333 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 ) {
3538 super ( $fs , $projectData , $projectDataService ) ;
3639 this . _androidProjectPropertiesManagers = Object . create ( null ) ;
3740 }
@@ -253,7 +256,52 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
253256 }
254257
255258 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 > ( ) ( ) ;
257305 }
258306
259307 public prepareAppResources ( appResourcesDirectoryPath : string ) : IFuture < void > {
@@ -275,7 +323,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
275323 }
276324
277325 public processConfigurationFilesFromAppResources ( ) : IFuture < void > {
278- return Future . fromResult ( ) ;
326+ return this . ensureConfigurationFileInAppResources ( ) ;
279327 }
280328
281329 private processResourcesFromPlugin ( pluginData : IPluginData , pluginPlatformsFolderPath : string ) : IFuture < void > {
@@ -462,5 +510,69 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
462510
463511 } ) . future < void > ( ) ( ) ;
464512 }
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+ }
465577}
466578$injector . register ( "androidProjectService" , AndroidProjectService ) ;
0 commit comments