这是我在这里发表的第一篇文章,所以如果我没有达到应有的完整和清晰,请不要责怪我。
我是 React Native 的新手,最近开始开发一个 React Native 应用程序,它可以大声朗读我收到的短信。我已经实现了检索传入消息并大声朗读它们......但前提是该应用程序是前台。
那么,您能给我一些关于这个主题的库或教程吗?
我正在开发搭载 Android 9 的诺基亚 5。
我目前使用以下库:
我现在在互联网上搜索了一个多星期(包括 Stack Overflow 和 这个示例问题),但我找不到我要找的东西。我已经尝试过 React-native-background-timer 和 React-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 选项卡中看到服务...有什么想法吗?
预先感谢您的帮助。
阅读或观看一些教程(例如这个或这个视频)后,我设法让我的应用程序在前台运行。现在它会显示持久通知。
但是,我不知道如何将我的服务和 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"/>
...
我取得了一些进展,但仍然陷入困境,所以如果您有任何想法,请分享!谢谢!
我正在使用带有后台计时器和后台操作包的 tts,但当 scrren 被锁定在 ios 和 android 物理设备中时,它会停止工作