在线文档教程

Headless JS

Headless JS

需要本机代码的项目

此页面仅适用于react-native init使用Create React Native App 制作的或使用此类应用程序弹出的项目。有关弹出的更多信息,请参阅创建React Native App存储库的指南。

Headless JS是一种在您的应用程序处于后台时使用JavaScript运行任务的方式。例如,它可用于同步新数据,处理推送通知或播放音乐。

The JS API

任务是您注册的简单异步功能AppRegistry,与注册React应用程序类似:

AppRegistry.registerHeadlessTask('SomeTaskName', () => require('SomeTaskName')

然后,在SomeTaskName.js

module.exports = async (taskData) => { // do stuff }

只要不触及用户界面,您就可以在任务中执行任何操作:网络请求,定时器等等。一旦您的任务完成(即承诺已解决),React Native将进入“已暂停”模式(除非有其他任务正在运行,或者有前台应用程序)。

The Java API

是的,这仍然需要一些本机代码,但它非常薄。您需要扩展HeadlessJsTaskService并覆盖getTaskConfig,例如:

public class MyTaskService extends HeadlessJsTaskService { @Override protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) { Bundle extras = intent.getExtras( if (extras != null) { return new HeadlessJsTaskConfig( "SomeTaskName", Arguments.fromBundle(extras), 5000 } return null; } }

然后将该服务添加到您的AndroidManifest.xml文件中:

<service android:name="com.example.MyTaskService" />

现在,无论何时你开始你的服务(https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent%29)),例如作为一项周期性任务或响应某个系统事件/广播,JS会旋转起来,运行你的任务,然后停下来。

例:

Intent service = new Intent(getApplicationContext(), MyTaskService.class Bundle bundle = new Bundle( bundle.putString("foo", "bar" service.putExtras(bundle getApplicationContext().startService(service

注意事项

  • 默认情况下,如果您尝试在应用处于前台时运行任务,您的应用将崩溃。这是为了防止开发人员通过在任务中执行大量工作并放慢用户界面的速度而在脚下自我拍摄。您可以传递第四个boolean参数来控制此行为。

  • 如果您从开始您的服务BroadcastReceiver,请确保HeadlessJsTaskService.acquireWakeLockNow()在从返回之前致电onReceive()

使用示例

服务可以从Java API启动。首先,您需要决定何时启动服务并相应地实施您的解决方案。这是一个简单的例子,对网络连接变化做出反应。

以下几行显示了用于注册广播接收器的Android清单文件的一部分。

<receiver android:name=".NetworkChangeReceiver" > <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver>

广播接收机然后处理在onReceive函数中广播的意图。这是检查您的应用程序是否在前台的好地方。如果应用程序不在前台,我们可以准备启动的意图,没有使用putExta捆绑的信息或附加信息(请记住,捆绑包只能处理可调参数值)。最终,服务开始并获得wakelock。

public class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, final Intent intent) { /** This part will be called everytime network connection is changed e.g. Connected -> Not Connected **/ if (!isAppOnForeground((context))) { /** We will start our service and send extra info about network connections **/ boolean hasInternet = isNetworkAvailable(context Intent serviceIntent = new Intent(context, MyTaskService.class serviceIntent.putExtra("hasInternet", hasInternet context.startService(serviceIntent HeadlessJsTaskService.acquireWakeLockNow(context } } private boolean isAppOnForeground(Context context) { /** We need to check if app is in foreground otherwise the app will crash. http://stackoverflow.com/questions/8489993/check-android-application-is-in-foreground-or-not **/ ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses( if (appProcesses == null) { return false; } final String packageName = context.getPackageName( for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) { return true; } } return false; } public static boolean isNetworkAvailable(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE NetworkInfo netInfo = cm.getActiveNetworkInfo( return (netInfo != null && netInfo.isConnected() } }