import * as fs from './fs' ; import * as path from './path' ; import * as helpers from '../helpers' ; import * as versionLib from './version' ; import * as nativeConstants from './native-constants' ; import * as FlagshipTypes from '../types' ; const kDefaultGoogleMapsAPIKey = '_FlagshipGoogleMapsAPIKey_' ; const EMULATOR_LOCALHOST_PROXY = '10.0.2.2' ; const gifSupport = [ 'implementation \'com.facebook.fresco:animated-base-support:1.3.0\'' , 'implementation \'com.facebook.fresco:animated-gif:2.0.0\'' ] ; const webPSupport = [ 'implementation \'com.facebook.fresco:animated-webp:2.1.0\'' , 'implementation \'com.facebook.fresco:webpsupport:2.0.0\'' , 'implementation \'com.facebook.fresco:webpsupport:2.0.0\'' ] ; const DEFAULT_ANDROID_CONFIG = { build : { versionName : ( version ) => version , versionShortCode : versionLib . normalize , versionCode : '"\${project.VERSION_CODE_SHORT}".toInteger()' } , manifest : { activityAttributes : { 'android:label' : '@string/app_name' , 'android:launchMode' : 'singleTask' , 'android:configChanges' : 'keyboard|keyboardHidden|orientation|screenSize' , 'android:screenOrientation' : 'fullSensor' , 'android:windowSoftInputMode' : 'adjustResize' } , applicationAttributes : { 'android:allowBackup' : 'false' , 'android:label' : '@string/app_name' , 'android:icon' : '@mipmap/ic_launcher' , 'android:theme' : '@style/AppTheme' , 'android:networkSecurityConfig' : '@xml/network_security_config' } , urlSchemeHost : 'app' } } ; param { FlagshipTypes . AndroidConfig | undefined } config returns { FlagshipTypes . AndroidConfig } export function androidConfigWithDefault ( config ) { return { build : { ... DEFAULT_ANDROID_CONFIG . build , ... config && config . build } , manifest : { ... DEFAULT_ANDROID_CONFIG . manifest , ... config && config . manifest , activityAttributes : { ... DEFAULT_ANDROID_CONFIG . manifest . activityAttributes , ... config && config . manifest && config . manifest . activityAttributes } , applicationAttributes : { ... DEFAULT_ANDROID_CONFIG . manifest . applicationAttributes , ... config && config . manifest && config . manifest . applicationAttributes } } } ; } param { FlagshipTypes . AndroidConfig } config export function additionalDependencies ( config ) { let additionalDependencies = config . build ?. additionalDependencies || [ ] ; if ( config . build ?. gifSupport !== false ) { additionalDependencies = additionalDependencies . concat ( gifSupport ) ; } if ( config . build ?. webPSupport !== false ) { additionalDependencies = additionalDependencies . concat ( webPSupport ) ; } if ( additionalDependencies . length === 0 ) { return ; } helpers . logInfo ( 'add additional android dependencies' ) ; fs . update ( path . android . gradlePath ( ) , '// __ADDITIONAL_DEPENDENCIES__' , additionalDependencies . join ( '\n    ' ) ) ; } param { FlagshipTypes . AndroidConfig } config export function additionalPermissions ( config ) { if ( ! config . manifest || ! config . manifest . additionalPermissions ) { return ; } helpers . logInfo ( 'add additional permissions to manifest' ) ; const additionalPermissions = config . manifest . additionalPermissions || [ ] ; fs . update ( path . android . manifestPath ( ) , '<!-- __ADDITIONAL_PERMISSIONS__ -->' , additionalPermissions . join ( '\n    ' ) ) ; } param { object } configuration export function bundleId ( configuration ) { if ( ! configuration . bundleIds || ! configuration . bundleIds . android ) { return ; } helpers . logInfo ( 'updating Android bundle id' ) ; fs . update ( path . android . gradlePath ( ) , /applicationId\s+".+"/ , `applicationId "${ configuration . bundleIds . android }"` ) ; } param { object } configuration export function displayName ( configuration ) { if ( ! configuration . displayName ) { return ; } helpers . logInfo ( `updating Android app display name` ) ; fs . update ( path . android . stringsPath ( ) , /<string name="app_name">[^<]+<\/string>/ , `<string name="app_name">${ configuration . displayName }</string>` ) ; } param { object } configuration export function googleMaps ( configuration ) { if ( ! configuration . googleMapApiKey ) { return ; } helpers . logInfo ( `updating Google Maps API key` ) ; fs . update ( path . android . manifestPath ( ) , kDefaultGoogleMapsAPIKey , configuration . googleMapApiKey ) ; } param { object } configuration export function icon ( configuration ) { if ( ! configuration || ! configuration . appIconDir || ! configuration . appIconDir . android ) { return ; } helpers . logInfo ( `updating Android app icon` ) ; const source = path . project . resolve ( configuration . appIconDir . android . replace ( /\/$/ , '' ) , '.' ) ; try { fs . copySync ( source , path . android . resourcesPath ( ) ) ; } catch ( err ) { helpers . logError ( `updating Android app icon` , err ) ; process . exit ( 1 ) ; } } param { object } configuration export function launchScreen ( configuration ) { if ( ! configuration || ! configuration . launchScreen || ! configuration . launchScreen . android ) { return ; } helpers . logInfo ( 'updating Android launch screen' ) ; const source = path . resolve ( configuration . launchScreen . android . replace ( /\/$/ , '' ) , '.' ) ; try { fs . copySync ( source , path . android . resourcesPath ( ) ) ; } catch ( err ) { helpers . logError ( 'updating Android launch screen' , err ) ; process . exit ( 1 ) ; } } param { FlagshipTypes . AndroidConfig } config export function mainActivityAttributes ( config ) { if ( ! config . manifest || ! config . manifest . activityAttributes ) { return ; } helpers . logInfo ( 'updating manifest activity attributes' ) ; const newAttributes = [ ] ; const attributes = config . manifest . activityAttributes || { } ; Object . keys ( attributes ) . forEach ( ( key ) => { if ( attributes [ key ] ) { newAttributes . push ( `${ key }=\"${ attributes [ key ] }\"` ) ; } } ) ; fs . update ( path . android . manifestPath ( ) , '__ACTIIVITY_ATTRIBUTES__="TEMPLATE"' , newAttributes . join ( '\n            ' ) ) ; } param { FlagshipTypes . AndroidConfig } config export function mainApplicationAttributes ( config ) { if ( ! config . manifest || ! config . manifest . applicationAttributes ) { return ; } helpers . logInfo ( 'updating manifest application attributes' ) ; const newAttributes = [ ] ; const attributes = config . manifest . applicationAttributes || { } ; Object . keys ( attributes ) . forEach ( ( key ) => { if ( attributes [ key ] ) { newAttributes . push ( `${ key }=\"${ attributes [ key ] }\"` ) ; } } ) ; fs . update ( path . android . manifestPath ( ) , '__APP_ATTRIBUTES__="TEMPLATE"' , newAttributes . join ( '\n        ' ) ) ; } param { FlagshipTypes . AndroidConfig } config export function mainApplicationElements ( config ) { if ( ! config . manifest || ! config . manifest . additionalElements ) { return ; } helpers . logInfo ( 'updating manifest application elements' ) ; const additionalElements = config . manifest . additionalElements || [ ] ; fs . update ( path . android . manifestPath ( ) , '<!-- __ADDITIONAL_APP_ELEMENTS -->' , additionalElements . join ( '\n        ' ) ) ; } param { string } newVersion param { FlagshipoTypes . AndroidConfig } config export function version ( newVersion , config ) { helpers . logInfo ( `setting Android version number to ${ newVersion }` ) ; versionName ( newVersion , config ) ; versionShortCode ( newVersion , config ) ; versionCode ( newVersion , config ) ; } param { string } newVersion param { FlagshipTypes . AndroidConfig } config function versionName ( newVersion , config ) { const newVersionName = config . build && config . build . versionName && ( typeof config . build . versionName === 'function' ? config . build . versionName ( newVersion ) : config . build . versionName ) || newVersion ; fs . update ( path . android . gradlePropertiesPath ( ) , /VERSION_NAME=[\d\.]+/ , `VERSION_NAME=${ newVersionName }` ) ; } param { string } newVersion param { FlagshipTypes . AndroidConfig } config function versionShortCode ( newVersion , config ) { const newVersionShortCode = config . build && config . build . versionShortCode && ( typeof config . build . versionShortCode === 'function' ? config . build . versionShortCode ( newVersion ) : config . build . versionShortCode ) || versionLib . normalize ( newVersion ) ; fs . update ( path . android . gradlePropertiesPath ( ) , /VERSION_CODE_SHORT=\d+/ , `VERSION_CODE_SHORT=${ newVersionShortCode }` ) ; } param { string } newVersion param { FlagshipTypes . AndroidConfig } config function versionCode ( newVersion , config ) { const newVersionCode = config . build && config . build . versionCode && ( typeof config . build . versionCode === 'function' ? config . build . versionCode ( newVersion ) : config . build . versionCode ) || '"\${project.VERSION_CODE_SHORT}".toInteger()' ; fs . update ( path . android . gradlePath ( ) , /^(\s*versionCode ).*$/m , `$1${ newVersionCode }` ) ; } param { object } configuration export function urlScheme ( configuration ) { const scheme = ( configuration && configuration . urlScheme ) || configuration . name . toLowerCase ( ) ; helpers . logInfo ( `setting Android URL scheme to ${ scheme }` ) ; fs . update ( path . android . manifestPath ( ) , /default-bb-rn-url-scheme/g , scheme ) ; } param { FlagshipTypes . AndroidConfig } config export function urlSchemeHost ( config ) { if ( config . manifest ) { if ( config . manifest . urlSchemeHost !== null ) { const host = config . manifest . urlSchemeHost ?? '' ; helpers . logInfo ( `setting Android URL scheme host path to ${ host }` ) ; fs . update ( path . android . manifestPath ( ) , '__URL_HOST_PATH__' , host ) ; } else { fs . update ( path . android . manifestPath ( ) , 'android:host="__URL_HOST_PATH__"' , '' ) ; } } } param { object } configuration export function sentryProperties ( configuration ) { if ( ! configuration || ! configuration . sentry || ! configuration . sentry . propertiesPath ) { return ; } helpers . logInfo ( `updating Android Sentry properties` ) ; const source = path . resolve ( configuration . sentry . propertiesPath . replace ( /\/$/ , '' ) , '.' ) ; const destination = path . project . resolve ( 'android' , 'sentry.properties' ) ; try { fs . removeSync ( destination ) ; fs . copySync ( source , destination ) ; } catch ( err ) { helpers . logError ( `updating Android Sentry properties` , err ) ; process . exit ( 1 ) ; } } param { object } configuration export function addDevMenuFlag ( configuration ) { nativeConstants . addAndroid ( configuration , 'ShowDevMenu' , 'true' ) ; } param { object } configuration param { string } env export function setEnvSwitcherInitialEnv ( configuration , env ) { helpers . logInfo ( `setting initial env in EnvSwitcher for Android` ) ; const envSwitcherPath = path . resolve ( path . android . nativeProjectPath ( configuration ) , 'EnvSwitcher.java' ) ; fs . update ( envSwitcherPath , /"\w*";\s*\/\/\s*\[EnvSwitcher initialEnvName\]/ , `"${ env }"; // [EnvSwitcher initialEnvName]` ) ; } param { object } configuration export function exceptionDomains ( configuration ) { const { exceptionDomains = [ ] } = configuration ; if ( Array . isArray ( exceptionDomains ) && exceptionDomains . length > 0 ) { helpers . logWarn ( `adding Android exception domains
      \tYou should not enable exception domains in a production app.` ) ; } if ( ! configuration . disableDevFeature ) { const hasLocalhost = hasExceptionDomain ( exceptionDomains , 'localhost' ) ; const hasProxyLocalhost = hasExceptionDomain ( exceptionDomains , EMULATOR_LOCALHOST_PROXY ) ; if ( ! hasLocalhost ) { exceptionDomains . push ( 'localhost' ) ; } if ( ! hasProxyLocalhost ) { exceptionDomains . push ( EMULATOR_LOCALHOST_PROXY ) ; } } if ( Array . isArray ( exceptionDomains ) && exceptionDomains . length > 0 ) { const domainElements = exceptionDomains . map ( domain => { const host = typeof domain === 'string' ? domain : domain . domain ; return `<domain includeSubdomains="true">${ host }</domain>` ; } ) . join ( '\n\t\t' ) ; const xml = `<domain-config cleartextTrafficPermitted="true">
      ${ domainElements }
    </domain-config>
    <debug-overrides>` ; fs . update ( path . resolve ( path . android . resourcesPath ( ) , 'xml' , 'network_security_config.xml' ) , '<debug-overrides>' , xml ) ; } } function hasExceptionDomain ( domains , target ) { const domainIndex = domains . findIndex ( domain => { if ( typeof domain === 'string' ) { return domain === target ; } else { return domain . domain === target ; } } ) ; return domainIndex !== - 1 ; }