import { BarCodeScanner, requestPermissionsAsync } from 'expo-barcode-scanner' import { Camera } from 'expo-camera' import React from 'react' import { BackHandler, Dimensions, Image, Platform, StatusBar, StyleSheet, TouchableOpacity, View } from 'react-native' import RootSiblings from 'react-native-root-siblings' import { initialWindowMetrics } from 'react-native-safe-area-context' import { chooseMedia, MEDIA_TYPE } from '../media' import iconClose from './icon_close.png' import iconPic from './icon_pic.png' export let scannerView const codeMap = { aztec: 'AZTEC', codabar: 'CODABAR', code39: 'CODE_39', code93: 'CODE_93', code128: 'CODE_128', code39mod43: 'CODE_93', // 未准确对应 datamatrix: 'DATA_MATRIX', ean13: 'EAN_13', ean8: 'EAN_8', interleaved2of5: 'ITF', // 未准确对应 itf14: 'ITF', // 未准确对应 maxicode: 'MAXICODE', pdf417: 'PDF_417', rss14: 'RSS_14', rssexpanded: 'RSS_EXPANDED', upc_a: 'UPC_A', upc_e: 'UPC_E', upc_ean: 'UPC_EAN_EXTENSION', qr: 'QR_CODE' } const typeMap = { barCode: ['aztec', 'codabar', 'code39', 'code93', 'code128', 'code39mod43', 'ean13', 'ean8', 'interleaved2of5', 'itf14', 'maxicode', 'rss14', 'rssexpanded', 'upc_a', 'upc_e', 'upc_ean'], qrCode: ['qr'], datamatrix: ['datamatrix'], pdf417: ['pdf417'] } const BarCodeType = BarCodeScanner.Constants.BarCodeType function findKey (value:string, data, compare = (a, b) => a === b):string { return Object.keys(data).find(k => compare(data[k], value)) || '' } const { width, height } = Dimensions.get('screen') function getBarCodeTypes(types:string[]): string[] { const result: string[] = [] for (const t of types) { result.push(...typeMap[t].map(type => { return BarCodeType[type] })) } return result.filter(r => !!r) } function formatCodeType(type:string):keyof Taro.scanCode.QRType { return codeMap[findKey(type, BarCodeType)] } function safeViewWrapper(element:any) { if (Platform.OS === 'ios') { return {element} } return element } let backAction: any = null function hide(view) { if (!(view instanceof RootSiblings)) { return } view.destroy() BackHandler.removeEventListener('hardwareBackPress', backAction) } backAction = () => { hide(scannerView) return true } const styles = StyleSheet.create({ container: { position: 'absolute', backgroundColor: '#FFF', justifyContent: 'center', alignItems: 'center', flex: 1, zIndex: 1000 }, closeIcon: { position: 'absolute', left: 20, top: 10 }, closeImg: { width: 25, height: 25, marginTop: StatusBar.currentHeight, }, closeBtnBg: { width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center' }, albumIcon: { position: 'absolute', right: 20, bottom: 40 }, albumImg: { width: 20, height: 20, }, albumBtnBg: { backgroundColor: 'rgba(0,0,0,0.2)', width: 40, height: 40, borderRadius: 20, justifyContent: 'center', alignItems: 'center' } }) function scanFromPhoto(callback, errorCallBack) { chooseMedia({ sourceType: ['album'], maxDuration: 60, camera: 'back', success: function (res) { const imageUrl = res.tempFilePaths[0] if (imageUrl) { BarCodeScanner.scanFromURLAsync(imageUrl).then(res => { res && res.length > 0 && callback(res[0].data, res[0].type) }) } } }, MEDIA_TYPE.Images).catch(errorCallBack) } export async function scanCode(option: Taro.scanCode.Option = {}): Promise { const { success, fail, complete, onlyFromCamera, scanType = ['barCode', 'qrCode'] } = option const { granted } = await requestPermissionsAsync() if (!granted) { const res = { errMsg: 'Permissions denied!' } fail?.(res) complete?.(res) return Promise.reject(res) } const barCodeTypes = getBarCodeTypes(scanType) return new Promise((resolve, reject) => { scannerView = new RootSiblings( ( ) ) BackHandler.addEventListener('hardwareBackPress', backAction) }) }