rns-nativecall 0.4.0 → 0.4.2

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/app.plugin.js CHANGED
@@ -1,13 +1,6 @@
1
1
  ///app.plugin.js
2
- const { withPlugins } = require('@expo/config-plugins');
3
2
  const withNativeCallVoip = require('./withNativeCallVoip');
4
- const withCallNativeConfig = require('./withCallNativeConfig');
5
- const withCallPermissions = require('./withCallPermissions');
6
3
 
7
- module.exports = function (config, props) {
8
- return withPlugins(config, [
9
- [withNativeCallVoip, props],
10
- [withCallNativeConfig, props],
11
- [withCallPermissions, props],
12
- ]);
4
+ module.exports = function (config) {
5
+ return withNativeCallVoip(config);
13
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
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",
@@ -1,3 +1,4 @@
1
+ ///withCallNativeConfig.js
1
2
  const { withAndroidManifest, withInfoPlist, withPlugins, withMainActivity } = require('@expo/config-plugins');
2
3
 
3
4
  /** 1. ANDROID MAIN ACTIVITY MODS **/
@@ -1,4 +1,5 @@
1
- const { withPlugins, withAndroidManifest } = require('@expo/config-plugins'); // Add this!
1
+ //withCallPermissions.js
2
+ const { withPlugins, withAndroidManifest } = require('@expo/config-plugins');
2
3
 
3
4
 
4
5
  /** 2. ANDROID MANIFEST MOD **/
@@ -1,140 +1,47 @@
1
1
  const { withAndroidManifest, withInfoPlist, withPlugins, withMainActivity } = require('@expo/config-plugins');
2
2
 
3
- /** 1. ANDROID MAIN ACTIVITY MOD **/
4
- // function withMainActivityDataFix(config) {
5
- // return withMainActivity(config, (config) => {
6
- // let contents = config.modResults.contents;
7
-
8
- // // 1. Ensure necessary Imports are present
9
- // if (!contents.includes('import android.content.Intent')) {
10
- // contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.content.Intent`);
11
- // }
12
- // if (!contents.includes('import android.os.Bundle')) {
13
- // contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.os.Bundle`);
14
- // }
15
-
16
- // // 2. Define the code blocks
17
- // const onNewIntentCode = `
18
- // override fun onNewIntent(intent: Intent) {
19
- // super.onNewIntent(intent)
20
- // setIntent(intent)
21
- // }
22
- // `;
23
-
24
- // const onCreateCode = `
25
- // override fun onCreate(savedInstanceState: Bundle?) {
26
- // super.onCreate(savedInstanceState)
27
- // // If woken up silently, move to back to prevent UI flicker
28
- // if (intent.getBooleanExtra("background_wake", false)) {
29
- // moveTaskToBack(true)
30
- // }
31
- // }
32
- // `;
33
-
34
- // // 3. Insert the codes before the last closing brace of the class
35
- // if (!contents.includes('override fun onNewIntent')) {
36
- // const lastBraceIndex = contents.lastIndexOf('}');
37
- // contents = contents.slice(0, lastBraceIndex) + onNewIntentCode + contents.slice(lastBraceIndex);
38
- // }
39
-
40
- // if (!contents.includes('override fun onCreate')) {
41
- // // Re-calculate lastBraceIndex because contents string has changed
42
- // const lastBraceIndex = contents.lastIndexOf('}');
43
- // contents = contents.slice(0, lastBraceIndex) + onCreateCode + contents.slice(lastBraceIndex);
44
- // }
45
-
46
- // config.modResults.contents = contents;
47
- // return config;
48
- // });
49
- // }
50
-
51
3
  /** 1. ANDROID MAIN ACTIVITY MOD **/
52
4
  function withMainActivityDataFix(config) {
53
5
  return withMainActivity(config, (config) => {
54
6
  let contents = config.modResults.contents;
55
7
 
56
- // --- 1. Imports ---
57
- const neededImports = [
8
+ // 1. Add required imports
9
+ const imports = [
58
10
  'import android.view.WindowManager',
59
11
  'import android.os.Build',
60
- 'import android.os.Bundle'
12
+ 'import android.os.Bundle',
13
+ 'import android.content.Intent'
61
14
  ];
62
-
63
- neededImports.forEach(imp => {
15
+ imports.forEach(imp => {
64
16
  if (!contents.includes(imp)) {
65
17
  contents = contents.replace(/package .*/, (match) => `${match}\n${imp}`);
66
18
  }
67
19
  });
68
20
 
69
- // --- 2. Replace onCreate ---
70
- // We look for the existing onCreate and replace the entire block with your version
71
- const editedOnCreate = `
72
- // override fun onCreate(savedInstanceState: Bundle?) {
73
- // setTheme(R.style.AppTheme)
74
- // super.onCreate(savedInstanceState)
75
-
76
- // // --- LOCK SCREEN WAKE LOGIC ---
77
- // // This allows the Activity to appear over the lock screen when Answer is pressed
78
- // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
79
- // setShowWhenLocked(true)
80
- // setTurnScreenOn(true)
81
- // } else {
82
- // @Suppress("DEPRECATION")
83
- // window.addFlags(
84
- // WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
85
- // WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
86
- // WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
87
- // )
88
- // }
89
- // }
90
- override fun onCreate(savedInstanceState: Bundle?) {
91
- setTheme(R.style.AppTheme)
92
- super.onCreate(savedInstanceState)
93
-
94
- // Only wake the screen/bypass lock if we are coming from a notification interaction
95
- // Otherwise, let the notification pill handle the UI.
96
- if (intent?.action?.startsWith("ACTION_SHOW_UI") == true) {
97
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
98
- setShowWhenLocked(true)
99
- setTurnScreenOn(true)
100
- } else {
101
- @Suppress("DEPRECATION")
102
- window.addFlags(
103
- WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
104
- WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
105
- WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
106
- )
107
- }
21
+ // 2. Add the Lockscreen / Wake logic inside onCreate
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)
108
29
  }
109
- }
110
- `;
111
-
112
-
113
-
30
+ }`;
114
31
 
115
- // Regex to find the existing onCreate block (including the setTheme and super calls)
116
- const onCreateRegex = /override fun onCreate\(savedInstanceState: Bundle\?\).*?\{[\s\S]*?super\.onCreate\(null\)\n\s*\}/;
117
- if (contents.match(onCreateRegex)) {
118
- contents = contents.replace(onCreateRegex, editedOnCreate);
32
+ if (!contents.includes('setShowWhenLocked')) {
33
+ contents = contents.replace(/super\.onCreate\(.*\)/, wakeLogic);
119
34
  }
120
35
 
121
- // --- 3. Update createReactActivityDelegate ---
122
- // Removing the "object :" and the empty trailing block "{})" to match your edited version
123
- contents = contents.replace(
124
- /return ReactActivityDelegateWrapper\([\s\S]*?object : (DefaultReactActivityDelegate\([\s\S]*?\))\{\}\)/,
125
- 'return ReactActivityDelegateWrapper($1)'
126
- );
127
-
128
- // --- 4. Ensure onNewIntent exists ---
129
- const onNewIntentCode = `
130
- override fun onNewIntent(intent: Intent) {
131
- super.onNewIntent(intent)
132
- setIntent(intent)
133
- }`;
134
-
36
+ // 3. Ensure onNewIntent is present
135
37
  if (!contents.includes('override fun onNewIntent')) {
38
+ const onNewIntentCode = `
39
+ override fun onNewIntent(intent: Intent) {
40
+ super.onNewIntent(intent)
41
+ setIntent(intent)
42
+ }\n`;
136
43
  const lastBraceIndex = contents.lastIndexOf('}');
137
- contents = contents.slice(0, lastBraceIndex) + onNewIntentCode + "\n" + contents.slice(lastBraceIndex);
44
+ contents = contents.slice(0, lastBraceIndex) + onNewIntentCode + contents.slice(lastBraceIndex);
138
45
  }
139
46
 
140
47
  config.modResults.contents = contents;
@@ -145,73 +52,83 @@ function withMainActivityDataFix(config) {
145
52
  /** 2. ANDROID MANIFEST CONFIG **/
146
53
  function withAndroidConfig(config) {
147
54
  return withAndroidManifest(config, (config) => {
148
- const manifest = config.modResults;
149
- const application = manifest.manifest.application[0];
55
+ const androidManifest = config.modResults.manifest;
56
+ const mainApplication = androidManifest.application[0];
57
+
58
+ // 1. Configure MainActivity flags in Manifest
59
+ const mainActivity = mainApplication.activity.find(a => a.$["android:name"] === ".MainActivity");
60
+ if (mainActivity) {
61
+ mainActivity.$["android:showWhenLocked"] = "true";
62
+ mainActivity.$["android:turnScreenOn"] = "true";
63
+ }
150
64
 
151
- // 1. Unified Permissions
65
+ // 2. Unified Permissions
152
66
  const permissions = [
153
67
  'android.permission.USE_FULL_SCREEN_INTENT',
154
68
  'android.permission.VIBRATE',
155
69
  'android.permission.FOREGROUND_SERVICE',
156
- 'android.permission.FOREGROUND_SERVICE_PHONE_CALL', // Required for Android 14
70
+ 'android.permission.FOREGROUND_SERVICE_PHONE_CALL',
157
71
  'android.permission.POST_NOTIFICATIONS',
158
72
  'android.permission.WAKE_LOCK',
159
73
  'android.permission.DISABLE_KEYGUARD',
160
- 'android.permission.RECEIVE_BOOT_COMPLETED' // Allows app to wake after phone restart
74
+ 'android.permission.RECEIVE_BOOT_COMPLETED'
161
75
  ];
162
76
 
163
- manifest.manifest['uses-permission'] = manifest.manifest['uses-permission'] || [];
77
+ androidManifest['uses-permission'] = androidManifest['uses-permission'] || [];
164
78
  permissions.forEach((perm) => {
165
- if (!manifest.manifest['uses-permission'].some((p) => p.$['android:name'] === perm)) {
166
- manifest.manifest['uses-permission'].push({ $: { 'android:name': perm } });
79
+ if (!androidManifest['uses-permission'].some((p) => p.$['android:name'] === perm)) {
80
+ androidManifest['uses-permission'].push({ $: { 'android:name': perm } });
167
81
  }
168
82
  });
169
83
 
170
- // 2. Activity Setup (Remain unchanged as your logic was correct)
171
- application.activity = application.activity || [];
172
- // ... (Keep your AcceptCallActivity logic here)
173
-
174
- // 3. Service Setup (CRITICAL UPDATES FOR ANDROID 14)
175
- application.service = application.service || [];
176
-
177
- // Add Firebase Messaging Service
178
- const firebaseServiceName = 'com.rnsnativecall.CallMessagingService';
179
- if (!application.service.some(s => s.$['android:name'] === firebaseServiceName)) {
180
- application.service.push({
84
+ // 3. AcceptCallActivity Registration
85
+ mainApplication.activity = mainApplication.activity || [];
86
+ if (!mainApplication.activity.some(a => a.$['android:name'] === 'com.rnsnativecall.AcceptCallActivity')) {
87
+ mainApplication.activity.push({
181
88
  $: {
182
- 'android:name': firebaseServiceName,
89
+ 'android:name': 'com.rnsnativecall.AcceptCallActivity',
90
+ 'android:theme': '@android:style/Theme.Translucent.NoTitleBar',
183
91
  'android:exported': 'false',
184
- // Adding type for Android 14 stability
185
- 'android:foregroundServiceType': 'phoneCall'
186
- },
187
- 'intent-filter': [{ action: [{ $: { 'android:name': 'com.google.firebase.MESSAGING_EVENT' } }] }]
92
+ 'android:showWhenLocked': 'true',
93
+ 'android:turnScreenOn': 'true'
94
+ }
188
95
  });
189
96
  }
190
97
 
191
- // Add Headless JS Task Service
192
- const headlessServiceName = 'com.rnsnativecall.CallHeadlessTask';
193
- if (!application.service.some(s => s.$['android:name'] === headlessServiceName)) {
194
- application.service.push({
195
- $: {
196
- 'android:name': headlessServiceName,
197
- 'android:exported': 'false',
198
- // This ensures the JS bridge is treated as a priority process
199
- 'android:foregroundServiceType': 'phoneCall'
98
+ // 4. Service Setup
99
+ mainApplication.service = mainApplication.service || [];
100
+
101
+ const services = [
102
+ {
103
+ name: 'com.rnsnativecall.CallMessagingService',
104
+ intentFilter: 'com.google.firebase.MESSAGING_EVENT'
105
+ },
106
+ {
107
+ name: 'com.rnsnativecall.CallHeadlessTask'
108
+ }
109
+ ];
110
+
111
+ services.forEach(svc => {
112
+ if (!mainApplication.service.some(s => s.$['android:name'] === svc.name)) {
113
+ const serviceEntry = {
114
+ $: {
115
+ 'android:name': svc.name,
116
+ 'android:exported': 'false',
117
+ 'android:foregroundServiceType': 'phoneCall'
118
+ }
119
+ };
120
+ if (svc.intentFilter) {
121
+ serviceEntry['intent-filter'] = [{ action: [{ $: { 'android:name': svc.intentFilter } }] }];
200
122
  }
201
- });
202
- }
123
+ mainApplication.service.push(serviceEntry);
124
+ }
125
+ });
203
126
 
204
- // 4. Receiver Setup
205
- application.receiver = application.receiver || [];
206
- const receiverName = 'com.rnsnativecall.CallActionReceiver';
207
- if (!application.receiver.some(r => r.$['android:name'] === receiverName)) {
208
- application.receiver.push({
209
- $: { 'android:name': receiverName, 'android:exported': 'false' },
210
- 'intent-filter': [{
211
- action: [
212
- { $: { 'android:name': 'android.intent.action.BOOT_COMPLETED' } }
213
- ]
214
- }]
127
+ // 5. Receiver Setup
128
+ mainApplication.receiver = mainApplication.receiver || [];
129
+ if (!mainApplication.receiver.some(r => r.$['android:name'] === 'com.rnsnativecall.CallActionReceiver')) {
130
+ mainApplication.receiver.push({
131
+ $: { 'android:name': 'com.rnsnativecall.CallActionReceiver', 'android:exported': 'false' }
215
132
  });
216
133
  }
217
134