rns-nativecall 1.3.2 → 1.3.3

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
@@ -297,4 +297,4 @@ MIT License
297
297
 
298
298
  ---
299
299
 
300
- Built for **production VoIP apps**, not demos.
300
+ Built for **production VoIP apps**, not demos.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
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",
@@ -48,8 +48,6 @@
48
48
  "react-native": ">=0.60.0"
49
49
  },
50
50
  "dependencies": {
51
- "@expo/config-plugins": "^9.0.0",
52
- "react-native-uuid": "^2.0.3",
53
- "expo-build-properties": "~0.14.8"
51
+ "@expo/config-plugins": "^9.0.0"
54
52
  }
55
53
  }
@@ -13,7 +13,6 @@ function withMainActivityDataFix(config) {
13
13
  'import android.Manifest'
14
14
  ];
15
15
 
16
- // Add imports if they don't exist
17
16
  imports.forEach(imp => {
18
17
  if (!contents.includes(imp)) {
19
18
  contents = contents.replace(/package .*/, (match) => `${match}\n${imp}`);
@@ -21,16 +20,21 @@ function withMainActivityDataFix(config) {
21
20
  });
22
21
 
23
22
  const onCreateCode = `
24
- override fun onCreate(savedInstanceState: Bundle?) {
23
+ override fun onCreate(savedInstanceState: Bundle?) {
25
24
  super.onCreate(savedInstanceState)
26
25
 
27
- // Request Notification Permissions for Android 13+ (Required for Pill UI)
26
+ // Request Permissions for Android 13+ and Calling Roles
27
+ val permissions = mutableListOf<String>()
28
28
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
29
- ActivityCompat.requestPermissions(
30
- this,
31
- arrayOf(Manifest.permission.POST_NOTIFICATIONS),
32
- 101
33
- )
29
+ permissions.add(Manifest.permission.POST_NOTIFICATIONS)
30
+ }
31
+ // MANAGE_OWN_CALLS is required for Foreground Service Type 'phoneCall' on SDK 34+
32
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
33
+ permissions.add(Manifest.permission.MANAGE_OWN_CALLS)
34
+ }
35
+
36
+ if (permissions.isNotEmpty()) {
37
+ ActivityCompat.requestPermissions(this, permissions.toTypedArray(), 101)
34
38
  }
35
39
 
36
40
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
@@ -69,35 +73,45 @@ function withMainActivityDataFix(config) {
69
73
  return config;
70
74
  });
71
75
  }
76
+
72
77
  function withNotificationColor(config) {
73
78
  // 1. Find the color in app.json (fallback to #218aff)
74
79
  const notificationPlugin = config.plugins?.find(p => Array.isArray(p) && p[0] === 'expo-notifications');
75
80
  const iconColor = notificationPlugin?.[1]?.color || '#218aff';
76
81
 
77
82
  return withAndroidStyles(config, (config) => {
83
+ // Corrected from config.config.modResults to config.modResults
78
84
  config.modResults = AndroidConfig.Styles.assignStylesValue(config.modResults, {
79
85
  name: 'notification_icon_color',
80
86
  value: iconColor,
81
- parent: 'AppTheme', // or your primary theme
87
+ parent: 'AppTheme',
82
88
  type: 'color',
83
89
  });
84
90
  return config;
85
91
  });
86
92
  }
87
- /** 2. ANDROID MANIFEST CONFIG **/
93
+
88
94
  function withAndroidConfig(config) {
89
95
  return withAndroidManifest(config, (config) => {
90
96
  const manifest = config.modResults;
97
+
98
+ // Ensure manifest structure exists
99
+ if (!manifest.manifest) manifest.manifest = {};
100
+ if (!manifest.manifest.application) manifest.manifest.application = [{}];
101
+
91
102
  const application = manifest.manifest.application[0];
92
103
 
93
- // Ensure MainActivity flags
94
- const mainActivity = application.activity.find((a) => a.$['android:name'] === '.MainActivity');
95
- if (mainActivity) {
96
- mainActivity.$['android:launchMode'] = 'singleTop';
97
- mainActivity.$['android:showWhenLocked'] = 'true';
98
- mainActivity.$['android:turnScreenOn'] = 'true';
104
+ // 1. Ensure MainActivity flags
105
+ if (application.activity) {
106
+ const mainActivity = application.activity.find((a) => a.$['android:name'] === '.MainActivity');
107
+ if (mainActivity) {
108
+ mainActivity.$['android:launchMode'] = 'singleTop';
109
+ mainActivity.$['android:showWhenLocked'] = 'true';
110
+ mainActivity.$['android:turnScreenOn'] = 'true';
111
+ }
99
112
  }
100
113
 
114
+ // 2. Fix Permissions (The 'some' error fix)
101
115
  const permissions = [
102
116
  'android.permission.VIBRATE',
103
117
  'android.permission.FOREGROUND_SERVICE',
@@ -110,16 +124,21 @@ function withAndroidConfig(config) {
110
124
  'android.permission.MANAGE_OWN_CALLS',
111
125
  ];
112
126
 
113
- manifest.manifest['uses-permission'] = manifest.manifest['uses-permission'] || [];
127
+ // Initialize uses-permission if it doesn't exist
128
+ if (!Array.isArray(manifest.manifest['uses-permission'])) {
129
+ manifest.manifest['uses-permission'] = [];
130
+ }
131
+
114
132
  permissions.forEach((perm) => {
115
- if (!manifest.manifest['uses-permission'].some((p) => p.$['android:name'] === perm)) {
133
+ if (!manifest.manifest['uses-permission'].some((p) => p.$ && p.$['android:name'] === perm)) {
116
134
  manifest.manifest['uses-permission'].push({ $: { 'android:name': perm } });
117
135
  }
118
136
  });
119
137
 
120
- application.service = application.service || [];
121
- application.activity = application.activity || [];
122
- application.receiver = application.receiver || [];
138
+ // 3. Fix Services
139
+ if (!Array.isArray(application.service)) {
140
+ application.service = [];
141
+ }
123
142
 
124
143
  const services = [
125
144
  { name: 'com.rnsnativecall.CallMessagingService', exported: 'false', filter: 'com.google.firebase.MESSAGING_EVENT' },
@@ -129,7 +148,7 @@ function withAndroidConfig(config) {
129
148
  ];
130
149
 
131
150
  services.forEach(svc => {
132
- if (!application.service.some(s => s.$['android:name'] === svc.name)) {
151
+ if (!application.service.some(s => s.$ && s.$['android:name'] === svc.name)) {
133
152
  const entry = { $: { 'android:name': svc.name, 'android:exported': svc.exported || 'false' } };
134
153
  if (svc.type) entry.$['android:foregroundServiceType'] = svc.type;
135
154
  if (svc.filter) {
@@ -139,13 +158,18 @@ function withAndroidConfig(config) {
139
158
  }
140
159
  });
141
160
 
161
+ // 4. Fix Activities
162
+ if (!Array.isArray(application.activity)) {
163
+ application.activity = [];
164
+ }
165
+
142
166
  const activities = [
143
167
  { name: 'com.rnsnativecall.AcceptCallActivity', theme: '@android:style/Theme.Translucent.NoTitleBar', launchMode: 'singleInstance' },
144
168
  { name: 'com.rnsnativecall.NotificationOverlayActivity', theme: '@android:style/Theme.NoTitleBar.Fullscreen', launchMode: 'singleInstance' }
145
169
  ];
146
170
 
147
171
  activities.forEach(act => {
148
- if (!application.activity.some(a => a.$['android:name'] === act.name)) {
172
+ if (!application.activity.some(a => a.$ && a.$['android:name'] === act.name)) {
149
173
  application.activity.push({
150
174
  $: {
151
175
  'android:name': act.name,
@@ -161,28 +185,28 @@ function withAndroidConfig(config) {
161
185
  }
162
186
  });
163
187
 
164
- if (!application.receiver.some(r => r.$['android:name'] === 'com.rnsnativecall.CallActionReceiver')) {
188
+ // 5. Fix Receiver (The other likely 'some' error source)
189
+ if (!Array.isArray(application.receiver)) {
190
+ application.receiver = [];
191
+ }
192
+
193
+ if (!application.receiver.some(r => r.$ && r.$['android:name'] === 'com.rnsnativecall.CallActionReceiver')) {
165
194
  application.receiver.push({ $: { 'android:name': 'com.rnsnativecall.CallActionReceiver', 'android:exported': 'false' } });
166
195
  }
167
196
 
168
197
  return config;
169
198
  });
170
199
  }
171
- /** 2. IOS APP DELEGATE MOD (The fix for Lock Screen Answer) **/
200
+
172
201
  function withIosAppDelegateMod(config) {
173
202
  return withAppDelegate(config, (config) => {
174
203
  let contents = config.modResults.contents;
175
-
176
- // 1. Surgical Import: Add 'import React' at the very top if missing
177
204
  if (!contents.includes('import React')) {
178
205
  contents = 'import React\n' + contents;
179
206
  }
180
207
 
181
- // 2. Check for the continue userActivity method
182
208
  if (!contents.includes('continue userActivity')) {
183
- // Method is missing, inject it before the final closing brace of the class
184
209
  const swiftLinkingCode = `
185
- // Universal Links
186
210
  public override func application(
187
211
  _ application: UIApplication,
188
212
  continue userActivity: NSUserActivity,
@@ -192,36 +216,26 @@ function withIosAppDelegateMod(config) {
192
216
  return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result
193
217
  }
194
218
  `;
195
- // This regex finds the last '}' in the file (closing the AppDelegate class)
196
219
  contents = contents.replace(/\n}\s*$/, `\n${swiftLinkingCode}\n}`);
197
- } else if (!contents.includes('RCTLinkingManager.application')) {
198
- // Method exists but is missing our logic, inject it inside
199
- contents = contents.replace(
200
- /continue userActivity: NSUserActivity,[\s\S]*?\) -> Bool \{/,
201
- `continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {\n let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)`
202
- );
203
220
  }
204
-
205
221
  config.modResults.contents = contents;
206
222
  return config;
207
223
  });
208
224
  }
209
- /** 3. IOS INFO.PLIST CONFIG (Existing) **/
225
+
210
226
  function withIosConfig(config, props = {}) {
211
227
  return withInfoPlist(config, (config) => {
212
228
  const infoPlist = config.modResults;
213
229
  if (!infoPlist.UIBackgroundModes) infoPlist.UIBackgroundModes = [];
214
-
215
230
  ['voip', 'remote-notification'].forEach(mode => {
216
231
  if (!infoPlist.UIBackgroundModes.includes(mode)) {
217
232
  infoPlist.UIBackgroundModes.push(mode);
218
233
  }
219
234
  });
220
-
221
235
  return config;
222
236
  });
223
237
  }
224
- // Main Plugin Entry
238
+
225
239
  module.exports = (config, props) => {
226
240
  return withPlugins(config, [
227
241
  withAndroidConfig,