@@ -10,6 +10,10 @@ import {
1010 Share ,
1111 Platform ,
1212 PermissionsAndroid ,
13+ Linking ,
14+ AppState ,
15+ type AppStateStatus ,
16+ NativeModules ,
1317} from 'react-native' ;
1418import { SafeAreaView } from 'react-native-safe-area-context' ;
1519import { useFocusEffect } from '@react-navigation/native' ;
@@ -65,6 +69,33 @@ export default function ScanScreen({ navigation }: Props) {
6569 }
6670 } ;
6771
72+ const checkInitialCameraPermission = useCallback ( async ( ) => {
73+ if ( Platform . OS === 'android' ) {
74+ const hasPerm = await PermissionsAndroid . check ( PermissionsAndroid . PERMISSIONS . CAMERA ) ;
75+ setHasPermission ( hasPerm ) ;
76+ } else if ( Platform . OS === 'ios' ) {
77+ try {
78+ const RNCameraKitModule = NativeModules . RNCameraKitModule ;
79+ if ( RNCameraKitModule ) {
80+ const status = await RNCameraKitModule . checkDeviceCameraAuthorizationStatus ( ) ;
81+ if ( status === true ) {
82+ setHasPermission ( true ) ;
83+ } else if ( status === - 1 ) {
84+ const granted = await RNCameraKitModule . requestDeviceCameraAuthorization ( ) ;
85+ setHasPermission ( granted === true ) ;
86+ } else {
87+ setHasPermission ( false ) ;
88+ }
89+ } else {
90+ setHasPermission ( true ) ;
91+ }
92+ } catch ( err ) {
93+ console . warn ( err ) ;
94+ setHasPermission ( false ) ;
95+ }
96+ }
97+ } , [ ] ) ;
98+
6899 const requestCameraPermission = async ( ) => {
69100 if ( Platform . OS === 'android' ) {
70101 try {
@@ -82,10 +113,34 @@ export default function ScanScreen({ navigation }: Props) {
82113 } catch ( err ) {
83114 console . warn ( err ) ;
84115 }
85- } else {
86- // iOS permissions would typically be handled via react-native-permissions
87- // For this demo, assume true if not Android
88- setHasPermission ( true ) ;
116+ } else if ( Platform . OS === 'ios' ) {
117+ try {
118+ const RNCameraKitModule = NativeModules . RNCameraKitModule ;
119+ if ( RNCameraKitModule ) {
120+ const status = await RNCameraKitModule . checkDeviceCameraAuthorizationStatus ( ) ;
121+ if ( status === true ) {
122+ setHasPermission ( true ) ;
123+ } else if ( status === - 1 ) {
124+ const granted = await RNCameraKitModule . requestDeviceCameraAuthorization ( ) ;
125+ setHasPermission ( granted === true ) ;
126+ } else {
127+ setHasPermission ( false ) ;
128+ Alert . alert (
129+ 'Camera Access Required' ,
130+ 'Please enable camera access in your device settings to scan QR codes.' ,
131+ [
132+ { text : 'Cancel' , style : 'cancel' } ,
133+ { text : 'Settings' , onPress : ( ) => Linking . openURL ( 'app-settings:' ) } ,
134+ ] ,
135+ ) ;
136+ }
137+ } else {
138+ setHasPermission ( true ) ;
139+ }
140+ } catch ( err ) {
141+ console . warn ( err ) ;
142+ setHasPermission ( false ) ;
143+ }
89144 }
90145 } ;
91146
@@ -104,7 +159,7 @@ export default function ScanScreen({ navigation }: Props) {
104159 title : 'My DevCard QR' ,
105160 url : uri ,
106161 } ) ;
107- } catch ( err ) {
162+ } catch {
108163 Alert . alert ( 'Error' , 'Failed to save QR code' ) ;
109164 }
110165 }
@@ -126,7 +181,8 @@ export default function ScanScreen({ navigation }: Props) {
126181 useFocusEffect (
127182 useCallback ( ( ) => {
128183 fetchCards ( ) ;
129- } , [ fetchCards ] )
184+ checkInitialCameraPermission ( ) ;
185+ } , [ fetchCards , checkInitialCameraPermission ] )
130186 ) ;
131187
132188 useEffect ( ( ) => {
@@ -144,6 +200,19 @@ export default function ScanScreen({ navigation }: Props) {
144200 loadStoredCardId ( ) ;
145201 } , [ ] ) ;
146202
203+ useEffect ( ( ) => {
204+ const handleAppStateChange = ( nextAppState : AppStateStatus ) => {
205+ if ( nextAppState === 'active' ) {
206+ checkInitialCameraPermission ( ) ;
207+ }
208+ } ;
209+
210+ const subscription = AppState . addEventListener ( 'change' , handleAppStateChange ) ;
211+ return ( ) => {
212+ subscription . remove ( ) ;
213+ } ;
214+ } , [ checkInitialCameraPermission ] ) ;
215+
147216 useEffect ( ( ) => {
148217 if ( ! hasLoadedStoredCard ) return ;
149218
0 commit comments