You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中Native服务调用的Headless JS任务未运行问题

问题描述

我尝试通过CallScreeningService触发Headless任务,将来电号码传递给Headless.js处理数据,同时为React Native(RN)应用启动前台服务。CallScreeningService.kt与CallHeadlessService.kt的日志已在logcat中输出,说明这两个服务正常运行,前台服务也处于活跃状态,但Headless.js始终未执行。

仅在启动前台服务时出现该问题,当RN应用处于打开状态时,Headless任务可正常运行。我已排除前台服务启动与Headless任务调用的延迟问题。

期望实现:当应用未运行时,由CallScreening触发前台服务并启动Headless任务。


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

CallForegroundService.kt

package com.dev.justcall

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat

class CallForegroundService : Service() {
    private val channelID = "CallServiceChannel"


    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d("Call_Receiver", "[FOREGROUND] Setting up")

        createNotificationChannel()

        val notification = NotificationCompat.Builder(this, channelID)
            .setContentTitle("Call Service")
            .setContentText("JustCall is active")
            .setSmallIcon(R.mipmap.ic_launcher)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build()

        startForeground(1, notification)
        Log.d("Call_Receiver", "[FOREGROUND] Service started")

        return START_STICKY
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val serviceChannel = NotificationChannel(
                channelID,
                "Caller ID Active",
                NotificationManager.IMPORTANCE_HIGH
            )
            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(serviceChannel)
            Log.d("Call_Receiver", "[FOREGROUND] Notification channel created")
        }
    }
}

内容的提问来源于stack exchange,提问作者NgKs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:17:07