rns-nativecall 0.2.7 → 0.3.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.
@@ -35,12 +35,12 @@ android {
35
35
  }
36
36
 
37
37
  compileOptions {
38
- sourceCompatibility JavaVersion.VERSION_1_8
39
- targetCompatibility JavaVersion.VERSION_1_8
38
+ sourceCompatibility JavaVersion.VERSION_17
39
+ targetCompatibility JavaVersion.VERSION_17
40
40
  }
41
41
 
42
42
  kotlinOptions {
43
- jvmTarget = '1.8'
43
+ jvmTarget = '17' // Changed from 1.8
44
44
  }
45
45
 
46
46
  // lintOptions is deprecated in newer AGP, using lint instead
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "0.2.7",
3
+ "version": "0.3.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",
@@ -5,12 +5,10 @@ function withMainActivityDataFix(config) {
5
5
  return withMainActivity(config, (config) => {
6
6
  let contents = config.modResults.contents;
7
7
 
8
- // Ensure Intent import exists
9
8
  if (!contents.includes('import android.content.Intent')) {
10
9
  contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.content.Intent`);
11
10
  }
12
11
 
13
- // Add onNewIntent to catch data when app is open
14
12
  const onNewIntentCode = `
15
13
  override fun onNewIntent(intent: Intent) {
16
14
  super.onNewIntent(intent)
@@ -34,15 +32,15 @@ function withAndroidConfig(config) {
34
32
  const manifest = config.modResults;
35
33
  const application = manifest.manifest.application[0];
36
34
 
37
- // 1. Updated Permissions for Custom Notifications & Android 13/14
35
+ // 1. Unified Permissions
38
36
  const permissions = [
39
37
  'android.permission.USE_FULL_SCREEN_INTENT',
40
38
  'android.permission.VIBRATE',
41
39
  'android.permission.FOREGROUND_SERVICE',
42
- 'android.permission.FOREGROUND_SERVICE_PHONE_CALL', // Required for Android 14
43
- 'android.permission.POST_NOTIFICATIONS', // Required for Android 13+
44
- 'android.permission.WAKE_LOCK', // Helps wake the screen
45
- 'android.permission.DISABLE_KEYGUARD' // Allows showing over lockscreen
40
+ 'android.permission.FOREGROUND_SERVICE_PHONE_CALL',
41
+ 'android.permission.POST_NOTIFICATIONS',
42
+ 'android.permission.WAKE_LOCK',
43
+ 'android.permission.DISABLE_KEYGUARD'
46
44
  ];
47
45
 
48
46
  manifest.manifest['uses-permission'] = manifest.manifest['uses-permission'] || [];
@@ -52,51 +50,54 @@ function withAndroidConfig(config) {
52
50
  }
53
51
  });
54
52
 
55
- // 2. AcceptCallActivity - The "Pill" UI handler
56
- // Added showWhenLocked and turnScreenOn for the "Gate" logic
53
+ // 2. Activity Cleanup & Setup
57
54
  application.activity = application.activity || [];
58
- const acceptActivityName = 'com.rnsnativecall.AcceptCallActivity';
59
55
 
60
- // Remove old entry if exists to avoid duplicates
61
- application.activity = application.activity.filter(a => a.$['android:name'] !== acceptActivityName);
56
+ // Remove old/redundant activities
57
+ application.activity = application.activity.filter(a =>
58
+ a.$['android:name'] !== 'com.rnsnativecall.IncomingCallActivity' &&
59
+ a.$['android:name'] !== 'com.rnsnativecall.AcceptCallActivity'
60
+ );
62
61
 
62
+ // Add the specific AcceptCallActivity (Trampoline)
63
63
  application.activity.push({
64
64
  $: {
65
- 'android:name': acceptActivityName,
65
+ 'android:name': 'com.rnsnativecall.AcceptCallActivity',
66
66
  'android:theme': '@android:style/Theme.Translucent.NoTitleBar',
67
67
  'android:excludeFromRecents': 'true',
68
68
  'android:noHistory': 'true',
69
69
  'android:exported': 'false',
70
70
  'android:launchMode': 'singleInstance',
71
- 'android:showWhenLocked': 'true', // CRUCIAL: Show over lockscreen
72
- 'android:turnScreenOn': 'true' // CRUCIAL: Wake device
71
+ 'android:showWhenLocked': 'true',
72
+ 'android:turnScreenOn': 'true'
73
73
  }
74
74
  });
75
75
 
76
- // 3. Updated Services
76
+ // 3. Service Cleanup & Setup (Firebase only)
77
77
  application.service = application.service || [];
78
- // Removed MyConnectionService as you are no longer using Telecom
79
- const services = [
80
- { name: 'com.rnsnativecall.CallMessagingService', action: 'com.google.firebase.MESSAGING_EVENT' }
81
- ];
82
78
 
83
- services.forEach(svc => {
84
- if (!application.service.some(s => s.$['android:name'] === svc.name)) {
85
- application.service.push({
86
- $: {
87
- 'android:name': svc.name,
88
- 'android:exported': 'false' // Firebase services should usually be false unless needed
89
- },
90
- 'intent-filter': [{ action: [{ $: { 'android:name': svc.action } }] }]
91
- });
92
- }
93
- });
79
+ // Explicitly remove Telecom Service
80
+ application.service = application.service.filter(
81
+ s => s.$['android:name'] !== 'com.rnsnativecall.MyConnectionService'
82
+ );
83
+
84
+ const firebaseServiceName = 'com.rnsnativecall.CallMessagingService';
85
+ if (!application.service.some(s => s.$['android:name'] === firebaseServiceName)) {
86
+ application.service.push({
87
+ $: {
88
+ 'android:name': firebaseServiceName,
89
+ 'android:exported': 'false'
90
+ },
91
+ 'intent-filter': [{ action: [{ $: { 'android:name': 'com.google.firebase.MESSAGING_EVENT' } }] }]
92
+ });
93
+ }
94
94
 
95
- // 4. Receivers (Answer/Reject Buttons)
95
+ // 4. Receiver Setup
96
96
  application.receiver = application.receiver || [];
97
- if (!application.receiver.some(r => r.$['android:name'] === 'com.rnsnativecall.CallActionReceiver')) {
97
+ const receiverName = 'com.rnsnativecall.CallActionReceiver';
98
+ if (!application.receiver.some(r => r.$['android:name'] === receiverName)) {
98
99
  application.receiver.push({
99
- $: { 'android:name': 'com.rnsnativecall.CallActionReceiver', 'android:exported': 'false' }
100
+ $: { 'android:name': receiverName, 'android:exported': 'false' }
100
101
  });
101
102
  }
102
103
 
@@ -109,7 +110,9 @@ function withIosConfig(config) {
109
110
  return withInfoPlist(config, (config) => {
110
111
  const infoPlist = config.modResults;
111
112
  if (!infoPlist.UIBackgroundModes) infoPlist.UIBackgroundModes = [];
112
- ['voip', 'audio'].forEach(mode => { if (!infoPlist.UIBackgroundModes.includes(mode)) infoPlist.UIBackgroundModes.push(mode); });
113
+ ['voip', 'audio'].forEach(mode => {
114
+ if (!infoPlist.UIBackgroundModes.includes(mode)) infoPlist.UIBackgroundModes.push(mode);
115
+ });
113
116
  return config;
114
117
  });
115
118
  }
@@ -1,93 +0,0 @@
1
- package com.rnsnativecall
2
-
3
- import android.app.*
4
- import android.content.Context
5
- import android.content.Intent
6
- import android.media.AudioAttributes
7
- import android.media.MediaPlayer
8
- import android.media.RingtoneManager
9
- import android.os.Build
10
- import androidx.core.app.NotificationCompat
11
-
12
- object NativeCallManager {
13
- private var mediaPlayer: MediaPlayer? = null
14
- private const val CHANNEL_ID = "incoming_calls"
15
- private const val NOTIFICATION_ID = 101
16
-
17
- fun handleIncomingPush(context: Context, data: Map<String, String>) {
18
- startRingtone(context)
19
- showIncomingCallNotification(context, data)
20
- }
21
-
22
- private fun startRingtone(context: Context) {
23
- if (mediaPlayer != null) return
24
- try {
25
- val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
26
- mediaPlayer = MediaPlayer().apply {
27
- setDataSource(context, uri)
28
- setAudioAttributes(AudioAttributes.Builder()
29
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
30
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
31
- .build())
32
- isLooping = true
33
- prepare()
34
- start()
35
- }
36
- } catch (e: Exception) { e.printStackTrace() }
37
- }
38
-
39
- fun stopRingtone() {
40
- mediaPlayer?.stop()
41
- mediaPlayer?.release()
42
- mediaPlayer = null
43
- }
44
-
45
- private fun showIncomingCallNotification(context: Context, data: Map<String, String>) {
46
- val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
47
-
48
- // Create Channel for Android O+
49
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
50
- val channel = NotificationChannel(CHANNEL_ID, "Incoming Calls", NotificationManager.IMPORTANCE_HIGH).apply {
51
- lockscreenVisibility = Notification.VISIBILITY_PUBLIC
52
- enableVibration(true)
53
- setSound(null, null) // We handle sound manually via MediaPlayer
54
- }
55
- notificationManager.createNotificationChannel(channel)
56
- }
57
-
58
- // 1. Full Screen Intent (To wake up the screen)
59
- val fullScreenIntent = Intent(context, AcceptCallActivity::class.java).apply {
60
- data.forEach { (k, v) -> putExtra(k, v) }
61
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NO_USER_ACTION)
62
- }
63
- val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
64
-
65
- // 2. Answer Action
66
- val answerIntent = Intent(context, CallActionReceiver::class.java).apply {
67
- action = "ACTION_ACCEPT"
68
- data.forEach { (k, v) -> putExtra(k, v) }
69
- }
70
- val answerPendingIntent = PendingIntent.getBroadcast(context, 1, answerIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
71
-
72
- // 3. Reject Action
73
- val rejectIntent = Intent(context, CallActionReceiver::class.java).apply {
74
- action = "ACTION_REJECT"
75
- data.forEach { (k, v) -> putExtra(k, v) }
76
- }
77
- val rejectPendingIntent = PendingIntent.getBroadcast(context, 2, rejectIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
78
-
79
- val builder = NotificationCompat.Builder(context, CHANNEL_ID)
80
- .setSmallIcon(context.applicationInfo.icon)
81
- .setContentTitle("Incoming Call")
82
- .setContentText(data["name"] ?: "Unknown Caller")
83
- .setPriority(NotificationCompat.PRIORITY_MAX)
84
- .setCategory(NotificationCompat.CATEGORY_CALL)
85
- .setAutoCancel(true)
86
- .setOngoing(true)
87
- .setFullScreenIntent(fullScreenPendingIntent, true)
88
- .addAction(0, "Answer", answerPendingIntent)
89
- .addAction(0, "Decline", rejectPendingIntent)
90
-
91
- notificationManager.notify(NOTIFICATION_ID, builder.build())
92
- }
93
- }
@@ -1,101 +0,0 @@
1
- package com.rnsnativecall
2
-
3
- import android.app.*
4
- import android.content.Context
5
- import android.content.Intent
6
- import android.media.AudioAttributes
7
- import android.media.MediaPlayer
8
- import android.media.RingtoneManager
9
- import android.os.Build
10
- import androidx.core.app.NotificationCompat
11
-
12
- object NativeCallManager {
13
- private var mediaPlayer: MediaPlayer? = null
14
- private const val CHANNEL_ID = "incoming_calls"
15
- private const val NOTIFICATION_ID = 101
16
-
17
- fun handleIncomingPush(context: Context, data: Map<String, String>) {
18
- startRingtone(context)
19
- showNotification(context, data)
20
- }
21
-
22
- private fun startRingtone(context: Context) {
23
- if (mediaPlayer != null) return
24
- try {
25
- val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
26
- mediaPlayer = MediaPlayer().apply {
27
- setDataSource(context, uri)
28
- setAudioAttributes(AudioAttributes.Builder()
29
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
30
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
31
- .build())
32
- isLooping = true
33
- prepare()
34
- start()
35
- }
36
- } catch (e: Exception) { e.printStackTrace() }
37
- }
38
-
39
- fun stopRingtone() {
40
- mediaPlayer?.stop()
41
- mediaPlayer?.release()
42
- mediaPlayer = null
43
- }
44
-
45
- private fun showNotification(context: Context, data: Map<String, String>) {
46
- val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
47
-
48
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
49
- val channel = NotificationChannel(CHANNEL_ID, "Calls", NotificationManager.IMPORTANCE_HIGH).apply {
50
- description = "Incoming call notifications"
51
- setSound(null, null)
52
- enableVibration(true)
53
- }
54
- notificationManager.createNotificationChannel(channel)
55
- }
56
-
57
- // 1. Full Screen Intent (Wakes up screen & goes to AcceptCallActivity)
58
- val fullScreenIntent = Intent(context, AcceptCallActivity::class.java).apply {
59
- data.forEach { (k, v) -> putExtra(k, v) }
60
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
61
- }
62
- val fullScreenPendingIntent = PendingIntent.getActivity(
63
- context, 0, fullScreenIntent,
64
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
65
- )
66
-
67
- // 2. Answer Button
68
- val answerIntent = Intent(context, CallActionReceiver::class.java).apply {
69
- action = "ACTION_ACCEPT"
70
- data.forEach { (k, v) -> putExtra(k, v) }
71
- }
72
- val answerPendingIntent = PendingIntent.getBroadcast(
73
- context, 1, answerIntent,
74
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
75
- )
76
-
77
- // 3. Reject Button
78
- val rejectIntent = Intent(context, CallActionReceiver::class.java).apply {
79
- action = "ACTION_REJECT"
80
- data.forEach { (k, v) -> putExtra(k, v) }
81
- }
82
- val rejectPendingIntent = PendingIntent.getBroadcast(
83
- context, 2, rejectIntent,
84
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
85
- )
86
-
87
- val builder = NotificationCompat.Builder(context, CHANNEL_ID)
88
- .setSmallIcon(android.R.drawable.ic_menu_call) // Replace with your app icon
89
- .setContentTitle("Incoming Call")
90
- .setContentText(data["name"] ?: "Raiidr User")
91
- .setPriority(NotificationCompat.PRIORITY_MAX)
92
- .setCategory(NotificationCompat.CATEGORY_CALL)
93
- .setFullScreenIntent(fullScreenPendingIntent, true)
94
- .setOngoing(true)
95
- .setAutoCancel(true)
96
- .addAction(0, "Answer", answerPendingIntent)
97
- .addAction(0, "Decline", rejectPendingIntent)
98
-
99
- notificationManager.notify(NOTIFICATION_ID, builder.build())
100
- }
101
- }