我正在尝试编写一个 React Native 应用程序,每 15 分钟运行一些处理。具体来说:我想从开放的第 3 方 API 获取状态,并在该状态发生更改时创建通知。
我想我可以使用 React Native 模块 和 Headless JS 来做到这一点:
a. JS端:
import { NativeModules } from "react-native";
const { WorkerModule } = NativeModules;
WorkerModule.configureWorker();
b.本机端:
class WorkerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
var context = reactContext.getApplicationContext()
override fun getName() = "WorkerModule"
@ReactMethod fun configureWorker() {
val periodicRequest = PeriodicWorkRequest
.Builder(MyWorker::class.java, 15, TimeUnit.MINUTES)
.setInitialDelay(10, TimeUnit.SECONDS)
.build()
WorkManager
.getInstance(this.context)
.enqueueUniquePeriodicWork("unique_work_name", ExistingPeriodicWorkPolicy.UPDATE, periodicRequest)
}
}
a. JS端:
AppRegistry.registerHeadlessTask("myBackgroundFetchFunction", (...args) => {
console.log('woo! im a react native background javascript task')
// do my fetch and notification logic in javascript
});
b. 本机侧
class JsTaskService : HeadlessJsTaskService() {
override fun getTaskConfig(intent: Intent): HeadlessJsTaskConfig? {
return intent.extras?.let {
HeadlessJsTaskConfig(
"myBackgroundFetchFunction",
null,
5000, // timeout for the task
true // optional: defines whether or not the task is allowed in foreground.
// Default is false )
}
}
}
class MyWorker(context: Context, private val workParams: WorkerParameters) : Worker(context, workParams) {
override fun doWork(): Result {
Log.d("MyWorker", "im a background task running in kotlin")
val service = Intent(applicationContext, JsTaskService::class.java);
HeadlessJsTaskService.acquireWakeLockNow(applicationContext)
applicationContext.startForegroundService(service)
// or for older version of android:
// applicationContext.startService(service)
return Result.success()
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="true"
android:theme="@style/AppTheme"
>
...
<service android:name=".....JsTaskService" />
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="shortService" />
</application>
</manifest>
但是,在运行 Android 14 的设备上,我在尝试运行该行时遇到错误
applicationContext.startForegroundService(service)
。
android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false
我理解这是因为在 Android 14 上不再可以从后台服务启动前台服务。
我还发现 Headless JS 没有得到 React Native 团队的积极支持或推荐,并且没有在 Meta 内部使用
问题:
Workers处于后台,后台任务一般不能启动前台任务(也有一些例外)。 你根本不应该有服务,你应该直接在你的工作线程中做任何事情,而不需要服务。
顺便说一句——这确实不太适合 ReactNative。 我强烈考虑原生编写它,RN 与 Android 的后台处理并没有真正很好地配合,并且对于希望在后台运行而不被杀死的东西来说,启动时间和内存成本很高。 我认为你可以让它发挥作用,但这不是我建议的。