我试图通过将传入号码传递给处理数据的 Headless.js 来调用由 CallScreeningService 触发的 Headless 任务。它还触发了我的 RN 应用程序的前台服务。
来自我的 CallScreeningService.kt 和 CallHeadlessService.kt 的日志记录在 logcat 中,这表明它正在运行。我的前台服务也在运行。但不知何故 Headless.js 没有运行。
这是我的 CallScreeningService.kt
@RequiresApi(Build.VERSION_CODES.N)
class CallScreeningService: CallScreeningService() {
@SuppressLint("VisibleForTests")
@RequiresApi(Build.VERSION_CODES.Q)
override fun onScreenCall(callDetails: Call.Details) {
Log.d("Call_Receiver", "[SERVICE] Fetching caller number")
val incomingNum = callDetails.handle.schemeSpecificPart
Log.d("Call_Receiver", "[SERVICE] Incoming call from: $incomingNum")
val intentForeground = Intent(this, CallForegroundService::class.java)
startService(intentForeground)
Log.d("Call_Receiver", "[FOREGROUND] Service called")
val intent = Intent(this, CallHeadlessService::class.java)
intent.putExtra("incomingNumber", incomingNum)
this.startService(intent)
HeadlessJsTaskService.acquireWakeLockNow(this)
Log.d("Call_Receiver", "[MODULE] Headless task waking up")
val response = CallResponse.Builder()
.setDisallowCall(false)
.setSilenceCall(false)
.build()
respondToCall(callDetails, response)
}
}
这是我的CallHeadlessService.kt
package com.dev.justcall
import android.content.Intent
import android.util.Log
import com.facebook.react.HeadlessJsTaskService
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap
import com.facebook.react.jstasks.HeadlessJsTaskConfig
class CallHeadlessService : HeadlessJsTaskService() {
override fun getTaskConfig(intent: Intent?): HeadlessJsTaskConfig {
Log.d("Call_Receiver", "[HEADLESS] Task called")
val incomingNumber = intent?.getStringExtra("incomingNumber") ?: ""
Log.d("Call_Receiver", "[HEADLESS] Incoming Number: $incomingNumber")
val taskData: WritableMap = Arguments.createMap()
taskData.putString("incomingNumber", incomingNumber)
Log.d("Call_Receiver", "[HEADLESS] Task Data: $taskData")
return HeadlessJsTaskConfig(
"IncomingCallTask",
taskData,
0,
true
)
}
}
这是我的 Headless.js
import { AppRegistry, NativeModules } from "react-native";
//Import Javascript components
import CallerID from "./CallerID";
import CleanPhoneNumber from "./CleanPhoneNumber";
import StartPage from "../../app";
import { name as appName } from '../../app.json';
const { CallNativeModule } = NativeModules;
const handleIncomingCallTask = async (taskData) => {
const { incomingNumber } = taskData;
console.log('[HEADLESS] Task received incoming number:', incomingNumber);
//Get wallet connection status and provider
const { walletSigner } = global.appData;
if (walletSigner) {
console.log('[HEADLESS] User logged in');
try {
const cleanedPhoneNumber = await CleanPhoneNumber(incomingNumber);
const profile = await CallerID(cleanedPhoneNumber, walletSigner);
const name = profile[0];
CallNativeModule.receiveCallerID(name, cleanedPhoneNumber);
console.log('[HEADLESS] Caller ID sent to Native Module');
} catch (error) {
if (error.message.includes('[HEADLESS] Invalid phone number length.')) {
console.log('[HEADLESS] Invalid phone number length.');
} else if (error.message.includes('[HEADLESS] Phone number is not registered')) {
console.log('[HEADLESS] Phone number is not registered.');
} else {
console.log('[HEADLESS] Error:', error);
};
};
} else {
console.log('[HEADLESS] User not logged in');
};
};
console.log('[HEADLESS] App starting...');
AppRegistry.registerComponent(appName, () => StartPage);
AppRegistry.registerHeadlessTask('IncomingCallTask', () => handleIncomingCallTask);
该问题仅在运行前台服务时出现。当 RN 应用程序打开时,无头任务完美运行。
我怀疑这是前台服务启动和调用无头任务之间的延迟时间。但事实并非如此。
我希望能够在应用程序最初未运行时在前台运行无头任务。基本上 CallScreening 会触发前台服务来启动应用程序。
为了启动前台服务,您需要运行
startForeground
并发出主动通知。 startService
不适用于在后台运行的前台任务,因为 api >=26。
这是在 React Native 中使用 Android 服务的示例,用于通过活动通知启动前台服务。
class SomeForegroundService : Service() {
private val SERVICE_NOTIFICATION_ID = 12345
private val CHANNEL_ID = "SOMENAME"
private val handler: Handler = Handler()
private val runnableCode: Runnable = object : Runnable {
override fun run() {
val context = applicationContext
val service = Intent(context, CallHeadlessService::class.java)
val bundle = Bundle()
bundle.putString("foo", "bar")
service.putExtras(bundle)
context.startService(service)
HeadlessJsTaskService.acquireWakeLockNow(context)
handler.postDelayed(this, 3000)
}
}
companion object {
var isRunning = false
}
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, "Foreground Service Channel", importance)
channel.description = "CHANNEL DESCRIPTION"
val notificationManager = getSystemService(
NotificationManager::class.java
)
notificationManager.createNotificationChannel(channel)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
handler.post(runnableCode)
isRunning = true
createNotificationChannel()
val notificationIntent = Intent(this, MainActivity::class.java)
val contentIntent = PendingIntent.getActivity(
this,
0,
notificationIntent,
PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(this.resources.getIdentifier("launcher_icon", "mipmap", this.packageName))
.setContentTitle("Some title")
.setContentIntent(contentIntent)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
startForeground(SERVICE_NOTIFICATION_ID, notification)
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacks(runnableCode)
isRunning = false;
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
}