rns-nativecall 1.1.9 → 1.2.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.
package/README.md CHANGED
@@ -132,16 +132,18 @@ export default function App() {
132
132
 
133
133
  | Method | Platform | Description |
134
134
  | :--- | :--- | :--- |
135
- | **registerHeadlessTask(callback)** | Android | Registers background logic. `eventType` is `INCOMING_CALL` or `BUSY`. |
136
- | **checkOverlayPermission()** | Android | Returns true if the app can draw over other apps (Required for Android Lockscreen). |
135
+ | **registerHeadlessTask(callback)** | Android | Registers background logic. `eventType` is `INCOMING_CALL`, `BUSY`, or `ABORTED_CALL`. |
136
+ | **checkOverlayPermission()** | Android | Returns true if the app can draw over other apps (Required for overlay UI). |
137
137
  | **requestOverlayPermission()** | Android | Opens System Settings to let the user enable "Draw over other apps". |
138
- | **displayCall(uuid, name, type)** | All | Shows the native call UI (Standard Notification on Android / CallKit on iOS). |
139
- | **checkCallValidity(uuid)** | All | Returns boolean values for `isValid` and `isCanceled`. |
140
- | **stopForegroundService()** | Android | Stops the ongoing service and clears the persistent notification/pill. |
141
- | **destroyNativeCallUI(uuid)** | All | Dismisses the native call interface and stops the ringtone. |
142
- | **getInitialCallData()** | All | Returns call data if the app was launched by clicking `Answer` from a killed state. |
143
- | **subscribe(onAccept, onReject)** | All | Listens for native button presses (Answer/End). |
144
-
138
+ | **checkFullScreenPermission()** | Android | [Android 14+] Checks if the app is allowed to show full-screen intents on the lockscreen. |
139
+ | **requestFullScreenSettings()** | Android | [Android 14+] Opens System Settings to enable the Full Screen Intent permission. |
140
+ | **displayCall(uuid, name, type)** | Android | Shows the native full-screen call UI and starts the ringtone. |
141
+ | **checkCallValidity(uuid)** | Android | Returns `{isValid, isCanceled}` based on persistent state and CANCEL signals. |
142
+ | **checkCallStatus(uuid)** | Android | Returns `{isCanceled, isActive, shouldDisplay}` for UI synchronization. |
143
+ | **reportRemoteEnded(uuid, reason)** | Android | Tells the native side the caller hung up so the UI can dismiss automatically. |
144
+ | **destroyNativeCallUI(uuid)** | Android | Forcefully dismisses the native interface, stops audio, and clears the current call state. |
145
+ | **getInitialCallData()** | Android | Returns the call payload if the app was cold-started by a notification interaction. |
146
+ | **subscribe(onAccept, onReject, onFailed)** | Android | Listens for native Answer/Decline button presses and system errors. |
145
147
  ---
146
148
 
147
149
  # Implementation Notes
@@ -107,7 +107,7 @@ class CallModule(
107
107
  }
108
108
 
109
109
  @ReactMethod
110
- fun openFullScreenIntentSettings() {
110
+ fun requestFullScreenSettings() {
111
111
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
112
112
  try {
113
113
  val intent =
@@ -1,4 +1,3 @@
1
- /////Users/bush/Desktop/Apps/Raiidr/package/android/src/main/java/com/rnsnativecall/CallPackage.kt
2
1
  package com.rnsnativecall
3
2
 
4
3
  import com.facebook.react.ReactPackage
@@ -7,11 +6,7 @@ import com.facebook.react.bridge.ReactApplicationContext
7
6
  import com.facebook.react.uimanager.ViewManager
8
7
 
9
8
  class CallPackage : ReactPackage {
10
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
- return listOf(CallModule(reactContext))
12
- }
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> = listOf(CallModule(reactContext))
13
10
 
14
- override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
- return emptyList()
16
- }
17
- }
11
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> = emptyList()
12
+ }
package/index.d.ts CHANGED
@@ -48,7 +48,6 @@ export interface CallHandlerType {
48
48
  /**
49
49
  * Registers the background "Headless" task.
50
50
  * This is the bridge between a Native push notification and your React Native UI.
51
- * @param callback Async function receiving call data and the event type.
52
51
  */
53
52
  registerHeadlessTask(
54
53
  callback: (data: CallData, eventType: CallEventType) => Promise<void>
@@ -56,11 +55,6 @@ export interface CallHandlerType {
56
55
 
57
56
  /**
58
57
  * Displays the full-screen Native Incoming Call UI.
59
- * Usually called inside registerHeadlessTask after validating the call.
60
- * @param uuid The unique call ID.
61
- * @param name Name to display on the call screen.
62
- * @param callType Defaults to 'audio'.
63
- * @returns Promise resolving to true if the UI was successfully launched.
64
58
  */
65
59
  displayCall(
66
60
  uuid: string,
@@ -69,69 +63,47 @@ export interface CallHandlerType {
69
63
  ): Promise<boolean>;
70
64
 
71
65
  /** * Checks if a call is still valid and has not been canceled.
72
- * Useful for Splash screen "Interceptors" to prevent ghost calls.
73
66
  */
74
67
  checkCallValidity(uuid: string): Promise<ValidityStatus>;
75
68
 
76
69
  /** * Detailed check of a call's status.
77
- * Useful for determining if the UI should remain visible.
78
70
  */
79
71
  checkCallStatus(uuid: string): Promise<CallStatus>;
80
72
 
81
- /**
82
- * [Android 14+] Checks if the user has granted the special "Full Screen Intent" permission.
83
- * This is required for the call to show over the lockscreen.
84
- */
85
- checkFullScreenPermission(): Promise<boolean>;
86
-
87
- /**
88
- * [Android 14+] Opens the specific system settings page for the user to
89
- * manually enable "Full Screen Intent" if it was revoked.
90
- */
91
- requestFullScreenSettings(): void;
92
-
93
73
  /**
94
74
  * Checks if the app has permission to draw over other apps (Overlay).
95
- * Necessary for showing the "Pill" or answer buttons while the phone is unlocked.
96
75
  */
97
76
  checkOverlayPermission(): Promise<boolean>;
98
77
 
99
78
  /**
100
79
  * Opens system settings to request the "Draw over other apps" (Overlay) permission.
80
+ * Note: Returns a promise that resolves to false if module is missing.
101
81
  */
102
- requestOverlayPermission(): void;
82
+ requestOverlayPermission(): Promise<boolean | void>;
83
+
84
+ /**
85
+ * [Android 14+] Opens the specific system settings page for Full Screen Intent.
86
+ */
87
+ requestFullScreenSettings(): Promise<boolean | void>;
103
88
 
104
89
  /**
105
90
  * Reports to the native side that the remote party has terminated the call.
106
- * @param uuid The unique call ID.
107
- * @param reason Custom string reason (e.g., "RemoteEnded", "TimedOut").
108
91
  */
109
92
  reportRemoteEnded(uuid: string, reason?: string): Promise<void>;
110
93
 
111
94
  /**
112
95
  * Forcefully dismisses the native call UI, stops the ringtone, and clears state.
113
- * Use this when the call is hung up or timed out.
114
96
  */
115
97
  destroyNativeCallUI(uuid: string): void;
116
98
 
117
99
  /**
118
- * Stops the "Connecting..." Foreground Service.
119
- * MUST be called after displayCall() or when a BUSY signal is handled to
120
- * remove the persistent system notification.
121
- */
122
- stopForegroundService(): Promise<void>;
123
-
124
- /**
125
- * Retrieves call data if the app was launched directly from an interaction
126
- * with a notification while the app was in a "Killed" state.
100
+ * Retrieves call data if the app was launched directly from an interaction.
101
+ * Returns the 'default' payload or the raw data object.
127
102
  */
128
103
  getInitialCallData(): Promise<any | null>;
129
104
 
130
105
  /**
131
106
  * Subscribes to user interactions on the Native Call UI.
132
- * @param onAccept Callback when user presses the Answer button.
133
- * @param onReject Callback when user presses the Decline button.
134
- * @param onFailed Callback for system errors (optional).
135
107
  * @returns A cleanup function to unsubscribe.
136
108
  */
137
109
  subscribe(
@@ -144,5 +116,5 @@ export interface CallHandlerType {
144
116
  /**
145
117
  * Main handler for Native VoIP Call interactions.
146
118
  */
147
- declare const CallHandler: CallHandlerType;
119
+ export const CallHandler: CallHandlerType;
148
120
  export default CallHandler;
package/index.js CHANGED
@@ -2,18 +2,13 @@ import {
2
2
  NativeModules,
3
3
  NativeEventEmitter,
4
4
  AppRegistry,
5
- Platform,
6
5
  } from 'react-native';
7
6
 
8
7
  const { CallModule } = NativeModules;
9
8
  const callEventEmitter = CallModule ? new NativeEventEmitter(CallModule) : null;
10
9
 
10
+
11
11
  export const CallHandler = {
12
- /**
13
- * REGISTER HEADLESS TASK
14
- * This is the "Engine" that listens for incoming push notifications
15
- * while the app is killed or in the background.
16
- */
17
12
  registerHeadlessTask: (onAction) => {
18
13
  AppRegistry.registerHeadlessTask('ColdStartCallTask', () => async (data) => {
19
14
  const { callUuid, isBusySignal } = data;
@@ -25,89 +20,73 @@ export const CallHandler = {
25
20
  return;
26
21
  }
27
22
 
28
- // Check if the call is still valid before showing UI
23
+ // CallModule.checkCallValidity is now accessible via the native bridge
29
24
  const status = await CallModule.checkCallValidity(uuid);
30
25
  if (!status.isValid) {
31
26
  if (onAction) await onAction(data, 'ABORTED_CALL');
32
27
  return;
33
28
  }
34
29
 
35
- if (onAction) await onAction(data, 'INCOMING_CALL');
30
+ if (onAction) {
31
+ await onAction(data, 'INCOMING_CALL');
32
+ }
36
33
  } catch (error) {
37
34
  console.error('[RNSNativeCall] Headless Task Error:', error);
38
35
  }
39
36
  });
40
37
  },
41
38
 
42
- // --- PERMISSION HEALTH CHECKS ---
39
+ // --- Added missing bridge methods ---
40
+ checkCallValidity: async (uuid) => {
41
+ if (!CallModule?.checkCallValidity) return { isValid: false, isCanceled: true };
42
+ return await CallModule.checkCallValidity(uuid.toLowerCase().trim());
43
+ },
43
44
 
44
- checkFullScreenPermission: async () => {
45
- if (Platform.OS !== 'android' || !CallModule?.checkFullScreenIntentPermission) return true;
46
- return await CallModule.checkFullScreenIntentPermission();
45
+ checkCallStatus: async (uuid) => {
46
+ if (!CallModule?.checkCallStatus) return { isCanceled: true, isActive: false, shouldDisplay: false };
47
+ return await CallModule.checkCallStatus(uuid.toLowerCase().trim());
47
48
  },
49
+ // ------------------------------------
48
50
 
49
- openFullScreenSettings: () => {
50
- if (Platform.OS === 'android' && CallModule?.openFullScreenIntentSettings) {
51
- CallModule.openFullScreenIntentSettings();
52
- }
51
+ reportRemoteEnded: async (uuid, endReason) => {
52
+ if (!CallModule?.reportRemoteEnded) return;
53
+ await CallModule.reportRemoteEnded(uuid.toLowerCase().trim(), endReason);
53
54
  },
54
55
 
55
- checkOverlayPermission: async () => {
56
- if (Platform.OS !== 'android' || !CallModule?.checkOverlayPermission) return true;
57
- return await CallModule.checkOverlayPermission();
56
+ requestOverlayPermission: async () => {
57
+ if (!CallModule?.requestOverlayPermission) return false;
58
+ return await CallModule.requestOverlayPermission();
58
59
  },
59
60
 
60
- requestFullScreenSettings: () => {
61
- if (Platform.OS === 'android' && CallModule?.requestOverlayPermission) {
62
- CallModule.requestOverlayPermission();
63
- }
61
+ requestFullScreenSettings: async () => {
62
+ if (!CallModule?.requestFullScreenSettings) return false;
63
+ return await CallModule.requestFullScreenSettings();
64
64
  },
65
65
 
66
- // --- CALL LIFECYCLE ACTIONS ---
66
+ checkOverlayPermission: async () => {
67
+ if (!CallModule?.checkOverlayPermission) return false;
68
+ return await CallModule.checkOverlayPermission();
69
+ },
67
70
 
68
71
  displayCall: async (uuid, name, callType = "audio") => {
69
72
  if (!CallModule) return false;
70
73
  return await CallModule.displayIncomingCall(uuid.toLowerCase().trim(), name, callType);
71
74
  },
72
75
 
73
- /** Stops the UI and the Foreground Service */
74
76
  destroyNativeCallUI: (uuid) => {
75
77
  if (CallModule?.endNativeCall) {
76
78
  CallModule.endNativeCall(uuid.toLowerCase().trim());
77
79
  }
78
80
  },
79
81
 
80
- /** Reports to the native side that the other person hung up */
81
- reportRemoteEnded: async (uuid, endReason = "RemoteEnded") => {
82
- if (CallModule?.reportRemoteEnded) {
83
- await CallModule.reportRemoteEnded(uuid.toLowerCase().trim(), endReason);
84
- }
85
- },
86
-
87
- stopForegroundService: async () => {
88
- if (CallModule?.stopForegroundService) {
89
- await CallModule.stopForegroundService();
90
- }
91
- },
92
-
93
- // --- STATE VERIFICATION ---
94
-
95
- checkCallValidity: async (uuid) => {
96
- if (!CallModule?.checkCallValidity) return { isValid: false, isCanceled: true };
97
- return await CallModule.checkCallValidity(uuid.toLowerCase().trim());
98
- },
99
-
100
- checkCallStatus: async (uuid) => {
101
- if (!CallModule?.checkCallStatus) return { isCanceled: true, isActive: false, shouldDisplay: false };
102
- return await CallModule.checkCallStatus(uuid.toLowerCase().trim());
103
- },
104
82
 
105
83
  getInitialCallData: async () => {
106
84
  if (!CallModule?.getInitialCallData) return null;
107
- return await CallModule.getInitialCallData();
108
- },
85
+ const data = await CallModule.getInitialCallData();
109
86
 
110
- // --- EVENT SUBSCRIPTION ---
87
+ // Return the 'default' call data if it exists, otherwise the whole object
88
+ return data?.default || data;
89
+ },
111
90
 
112
91
  subscribe: (onAccept, onReject, onFailed) => {
113
92
  if (!callEventEmitter) return () => { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "1.1.9",
3
+ "version": "1.2.0",
4
4
  "description": "High-performance React Native module for handling native VoIP call UI on Android and iOS.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",