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

问题描述 投票:0回答:1

这是我在这里发表的第一篇文章,所以如果我没有达到应有的完整和清晰,请不要责怪我。

问题

我是 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 大声朗读它们。

这是这两个文件:

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 开发者选项的 Running services 选项卡中看到服务...有什么想法吗?

预先感谢您的帮助。

更新(01/06/2019)

阅读或观看一些教程(例如这个这个视频)后,我设法让我的应用程序在前台运行。现在它会显示持久通知。

但是,我不知道如何将我的服务和 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"/>
...

我取得了一些进展,但仍然陷入困境,所以如果您有任何想法,请分享!谢谢!

javascript java android react-native background-process
1个回答
0
投票

我正在使用带有后台计时器和后台操作包的 tts,但当 scrren 被锁定在 ios 和 android 物理设备中时,它会停止工作

© www.soinside.com 2019 - 2024. All rights reserved.