@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 +21 -0
- package/README.md +155 -0
- package/index.js +6 -0
- package/package.json +51 -0
- package/plugin/withIncallManager.js +131 -0
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
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;
|