rns-nativecall 1.1.4 → 1.1.6
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 +17 -16
- package/android/src/main/java/com/rnsnativecall/CallModule.kt +21 -43
- package/android/src/main/java/com/rnsnativecall/NativeCallManager.kt +1 -10
- package/index.d.ts +6 -30
- package/index.js +26 -51
- package/package.json +1 -1
- package/withNativeCallVoip.js +30 -44
package/README.md
CHANGED
|
@@ -130,31 +130,32 @@ export default function App() {
|
|
|
130
130
|
### 📖 API Reference
|
|
131
131
|
# rns-nativecall API Reference
|
|
132
132
|
|
|
133
|
-
| Method
|
|
134
|
-
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
|
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
|
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
|
|
|
144
|
-
| getInitialCallData() | All | Returns call data if the app was launched by clicking "Answer" from a killed state. |
|
|
145
|
-
| subscribe(onAccept, onReject)| All | Listens for native button presses (Answer/End/Failed) and returns a cleanup function. |
|
|
133
|
+
| Method | Platform | Description |
|
|
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). |
|
|
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). |
|
|
146
144
|
|
|
147
145
|
---
|
|
148
146
|
|
|
149
147
|
# Implementation Notes
|
|
150
148
|
|
|
151
|
-
1. Android
|
|
149
|
+
1. Android Persistence:
|
|
150
|
+
Because this library uses a Foreground Service on Android, the notification will persist and show a "Call Pill" in the status bar. To remove this after the call ends or connects, you MUST call 'CallHandler.stopForegroundService()'.
|
|
151
|
+
|
|
152
|
+
2. Android Overlay:
|
|
152
153
|
For your React Native call screen to show up when the phone is locked, the user must grant the "Overlay Permission". Use 'checkOverlayPermission()' and 'requestOverlayPermission()' during your app's onboarding or call initiation.
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
3. iOS CallKit:
|
|
155
156
|
On iOS, 'displayCall' uses the native system CallKit UI. This works automatically in the background and on the lockscreen without extra overlay permissions.
|
|
156
157
|
|
|
157
|
-
|
|
158
|
+
4. Single Call Gate:
|
|
158
159
|
The library automatically prevents multiple overlapping native UIs. If a call is already active, subsequent calls will trigger the 'BUSY' event in your Headless Task.
|
|
159
160
|
---
|
|
160
161
|
|
|
@@ -61,6 +61,7 @@ class CallModule(
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// Inside your CallModule class
|
|
64
65
|
@ReactMethod
|
|
65
66
|
fun checkOverlayPermission(promise: Promise) {
|
|
66
67
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
@@ -70,16 +71,6 @@ class CallModule(
|
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
@ReactMethod
|
|
74
|
-
fun reportRemoteEnded(
|
|
75
|
-
uuid: String,
|
|
76
|
-
reason: String,
|
|
77
|
-
promise: Promise,
|
|
78
|
-
) {
|
|
79
|
-
NativeCallManager.dismissIncomingCall(reactApplicationContext, uuid)
|
|
80
|
-
promise.resolve(true)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
74
|
@ReactMethod
|
|
84
75
|
fun requestOverlayPermission() {
|
|
85
76
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
@@ -95,39 +86,10 @@ class CallModule(
|
|
|
95
86
|
}
|
|
96
87
|
}
|
|
97
88
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
promise.resolve(notificationManager.canUseFullScreenIntent())
|
|
103
|
-
} else {
|
|
104
|
-
// Automatically true for Android 13 and below
|
|
105
|
-
promise.resolve(true)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
@ReactMethod
|
|
110
|
-
fun openFullScreenIntentSettings() {
|
|
111
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
112
|
-
try {
|
|
113
|
-
val intent =
|
|
114
|
-
Intent(Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT).apply {
|
|
115
|
-
data = Uri.fromParts("package", reactApplicationContext.packageName, null)
|
|
116
|
-
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
117
|
-
}
|
|
118
|
-
reactApplicationContext.startActivity(intent)
|
|
119
|
-
} catch (e: Exception) {
|
|
120
|
-
// Fallback for some OEM skins that might not support the direct intent
|
|
121
|
-
val intent =
|
|
122
|
-
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
|
123
|
-
data = Uri.fromParts("package", reactApplicationContext.packageName, null)
|
|
124
|
-
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
125
|
-
}
|
|
126
|
-
reactApplicationContext.startActivity(intent)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Combined Validity Check:
|
|
91
|
+
* Used by Headless Task to see if it should proceed with the UI.
|
|
92
|
+
*/
|
|
131
93
|
@ReactMethod
|
|
132
94
|
fun checkCallValidity(
|
|
133
95
|
uuid: String,
|
|
@@ -145,6 +107,22 @@ class CallModule(
|
|
|
145
107
|
promise.resolve(map)
|
|
146
108
|
}
|
|
147
109
|
|
|
110
|
+
@ReactMethod
|
|
111
|
+
fun stopForegroundService(promise: Promise) {
|
|
112
|
+
try {
|
|
113
|
+
// Using the current react context to stop the service
|
|
114
|
+
val intent = Intent(reactApplicationContext, CallForegroundService::class.java)
|
|
115
|
+
reactApplicationContext.stopService(intent)
|
|
116
|
+
promise.resolve(true)
|
|
117
|
+
} catch (e: Exception) {
|
|
118
|
+
promise.reject("SERVICE_STOP_ERROR", e.message)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* General Status Check:
|
|
124
|
+
* Useful for checking if the UI is still relevant.
|
|
125
|
+
*/
|
|
148
126
|
@ReactMethod
|
|
149
127
|
fun checkCallStatus(
|
|
150
128
|
uuid: String,
|
|
@@ -14,7 +14,7 @@ import androidx.core.app.Person
|
|
|
14
14
|
import androidx.core.content.ContextCompat
|
|
15
15
|
|
|
16
16
|
object NativeCallManager {
|
|
17
|
-
const val channelId = "
|
|
17
|
+
const val channelId = "CALL_CHANNEL_V15_URGENT"
|
|
18
18
|
private var currentCallData: Map<String, String>? = null
|
|
19
19
|
|
|
20
20
|
@JvmStatic internal var pendingCallNotification: Notification? = null
|
|
@@ -102,7 +102,6 @@ object NativeCallManager {
|
|
|
102
102
|
.setOngoing(true)
|
|
103
103
|
.setFullScreenIntent(fullScreenPendingIntent, true)
|
|
104
104
|
.setStyle(NotificationCompat.CallStyle.forIncomingCall(caller, rejectPendingIntent, answerPendingIntent))
|
|
105
|
-
.setAutoCancel(false)
|
|
106
105
|
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
|
|
107
106
|
|
|
108
107
|
val notification = builder.build()
|
|
@@ -118,14 +117,6 @@ object NativeCallManager {
|
|
|
118
117
|
}
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
fun refreshNotificationOnly(
|
|
122
|
-
context: Context,
|
|
123
|
-
uuid: String,
|
|
124
|
-
) {
|
|
125
|
-
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
126
|
-
manager.cancel(uuid.hashCode())
|
|
127
|
-
}
|
|
128
|
-
|
|
129
120
|
fun dismissIncomingCall(
|
|
130
121
|
context: Context,
|
|
131
122
|
uuid: String?,
|
package/index.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ 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.
|
|
51
|
+
* * @param callback Async function receiving call data and the event type.
|
|
52
52
|
*/
|
|
53
53
|
registerHeadlessTask(
|
|
54
54
|
callback: (data: CallData, eventType: CallEventType) => Promise<void>
|
|
@@ -57,7 +57,7 @@ export interface CallHandlerType {
|
|
|
57
57
|
/**
|
|
58
58
|
* Displays the full-screen Native Incoming Call UI.
|
|
59
59
|
* Usually called inside registerHeadlessTask after validating the call.
|
|
60
|
-
* @param uuid The unique call ID.
|
|
60
|
+
* * @param uuid The unique call ID.
|
|
61
61
|
* @param name Name to display on the call screen.
|
|
62
62
|
* @param callType Defaults to 'audio'.
|
|
63
63
|
* @returns Promise resolving to true if the UI was successfully launched.
|
|
@@ -65,7 +65,7 @@ export interface CallHandlerType {
|
|
|
65
65
|
displayCall(
|
|
66
66
|
uuid: string,
|
|
67
67
|
name: string,
|
|
68
|
-
callType
|
|
68
|
+
callType: 'audio' | 'video',
|
|
69
69
|
): Promise<boolean>;
|
|
70
70
|
|
|
71
71
|
/** * Checks if a call is still valid and has not been canceled.
|
|
@@ -78,36 +78,12 @@ export interface CallHandlerType {
|
|
|
78
78
|
*/
|
|
79
79
|
checkCallStatus(uuid: string): Promise<CallStatus>;
|
|
80
80
|
|
|
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>;
|
|
81
|
+
requestOverlayPermission(): Promise<boolean>;
|
|
86
82
|
|
|
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
|
-
openFullScreenSettings(): void;
|
|
83
|
+
reportRemoteEnded(uuid: string, reason: number): void;
|
|
92
84
|
|
|
93
|
-
/**
|
|
94
|
-
* 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
|
-
*/
|
|
97
85
|
checkOverlayPermission(): Promise<boolean>;
|
|
98
86
|
|
|
99
|
-
/**
|
|
100
|
-
* Opens system settings to request the "Draw over other apps" (Overlay) permission.
|
|
101
|
-
*/
|
|
102
|
-
requestOverlayPermission(): void;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* 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
|
-
*/
|
|
109
|
-
reportRemoteEnded(uuid: string, reason?: string): Promise<void>;
|
|
110
|
-
|
|
111
87
|
/**
|
|
112
88
|
* Forcefully dismisses the native call UI, stops the ringtone, and clears state.
|
|
113
89
|
* Use this when the call is hung up or timed out.
|
|
@@ -129,7 +105,7 @@ export interface CallHandlerType {
|
|
|
129
105
|
|
|
130
106
|
/**
|
|
131
107
|
* Subscribes to user interactions on the Native Call UI.
|
|
132
|
-
* @param onAccept Callback when user presses the Answer button.
|
|
108
|
+
* * @param onAccept Callback when user presses the Answer button.
|
|
133
109
|
* @param onReject Callback when user presses the Decline button.
|
|
134
110
|
* @param onFailed Callback for system errors (optional).
|
|
135
111
|
* @returns A cleanup function to unsubscribe.
|
package/index.js
CHANGED
|
@@ -2,18 +2,12 @@ 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
|
|
|
11
10
|
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
11
|
registerHeadlessTask: (onAction) => {
|
|
18
12
|
AppRegistry.registerHeadlessTask('ColdStartCallTask', () => async (data) => {
|
|
19
13
|
const { callUuid, isBusySignal } = data;
|
|
@@ -25,81 +19,64 @@ export const CallHandler = {
|
|
|
25
19
|
return;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
//
|
|
22
|
+
// CallModule.checkCallValidity is now accessible via the native bridge
|
|
29
23
|
const status = await CallModule.checkCallValidity(uuid);
|
|
30
24
|
if (!status.isValid) {
|
|
31
25
|
if (onAction) await onAction(data, 'ABORTED_CALL');
|
|
32
26
|
return;
|
|
33
27
|
}
|
|
34
28
|
|
|
35
|
-
if (onAction)
|
|
29
|
+
if (onAction) {
|
|
30
|
+
await onAction(data, 'INCOMING_CALL');
|
|
31
|
+
}
|
|
36
32
|
} catch (error) {
|
|
37
33
|
console.error('[RNSNativeCall] Headless Task Error:', error);
|
|
38
34
|
}
|
|
39
35
|
});
|
|
40
36
|
},
|
|
41
37
|
|
|
42
|
-
// ---
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return await CallModule.checkFullScreenIntentPermission();
|
|
38
|
+
// --- Added missing bridge methods ---
|
|
39
|
+
checkCallValidity: async (uuid) => {
|
|
40
|
+
if (!CallModule?.checkCallValidity) return { isValid: false, isCanceled: true };
|
|
41
|
+
return await CallModule.checkCallValidity(uuid.toLowerCase().trim());
|
|
47
42
|
},
|
|
48
43
|
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
}
|
|
44
|
+
checkCallStatus: async (uuid) => {
|
|
45
|
+
if (!CallModule?.checkCallStatus) return { isCanceled: true, isActive: false, shouldDisplay: false };
|
|
46
|
+
return await CallModule.checkCallStatus(uuid.toLowerCase().trim());
|
|
53
47
|
},
|
|
48
|
+
// ------------------------------------
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
|
|
50
|
+
reportRemoteEnded: async (uuid, endReason) => {
|
|
51
|
+
if (!CallModule?.reportRemoteEnded) return;
|
|
52
|
+
await CallModule.reportRemoteEnded(uuid.toLowerCase().trim(), endReason);
|
|
58
53
|
},
|
|
59
54
|
|
|
60
|
-
requestOverlayPermission: () => {
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
}
|
|
55
|
+
requestOverlayPermission: async () => {
|
|
56
|
+
if (!CallModule?.requestOverlayPermission) return false;
|
|
57
|
+
return await CallModule.requestOverlayPermission();
|
|
64
58
|
},
|
|
65
59
|
|
|
66
|
-
|
|
60
|
+
checkOverlayPermission: async () => {
|
|
61
|
+
if (!CallModule?.checkOverlayPermission) return false;
|
|
62
|
+
return await CallModule.checkOverlayPermission();
|
|
63
|
+
},
|
|
67
64
|
|
|
68
65
|
displayCall: async (uuid, name, callType = "audio") => {
|
|
69
66
|
if (!CallModule) return false;
|
|
70
67
|
return await CallModule.displayIncomingCall(uuid.toLowerCase().trim(), name, callType);
|
|
71
68
|
},
|
|
72
69
|
|
|
73
|
-
/** Stops the UI and the Foreground Service */
|
|
74
|
-
destroyNativeCallUI: (uuid) => {
|
|
75
|
-
if (CallModule?.endNativeCall) {
|
|
76
|
-
CallModule.endNativeCall(uuid.toLowerCase().trim());
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
|
|
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
70
|
stopForegroundService: async () => {
|
|
88
71
|
if (CallModule?.stopForegroundService) {
|
|
89
72
|
await CallModule.stopForegroundService();
|
|
90
73
|
}
|
|
91
74
|
},
|
|
92
75
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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());
|
|
76
|
+
destroyNativeCallUI: (uuid) => {
|
|
77
|
+
if (CallModule?.endNativeCall) {
|
|
78
|
+
CallModule.endNativeCall(uuid.toLowerCase().trim());
|
|
79
|
+
}
|
|
103
80
|
},
|
|
104
81
|
|
|
105
82
|
getInitialCallData: async () => {
|
|
@@ -107,8 +84,6 @@ export const CallHandler = {
|
|
|
107
84
|
return await CallModule.getInitialCallData();
|
|
108
85
|
},
|
|
109
86
|
|
|
110
|
-
// --- EVENT SUBSCRIPTION ---
|
|
111
|
-
|
|
112
87
|
subscribe: (onAccept, onReject, onFailed) => {
|
|
113
88
|
if (!callEventEmitter) return () => { };
|
|
114
89
|
const subs = [
|
package/package.json
CHANGED
package/withNativeCallVoip.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { withAndroidManifest, withInfoPlist, withPlugins, withMainActivity, withAppDelegate } = require('@expo/config-plugins');
|
|
2
2
|
|
|
3
|
-
/** 1. MAIN ACTIVITY MOD **/
|
|
4
3
|
function withMainActivityDataFix(config) {
|
|
5
4
|
return withMainActivity(config, (config) => {
|
|
6
5
|
let contents = config.modResults.contents;
|
|
@@ -14,52 +13,56 @@ function withMainActivityDataFix(config) {
|
|
|
14
13
|
'import android.Manifest'
|
|
15
14
|
];
|
|
16
15
|
|
|
17
|
-
//
|
|
16
|
+
// Add imports if they don't exist
|
|
18
17
|
imports.forEach(imp => {
|
|
19
18
|
if (!contents.includes(imp)) {
|
|
20
19
|
contents = contents.replace(/package .*/, (match) => `${match}\n${imp}`);
|
|
21
20
|
}
|
|
22
21
|
});
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const onCreateCode = `
|
|
24
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
25
|
+
super.onCreate(savedInstanceState)
|
|
26
|
+
|
|
27
|
+
// Request Notification Permissions for Android 13+ (Required for Pill UI)
|
|
26
28
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
27
|
-
ActivityCompat.requestPermissions(
|
|
29
|
+
ActivityCompat.requestPermissions(
|
|
30
|
+
this,
|
|
31
|
+
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
|
32
|
+
101
|
|
33
|
+
)
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
31
37
|
setShowWhenLocked(true)
|
|
32
38
|
setTurnScreenOn(true)
|
|
33
39
|
} else {
|
|
34
|
-
window.addFlags(
|
|
40
|
+
window.addFlags(
|
|
41
|
+
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
|
|
42
|
+
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
|
|
43
|
+
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
|
44
|
+
)
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
if (intent.getBooleanExtra("background_wake", false)) {
|
|
38
48
|
moveTaskToBack(true)
|
|
39
49
|
}
|
|
40
|
-
`;
|
|
41
|
-
|
|
42
|
-
if (contents.includes('override fun onCreate')) {
|
|
43
|
-
// If onCreate exists, inject logic after super.onCreate
|
|
44
|
-
if (!contents.includes('setShowWhenLocked(true)')) {
|
|
45
|
-
contents = contents.replace(
|
|
46
|
-
/super\.onCreate\(.*\)/,
|
|
47
|
-
(match) => `${match}\n${voipOnCreateLogic}`
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
50
|
+
}`;
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const onNewIntentCode = `
|
|
53
|
+
override fun onNewIntent(intent: Intent) {
|
|
54
|
+
super.onNewIntent(intent)
|
|
55
|
+
setIntent(intent)
|
|
56
|
+
}`;
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
const classRegex = /class MainActivity\s*:\s*ReactActivity\(\)\s*\{/;
|
|
59
|
+
|
|
60
|
+
if (!contents.includes('override fun onCreate')) {
|
|
61
|
+
contents = contents.replace(classRegex, (match) => `${match}${onCreateCode}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!contents.includes('override fun onNewIntent')) {
|
|
65
|
+
contents = contents.replace(classRegex, (match) => `${match}${onNewIntentCode}`);
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
config.modResults.contents = contents;
|
|
@@ -146,23 +149,6 @@ function withAndroidConfig(config) {
|
|
|
146
149
|
application.receiver.push({ $: { 'android:name': 'com.rnsnativecall.CallActionReceiver', 'android:exported': 'false' } });
|
|
147
150
|
}
|
|
148
151
|
|
|
149
|
-
// 2. ADDED UnlockReceiver with intent-filter
|
|
150
|
-
if (!application.receiver.some(r => r.$['android:name'] === 'com.rnsnativecall.UnlockReceiver')) {
|
|
151
|
-
application.receiver.push({
|
|
152
|
-
$: {
|
|
153
|
-
'android:name': 'com.rnsnativecall.UnlockReceiver',
|
|
154
|
-
'android:exported': 'false'
|
|
155
|
-
},
|
|
156
|
-
'intent-filter': [
|
|
157
|
-
{
|
|
158
|
-
action: [
|
|
159
|
-
{ $: { 'android:name': 'android.intent.action.USER_PRESENT' } }
|
|
160
|
-
]
|
|
161
|
-
}
|
|
162
|
-
]
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
152
|
return config;
|
|
167
153
|
});
|
|
168
154
|
}
|