@novartc/expo-config-plugin-incall-manager 1.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ahsan Zia
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # expo-config-plugin-incall-manager
2
+
3
+ 📱 **A Config Plugin for integrating `react-native-incall-manager` into Expo or React Native projects** — automatically adds required permissions, Podfile entries, and Android native linking.
4
+
5
+ ## 🚀 Installation
6
+
7
+ ```bash
8
+ npm install react-native-incall-manager expo-config-plugin-incall-manager
9
+ ```
10
+
11
+ or
12
+
13
+ ```bash
14
+ yarn add react-native-incall-manager expo-config-plugin-incall-manager
15
+ ```
16
+
17
+ ## 🧩 Usage (in app.json or app.config.js)
18
+
19
+ ### Option 1 – JSON config (app.json)
20
+ ```json
21
+ {
22
+ "expo": {
23
+ "plugins": ["expo-config-plugin-incall-manager"]
24
+ }
25
+ }
26
+ ```
27
+
28
+ ### Option 2 – JS config (app.config.js)
29
+ ```javascript
30
+ module.exports = {
31
+ expo: {
32
+ name: "my-app",
33
+ slug: "my-app",
34
+ plugins: [
35
+ "expo-config-plugin-incall-manager"
36
+ ]
37
+ }
38
+ };
39
+ ```
40
+
41
+ ## 🛠 What this plugin does automatically
42
+
43
+ ✅ **Adds these Android permissions to AndroidManifest.xml:**
44
+
45
+ ```xml
46
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
47
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
48
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
49
+ <uses-permission android:name="android.permission.BLUETOOTH" />
50
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
51
+ <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
52
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
53
+ <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
54
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
55
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
56
+ ```
57
+
58
+ ✅ **Modifies settings.gradle and build.gradle to include:**
59
+
60
+ ```gradle
61
+ include ':react-native-incall-manager'
62
+ project(':react-native-incall-manager').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-incall-manager/android')
63
+ implementation(project(':react-native-incall-manager'))
64
+ ```
65
+
66
+ ✅ **Updates MainApplication.java with:**
67
+
68
+ ```java
69
+ import com.zxcpoiu.incallmanager.InCallManagerPackage;
70
+ packages.add(new InCallManagerPackage());
71
+ ```
72
+
73
+ ✅ **Adds iOS Pod dependency:**
74
+
75
+ ```ruby
76
+ pod 'ReactNativeIncallManager', :path => '../node_modules/react-native-incall-manager'
77
+ ```
78
+
79
+ ## ⚠️ Requirements
80
+
81
+ - Expo SDK 48+ or React Native 0.70+
82
+ - EAS Build (for managed workflow)
83
+ - `react-native-incall-manager` installed in your project
84
+
85
+ ## 📱 Usage in your React Native code
86
+
87
+ After installing and configuring the plugin, you can use `react-native-incall-manager` in your app:
88
+
89
+ ```javascript
90
+ import InCallManager from 'react-native-incall-manager';
91
+
92
+ // Start call management
93
+ InCallManager.start({media: 'audio'});
94
+
95
+ // Stop call management
96
+ InCallManager.stop();
97
+
98
+ // Enable/disable speaker
99
+ InCallManager.setSpeakerphoneOn(true);
100
+
101
+ // Turn screen on/off
102
+ InCallManager.turnScreenOn();
103
+ InCallManager.turnScreenOff();
104
+ ```
105
+
106
+ ## 🏗 Building your app
107
+
108
+ After adding the plugin to your config, you need to regenerate the native code:
109
+
110
+ ```bash
111
+ # For Expo managed workflow
112
+ expo prebuild --clean
113
+
114
+ # Then build
115
+ eas build --platform all
116
+ ```
117
+
118
+ ```bash
119
+ # For bare React Native
120
+ cd ios && pod install
121
+ ```
122
+
123
+ ## 🧑‍💻 Contributing
124
+
125
+ PRs and issues are welcome! Please open a GitHub issue if you encounter any linking or permission problems.
126
+
127
+ ## 📄 License
128
+
129
+ MIT © Ahsan Zia
130
+
131
+ ---
132
+
133
+ ## 🔧 Troubleshooting
134
+
135
+ ### Android Build Issues
136
+ - Make sure you have the correct Android permissions in your `AndroidManifest.xml`
137
+ - Verify that the plugin is properly linked in `settings.gradle` and `build.gradle`
138
+ - Check that `MainApplication.java` includes the InCallManagerPackage
139
+
140
+ ### iOS Build Issues
141
+ - Ensure the pod is properly added to your `Podfile`
142
+ - Run `cd ios && pod install` after adding the plugin
143
+ - Clean and rebuild your project if needed
144
+
145
+ ### Plugin Not Working
146
+ - Make sure you've run `expo prebuild --clean` after adding the plugin
147
+ - Verify the plugin is listed in your `app.json` or `app.config.js`
148
+ - Check that `react-native-incall-manager` is installed as a dependency
149
+
150
+ ### Need Help?
151
+ Open an issue on GitHub with:
152
+ - Your Expo SDK version
153
+ - Your React Native version
154
+ - Full error logs
155
+ - Your config file (`app.json` or `app.config.js`)
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ const withIncallManager = require('./plugin/withIncallManager');
2
+
3
+ module.exports = {
4
+ withIncallManager,
5
+ default: withIncallManager,
6
+ };
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@novartc/expo-config-plugin-incall-manager",
3
+ "version": "1.1.0",
4
+ "description": "Expo config plugin to integrate react-native-incall-manager in managed and bare workflow apps.",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"No tests specified\" && exit 0",
8
+ "lint": "echo \"No linting configured\" && exit 0",
9
+ "prepare": "echo \"Package is ready for publishing\"",
10
+ "prepack": "echo \"Preparing package...\""
11
+ },
12
+ "keywords": [
13
+ "expo",
14
+ "config-plugin",
15
+ "react-native",
16
+ "incall-manager",
17
+ "expo-plugin",
18
+ "expo-config-plugin",
19
+ "android-permissions",
20
+ "ios-pods",
21
+ "call-management",
22
+ "audio-routing",
23
+ "bluetooth-audio"
24
+ ],
25
+ "author": "Ahsan Zia",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/ahsanch11/expo-config-plugin-incall-manager.git"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/ahsanch11/expo-config-plugin-incall-manager/issues"
33
+ },
34
+ "homepage": "https://github.com/ahsanch11/expo-config-plugin-incall-manager#readme",
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "peerDependencies": {
39
+ "@expo/config-plugins": ">=6.0.0"
40
+ },
41
+ "devDependencies": {},
42
+ "files": [
43
+ "index.js",
44
+ "plugin/",
45
+ "README.md",
46
+ "LICENSE"
47
+ ],
48
+ "engines": {
49
+ "node": ">=14"
50
+ }
51
+ }
@@ -0,0 +1,131 @@
1
+ const {
2
+ withAndroidManifest,
3
+ withDangerousMod,
4
+ withPlugins,
5
+ } = require('@expo/config-plugins');
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const ANDROID_PERMISSIONS = [
10
+ 'android.permission.MODIFY_AUDIO_SETTINGS',
11
+ 'android.permission.RECORD_AUDIO',
12
+ 'android.permission.BLUETOOTH',
13
+ 'android.permission.BLUETOOTH_ADMIN',
14
+ 'android.permission.BLUETOOTH_CONNECT',
15
+ 'android.permission.BLUETOOTH_PRIVILEGED',
16
+ 'android.permission.BLUETOOTH_SCAN',
17
+ 'android.permission.BLUETOOTH_ADVERTISE',
18
+ 'android.permission.WAKE_LOCK',
19
+ 'android.permission.FOREGROUND_SERVICE',
20
+ ];
21
+
22
+ function addAndroidPermissions(config) {
23
+ return withAndroidManifest(config, async (config) => {
24
+ const manifest = config.modResults.manifest;
25
+ manifest['uses-permission'] = [
26
+ ...(manifest['uses-permission'] || []),
27
+ ...ANDROID_PERMISSIONS.map((name) => ({ $: { 'android:name': name } })),
28
+ ];
29
+ return config;
30
+ });
31
+ }
32
+
33
+ function addIosPod(config) {
34
+ return withDangerousMod(config, [
35
+ 'ios',
36
+ async (config) => {
37
+ const podfilePath = path.join(config.modRequest.platformProjectRoot, 'Podfile');
38
+ if (!fs.existsSync(podfilePath)) return config;
39
+
40
+ let podfileContent = fs.readFileSync(podfilePath, 'utf8');
41
+ const podLine = `pod 'ReactNativeIncallManager', :path => './react-native-incall-manager'`;
42
+
43
+ if (!podfileContent.includes(podLine)) {
44
+ podfileContent = podfileContent.replace(
45
+ /use_native_modules!\n/,
46
+ `use_native_modules!\n${podLine}\n`
47
+ );
48
+ fs.writeFileSync(podfilePath, podfileContent);
49
+ }
50
+ return config;
51
+ },
52
+ ]);
53
+ }
54
+
55
+ function addAndroidNativeLinking(config) {
56
+ return withDangerousMod(config, [
57
+ 'android',
58
+ async (config) => {
59
+ const settingsGradlePath = path.join(config.modRequest.platformProjectRoot, 'settings.gradle');
60
+ const buildGradlePath = path.join(config.modRequest.platformProjectRoot, 'app', 'build.gradle');
61
+ const appSrcPath = path.join(config.modRequest.platformProjectRoot, 'app', 'src', 'main', 'java');
62
+
63
+ // --- settings.gradle ---
64
+ if (fs.existsSync(settingsGradlePath)) {
65
+ let settingsGradle = fs.readFileSync(settingsGradlePath, 'utf8');
66
+ if (!settingsGradle.includes("react-native-incall-manager")) {
67
+ settingsGradle += `
68
+ include ':react-native-incall-manager'
69
+ project(':react-native-incall-manager').projectDir = new File(rootProject.projectDir, './react-native-incall-manager/android')
70
+ `;
71
+ fs.writeFileSync(settingsGradlePath, settingsGradle);
72
+ }
73
+ }
74
+
75
+ // --- app/build.gradle ---
76
+ if (fs.existsSync(buildGradlePath)) {
77
+ let buildGradle = fs.readFileSync(buildGradlePath, 'utf8');
78
+ if (!buildGradle.includes("implementation(project(':react-native-incall-manager'))")) {
79
+ buildGradle = buildGradle.replace(
80
+ /(dependencies\s*{[\s\S]*?)(^\})/m,
81
+ (match, depsBlock, closingBrace) => {
82
+ return `${depsBlock} implementation(project(':react-native-incall-manager'))\n${closingBrace}`;
83
+ }
84
+ );
85
+ fs.writeFileSync(buildGradlePath, buildGradle);
86
+ }
87
+ }
88
+
89
+ // --- MainApplication.java ---
90
+ function findMainApplication(dir) {
91
+ const files = fs.readdirSync(dir);
92
+ for (const file of files) {
93
+ const fullPath = path.join(dir, file);
94
+ if (fs.statSync(fullPath).isDirectory()) {
95
+ const result = findMainApplication(fullPath);
96
+ if (result) return result;
97
+ } else if (file === 'MainApplication.java') {
98
+ return fullPath;
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+
104
+ const mainAppPath = findMainApplication(appSrcPath);
105
+ if (mainAppPath) {
106
+ let mainAppContent = fs.readFileSync(mainAppPath, 'utf8');
107
+ if (!mainAppContent.includes('import com.zxcpoiu.incallmanager.InCallManagerPackage;')) {
108
+ mainAppContent = mainAppContent.replace(
109
+ 'import com.facebook.react.ReactApplication;',
110
+ `import com.facebook.react.ReactApplication;\nimport com.zxcpoiu.incallmanager.InCallManagerPackage;`
111
+ );
112
+ }
113
+ if (!mainAppContent.includes('packages.add(new InCallManagerPackage())')) {
114
+ mainAppContent = mainAppContent.replace(
115
+ /return packages;/,
116
+ `packages.add(new InCallManagerPackage());\n return packages;`
117
+ );
118
+ }
119
+ fs.writeFileSync(mainAppPath, mainAppContent);
120
+ }
121
+
122
+ return config;
123
+ },
124
+ ]);
125
+ }
126
+
127
+ function withIncallManager(config) {
128
+ return withPlugins(config, [addAndroidPermissions, addAndroidNativeLinking, addIosPod]);
129
+ }
130
+
131
+ module.exports = withIncallManager;