Skip to content

Commit cea5578

Browse files
chore(android): update permissions plugin (#12)
Signed-off-by: Berend Sliedrecht <[email protected]>
1 parent a131ebf commit cea5578

File tree

9 files changed

+22565
-15999
lines changed

9 files changed

+22565
-15999
lines changed

android/src/main/java/id/animo/mdocdatatransfer/MdocDataTransferManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ object MdocDataTransferManager {
3232

3333
}.build()
3434
}
35-
}
35+
}

example/app/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const App = () => {
3535
}
3636

3737
const shutdown = () => {
38-
mdocDataTransfer.instance().shutdown()
38+
mdocDataTransfer.instance().shutdown()
3939
}
4040

4141
return (

example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"expo-build-properties": "~0.12.5",
1818
"expo-dev-client": "~4.0.29",
1919
"react": "18.2.0",
20-
"react-native": "0.75.3",
20+
"react-native": "0.74.5",
2121
"react-native-gesture-handler": "2.16.2",
2222
"react-native-qrcode-svg": "^6.3.12",
2323
"react-native-reanimated": "~3.10.1",

example/pnpm-lock.yaml

Lines changed: 9498 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/yarn.lock

Lines changed: 0 additions & 7617 deletions
This file was deleted.

plugin/src/withAndroid.ts

Lines changed: 150 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,160 @@
1-
import type { ConfigPlugin } from '@expo/config-plugins'
2-
import { withAndroidManifest, withAppBuildGradle, withPlugins } from '@expo/config-plugins'
3-
4-
const permissions = [
5-
'android.permission.INTERNET',
6-
'android.permission.BLUETOOTH',
7-
'android.permission.BLUETOOTH_ADMIN',
8-
'android.permission.BLUETOOTH_SCAN',
9-
'android.permission.BLUETOOTH_ADVERTISE',
10-
'android.permission.BLUETOOTH_CONNECT',
11-
'android.permission.ACCESS_BACKGROUND_LOCATION',
12-
'android.permission.ACCESS_FINE_LOCATION',
13-
'android.permission.ACCESS_COARSE_LOCATION',
14-
]
15-
16-
const withAndroidExcludeMetaInf: ConfigPlugin = (expoConfig) =>
17-
withAppBuildGradle(expoConfig, (c) => {
18-
if (c.modResults.contents.includes('resources.excludes.add("META-INF/versions/9/OSGI-INF/MANIFEST.MF")')) return c
19-
c.modResults.contents += `packaging { resources.excludes.add("META-INF/versions/9/OSGI-INF/MANIFEST.MF") }`
20-
return c
1+
import {
2+
AndroidConfig,
3+
type ConfigPlugin,
4+
withAndroidManifest,
5+
withAppBuildGradle,
6+
withPlugins,
7+
} from '@expo/config-plugins'
8+
9+
type InnerManifest = AndroidConfig.Manifest.AndroidManifest['manifest']
10+
11+
type ManifestPermission = InnerManifest['permission']
12+
13+
type ExtraItems = {
14+
'tools:targetApi'?: string
15+
'android:usesPermissionFlags'?: string
16+
'android:maxSdkVersion'?: string
17+
}
18+
19+
type ManifestUsesPermissionWithExtraItems = {
20+
$: AndroidConfig.Manifest.ManifestUsesPermission['$'] & ExtraItems
21+
}
22+
23+
type AndroidManifest = {
24+
manifest: InnerManifest & {
25+
permission?: ManifestPermission
26+
'uses-permission'?: ManifestUsesPermissionWithExtraItems[]
27+
'uses-permission-sdk-23'?: ManifestUsesPermissionWithExtraItems[]
28+
'uses-feature'?: InnerManifest['uses-feature']
29+
}
30+
}
31+
32+
const withBleAndroidManifest: ConfigPlugin = (config) =>
33+
withAndroidManifest(config, (config) => {
34+
config.modResults = addLocationPermissionToManifest(config.modResults)
35+
config.modResults = addScanAndAdvertisePermissionToManifest(config.modResults)
36+
config.modResults = addConnectPermissionToManifest(config.modResults)
37+
config.modResults = addLegacyBlePermissionToManifest(config.modResults)
38+
39+
return config
2140
})
2241

42+
function addLocationPermissionToManifest(androidManifest: AndroidManifest) {
43+
if (!Array.isArray(androidManifest.manifest['uses-permission-sdk-23'])) {
44+
androidManifest.manifest['uses-permission-sdk-23'] = []
45+
}
46+
47+
if (
48+
!androidManifest.manifest['uses-permission-sdk-23'].find(
49+
(item) => item.$['android:name'] === 'android.permission.ACCESS_COARSE_LOCATION'
50+
)
51+
) {
52+
androidManifest.manifest['uses-permission-sdk-23'].push({
53+
$: {
54+
'android:name': 'android.permission.ACCESS_COARSE_LOCATION',
55+
'android:maxSdkVersion': '30',
56+
},
57+
})
58+
}
59+
60+
if (
61+
!androidManifest.manifest['uses-permission-sdk-23'].find(
62+
(item) => item.$['android:name'] === 'android.permission.ACCESS_FINE_LOCATION'
63+
)
64+
) {
65+
androidManifest.manifest['uses-permission-sdk-23'].push({
66+
$: {
67+
'android:name': 'android.permission.ACCESS_FINE_LOCATION',
68+
'android:maxSdkVersion': '30',
69+
},
70+
})
71+
}
72+
73+
return androidManifest
74+
}
75+
76+
function addLegacyBlePermissionToManifest(androidManifest: AndroidManifest) {
77+
if (!Array.isArray(androidManifest.manifest['uses-permission'])) {
78+
androidManifest.manifest['uses-permission'] = []
79+
}
80+
81+
if (
82+
!androidManifest.manifest['uses-permission'].find(
83+
(item) => item.$['android:name'] === 'android.permission.BLUETOOTH'
84+
)
85+
) {
86+
AndroidConfig.Manifest.ensureToolsAvailable(androidManifest)
87+
androidManifest.manifest['uses-permission']?.push({
88+
$: {
89+
'android:name': 'android.permission.BLUETOOTH',
90+
'android:maxSdkVersion': '30',
91+
},
92+
})
93+
androidManifest.manifest['uses-permission']?.push({
94+
$: {
95+
'android:name': 'android.permission.BLUETOOTH_ADMIN',
96+
'android:maxSdkVersion': '30',
97+
},
98+
})
99+
}
100+
return androidManifest
101+
}
102+
103+
function addScanAndAdvertisePermissionToManifest(androidManifest: AndroidManifest) {
104+
if (!Array.isArray(androidManifest.manifest['uses-permission'])) {
105+
androidManifest.manifest['uses-permission'] = []
106+
}
107+
108+
if (
109+
!androidManifest.manifest['uses-permission'].find(
110+
(item) => item.$['android:name'] === 'android.permission.BLUETOOTH_SCAN'
111+
)
112+
) {
113+
AndroidConfig.Manifest.ensureToolsAvailable(androidManifest)
114+
androidManifest.manifest['uses-permission']?.push({
115+
$: {
116+
'android:name': 'android.permission.BLUETOOTH_SCAN',
117+
'android:usesPermissionFlags': 'neverForLocation',
118+
'tools:targetApi': '31',
119+
},
120+
})
121+
androidManifest.manifest['uses-permission']?.push({
122+
$: {
123+
'android:name': 'android.permission.BLUETOOTH_ADVERTISE',
124+
'tools:targetApi': '31',
125+
},
126+
})
127+
}
128+
return androidManifest
129+
}
130+
131+
function addConnectPermissionToManifest(androidManifest: AndroidManifest) {
132+
if (!Array.isArray(androidManifest.manifest['uses-permission'])) {
133+
androidManifest.manifest['uses-permission'] = []
134+
}
135+
136+
if (
137+
!androidManifest.manifest['uses-permission'].find(
138+
(item) => item.$['android:name'] === 'android.permission.BLUETOOTH_CONNECT'
139+
)
140+
) {
141+
AndroidConfig.Manifest.ensureToolsAvailable(androidManifest)
142+
androidManifest.manifest['uses-permission']?.push({
143+
$: {
144+
'android:name': 'android.permission.BLUETOOTH_CONNECT',
145+
},
146+
})
147+
}
148+
return androidManifest
149+
}
150+
23151
const withAndroidExcludeBcProv: ConfigPlugin = (expoConfig) =>
24152
withAppBuildGradle(expoConfig, (c) => {
25153
if (c.modResults.contents.includes("all*.exclude module: 'bcprov-jdk15to18'")) return c
26154
c.modResults.contents += `android { configurations { all*.exclude module: 'bcprov-jdk15to18' } }`
27155
return c
28156
})
29157

30-
// TODO: make it possible to optionally enable NFC
31158
const withAndroidNfcProperties: ConfigPlugin = (expoConfig) =>
32159
withAndroidManifest(expoConfig, (c) => {
33160
const androidManifest = c.modResults.manifest
@@ -79,26 +206,10 @@ const withAndroidNfcProperties: ConfigPlugin = (expoConfig) =>
79206
return c
80207
})
81208

82-
const withAndroidPermissions: ConfigPlugin = (expoConfig) =>
83-
withAndroidManifest(expoConfig, (c) => {
84-
const androidManifest = c.modResults.manifest
85-
86-
for (const permission of permissions) {
87-
if (androidManifest['uses-permission']?.some((p) => p.$['android:name'] === permission)) continue
88-
androidManifest['uses-permission']?.push({
89-
$: {
90-
'android:name': permission,
91-
},
92-
})
93-
}
94-
95-
return c
96-
})
97-
98209
export const withAndroid: ConfigPlugin = (config) =>
99210
withPlugins(config, [
100-
withAndroidExcludeMetaInf,
211+
(c) => AndroidConfig.Permissions.withPermissions(c, ['android.permission.BLUETOOTH_CONNECT']),
212+
withBleAndroidManifest,
101213
withAndroidExcludeBcProv,
102214
withAndroidNfcProperties,
103-
withAndroidPermissions,
104215
])

plugin/src/withIos.ts

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,15 @@
1-
import { type ConfigPlugin, withInfoPlist, withPlugins, withPodfile } from '@expo/config-plugins'
2-
import type { ExpoConfig } from '@expo/config-types'
3-
import type { Props } from '.'
1+
import { type ConfigPlugin, withInfoPlist } from '@expo/config-plugins'
42

5-
const withIosPodfile: ConfigPlugin<Props> = (expoConfig: ExpoConfig, props) =>
6-
withPodfile(expoConfig, (c) => {
7-
if (!props.ios?.buildStatic) return c
8-
const staticLibraries = `mdoc_data_transfer_static_libraries=[${props.ios.buildStatic.map((i) => `"${i}"`).join(', ')}]`
9-
if (c.modResults.contents.includes('mdoc_data_transfer_static_libraries')) {
10-
c.modResults.contents = c.modResults.contents.replace(/mdoc_data_transfer_static_libraries=.*/, staticLibraries)
11-
} else {
12-
c.modResults.contents += staticLibraries
13-
}
14-
15-
if (c.modResults.contents.includes('Pod::BuildType.static_library')) return c
16-
17-
c.modResults.contents += `
18-
pre_install do |installer|
19-
installer.pod_targets.each do |pod|
20-
if mdoc_data_transfer_static_libraries.include?(pod.name)
21-
def pod.build_type;
22-
Pod::BuildType.static_library
23-
end
24-
end
25-
end
26-
end
27-
`
28-
return c
29-
})
3+
const BLUETOOTH_ALWAYS = 'Allow $(PRODUCT_NAME) to connect to bluetooth devices for data sharing'
304

31-
const withIosBluetoothUsage: ConfigPlugin<Props> = (config, props) => {
32-
return withInfoPlist(config, (c) => {
33-
const defaultDescription = 'This app uses Bluetooth to connect to external devices for credential sharing.'
34-
35-
const usageDescription = props?.ios?.bluetoothDescription || defaultDescription
36-
37-
if (c.ios?.infoPlist) {
38-
c.ios.infoPlist.NSBluetoothAlwaysUsageDescription = usageDescription
5+
export const withIos: ConfigPlugin<{
6+
bluetoothAlwaysPermission?: string | false
7+
}> = (c, { bluetoothAlwaysPermission } = {}) => {
8+
return withInfoPlist(c, (config) => {
9+
if (bluetoothAlwaysPermission !== false) {
10+
config.modResults.NSBluetoothAlwaysUsageDescription =
11+
bluetoothAlwaysPermission || config.modResults.NSBluetoothAlwaysUsageDescription || BLUETOOTH_ALWAYS
3912
}
40-
41-
return c
13+
return config
4214
})
4315
}
44-
45-
export const withIos: ConfigPlugin<Props> = (config, props) =>
46-
withPlugins(config, [
47-
[withIosPodfile, props],
48-
[withIosBluetoothUsage, props],
49-
])

0 commit comments

Comments
 (0)