使用Expo和React Native创建前台服务。

7
我正在使用React Native和Expo构建一个跟踪锻炼的应用程序。我想要实现一个前台服务,用于正在进行的锻炼,同时也要保持Expo在我的项目中。
我尝试使用这种方法:https://github.com/cristianoccazinsp/react-native-foreground-service 为此,在Android Manifest文件中需要添加权限,为了做到这一点,我在app.json文件中添加了权限:
"android": {
  "adaptiveIcon": {
    "foregroundImage": "./assets/adaptive-icon.png",
    "backgroundColor": "#FFFFFF",
    "permissions": ["FOREGROUND_SERVICE", "WAKE_LOCK"]
  }
},

下一步是将该服务添加到Android清单文件中:
<meta-data android:name="com.zinspector.foregroundservice.notification_channel_name"
            android:value="zInspector Service"/>
<meta-data  android:name="com.zinspector.foregroundservice.notification_channel_description"
            android:value="zInspector Service."/>
<meta-data  android:name="com.zinspector.foregroundservice.notification_color"
            android:resource="@color/orange"/>

<service android:name="com.zinspector.foregroundservice.ForegroundService"></service>
<service android:name="com.zinspector.foregroundservice.ForegroundServiceTask"></service>
```

问题在于我没有找到一种解决方案来使用app.json添加这些服务属性,同时保持使用Expo。
是否有人可以帮我解决这个问题,或者提供另一种方式来实现前台服务并继续使用Expo呢? 谢谢。

基本上,这依赖于 Android 能力,它并不是 Expo 应用程序的官方 SDK react-native 中内置的。所以像这样的所有东西,您都必须构建自己的应用程序。 - edvard chen
2个回答

6

看起来你需要创建一个expo配置插件,将元数据和服务值添加到AndroidManifest.xml中,还需要复制一个文件。

我将使用提到的https://github.com/cristianoccazinsp/react-native-foreground-service库安装步骤作为示例。

首先,您需要在项目中开始使用expo prebuild,它公开了本地文件而不需要从expo中弹出,并让我们保留所有expo工具,您可以忽略存储库中的本机文件夹,因为它们将在每次构建时重新生成。

通常,我会在package.json脚本中拥有类似这样的东西,以便更轻松地访问:

"eas:build": "npx expo prebuild && eas build --platform=android",
"prebuild": "npx expo prebuild",

您可以通过运行npx expo prebuild来单独测试预构建,并检查是否创建了本机iOS和Android文件夹。

接下来,让我们在项目根目录中创建一个configPlugins文件夹以获取所需的文件。

接下来,我们需要创建一个Expo配置插件,它允许我们在Expo预构建步骤期间编辑和复制本机文件。

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
}

接下来,按照库的要求创建color.xml文件。

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>

现在我们需要告诉 app.config.ts 关于这个插件。你也可以使用 app.json,但是 withForegroundService.ts 需要是一个 .js 文件,并且将被注册如下: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,
    ],
})

要测试它,只需运行npx expo prebuild,如果一切设置正确,您应该在android/app/src/main/AndroidManifest.xml中看到更改,并且color.xml应该被复制到android/app/src/main/res/values/color.xml

现在唯一需要做的就是配置前台任务并运行npx expo prebuild && eas build --platform=android

我测试了这种方法,并成功让前台服务通知出现。 foreground service notification

希望这可以帮助到您!


1

虽然不是完整的答案,但总比没有强。我曾经创建了一个前台服务,但是挑战在于要保持项目中的Expo。我使用的是Expo 管理版(EAS),但是目前还无法根据这里的说明构建它,没有Expo的话可以正常工作。

https://github.com/Raja0sama/rn-foreground-service

如果有更有经验的人能够解释如何启动前台服务,最好是与Expo完全集成,但如果不行,也可用于通过EAS构建的项目,请帮忙。


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接