rns-nativecall 0.6.2 → 0.6.4
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 +77 -157
- package/android/build.gradle +0 -3
- package/android/src/main/java/com/rnsnativecall/AcceptCallActivity.kt +38 -38
- package/android/src/main/java/com/rnsnativecall/CallActionReceiver.kt +32 -27
- package/android/src/main/java/com/rnsnativecall/CallHeadlessTask.kt +21 -49
- package/android/src/main/java/com/rnsnativecall/CallMessagingService.kt +87 -83
- package/android/src/main/java/com/rnsnativecall/CallModule.kt +90 -21
- package/android/src/main/java/com/rnsnativecall/CallState.kt +54 -0
- package/android/src/main/java/com/rnsnativecall/NativeCallManager.kt +93 -53
- package/android/src/main/java/com/rnsnativecall/UnlockPromptActivity.kt +55 -0
- package/app.plugin.js +1 -1
- package/index.d.ts +13 -26
- package/index.js +36 -10
- package/package.json +12 -24
- package/rns-nativecall.podspec +1 -1
- package/withNativeCallVoip.js +94 -80
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package com.rnsnativecall
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.app.KeyguardManager
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.Intent
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.os.Bundle
|
|
9
|
+
import android.view.WindowManager
|
|
10
|
+
|
|
11
|
+
class UnlockPromptActivity : Activity() {
|
|
12
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
13
|
+
super.onCreate(savedInstanceState)
|
|
14
|
+
|
|
15
|
+
// Ensure this activity shows over the lockscreen to trigger the prompt
|
|
16
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
17
|
+
setShowWhenLocked(true)
|
|
18
|
+
setTurnScreenOn(true)
|
|
19
|
+
} else {
|
|
20
|
+
window.addFlags(
|
|
21
|
+
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
|
|
22
|
+
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
val km = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
|
27
|
+
|
|
28
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
29
|
+
km.requestDismissKeyguard(this, object : KeyguardManager.KeyguardDismissCallback() {
|
|
30
|
+
override fun onDismissSucceeded() {
|
|
31
|
+
super.onDismissSucceeded()
|
|
32
|
+
// Unlock successful, launch the main app
|
|
33
|
+
val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
|
|
34
|
+
startActivity(launchIntent)
|
|
35
|
+
finish()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override fun onDismissCancelled() {
|
|
39
|
+
super.onDismissCancelled()
|
|
40
|
+
finish()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override fun onDismissError() {
|
|
44
|
+
super.onDismissError()
|
|
45
|
+
finish()
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
} else {
|
|
49
|
+
// Fallback for older Android versions
|
|
50
|
+
val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
|
|
51
|
+
startActivity(launchIntent)
|
|
52
|
+
finish()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
package/app.plugin.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -2,50 +2,37 @@ export interface CallData {
|
|
|
2
2
|
callUuid: string;
|
|
3
3
|
name?: string;
|
|
4
4
|
callType?: 'audio' | 'video';
|
|
5
|
-
|
|
5
|
+
isBusySignal?: boolean;
|
|
6
|
+
[key: string]: any;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
export type
|
|
9
|
-
export type CallRejectedCallback = (data: CallData) => void;
|
|
10
|
-
export type CallFailedCallback = (data: any) => void;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Manually request/check Android permissions for Telecom.
|
|
14
|
-
*/
|
|
15
|
-
export function ensureAndroidPermissions(): Promise<boolean>;
|
|
9
|
+
export type CallEventType = 'INCOMING_CALL' | 'BUSY';
|
|
16
10
|
|
|
17
11
|
export interface CallHandlerType {
|
|
18
12
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* @param name Caller display name
|
|
22
|
-
* @param callType 'audio' or 'video'
|
|
13
|
+
* Registers the Headless JS task.
|
|
14
|
+
* Handles Busy signals and Call Validity automatically.
|
|
23
15
|
*/
|
|
16
|
+
registerHeadlessTask(
|
|
17
|
+
callback: (data: CallData, eventType: CallEventType) => Promise<void>
|
|
18
|
+
): void;
|
|
19
|
+
|
|
24
20
|
displayCall(
|
|
25
21
|
uuid: string,
|
|
26
22
|
name: string,
|
|
27
23
|
callType: 'audio' | 'video',
|
|
28
24
|
): Promise<boolean>;
|
|
29
25
|
|
|
30
|
-
/**
|
|
31
|
-
* Dismiss the native call UI (Sticky Pill).
|
|
32
|
-
*/
|
|
33
26
|
destroyNativeCallUI(uuid: string): void;
|
|
34
27
|
|
|
28
|
+
getInitialCallData(): Promise<any | null>;
|
|
35
29
|
|
|
36
|
-
getInitialCallData(): Promise<CallData | null>;
|
|
37
|
-
/**
|
|
38
|
-
* Subscribe to call events. Automatically checks for cold-start data
|
|
39
|
-
* if the app was opened via the Answer button.
|
|
40
|
-
* @returns Function to unsubscribe
|
|
41
|
-
*/
|
|
42
30
|
subscribe(
|
|
43
|
-
onAccept:
|
|
44
|
-
onReject:
|
|
45
|
-
onFailed?:
|
|
31
|
+
onAccept: (data: CallData) => void,
|
|
32
|
+
onReject: (data: CallData) => void,
|
|
33
|
+
onFailed?: (data: any) => void
|
|
46
34
|
): () => void;
|
|
47
35
|
}
|
|
48
36
|
|
|
49
37
|
declare const CallHandler: CallHandlerType;
|
|
50
|
-
|
|
51
38
|
export default CallHandler;
|
package/index.js
CHANGED
|
@@ -1,13 +1,48 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NativeModules,
|
|
3
3
|
NativeEventEmitter,
|
|
4
|
+
AppRegistry,
|
|
4
5
|
} from 'react-native';
|
|
5
6
|
|
|
6
7
|
const { CallModule } = NativeModules;
|
|
7
|
-
|
|
8
8
|
const callEventEmitter = CallModule ? new NativeEventEmitter(CallModule) : null;
|
|
9
9
|
|
|
10
10
|
export const CallHandler = {
|
|
11
|
+
/**
|
|
12
|
+
* INTERNAL GATEKEEPER: Moves headless logic into the package.
|
|
13
|
+
* The dev just passes their "NativeCall" function.
|
|
14
|
+
*/
|
|
15
|
+
registerHeadlessTask: (onAction) => {
|
|
16
|
+
AppRegistry.registerHeadlessTask('ColdStartCallTask', () => async (data) => {
|
|
17
|
+
const { callUuid, isBusySignal } = data;
|
|
18
|
+
const uuid = callUuid?.toLowerCase().trim();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// 1. Handle Busy Signal (Second Caller)
|
|
22
|
+
if (isBusySignal) {
|
|
23
|
+
console.log(`[RNSNativeCall] System busy. Informing app to send busy signal for: ${uuid}`);
|
|
24
|
+
if (onAction) await onAction(data, 'BUSY');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 2. Gatekeeping: Check Validity with Native logic
|
|
29
|
+
const status = await CallModule.checkCallValidity(uuid);
|
|
30
|
+
if (!status.isValid) {
|
|
31
|
+
console.log(`[RNSNativeCall] Aborting task: ${uuid} no longer valid or canceled.`);
|
|
32
|
+
if (onAction) await onAction(data, 'ABORTED_CALL');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 3. Valid Incoming Call: Pass to Developer's UI logic
|
|
37
|
+
if (onAction) {
|
|
38
|
+
await onAction(data, 'INCOMING_CALL');
|
|
39
|
+
}
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('[RNSNativeCall] Headless Task Error:', error);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
|
|
11
46
|
displayCall: async (uuid, name, callType = "audio") => {
|
|
12
47
|
if (!CallModule) return false;
|
|
13
48
|
return await CallModule.displayIncomingCall(uuid.toLowerCase().trim(), name, callType);
|
|
@@ -19,10 +54,6 @@ export const CallHandler = {
|
|
|
19
54
|
}
|
|
20
55
|
},
|
|
21
56
|
|
|
22
|
-
/**
|
|
23
|
-
* Manually check for cold-start data (App killed -> Answered).
|
|
24
|
-
* Call this in your App.js useEffect.
|
|
25
|
-
*/
|
|
26
57
|
getInitialCallData: async () => {
|
|
27
58
|
if (!CallModule?.getInitialCallData) return null;
|
|
28
59
|
return await CallModule.getInitialCallData();
|
|
@@ -40,11 +71,6 @@ export const CallHandler = {
|
|
|
40
71
|
subs.push(callEventEmitter.addListener('onCallFailed', onFailed));
|
|
41
72
|
}
|
|
42
73
|
|
|
43
|
-
// Auto-check on subscribe for convenience
|
|
44
|
-
CallHandler.getInitialCallData().then((data) => {
|
|
45
|
-
if (data) onAccept(data);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
74
|
return () => subs.forEach(s => s.remove());
|
|
49
75
|
}
|
|
50
76
|
};
|
package/package.json
CHANGED
|
@@ -1,37 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rns-nativecall",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.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",
|
|
7
7
|
"homepage": "https://github.com/raiidr/rns-nativecall",
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"author":
|
|
10
|
-
"name": "Your Name",
|
|
11
|
-
"email": "your.email@example.com"
|
|
12
|
-
},
|
|
9
|
+
"author": "Your Name <your.email@example.com>",
|
|
13
10
|
"repository": {
|
|
14
11
|
"type": "git",
|
|
15
|
-
"url": "https://github.com/raiidr/rns-nativecall.git"
|
|
12
|
+
"url": "git+https://github.com/raiidr/rns-nativecall.git"
|
|
16
13
|
},
|
|
17
|
-
"react-native": "index.js",
|
|
18
14
|
"scripts": {
|
|
19
15
|
"p": "npm publish --access public"
|
|
20
16
|
},
|
|
21
|
-
"expo": {
|
|
22
|
-
"autolink": true,
|
|
23
|
-
"plugins": [
|
|
24
|
-
"./app.plugin.js"
|
|
25
|
-
]
|
|
26
|
-
},
|
|
27
17
|
"keywords": [
|
|
28
18
|
"react-native",
|
|
29
19
|
"nativecall",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"call keep",
|
|
20
|
+
"voip",
|
|
21
|
+
"callkit",
|
|
33
22
|
"android",
|
|
34
|
-
"
|
|
23
|
+
"ios",
|
|
24
|
+
"expo",
|
|
25
|
+
"config-plugin"
|
|
35
26
|
],
|
|
36
27
|
"files": [
|
|
37
28
|
"android",
|
|
@@ -39,18 +30,15 @@
|
|
|
39
30
|
"app.plugin.js",
|
|
40
31
|
"index.d.ts",
|
|
41
32
|
"index.js",
|
|
42
|
-
"package.json",
|
|
43
33
|
"react-native.config.js",
|
|
44
|
-
"README.md",
|
|
45
34
|
"rns-nativecall.podspec",
|
|
46
35
|
"withNativeCallVoip.js"
|
|
47
36
|
],
|
|
48
37
|
"peerDependencies": {
|
|
49
|
-
"
|
|
50
|
-
"
|
|
38
|
+
"react-native": ">=0.60.0",
|
|
39
|
+
"expo": ">=45.0.0"
|
|
51
40
|
},
|
|
52
41
|
"dependencies": {
|
|
53
|
-
"@expo/config-plugins": "
|
|
54
|
-
"rns-nativecall": "^0.5.9"
|
|
42
|
+
"@expo/config-plugins": "^9.0.0"
|
|
55
43
|
}
|
|
56
44
|
}
|
package/rns-nativecall.podspec
CHANGED
|
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package["license"]
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
s.platforms = { :ios => "10.0" }
|
|
13
|
-
s.source = { :git => "https://github.com/
|
|
13
|
+
s.source = { :git => "https://github.com/raiidr.git", :tag => "#{s.version}" }
|
|
14
14
|
|
|
15
15
|
s.source_files = "ios/**/*.{h,m,mm}"
|
|
16
16
|
|
package/withNativeCallVoip.js
CHANGED
|
@@ -5,133 +5,147 @@ function withMainActivityDataFix(config) {
|
|
|
5
5
|
return withMainActivity(config, (config) => {
|
|
6
6
|
let contents = config.modResults.contents;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'import android.os.Bundle',
|
|
12
|
-
'import android.content.Intent',
|
|
13
|
-
'import android.content.Context' // Added: Required for KEYGUARD_SERVICE
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
imports.forEach(imp => {
|
|
17
|
-
if (!contents.includes(imp)) {
|
|
18
|
-
contents = contents.replace(/package .*/, (match) => `${match}\n${imp}`);
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const wakeLogic = `super.onCreate(savedInstanceState)
|
|
23
|
-
if (intent?.getBooleanExtra("navigatingToCall", false) == true) {
|
|
24
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
25
|
-
setShowWhenLocked(true)
|
|
26
|
-
setTurnScreenOn(true)
|
|
27
|
-
} else {
|
|
28
|
-
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
|
|
8
|
+
// Ensure imports exist
|
|
9
|
+
if (!contents.includes('import android.content.Intent')) {
|
|
10
|
+
contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.content.Intent`);
|
|
29
11
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
keyguardManager?.requestDismissKeyguard(this, null)
|
|
33
|
-
}`;
|
|
34
|
-
|
|
35
|
-
if (!contents.includes('setShowWhenLocked')) {
|
|
36
|
-
contents = contents.replace(/super\.onCreate\(.*\)/, wakeLogic);
|
|
12
|
+
if (!contents.includes('import android.os.Bundle')) {
|
|
13
|
+
contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.os.Bundle`);
|
|
37
14
|
}
|
|
38
15
|
|
|
39
|
-
|
|
40
|
-
const onNewIntentCode = `
|
|
16
|
+
const onNewIntentCode = `
|
|
41
17
|
override fun onNewIntent(intent: Intent) {
|
|
42
18
|
super.onNewIntent(intent)
|
|
43
19
|
setIntent(intent)
|
|
44
|
-
|
|
20
|
+
|
|
21
|
+
// Only fire JS event if the user actually pressed "Answer"
|
|
22
|
+
val isAnswerAction = intent.action == "com.rnsnativecall.ACTION_ANSWER"
|
|
23
|
+
|
|
24
|
+
val dataMap = mutableMapOf<String, String>()
|
|
25
|
+
intent.extras?.keySet()?.forEach { key ->
|
|
26
|
+
dataMap[key] = intent.extras?.get(key)?.toString() ?: ""
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (dataMap.isNotEmpty() && isAnswerAction) {
|
|
30
|
+
com.rnsnativecall.CallModule.setPendingCallData(dataMap)
|
|
31
|
+
com.rnsnativecall.CallModule.sendEventToJS("onCallAccepted", dataMap)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const onCreateCode = `
|
|
37
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
38
|
+
super.onCreate(savedInstanceState)
|
|
39
|
+
|
|
40
|
+
val isAnswerAction = intent.action == "com.rnsnativecall.ACTION_ANSWER"
|
|
41
|
+
|
|
42
|
+
// Logic for Cold Start (App was dead, user answered)
|
|
43
|
+
if (isAnswerAction) {
|
|
44
|
+
val dataMap = mutableMapOf<String, String>()
|
|
45
|
+
intent.extras?.keySet()?.forEach { key ->
|
|
46
|
+
dataMap[key] = intent.extras?.get(key)?.toString() ?: ""
|
|
47
|
+
}
|
|
48
|
+
com.rnsnativecall.CallModule.setPendingCallData(dataMap)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Move to back if it's a background wake (FCM) and NOT an answer click
|
|
52
|
+
if (intent.getBooleanExtra("background_wake", false) && !isAnswerAction) {
|
|
53
|
+
moveTaskToBack(true)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
// Inject codes
|
|
59
|
+
if (!contents.includes('override fun onNewIntent')) {
|
|
45
60
|
const lastBraceIndex = contents.lastIndexOf('}');
|
|
46
61
|
contents = contents.slice(0, lastBraceIndex) + onNewIntentCode + contents.slice(lastBraceIndex);
|
|
47
62
|
}
|
|
63
|
+
if (!contents.includes('override fun onCreate')) {
|
|
64
|
+
const lastBraceIndex = contents.lastIndexOf('}');
|
|
65
|
+
contents = contents.slice(0, lastBraceIndex) + onCreateCode + contents.slice(lastBraceIndex);
|
|
66
|
+
}
|
|
48
67
|
|
|
49
68
|
config.modResults.contents = contents;
|
|
50
69
|
return config;
|
|
51
70
|
});
|
|
52
71
|
}
|
|
53
|
-
|
|
54
72
|
/** 2. ANDROID MANIFEST CONFIG **/
|
|
55
73
|
function withAndroidConfig(config) {
|
|
56
74
|
return withAndroidManifest(config, (config) => {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
// Permissions
|
|
75
|
+
const manifest = config.modResults;
|
|
76
|
+
const application = manifest.manifest.application[0];
|
|
61
77
|
const permissions = [
|
|
62
78
|
'android.permission.USE_FULL_SCREEN_INTENT',
|
|
63
79
|
'android.permission.VIBRATE',
|
|
64
80
|
'android.permission.FOREGROUND_SERVICE',
|
|
65
81
|
'android.permission.FOREGROUND_SERVICE_PHONE_CALL',
|
|
66
82
|
'android.permission.POST_NOTIFICATIONS',
|
|
83
|
+
'android.permission.SYSTEM_ALERT_WINDOW',
|
|
67
84
|
'android.permission.WAKE_LOCK',
|
|
68
|
-
'android.permission.
|
|
69
|
-
'android.permission.DISABLE_KEYGUARD',
|
|
70
|
-
'android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS',
|
|
71
|
-
'android.permission.RECEIVE_BOOT_COMPLETED'
|
|
85
|
+
'android.permission.DISABLE_KEYGUARD'
|
|
72
86
|
];
|
|
73
|
-
|
|
74
|
-
androidManifest['uses-permission'] = androidManifest['uses-permission'] || [];
|
|
87
|
+
manifest.manifest['uses-permission'] = manifest.manifest['uses-permission'] || [];
|
|
75
88
|
permissions.forEach((perm) => {
|
|
76
|
-
if (!
|
|
77
|
-
|
|
89
|
+
if (!manifest.manifest['uses-permission'].some((p) => p.$['android:name'] === perm)) {
|
|
90
|
+
manifest.manifest['uses-permission'].push({ $: { 'android:name': perm } });
|
|
78
91
|
}
|
|
79
92
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (!mainApplication.activity.some(a => a.$['android:name'] === 'com.rnsnativecall.AcceptCallActivity')) {
|
|
84
|
-
mainApplication.activity.push({
|
|
93
|
+
application.activity = application.activity || [];
|
|
94
|
+
if (!application.activity.some(a => a.$['android:name'] === 'com.rnsnativecall.AcceptCallActivity')) {
|
|
95
|
+
application.activity.push({
|
|
85
96
|
$: {
|
|
86
97
|
'android:name': 'com.rnsnativecall.AcceptCallActivity',
|
|
87
98
|
'android:theme': '@android:style/Theme.Translucent.NoTitleBar',
|
|
88
|
-
'android:
|
|
99
|
+
'android:excludeFromRecents': 'true',
|
|
100
|
+
'android:noHistory': 'true',
|
|
101
|
+
'android:exported': 'false',
|
|
102
|
+
'android:launchMode': 'singleInstance',
|
|
89
103
|
'android:showWhenLocked': 'true',
|
|
90
|
-
'android:turnScreenOn': 'true'
|
|
91
|
-
'android:launchMode': 'singleInstance' // Add this to prevent multiple instances
|
|
104
|
+
'android:turnScreenOn': 'true'
|
|
92
105
|
}
|
|
93
106
|
});
|
|
94
107
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
mainApplication.receiver = mainApplication.receiver || [];
|
|
98
|
-
if (!mainApplication.receiver.some(r => r.$['android:name'] === 'com.rnsnativecall.CallActionReceiver')) {
|
|
99
|
-
mainApplication.receiver.push({
|
|
108
|
+
if (!application.activity.some(a => a.$['android:name'] === 'com.rnsnativecall.UnlockPromptActivity')) {
|
|
109
|
+
application.activity.push({
|
|
100
110
|
$: {
|
|
101
|
-
'android:name': 'com.rnsnativecall.
|
|
102
|
-
'android:
|
|
111
|
+
'android:name': 'com.rnsnativecall.UnlockPromptActivity',
|
|
112
|
+
'android:theme': '@android:style/Theme.Translucent.NoTitleBar',
|
|
113
|
+
'android:excludeFromRecents': 'true',
|
|
114
|
+
'android:noHistory': 'true',
|
|
115
|
+
'android:exported': 'false',
|
|
116
|
+
'android:launchMode': 'singleInstance',
|
|
117
|
+
'android:showWhenLocked': 'true',
|
|
118
|
+
'android:turnScreenOn': 'true'
|
|
103
119
|
}
|
|
104
120
|
});
|
|
105
121
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
mainApplication.service.push({
|
|
112
|
-
$: { 'android:name': 'com.rnsnativecall.CallMessagingService', 'android:exported': 'false' },
|
|
122
|
+
application.service = application.service || [];
|
|
123
|
+
const firebaseServiceName = 'com.rnsnativecall.CallMessagingService';
|
|
124
|
+
if (!application.service.some(s => s.$['android:name'] === firebaseServiceName)) {
|
|
125
|
+
application.service.push({
|
|
126
|
+
$: { 'android:name': firebaseServiceName, 'android:exported': 'false' },
|
|
113
127
|
'intent-filter': [{ action: [{ $: { 'android:name': 'com.google.firebase.MESSAGING_EVENT' } }] }]
|
|
114
128
|
});
|
|
115
129
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
else mainApplication.service.push(headlessEntry);
|
|
130
|
+
const headlessServiceName = 'com.rnsnativecall.CallHeadlessTask';
|
|
131
|
+
if (!application.service.some(s => s.$['android:name'] === headlessServiceName)) {
|
|
132
|
+
application.service.push({
|
|
133
|
+
$: { 'android:name': headlessServiceName, 'android:exported': 'false' }
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
application.receiver = application.receiver || [];
|
|
137
|
+
const receiverName = 'com.rnsnativecall.CallActionReceiver';
|
|
138
|
+
if (!application.receiver.some(r => r.$['android:name'] === receiverName)) {
|
|
139
|
+
application.receiver.push({
|
|
140
|
+
$: { 'android:name': receiverName, 'android:exported': 'false' }
|
|
141
|
+
});
|
|
142
|
+
}
|
|
130
143
|
|
|
131
144
|
return config;
|
|
132
145
|
});
|
|
133
146
|
}
|
|
134
147
|
|
|
148
|
+
/** 3. IOS CONFIG **/
|
|
135
149
|
function withIosConfig(config) {
|
|
136
150
|
return withInfoPlist(config, (config) => {
|
|
137
151
|
const infoPlist = config.modResults;
|