Skip to content

Commit d75602d

Browse files
authored
feat: setup expo config plugin for ios permissions setup (#834)
1 parent 2a314f3 commit d75602d

File tree

7 files changed

+293
-24
lines changed

7 files changed

+293
-24
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ fetchWindowsCapabilites.js
66
mock.js
77
node_modules
88
react-native.config.js
9+
app.plugin.js

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = {
1111
},
1212

1313
parserOptions: {
14-
project: './tsconfig.json',
14+
project: ['./tsconfig.json', './plugin/tsconfig.json'],
1515
ecmaFeatures: {jsx: true},
1616
ecmaVersion: 2018,
1717
sourceType: 'module',

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,25 @@ setup_permissions([
9393
```
9494

9595
3. Then execute `pod install` _(📌  Note that it must be re-executed each time you update this config)_.
96+
97+
Tip: If you use Expo and Expo CNG (Continuous Native Generation), you can utilize the built-in Expo Config plugin to perform the work outlined in steps 1 & 2 for you (supported on React Native 0.72+).
98+
To use the plugin, simply specify the array of the permissions which you want to set up as outlined in step 2 - for example:
99+
100+
```json
101+
{
102+
"name": "my app",
103+
"plugins": [
104+
[
105+
"react-native-permissions",
106+
{
107+
// ...
108+
"iosPermissions": ["Bluetooth"]
109+
}
110+
]
111+
]
112+
}
113+
```
114+
96115
4. Finally, update your `Info.plist` with the wanted permissions usage descriptions:
97116

98117
```xml

app.plugin.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./dist/commonjs/expo-plugin/index');

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
"/src",
3131
"/*.podspec",
3232
"react-native.config.js",
33-
"mock.js"
33+
"mock.js",
34+
"app.plugin.js"
3435
],
3536
"scripts": {
3637
"format": "prettier '**/*' -u -w",
@@ -69,6 +70,7 @@
6970
"devDependencies": {
7071
"@babel/core": "^7.20.0",
7172
"@babel/preset-env": "^7.20.0",
73+
"@expo/config-plugins": "^7.2.5",
7274
"@types/react": "^18.2.47",
7375
"@typescript-eslint/eslint-plugin": "^6.18.0",
7476
"@typescript-eslint/parser": "^6.18.0",

src/expo-plugin/index.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import {ConfigPlugin, withDangerousMod} from '@expo/config-plugins';
2+
import {mergeContents} from '@expo/config-plugins/build/utils/generateCode';
3+
4+
const fs = require('fs');
5+
const path = require('path');
6+
7+
type Props = {
8+
iosPermissions?: Array<
9+
| 'AppTrackingTransparency'
10+
| 'Bluetooth'
11+
| 'Calendars'
12+
| 'CalendarsWriteOnly'
13+
| 'Camera'
14+
| 'Contacts'
15+
| 'FaceID'
16+
| 'LocationAccuracy'
17+
| 'LocationAlways'
18+
| 'LocationWhileInUse'
19+
| 'MediaLibrary'
20+
| 'Microphone'
21+
| 'Motion'
22+
| 'Notifications'
23+
| 'PhotoLibrary'
24+
| 'PhotoLibraryAddOnly'
25+
| 'Reminders'
26+
| 'Siri'
27+
| 'SpeechRecognition'
28+
| 'StoreKit'
29+
>;
30+
};
31+
32+
const plugin: ConfigPlugin<Props> = (config, {iosPermissions}) => {
33+
if (iosPermissions == null || iosPermissions.length === 0) {
34+
return config;
35+
}
36+
37+
return withDangerousMod(config, [
38+
'ios',
39+
async (config) => {
40+
const file = path.join(config.modRequest.platformProjectRoot, 'Podfile');
41+
let contents = await fs.promises.readFile(file, 'utf8');
42+
43+
contents = mergeContents({
44+
tag: 'node-require-function',
45+
src: contents,
46+
newSrc: `def node_require(script)\n\t# Resolve script with node to allow for hoisting\n\trequire Pod::Executable.execute_command('node', ['-p',\n\t\t"require.resolve(\n\t\t\t'#{script}',\n\t\t\t {paths: [process.argv[1]]},\n\t\t)", __dir__]).strip\nend\n\nnode_require('react-native-permissions/scripts/setup.rb')`,
47+
anchor: /scripts\/react_native_pods/,
48+
offset: 1,
49+
comment: '#',
50+
}).contents;
51+
52+
contents = mergeContents({
53+
tag: 'permissions-array',
54+
src: contents,
55+
newSrc: `setup_permissions([${iosPermissions
56+
.map((permission) => `'${permission}'`)
57+
.join(',')}])`,
58+
anchor: /prepare_react_native_project!/,
59+
offset: 1,
60+
comment: '#',
61+
}).contents;
62+
63+
await fs.promises.writeFile(file, contents, 'utf-8');
64+
return config;
65+
},
66+
]);
67+
};
68+
69+
export default plugin;

0 commit comments

Comments
 (0)