rns-nativecall 0.3.8 → 0.3.9

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.
@@ -23,7 +23,7 @@ class CallModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
23
23
  writableMap
24
24
  }
25
25
  promise.resolve(data)
26
- pendingCallDataMap = null // Clear after use
26
+ pendingCallDataMap = null
27
27
  }
28
28
 
29
29
  @ReactMethod
@@ -48,7 +48,7 @@ class CallModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
48
48
  pendingCallDataMap = null
49
49
 
50
50
  val notificationManager = reactApplicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
51
- notificationManager.cancel(101)
51
+ notificationManager.cancel(uuid.hashCode())
52
52
  }
53
53
 
54
54
  @ReactMethod
@@ -14,7 +14,6 @@ import android.graphics.Color
14
14
  object NativeCallManager {
15
15
 
16
16
  private var ringtone: Ringtone? = null
17
- const val INCOMING_CALL_ID = 101
18
17
  const val CALL_CHANNEL_ID = "CALL_CHANNEL_ID"
19
18
 
20
19
  fun handleIncomingPush(context: Context, data: Map<String, String>) {
@@ -50,9 +49,10 @@ object NativeCallManager {
50
49
  val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
51
50
 
52
51
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
53
- val channel = NotificationChannel(CALL_CHANNEL_ID, "Incoming Calls", NotificationManager.IMPORTANCE_HIGH).apply {
52
+ val channel = NotificationChannel(CALL_CHANNEL_ID, "Incoming Call", NotificationManager.IMPORTANCE_HIGH).apply {
54
53
  setBypassDnd(true)
55
54
  lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
55
+ enableVibration(true) //can be removed
56
56
  setSound(null, null)
57
57
  }
58
58
  notificationManager.createNotificationChannel(channel)
@@ -62,11 +62,13 @@ object NativeCallManager {
62
62
  .setSmallIcon(context.applicationInfo.icon)
63
63
  .setContentTitle("Incoming $callType call")
64
64
  .setContentText(name)
65
- .setPriority(NotificationCompat.PRIORITY_MAX)
65
+
66
+ .setPriority(NotificationCompat.PRIORITY_HIGH) //old was PRIORITY_MAX
66
67
  .setCategory(NotificationCompat.CATEGORY_CALL)
67
68
  .setOngoing(true)
68
69
  .setAutoCancel(false)
69
- .setFullScreenIntent(fullScreenPendingIntent, true)
70
+
71
+ .setFullScreenIntent(fullScreenPendingIntent, false) //can be true
70
72
  .addAction(0, "Answer", fullScreenPendingIntent)
71
73
  .addAction(0, "Decline", rejectPendingIntent)
72
74
 
package/app.plugin.js CHANGED
@@ -1,6 +1,13 @@
1
- ////Users/bush/Desktop/Apps/Raiidr/package/app.plugin.js
1
+ ///app.plugin.js
2
+ const { withPlugins } = require('@expo/config-plugins');
2
3
  const withNativeCallVoip = require('./withNativeCallVoip');
4
+ const withCallNativeConfig = require('./withCallNativeConfig');
5
+ const withCallPermissions = require('./withCallPermissions');
3
6
 
4
- module.exports = function (config) {
5
- return withNativeCallVoip(config);
7
+ module.exports = function (config, props) {
8
+ return withPlugins(config, [
9
+ [withNativeCallVoip, props],
10
+ [withCallNativeConfig, props],
11
+ [withCallPermissions, props],
12
+ ]);
6
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
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",
@@ -44,6 +44,7 @@
44
44
  "README.md",
45
45
  "rns-nativecall.podspec",
46
46
  "withCallNativeConfig.js",
47
+ "withCallPermissions.js",
47
48
  "withNativeCallVoip.js"
48
49
  ],
49
50
  "peerDependencies": {
@@ -0,0 +1,40 @@
1
+ const { withAndroidManifest } = require("@expo/config-plugins");
2
+
3
+ /** 2. ANDROID MANIFEST MOD **/
4
+ function withCallPermissions(config) {
5
+ return withAndroidManifest(config, async (config) => {
6
+ const androidManifest = config.modResults.manifest;
7
+
8
+ // 1. Add the Full Screen Intent Permission
9
+ if (!androidManifest["uses-permission"]) {
10
+ androidManifest["uses-permission"] = [];
11
+ }
12
+
13
+ const hasPermission = androidManifest["uses-permission"].some(
14
+ (p) => p.$["android:name"] === "android.permission.USE_FULL_SCREEN_INTENT"
15
+ );
16
+
17
+ if (!hasPermission) {
18
+ androidManifest["uses-permission"].push({
19
+ $: { "android:name": "android.permission.USE_FULL_SCREEN_INTENT" },
20
+ });
21
+ }
22
+
23
+ // 2. Ensure the Activity has the correct flags to appear over lockscreen
24
+ const mainApplication = androidManifest.application[0];
25
+ const mainActivity = mainApplication.activity.find(
26
+ (a) => a.$["android:name"] === ".MainActivity"
27
+ );
28
+
29
+ if (mainActivity) {
30
+ mainActivity.$["android:showOnLockScreen"] = "true";
31
+ mainActivity.$["android:lockTaskMode"] = "if_whitelisted";
32
+ }
33
+
34
+ return config;
35
+ });
36
+ }
37
+
38
+ module.exports = (config) => {
39
+ return withPlugins(config, [withCallPermissions]);
40
+ };
@@ -1,46 +1,140 @@
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
+
3
51
  /** 1. ANDROID MAIN ACTIVITY MOD **/
4
52
  function withMainActivityDataFix(config) {
5
53
  return withMainActivity(config, (config) => {
6
54
  let contents = config.modResults.contents;
7
55
 
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`);
56
+ // --- 1. Imports ---
57
+ const neededImports = [
58
+ 'import android.view.WindowManager',
59
+ 'import android.os.Build',
60
+ 'import android.os.Bundle'
61
+ ];
62
+
63
+ neededImports.forEach(imp => {
64
+ if (!contents.includes(imp)) {
65
+ contents = contents.replace(/package .*/, (match) => `${match}\n${imp}`);
66
+ }
67
+ });
68
+
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
+ }
11
108
  }
12
- if (!contents.includes('import android.os.Bundle')) {
13
- contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.os.Bundle`);
109
+ }
110
+ `;
111
+
112
+
113
+
114
+
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);
14
119
  }
15
120
 
16
- // 2. Define the code blocks
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 ---
17
129
  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
- `;
130
+ override fun onNewIntent(intent: Intent) {
131
+ super.onNewIntent(intent)
132
+ setIntent(intent)
133
+ }`;
33
134
 
34
- // 3. Insert the codes before the last closing brace of the class
35
135
  if (!contents.includes('override fun onNewIntent')) {
36
136
  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);
137
+ contents = contents.slice(0, lastBraceIndex) + onNewIntentCode + "\n" + contents.slice(lastBraceIndex);
44
138
  }
45
139
 
46
140
  config.modResults.contents = contents;