无法在React Native中运行后台服务

时间:2019-05-09 21:01:57

标签: javascript java android react-native background-process

这是我在这里的第一篇文章,因此,如果我不像我必须的那样完整和清晰,请不要怪我。

问题

我对React native还是陌生的,最近我开始开发一个react native应用,该应用可以大声朗读传入的SMS。我已经实现了检索传入消息并大声阅读它们的功能……但前提是应用程序是前台。

那么,您能为我提供一些关于该主题的图书馆或教程吗?

我正在使用配备Android 9的诺基亚5。

我目前使用以下库:

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

我已经尝试过的东西

我现在在互联网上搜索了一个多星期(包括Stack Overflow和this example question),但找不到所需的内容。我已经尝试过React-native-background-timerReact-native-background-job。但是我永远无法让后台计时器工作,而且React-native-background-job允许任务每15分钟执行一次(由于Android的限制)。

因此,直到今天我找到this one为止,我读了许多诸如Headless JS之类的文章,解释了如何使用this codeburst tutorial和其他库,并解释了如何开发后台服务来记录音频呼叫。我尝试对其进行调整,但是后台服务永远不会启动。

我的代码

我必须告诉你,我对Java没有任何了解,因此即使基于教程和React本机文档,以下本机代码也可能包含错误。

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

这是这两个文件:

IncomingSMSService.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;
  }
}

HandleIncomingSMS.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));

这些代码段在此处的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;
  }
}

我也在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>

我做错了什么?我什至没有在Android开发者选项的运行服务标签中看到该服务...有什么想法吗?

预先感谢您的帮助。

更新(01/06/2019)

阅读或观看了this onethis video之类的一些教程后,我设法使我的应用程序在前台运行。现在,它将显示一个持久性通知。

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

这是我更新的代码:

// IncomingSMSService

package com.ava.service;

import android.graphics.Color;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.ContextWrapper;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;

import com.facebook.react.HeadlessJsTaskService;
import com.ava.MainActivity;
import com.ava.R;

public class IncomingSMSService extends Service {
    private NotificationManager notifManager;
    private String CHANNEL_ID = "47";
    private int SERVICE_NOTIFICATION_ID = 47;

    private Handler handler = new Handler();
    private Runnable runnableCode = new Runnable() {
        @Override
        public void run() {
            Context context = getApplicationContext();
            Intent myIntent = new Intent(context, IncomingSMSEventService.class);
            context.startService(myIntent);
            HeadlessJsTaskService.acquireWakeLockNow(context);
            handler.postDelayed(this, 2000);
        }
    };


    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public void createNotificationChannel() {
      NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, "General", notifManager.IMPORTANCE_HIGH);
      notificationChannel.enableLights(true);
      notificationChannel.setLightColor(Color.RED);
      notificationChannel.setShowBadge(true);
      notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
      getManager().createNotificationChannel(notificationChannel);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        this.handler.post(this.runnableCode);
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Ava")
                .setContentText("Listening for new messages...")
                .setSmallIcon(R.mipmap.ic_launcher_round)
                .setContentIntent(contentIntent)
                .setOngoing(true)
                .build();
        startForeground(SERVICE_NOTIFICATION_ID, notification);
        return START_NOT_STICKY;
    }

    private NotificationManager getManager() {
       if (notifManager == null) {
          notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
       }
       return notifManager;
   }
}

我的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);
    });
  });
}

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

...
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
...

我取得了一些进步,但我仍然受阻,因此,如果您有任何想法,请与我们分享!谢谢!

0 个答案:

没有答案