rns-nativecall 0.4.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,33 +18,45 @@ class CallHeadlessTask : HeadlessJsTaskService() {
18
18
  override fun onCreate() {
19
19
  super.onCreate()
20
20
  val channelId = "call_service"
21
+ val notificationId = 1 // Constant ID for the foreground service
22
+
21
23
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
22
- val channel = NotificationChannel(channelId, "Call Service", NotificationManager.IMPORTANCE_LOW)
24
+ val channel = NotificationChannel(
25
+ channelId,
26
+ "Call Connection Service",
27
+ NotificationManager.IMPORTANCE_LOW
28
+ )
23
29
  val manager = getSystemService(NotificationManager::class.java)
24
30
  manager.createNotificationChannel(channel)
25
31
  }
26
32
 
33
+ // IMPORTANT: Must have a setSmallIcon or the service will crash on modern Android
27
34
  val notification: Notification = NotificationCompat.Builder(this, channelId)
28
- .setContentTitle("incoming...")
35
+ .setContentTitle("Incoming call...")
36
+ .setContentText("Establishing connection")
37
+ .setSmallIcon(android.R.drawable.sym_action_call) // Built-in icon as fallback
29
38
  .setPriority(NotificationCompat.PRIORITY_LOW)
39
+ .setCategory(NotificationCompat.CATEGORY_SERVICE)
30
40
  .build()
31
41
 
32
42
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
33
- startForeground(1, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL)
43
+ // Android 14+ requires the FOREGROUND_SERVICE_TYPE_PHONE_CALL type
44
+ startForeground(notificationId, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL)
34
45
  } else {
35
- startForeground(1, notification)
46
+ startForeground(notificationId, notification)
36
47
  }
37
48
  }
38
49
 
39
50
  override fun getTaskConfig(intent: Intent?): HeadlessJsTaskConfig? {
40
51
  val extras = intent?.extras
41
52
  return if (extras != null) {
53
+ // Linear retry helps if the JS bridge is busy or mid-reload
42
54
  val retryPolicy = LinearCountingRetryPolicy(3, 1000)
43
55
  HeadlessJsTaskConfig(
44
56
  "ColdStartCallTask",
45
57
  Arguments.fromBundle(extras),
46
- 60000,
47
- true,
58
+ 60000, // Timeout after 60s
59
+ true, // Allow task to run in foreground
48
60
  retryPolicy
49
61
  )
50
62
  } else null
@@ -11,6 +11,7 @@ import android.app.NotificationChannel
11
11
  import android.app.PendingIntent
12
12
  import android.os.Build
13
13
  import androidx.core.app.NotificationCompat
14
+ import androidx.core.content.ContextCompat
14
15
  import com.google.firebase.messaging.FirebaseMessagingService
15
16
  import com.google.firebase.messaging.RemoteMessage
16
17
  import com.facebook.react.HeadlessJsTaskService
@@ -39,33 +40,28 @@ class CallMessagingService : FirebaseMessagingService() {
39
40
  }
40
41
 
41
42
  if (isAppInForeground(context)) {
42
- // When in foreground, we just tell JS to show the in-app UI
43
43
  CallModule.sendEventToJS("onCallReceived", data)
44
44
  } else {
45
- // 1. Show the Notification IMMEDIATELY
46
- // Do not wait for HeadlessJS. Android requires immediate feedback for background starts.
45
+ // 1. Show the Full Screen Notification IMMEDIATELY
47
46
  NativeCallManager.handleIncomingPush(context, data)
48
47
 
49
- // 2. Start HeadlessJS Task to sync Javascript state (WebRTC initialization, etc.)
48
+ // 2. Start HeadlessJS Task as a Foreground Service
50
49
  try {
51
50
  val headlessIntent = Intent(context, CallHeadlessTask::class.java).apply {
52
- putExtras(Bundle().apply {
53
- data.forEach { (k, v) -> putString(k, v) }
54
- })
51
+ val bundle = Bundle()
52
+ data.forEach { (k, v) -> bundle.putString(k, v) }
53
+ putExtras(bundle)
55
54
  }
56
55
 
57
- // Use a standard startService. If CallHeadlessTask is a HeadlessJsTaskService,
58
- // it handles its own foreground/background lifecycle.
59
- context.startService(headlessIntent)
56
+ // CRITICAL: Must use startForegroundService for background starts on Android 8+
57
+ ContextCompat.startForegroundService(context, headlessIntent)
60
58
  HeadlessJsTaskService.acquireWakeLockNow(context)
61
59
  } catch (e: Exception) {
62
60
  e.printStackTrace()
63
61
  }
64
62
 
65
- // 3. Backup Safety: Ensure if JS fails, the notification is eventually handled
63
+ // 3. Backup Safety
66
64
  val showNotificationRunnable = Runnable {
67
- // If the notification was somehow canceled or not showing, re-trigger
68
- // (Usually not needed if handleIncomingPush is called above, but kept for your logic)
69
65
  if (!isAppInForeground(context)) {
70
66
  NativeCallManager.handleIncomingPush(context, data)
71
67
  }
@@ -77,10 +77,11 @@ object NativeCallManager {
77
77
  val caller = Person.Builder()
78
78
  .setName(name)
79
79
  .setImportant(true)
80
+ .setIcon(context.applicationInfo.icon)
80
81
  .build()
81
82
 
82
83
  val builder = NotificationCompat.Builder(context, CALL_CHANNEL_ID)
83
- .setSmallIcon(context.applicationInfo.icon)
84
+ //.setSmallIcon(context.applicationInfo.icon)
84
85
  .setContentTitle("Incoming $callType call")
85
86
  .setContentText(name)
86
87
  .setPriority(NotificationCompat.PRIORITY_MAX)
@@ -93,8 +94,8 @@ object NativeCallManager {
93
94
  .setStyle(
94
95
  NotificationCompat.CallStyle.forIncomingCall(
95
96
  caller,
96
- rejectPendingIntent,
97
97
  answerPendingIntent
98
+ rejectPendingIntent,
98
99
  )
99
100
  )
100
101
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "0.4.8",
3
+ "version": "0.5.0",
4
4
  "description": "RNS nativecall component with native Android/iOS for handling native call ui, when app is not open or open.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",