QRScanner.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**
  2. * QR码扫描器
  3. * @邠心vbe on 2026/04/21
  4. */
  5. import React, { useEffect, useState } from 'react';
  6. import { Pressable, StyleSheet, View } from 'react-native';
  7. import TextView from '../../components/TextView';
  8. import { Camera, useCameraDevice, useCodeScanner } from 'react-native-vision-camera';
  9. import { check, PERMISSIONS, RESULTS } from 'react-native-permissions';
  10. import utils from '../../utils/utils';
  11. const checkPermission = (back) => {
  12. if (isIOS) {
  13. back(true);
  14. } else {
  15. check(PERMISSIONS.ANDROID.CAMERA).then(res => {
  16. console.log('checkPermission', res);
  17. switch (res) {
  18. case RESULTS.DENIED://权限未被请求/被拒绝,但可以请求
  19. back(false);
  20. break;
  21. case RESULTS.LIMITED://权限是有限的:有些操作是可能的
  22. back(true);
  23. break;
  24. case RESULTS.GRANTED://许可被授予
  25. back(true);
  26. break;
  27. case RESULTS.BLOCKED://权限被拒绝,不再可请求
  28. back(false);
  29. break;
  30. default:
  31. back(false);
  32. break;
  33. }
  34. }).catch(err => {
  35. back(false);
  36. })
  37. }
  38. }
  39. const QRScanner = ({ onResult, isActive }) => {
  40. const [flashOn, switchFlash] = useState(false);
  41. const [hasPermission, setHasPermission] = useState(false);
  42. const [permissionStr, setPermissionStr] = useState("");
  43. const device = useCameraDevice('back');
  44. useEffect(() => {
  45. console.log("相机设备", device);
  46. checkPermission(result => {
  47. setHasPermission(result);
  48. })
  49. Camera.requestCameraPermission().then(res => {
  50. setPermissionStr(res);
  51. utils.logEventTracking("scan_camera_permission", res)
  52. if (!hasPermission) {
  53. setHasPermission(res == 'granted');
  54. }
  55. }).catch(err => {
  56. console.warn("相机权限请求错误", err);
  57. utils.logEventTracking("scan_camera_permission_error", err)
  58. setHasPermission(false);
  59. });
  60. }, []);
  61. const codeScanner = useCodeScanner({
  62. codeTypes: ['qr'],
  63. onCodeScanned: (codes) => {
  64. if (codes && codes.length > 0) {
  65. onResult(codes)
  66. }
  67. },
  68. });
  69. if (!device || !hasPermission) {
  70. return (
  71. <View style={styles.tipsScreen}>
  72. <TextView style={styles.tipsText}>
  73. {!hasPermission ? "Camera access has been denied. Please enable it in your device settings.(E0)" : "Can not find camera device.(E1)"}
  74. </TextView>
  75. </View>
  76. )
  77. }
  78. return (
  79. <>
  80. <Camera
  81. style={{width: $width, height: $vh(110)}}
  82. device={device}
  83. isActive={isActive}
  84. codeScanner={codeScanner}
  85. enableZoomGesture={true}
  86. photo={false}
  87. video={false}
  88. audio={false}
  89. resizeMode="cover"
  90. torch={flashOn ? 'on' : 'off'}
  91. />
  92. { isActive &&
  93. <Pressable
  94. style={styles.flashLight}
  95. onPress={() => switchFlash(!flashOn)}>
  96. <MaterialIcons
  97. name={flashOn ? "flashlight-on" : "flashlight-off"}
  98. size={36}
  99. color="#fff"/>
  100. <TextView style={{color: "#fff", fontSize: 12}}>{permissionStr}</TextView>
  101. </Pressable>
  102. }
  103. </>
  104. );
  105. };
  106. export default QRScanner;
  107. const styles = StyleSheet.create({
  108. tipsScreen: {
  109. top: 0,
  110. left: 0,
  111. right: 0,
  112. bottom: 0,
  113. position: 'absolute',
  114. alignItems: "center",
  115. justifyContent: "center",
  116. backgroundColor: '#111',
  117. },
  118. tipsText: {
  119. color: textLight,
  120. fontSize: 14,
  121. textAlign: "center"
  122. },
  123. flashLight: {
  124. bottom: 120,
  125. zIndex: 2,
  126. opacity: 0.7,
  127. padding: 8,
  128. position: 'absolute'
  129. }
  130. })