在 React Native 中运行后台服务时遇到问题

bel*_*eek 5 javascript java android background-process react-native

这是我在这里的第一篇文章,所以如果我不够完整和清晰,请不要责怪我。

问题

我是 React Native 的新手,最近我开始开发一个 React Native 应用程序,它可以大声读取我收到的短信。我已经实现了检索传入消息并大声朗读它们......但前提是应用程序是前台。

那么,你能告诉我一些关于这个主题的图书馆或教程吗?

我正在使用带有 Android 9 的诺基亚 5。

我目前使用以下库:

  1. React-native-android-sms-listener来检索传入的消息。
  2. React-native-tts大声朗读内容。

我已经尝试过的

我现在在互联网上搜索了一个多星期(包括 Stack Overflow 和这个示例问题),但我找不到我要找的东西。我已经尝试过React-native-background-timerReact-native-background-job。但是我不可能永远让后台计时器工作,而 React-native-background-job 只允许每 15 分钟执行一次任务(由于 Android 的限制)。

所以我阅读了很多类似这样的文章,解释如何使用Headless JS和其他库,直到今天我找到了这个 codeburst 教程,解释了如何开发后台服务来记录音频通话。我试图适应它,但后台服务从未启动。

我的代码

我必须告诉你,我没有任何 Java 知识,所以下面的原生代码可能包含错误,即使它是基于教程和 React 原生文档。

目前,当应用程序启动时,服务IncomingSMSService被调用。该服务是根据上面引用的 Codeburst 教程开发的,它依赖于 Headless JS 和一个 JS 函数,该函数侦听传入的消息,然后借助 React-native-tts 大声朗读它们。

这是这两个文件:

接收短信服务.java

package com.ava.service;

import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;

public class IncomingSMSService extends HeadlessJsTaskService {
  @Override
  protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
    Bundle extras = intent.getExtras();

    if (extras != null) {
    return new HeadlessJsTaskConfig(
      "HandleIncomingSMS",
      Arguments.fromBundle(extras),
      5000,
      true
      );
    }
    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

处理传入SMS.js

import { AppRegistry } from 'react-native';
import SmsListener  from 'react-native-android-sms-listener';
import Tts from 'react-native-tts';

const HandleIncomingSMS = async (taskData) => {
  SmsListener.addListener(message => {
    Tts.getInitStatus().then(() => {
      Tts.speak(`New message from number ${message.originatingAddress} : ${message.body}`);
    });
  });
}

AppRegistry.registerHeadlessTask('HandleIncomingSMS', () => HandleIncomingSMS));
Run Code Online (Sandbox Code Playgroud)

这些代码段在此处的 BroadcastReceiver ( IncomingSMSReceiver.java )中调用:

package com.ava.receiver;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.ava.service.IncomingSMSService;
import com.facebook.react.HeadlessJsTaskService;
import java.util.List;

public final class IncomingSMSReceiver extends BroadcastReceiver {
  @Override
  public final void onReceive(Context context, Intent intent) {
    if (!isAppOnForeground((context))) {
      Intent service = new Intent(context, IncomingSMSService.class);
      context.startService(service);
      HeadlessJsTaskService.acquireWakeLockNow(context);
    }
  }

  private boolean isAppOnForeground(Context context) {
    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;
  }
}
Run Code Online (Sandbox Code Playgroud)

我还在我的 AndroidManifest 文件中请求了良好的权限,我像这样注册了服务:

   <service
    android:name="com.ava.service.IncomingSMSService"
    android:enabled="true"
    android:label="IncomingSMSService"
  />
  <receiver android:name="com.ava.receiver.IncomingSMSReceiver">
    <intent-filter android:priority="0">
      <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
  </receiver>
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么 ?我什至没有在 Android 开发人员选项的运行服务选项卡中看到服务......有任何想法吗?

在此先感谢您的帮助。

更新 (01/06/2019)

看书或看几个教程等之后,这一个这个视频,我设法让我的应用程序工作在前台。它现在显示持久通知。

但是,我不知道如何将我的服务和 Broadcsat 接收器“链接”到此通知(目前,仅当应用程序处于前台时才会调用该服务)。

这是我更新的代码:

package com.ava.service;

import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;

public class IncomingSMSService extends HeadlessJsTaskService {
  @Override
  protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
    Bundle extras = intent.getExtras();

    if (extras != null) {
    return new HeadlessJsTaskConfig(
      "HandleIncomingSMS",
      Arguments.fromBundle(extras),
      5000,
      true
      );
    }
    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

我的 headlessJS 任务:

// HandleIncomingSMS.js

import SmsListener from 'react-native-android-sms-listener';
import Tts from 'react-native-tts';
import Contacts from 'react-native-contacts';
import { text } from 'react-native-communications';

module.exports = async () => {
  // To lower other applications' sounds
  Tts.setDucking(true);

  // Prevent the TTS engine from repeating messages multiple times
  Tts.addEventListener('tts-finish', (event) => Tts.stop());

  SmsListener.addListener(message => {
    Contacts.getAll((err, contacts) => {
      if (err) throw err;

      const contactsLoop = () => {
        contacts.forEach((contact, index, contacts) => {
          // Search only for mobile numbers
          if (contact.phoneNumbers[0].label === 'mobile') {
            // Format the contact number to be compared with the message.oritignatingAddress variable
            let contactNumber = contact.phoneNumbers[0].number.replace(/^00/, '+');
            contactNumber = contactNumber.replace(/[\s-]/g, '');
            // Phone numbers comparison
            if (contactNumber === message.originatingAddress) {
              if (contact.familyName !== null) {
                Tts.speak(`Nouveau message de ${contact.givenName} ${contact.familyName} : ${message.body}`);
              } else {
                // If the contact doesn't have a known family name, just say his first name
                Tts.speak(`Nouveau message de ${contact.givenName} : ${message.body}`);
              }
            } else if (contactNumber !== message.originatingAddress && index === contacts.length) {
              // If the number isn't recognized and if the contacts have been all checked, just say the phone number
              Tts.speak(`Nouveau message du numéro ${message.originatingAddress} : ${message.body}`);
            }
          }
        });
      }
      contactsLoop();
      // Redirect to the SMS app
      text(message.originatingAddress, message = false);
    });
  });
}
Run Code Online (Sandbox Code Playgroud)

我还在我的 AndroidManifest.xml 文件中添加了良好的权限,如下所示:

import { AppRegistry } from 'react-native';
import SmsListener  from 'react-native-android-sms-listener';
import Tts from 'react-native-tts';

const HandleIncomingSMS = async (taskData) => {
  SmsListener.addListener(message => {
    Tts.getInitStatus().then(() => {
      Tts.speak(`New message from number ${message.originatingAddress} : ${message.body}`);
    });
  });
}

AppRegistry.registerHeadlessTask('HandleIncomingSMS', () => HandleIncomingSMS));
Run Code Online (Sandbox Code Playgroud)

我取得了一些进展,但我仍然卡住了,所以如果你有任何想法,请分享它们!谢谢 !