Looks like you need to create an expo config plugin to add meta-data and service values to the AndroidManifest.xml, also you need to copy one file.
I'll use the mentioned https://github.com/cristianoccazinsp/react-native-foreground-service library installation steps as an example.
First, you will need to start using expo prebuild in your project, it exposes the native files without ejecting from expo and lets us keep all of the expo tooling, you can ignore the native folders in your repo because they will be re-generated on every build.
I usually end up having something like this in the package.json scripts for easier access:
"eas:build": "npx expo prebuild && eas build --platform=android",
"prebuild": "npx expo prebuild",
You can test the prebuild separately also by just running npx expo prebuild
and check if the native ios and android folders are created.
Next, let's create a configPlugins
folder for the files we need into your project root.
Next, we need to create an expo config plugin, which allows us to edit and copy native files during the expo prebuild step.
configPlugins/withForegroundService.ts
import { AndroidConfig, ConfigPlugin, withAndroidManifest } from '@expo/config-plugins'
import path from 'path'
import { Paths } from '@expo/config-plugins/build/android'
import fs from 'fs'
export const withForegroundService: ConfigPlugin = (config) => {
config = withAndroidManifest(config, async (config) => {
const mainApplication = AndroidConfig.Manifest.getMainApplicationOrThrow(config.modResults)
// set the metadata
AndroidConfig.Manifest.addMetaDataItemToMainApplication(
mainApplication,
'com.zinspector.foregroundservice.notification_channel_name',
'zInspector Service',
'value',
)
AndroidConfig.Manifest.addMetaDataItemToMainApplication(
mainApplication,
'com.zinspector.foregroundservice.notification_channel_description',
'zInspector Service.',
'value',
)
AndroidConfig.Manifest.addMetaDataItemToMainApplication(
mainApplication,
'com.zinspector.foregroundservice.notification_color',
'@color/orange',
'resource',
)
// set the services
mainApplication.service = []
mainApplication.service.push({
$: {
'android:name': 'com.zinspector.foregroundservice.ForegroundService',
},
})
mainApplication.service.push({
$: {
'android:name': 'com.zinspector.foregroundservice.ForegroundServiceTask',
},
})
// copy the color.xml
const srcFilePath = path.join(__dirname, 'color.xml')
const resFilePath = path.join(
await Paths.getResourceFolderAsync(config.modRequest.projectRoot),
'values',
'color.xml',
)
const res_dir = path.resolve(resFilePath, '..')
if (!fs.existsSync(res_dir)) {
await fs.promises.mkdir(res_dir)
}
try {
await fs.promises.copyFile(srcFilePath, resFilePath)
} catch (e) {
throw e
}
return config
})
return config
}
Next, create the color.xml as the library requires
configPlugins/color.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="orange" type="color">#FF4500
</item>
<integer-array name="androidcolors">
<item>@color/orange</item>
</integer-array>
</resources>
Now we need to tell our app.config.ts about the plugin. You can use app.json also, but then the withForegroundService.ts
needs to be a .js file and will be registered like this: plugins: [['./configPlugins/withForegroundService']]
.
app.config.ts
import { ExpoConfig, ConfigContext } from '@expo/config'
import { withForegroundService } from './configPlugins/withForegroundService'
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
...
...
plugins: [
withForegroundService,
],
})
And to test it out just run npx expo prebuild
, if everything is set up correctly, you should see the changes in android/app/src/main/AndroidManifest.xml
and color.xml
should be copied to android/app/src/main/res/values/color.xml
Now only thing to do is configure your foreground task and run npx expo prebuild && eas build --platform=android
I tested this approach and got the foreground service notification to appear.
Hope this helps!