├── .babelrc ├── .buckconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .watchmanconfig ├── README.md ├── ScanView.js ├── __tests__ ├── index.android.js └── index.ios.js ├── android ├── app │ ├── BUCK │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── scanidcard │ │ │ ├── CameraManager.java │ │ │ ├── CameraPreview.java │ │ │ ├── CustomExceptionHandler.java │ │ │ ├── DisplayUtil.java │ │ │ ├── IDCard.java │ │ │ ├── IdCardView.java │ │ │ ├── ImageFilter.java │ │ │ ├── MainActivity.java │ │ │ ├── MainApplication.java │ │ │ ├── ScanPackage.java │ │ │ ├── ScanView.java │ │ │ └── ScanViewManager.java │ │ └── res │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── idcard-library │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── license.info │ │ ├── java │ │ └── com │ │ │ └── ym │ │ │ └── idcard │ │ │ └── reg │ │ │ ├── NativeImage.java │ │ │ ├── NativeOcr.java │ │ │ ├── bean │ │ │ └── IDCard.java │ │ │ ├── engine │ │ │ ├── ImageEngine.java │ │ │ └── OcrEngine.java │ │ │ └── util │ │ │ ├── FileUtil.java │ │ │ └── StringUtil.java │ │ ├── jniLibs │ │ ├── armeabi-v7a │ │ │ ├── libIDCardengine.so │ │ │ └── libimageengine.so │ │ └── armeabi │ │ │ ├── libIDCardengine.so │ │ │ └── libimageengine.so │ │ └── res │ │ └── values │ │ └── strings.xml ├── keystores │ ├── BUCK │ └── debug.keystore.properties └── settings.gradle ├── app.json ├── debug.log ├── index.android.js ├── index.ios.js ├── ios ├── ScanIdCard-tvOS │ └── Info.plist ├── ScanIdCard-tvOSTests │ └── Info.plist ├── ScanIdCard.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── ScanIdCard-tvOS.xcscheme │ │ └── ScanIdCard.xcscheme ├── ScanIdCard │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m └── ScanIdCardTests │ ├── Info.plist │ └── ScanIdCardTests.m ├── js └── scan.js ├── jsconfig.json ├── native_ui ├── ScanView.js └── Viewfinder.js ├── package.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | experimental.strict_type_args=true 30 | 31 | munge_underscores=true 32 | 33 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 34 | 35 | suppress_type=$FlowIssue 36 | suppress_type=$FlowFixMe 37 | suppress_type=$FixMe 38 | 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-2]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-2]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 42 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 43 | 44 | unsafe.enable_getters_and_setters=true 45 | 46 | [version] 47 | ^0.42.0 48 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 50 | 51 | fastlane/report.xml 52 | fastlane/Preview.html 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-scanidcard 2 | react-native 身份证扫描(Android版) 3 | 4 | IOS版本将在稍后补上 5 | 6 | 实现原理为Camera自动对焦成功后获取当前帧进行针对身份证的图像识别,识别后验证身份证,验证通过则返回,不通过则进行2次对焦并识别,直到通过为止 7 | 8 | 返回的字段包含【姓名】【身份证号】【性别】【年龄】 9 | 10 | 地址如需返回的,可修改源码的ScanView.class 11 | 12 | # 安装 13 | ```javascript 14 | npm install react-native-scanidcard 15 | ``` 16 | 17 | 在android目录下的settings.gradle中加入 18 | ```javascript 19 | include ':react-native-scanidcard' 20 | project(':react-native-scanidcard').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-scanidcard/android/app') 21 | include ':idcard-library' 22 | project(':idcard-library').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-scanidcard/android/idcard-library') 23 | ``` 24 | 25 | 在android/app中的build.gradle中加入 26 | ```javascript 27 | compile project(':react-native-scanidcard') 28 | compile project(':idcard-library') 29 | ``` 30 | 31 | 32 | 在android/app/src MainApplication中加入 33 | ``` 34 | import com.scanidcard.ScanPackage; 35 | ``` 36 | 在android/app/src MainApplication的getPackages方法中加入 37 | ``` 38 | new ScanPackage() 39 | ``` 40 | 41 | # 调用demo 42 | ```javascript 43 | import React, { Component } from 'react'; 44 | import { 45 | AppRegistry, 46 | StyleSheet, 47 | Text, 48 | Vibration, 49 | View, 50 | TextInput, 51 | DeviceEventEmitter 52 | } from 'react-native'; 53 | 54 | import ScanView from 'react-native-scanidcard'; 55 | 56 | class ScanScreen extends Component { 57 | constructor(props) { 58 | super(props); 59 | 60 | this.state = { 61 | torchMode: 'off', 62 | cameraType: 'back' 63 | }; 64 | } 65 | 66 | componentDidMount() { 67 | this.listener = DeviceEventEmitter.addListener('scanCallBack', this.scanCallBack.bind(this)); //对应了原生端的名字 68 | } 69 | 70 | componentWillUnmount() { 71 | this.listener && this.listener.remove(); //记得remove哦 72 | this.listener = null; 73 | } 74 | 75 | scanCallBack(e) { 76 | console.info(e) 77 | } 78 | 79 | render() { 80 | return ( 81 | 86 | ); 87 | } 88 | } 89 | 90 | export default ScanScreen; 91 | ``` 92 | # The End 93 | 感谢dreamkid提供的library 94 | -------------------------------------------------------------------------------- /ScanView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | Component, 5 | PropTypes, 6 | } from 'react'; 7 | import { 8 | requireNativeComponent, 9 | StyleSheet, 10 | View, 11 | Text, 12 | } from 'react-native'; 13 | 14 | class ScanView extends Component { 15 | constructor(props) { 16 | super(props); 17 | 18 | } 19 | 20 | render() { 21 | 22 | return ( 23 | 24 | 25 | 26 | ); 27 | } 28 | } 29 | 30 | ScanView.propTypes = { 31 | ...View.propTypes, 32 | cameraType: PropTypes.string, 33 | torchMode: PropTypes.string, 34 | 35 | }; 36 | 37 | ScanView.defaultProps = { 38 | showViewFinder: true, 39 | }; 40 | 41 | var RCTScanView = requireNativeComponent('RCTScanView', ScanView, { 42 | nativeOnly: {onChange: true} 43 | }); 44 | 45 | module.exports = ScanView; -------------------------------------------------------------------------------- /__tests__/index.android.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.android.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /__tests__/index.ios.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.ios.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.scanidcard", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.scanidcard", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"], 59 | * 60 | * // override which node gets called and with what additional arguments 61 | * nodeExecutableAndArgs: ["node"], 62 | * 63 | * // supply additional arguments to the packager 64 | * extraPackagerArgs: [] 65 | * ] 66 | */ 67 | 68 | apply from: "../../node_modules/react-native/react.gradle" 69 | 70 | /** 71 | * Set this to true to create two separate APKs instead of one: 72 | * - An APK that only works on ARM devices 73 | * - An APK that only works on x86 devices 74 | * The advantage is the size of the APK is reduced by about 4MB. 75 | * Upload all the APKs to the Play Store and people will download 76 | * the correct one based on the CPU architecture of their device. 77 | */ 78 | def enableSeparateBuildPerCPUArchitecture = false 79 | 80 | /** 81 | * Run Proguard to shrink the Java bytecode in release builds. 82 | */ 83 | def enableProguardInReleaseBuilds = false 84 | 85 | android { 86 | compileSdkVersion 23 87 | buildToolsVersion "23.0.1" 88 | 89 | defaultConfig { 90 | applicationId "com.scanidcard" 91 | minSdkVersion 16 92 | targetSdkVersion 22 93 | versionCode 1 94 | versionName "1.0" 95 | ndk { 96 | abiFilters "armeabi-v7a", "x86" 97 | } 98 | } 99 | splits { 100 | abi { 101 | reset() 102 | enable enableSeparateBuildPerCPUArchitecture 103 | universalApk false // If true, also generate a universal APK 104 | include "armeabi-v7a", "x86" 105 | } 106 | } 107 | buildTypes { 108 | release { 109 | minifyEnabled enableProguardInReleaseBuilds 110 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 111 | } 112 | } 113 | // applicationVariants are e.g. debug, release 114 | applicationVariants.all { variant -> 115 | variant.outputs.each { output -> 116 | // For each separate APK per architecture, set a unique version code as described here: 117 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 118 | def versionCodes = ["armeabi-v7a":1, "x86":2] 119 | def abi = output.getFilter(OutputFile.ABI) 120 | if (abi != null) { // null for the universal-debug, universal-release variants 121 | output.versionCodeOverride = 122 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 123 | } 124 | } 125 | } 126 | 127 | } 128 | 129 | dependencies { 130 | compile fileTree(dir: "libs", include: ["*.jar"]) 131 | compile "com.android.support:appcompat-v7:23.0.1" 132 | compile "com.facebook.react:react-native:+" // From node_modules 133 | // 身份证扫描 134 | compile project(path: ':idcard-library') 135 | compile project(':idcard-library') 136 | } 137 | 138 | // Run this once to be able to run the application with BUCK 139 | // puts all compile dependencies into folder libs for BUCK to use 140 | task copyDownloadableDepsToLibs(type: Copy) { 141 | from configurations.compile 142 | into 'libs' 143 | } 144 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/CameraManager.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.hardware.Camera; 4 | import android.view.View; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 相机管理 10 | * Created by mmjbds999 on 2017/6/5. 11 | */ 12 | public class CameraManager { 13 | 14 | private int id = -1;//相机ID 15 | private Camera camera;//相机对象 16 | 17 | /** 18 | * 默认构造函数,当创建对象的时候,返回一个ID为-1的相机实例 19 | */ 20 | public CameraManager(){ 21 | camera = getInstance(); 22 | } 23 | 24 | /** 25 | * 获取相机实例 26 | * @return 27 | */ 28 | public Camera getCamera(){ 29 | if (camera == null){ 30 | camera = getInstance(); 31 | } 32 | return camera; 33 | } 34 | 35 | /** 36 | * 根据相机类型获取实例(前置/后置) 37 | * @param cameraType 38 | * @return 39 | */ 40 | public Camera getCamera(String cameraType){ 41 | if (camera == null){ 42 | camera = getInstance(cameraType); 43 | } 44 | return camera; 45 | } 46 | 47 | /** 48 | * 默认实例,ID为-1 49 | * @return 50 | */ 51 | public Camera getInstance() { 52 | return getInstance(-1); 53 | } 54 | 55 | /** 56 | * 释放相机 57 | */ 58 | public void releaseCamera(){ 59 | if(camera != null){ 60 | camera.release(); 61 | camera = null; 62 | } 63 | } 64 | 65 | /** 66 | * 根据相机类型获取ID并创建实例(前置/后置) 67 | * @param cameraType 68 | * @return 69 | */ 70 | public Camera getInstance(String cameraType) { 71 | id = -1; 72 | 73 | Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); 74 | 75 | for (int cameraId = 0; cameraId < Camera.getNumberOfCameras(); cameraId++) { 76 | Camera.getCameraInfo(cameraId, cameraInfo); 77 | if (cameraType.equals("back") && cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { 78 | id = cameraId; 79 | break; 80 | } 81 | if (cameraType.equals("front") && cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 82 | id = cameraId; 83 | break; 84 | } 85 | } 86 | 87 | return getInstance(id); 88 | } 89 | 90 | /** 91 | * 根据相机ID创建实例 92 | * @param id 93 | * @return 94 | */ 95 | public Camera getInstance(int id){ 96 | Camera c = null; 97 | try{ 98 | if(id == -1){ 99 | c = Camera.open();//获取相机的实例 100 | }else{ 101 | c = Camera.open(id); 102 | } 103 | }catch (Exception e){ 104 | //未找到相机对象,正在使用或者没有相机 105 | } 106 | return c; 107 | } 108 | 109 | /** 110 | * 判断相机是否有Flash支持 111 | * @param camera 112 | * @return 113 | */ 114 | public boolean isFlashSupported(Camera camera){ 115 | if(camera != null){ 116 | Camera.Parameters parameters = camera.getParameters(); 117 | if(parameters.getFlashMode() == null){ 118 | return false; 119 | } 120 | 121 | List supportedFlashModes = parameters.getSupportedFlashModes(); 122 | if(supportedFlashModes == null || supportedFlashModes.isEmpty() || supportedFlashModes.size() == 1 && supportedFlashModes.get(0).equals(Camera.Parameters.FLASH_MODE_OFF)){ 123 | return false; 124 | } 125 | }else{ 126 | return false; 127 | } 128 | return true; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/CameraPreview.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.ImageFormat; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.Rect; 11 | import android.graphics.YuvImage; 12 | import android.hardware.Camera; 13 | import android.os.Handler; 14 | import android.util.Log; 15 | import android.util.Size; 16 | import android.view.Display; 17 | import android.view.MotionEvent; 18 | import android.view.Surface; 19 | import android.view.SurfaceHolder; 20 | import android.view.SurfaceView; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.view.Window; 24 | import android.view.WindowManager; 25 | import android.widget.FrameLayout; 26 | 27 | import java.io.ByteArrayOutputStream; 28 | import java.util.List; 29 | 30 | /** 31 | * 相机预览接口 32 | * 继承SurfaceView并实现其Callback接口 33 | * SurfaceView是一个可以在主线程之外的线程向屏幕绘图的容器 34 | * Created by mmjbds999 on 2017/6/5. 35 | */ 36 | public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 37 | 38 | private CameraManager cameraManager;//相机管理对象 39 | private Camera camera;//相机实例 40 | private String cameraType;//相机类型(back/front) 41 | private Camera.PictureCallback pictureCallback;//相机预览的回调 42 | 43 | private Handler autoFocusHandler;//自动对焦处理程序 44 | private boolean surfaceCreated;//绘图容器是否创建 45 | private boolean previewing = true;//是否开启预览 46 | private boolean autoFocus = true;//是否自动对焦 47 | 48 | private static final String TAG = "CameraPreview";//标记 49 | 50 | /** 51 | * 构造函数,需将相机预览回调对象传入 52 | * @param context 53 | * @param callback 54 | */ 55 | public CameraPreview(Context context, Camera.PictureCallback callback) { 56 | super(context); 57 | 58 | cameraManager = new CameraManager(); 59 | autoFocusHandler = new Handler(); 60 | pictureCallback = callback; 61 | this.setZOrderOnTop(false); 62 | 63 | // setOnTouchListener(new OnTouchListener() { 64 | // @Override 65 | // public boolean onTouch(View v, MotionEvent event) { 66 | // if (camera == null) 67 | // camera.startPreview(); 68 | // return true; 69 | // } 70 | // }); 71 | 72 | } 73 | 74 | /** 75 | * 启动相机 76 | */ 77 | public void startCamera(){ 78 | camera = cameraManager.getCamera(cameraType); 79 | startCameraPreview(); 80 | } 81 | 82 | /** 83 | * 变形解决 84 | * @param sizes 85 | * @param w 86 | * @param h 87 | * @return 88 | */ 89 | private Camera.Size getOptimalPreviewSize(List sizes, int w, int h) { 90 | final double ASPECT_TOLERANCE = 0.1; 91 | double targetRatio = (double) w / h; 92 | if (sizes == null) return null; 93 | 94 | Camera.Size optimalSize = null; 95 | double minDiff = Double.MAX_VALUE; 96 | 97 | int targetHeight = h; 98 | 99 | // Try to find an size match aspect ratio and size 100 | for (Camera.Size size : sizes) { 101 | double ratio = (double) size.width / size.height; 102 | if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; 103 | if (Math.abs(size.height - targetHeight) < minDiff) { 104 | optimalSize = size; 105 | minDiff = Math.abs(size.height - targetHeight); 106 | } 107 | } 108 | 109 | // Cannot find the one match the aspect ratio, ignore the requirement 110 | if (optimalSize == null) { 111 | minDiff = Double.MAX_VALUE; 112 | for (Camera.Size size : sizes) { 113 | if (Math.abs(size.height - targetHeight) < minDiff) { 114 | optimalSize = size; 115 | minDiff = Math.abs(size.height - targetHeight); 116 | } 117 | } 118 | } 119 | return optimalSize; 120 | } 121 | 122 | /** 123 | * 启动相机预览 124 | */ 125 | public void startCameraPreview(){ 126 | if(camera != null){ 127 | try { 128 | previewing = true; 129 | getHolder().addCallback(this); 130 | camera.setPreviewDisplay(getHolder()); 131 | // camera.setDisplayOrientation(90); 132 | camera.setDisplayOrientation(getDisplayOrientation()); 133 | // camera.setPreviewCallback(pictureCallback); 134 | 135 | Camera.Parameters cp = camera.getParameters(); 136 | 137 | int w = this.getLayoutParams().width; 138 | int h = this.getLayoutParams().height; 139 | 140 | if(h>w){ 141 | w = this.getLayoutParams().height; 142 | h = this.getLayoutParams().width; 143 | } 144 | 145 | List sizeList = cp.getSupportedPreviewSizes();//获取所有支持的camera尺寸 146 | Camera.Size optionSize = getOptimalPreviewSize(sizeList, w, h);//获取一个最为适配的camera.size 147 | 148 | cp.setPreviewSize(optionSize.width, optionSize.height); 149 | cp.setPictureSize(optionSize.width, optionSize.height); 150 | 151 | camera.setParameters(cp); 152 | 153 | camera.startPreview(); 154 | if(autoFocus){ 155 | if(surfaceCreated){ 156 | autoFocus(); 157 | }else{ 158 | scheduleAutoFocus(); 159 | } 160 | } 161 | }catch (Exception e){ 162 | Log.e(TAG, e.toString(), e); 163 | } 164 | } 165 | } 166 | 167 | public static Bitmap rotaingImageView(int angle , Bitmap bitmap) { 168 | //旋转图片 动作 169 | Matrix matrix = new Matrix(); 170 | matrix.postRotate(angle); 171 | System.out.println("angle2=" + angle); 172 | // 创建新的图片 173 | Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, 174 | bitmap.getWidth(), bitmap.getHeight(), matrix, true); 175 | return resizedBitmap; 176 | } 177 | 178 | /** 179 | * 停止camera 180 | */ 181 | public void stopCamera() { 182 | stopCameraPreview(); 183 | cameraManager.releaseCamera();//释放相机资源 184 | } 185 | 186 | /** 187 | * 设置相机类型,先释放资源,再开启 188 | * @param cameraType 189 | */ 190 | public void setCameraType(String cameraType) { 191 | this.cameraType = cameraType; 192 | stopCamera(); 193 | startCamera(); 194 | } 195 | 196 | /** 197 | * 停止相机预览 198 | */ 199 | public void stopCameraPreview() { 200 | if(camera != null) { 201 | try { 202 | previewing = false; 203 | getHolder().removeCallback(this); 204 | camera.cancelAutoFocus(); 205 | camera.setOneShotPreviewCallback(null); 206 | camera.stopPreview(); 207 | } catch(Exception e) { 208 | Log.e(TAG, e.toString(), e); 209 | } 210 | } 211 | } 212 | 213 | /** 214 | * 自动对焦 215 | */ 216 | public void autoFocus(){ 217 | try { 218 | camera.autoFocus(new Camera.AutoFocusCallback(){ 219 | public void onAutoFocus(boolean success, Camera camera) { 220 | if(success){ 221 | camera.takePicture(null, null, pictureCallback); 222 | } 223 | scheduleAutoFocus(); 224 | } 225 | }); 226 | }catch (RuntimeException e){ 227 | scheduleAutoFocus(); 228 | } 229 | } 230 | 231 | /** 232 | * 延迟2秒自动对焦 233 | */ 234 | private void scheduleAutoFocus() { 235 | autoFocusHandler.postDelayed(new Runnable() { 236 | @Override 237 | public void run() { 238 | if(camera != null && previewing && autoFocus && surfaceCreated) { 239 | autoFocus(); 240 | } 241 | } 242 | }, 500); 243 | } 244 | 245 | /** 246 | * 获取相机的显示方向角度值 247 | * @return 248 | */ 249 | public int getDisplayOrientation(){ 250 | Camera.CameraInfo info = new Camera.CameraInfo(); 251 | Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info); 252 | WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); 253 | Display display = wm.getDefaultDisplay(); 254 | 255 | // Camera.Parameters cp = camera.getParameters(); 256 | // List sizeList = cp.getSupportedPreviewSizes();//获取所有支持的camera尺寸 257 | // Camera.Size optionSize = getOptimalPreviewSize(sizeList, display.getWidth(), display.getWidth()*3/5);//获取一个最为适配的camera.size 258 | // this.setLayoutParams(new FrameLayout.LayoutParams(display.getWidth(), display.getWidth()*optionSize.height/optionSize.width)); 259 | 260 | this.setLayoutParams(new FrameLayout.LayoutParams(display.getWidth(), display.getHeight())); 261 | 262 | int rotation = display.getRotation();//旋转值根据当前显示获取 263 | int degrees = 0;//角度根据当前Surface旋转值获取 264 | switch (rotation){ 265 | case Surface.ROTATION_0: degrees = 0; break; 266 | case Surface.ROTATION_90: degrees = 90; break; 267 | case Surface.ROTATION_180: degrees = 180; break; 268 | case Surface.ROTATION_270: degrees = 270; break; 269 | } 270 | 271 | int result; 272 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 273 | result = (info.orientation + degrees) % 360; 274 | result = (360 - result) % 360; // compensate the mirror 275 | } else { // back-facing 276 | result = (info.orientation - degrees + 360) % 360; 277 | } 278 | return result; 279 | } 280 | 281 | /** 282 | * 创建时触发事件 283 | * @param holder 284 | */ 285 | @Override 286 | public void surfaceCreated(SurfaceHolder holder) { 287 | surfaceCreated = true; 288 | startCamera(); 289 | } 290 | 291 | /** 292 | * 大小发生改变时触发事件 293 | * @param holder 294 | * @param format 295 | * @param width 296 | * @param height 297 | */ 298 | @Override 299 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 300 | if(holder.getSurface() == null){ 301 | return; 302 | } 303 | if(camera != null){ 304 | try{ 305 | camera.setDisplayOrientation(getDisplayOrientation()); 306 | }catch (Exception e){ 307 | Log.e(TAG, e.toString(), e); 308 | } 309 | } 310 | } 311 | 312 | /** 313 | * 销毁时触发事件,一般将绘图线程停止并释放 314 | * @param holder 315 | */ 316 | @Override 317 | public void surfaceDestroyed(SurfaceHolder holder) { 318 | stopCamera(); 319 | } 320 | 321 | /** 322 | * 设置flash动画 323 | * @param flag 324 | */ 325 | public void setFlash(boolean flag) { 326 | if(camera != null && cameraManager.isFlashSupported(camera)) { 327 | Camera.Parameters parameters = camera.getParameters(); 328 | if(flag) { 329 | if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) { 330 | return; 331 | } 332 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 333 | } else { 334 | if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_OFF)) { 335 | return; 336 | } 337 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 338 | } 339 | camera.setParameters(parameters); 340 | } 341 | } 342 | 343 | } 344 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/CustomExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Created by mmjbds999 on 2017/6/26. 7 | */ 8 | public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler { 9 | 10 | private static final String TAG = "CustomExceptionHandler"; 11 | 12 | private Thread.UncaughtExceptionHandler mDefaultUEH; 13 | 14 | public CustomExceptionHandler() { 15 | Log.d(TAG, "------------ CustomExceptionHandler ------------"); 16 | mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler(); 17 | } 18 | 19 | @Override 20 | public void uncaughtException(Thread thread, Throwable ex) { 21 | Log.e(TAG, "------------ uncaughtException ------------ " + ex.getMessage()); 22 | mDefaultUEH.uncaughtException(thread, ex); // 不加本语句会导致ANR 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/DisplayUtil.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by panda on 2018/1/15. 7 | */ 8 | public class DisplayUtil { 9 | 10 | /** 11 | * 将px装换成dp,保证尺寸不变 12 | * @param context 13 | * @param pxValue 14 | * @return 15 | */ 16 | public static int px2dp(Context context, float pxValue){ 17 | float density = context.getResources().getDisplayMetrics().density;//得到设备的密度 18 | return (int) (pxValue/density+0.5f); 19 | } 20 | public static int dp2px(Context context, float dpValue){ 21 | float density = context.getResources().getDisplayMetrics().density; 22 | return (int) (dpValue*density+0.5f); 23 | } 24 | public static int px2sp(Context context, float pxValue){ 25 | float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity;//缩放密度 26 | return (int) (pxValue/scaleDensity+0.5f); 27 | } 28 | public static int sp2px(Context context, float spValue) { 29 | float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity; 30 | return (int) (spValue*scaleDensity+0.5f); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/IDCard.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Calendar; 6 | import java.util.GregorianCalendar; 7 | import java.util.Hashtable; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | /** 12 | * Created by mmjbds999 on 2017/6/14. 13 | */ 14 | public class IDCard { 15 | 16 | /*********************************** 身份证验证开始 ****************************************/ 17 | /** 18 | * 身份证号码验证 1、号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码, 19 | * 八位数字出生日期码,三位数字顺序码和一位数字校验码。 2、地址码(前六位数) 20 | * 表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。 3、出生日期码(第七位至十四位) 21 | * 表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。 4、顺序码(第十五位至十七位) 22 | * 表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号, 顺序码的奇数分配给男性,偶数分配给女性。 5、校验码(第十八位数) 23 | * (1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和 24 | * Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 25 | * (2)计算模 Y = mod(S, 11) (3)通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2 26 | */ 27 | 28 | /** 29 | * 功能:身份证的有效验证 30 | * 31 | * @param IDStr 32 | * 身份证号 33 | * @return 有效:返回"" 无效:返回String信息 34 | * @throws ParseException 35 | */ 36 | @SuppressWarnings("unchecked") 37 | public static String IDCardValidate(String IDStr) throws ParseException { 38 | String errorInfo = "";// 记录错误信息 39 | String[] ValCodeArr = { "1", "0", "x", "9", "8", "7", "6", "5", "4", 40 | "3", "2" }; 41 | String[] Wi = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", 42 | "9", "10", "5", "8", "4", "2" }; 43 | String Ai = ""; 44 | // ================ 号码的长度 15位或18位 ================ 45 | if (IDStr.length() != 15 && IDStr.length() != 18) { 46 | errorInfo = "身份证号码长度应该为15位或18位。"; 47 | return errorInfo; 48 | } 49 | // =======================(end)======================== 50 | 51 | // ================ 数字 除最后以为都为数字 ================ 52 | if (IDStr.length() == 18) { 53 | Ai = IDStr.substring(0, 17); 54 | } else if (IDStr.length() == 15) { 55 | Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15); 56 | } 57 | if (isNumeric(Ai) == false) { 58 | errorInfo = "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。"; 59 | return errorInfo; 60 | } 61 | // =======================(end)======================== 62 | 63 | // ================ 出生年月是否有效 ================ 64 | String strYear = Ai.substring(6, 10);// 年份 65 | String strMonth = Ai.substring(10, 12);// 月份 66 | String strDay = Ai.substring(12, 14);// 月份 67 | if (isDate(strYear + "-" + strMonth + "-" + strDay) == false) { 68 | errorInfo = "身份证生日无效。"; 69 | return errorInfo; 70 | } 71 | GregorianCalendar gc = new GregorianCalendar(); 72 | SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd"); 73 | try { 74 | if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150 75 | || (gc.getTime().getTime() - s.parse( 76 | strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) { 77 | errorInfo = "身份证生日不在有效范围。"; 78 | return errorInfo; 79 | } 80 | } catch (NumberFormatException e) { 81 | e.printStackTrace(); 82 | } catch (java.text.ParseException e) { 83 | e.printStackTrace(); 84 | } 85 | if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) { 86 | errorInfo = "身份证月份无效"; 87 | return errorInfo; 88 | } 89 | if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) { 90 | errorInfo = "身份证日期无效"; 91 | return errorInfo; 92 | } 93 | // =====================(end)===================== 94 | 95 | // ================ 地区码时候有效 ================ 96 | Hashtable h = GetAreaCode(); 97 | if (h.get(Ai.substring(0, 2)) == null) { 98 | errorInfo = "身份证地区编码错误。"; 99 | return errorInfo; 100 | } 101 | // ============================================== 102 | 103 | // ================ 判断最后一位的值 ================ 104 | int TotalmulAiWi = 0; 105 | for (int i = 0; i < 17; i++) { 106 | TotalmulAiWi = TotalmulAiWi 107 | + Integer.parseInt(String.valueOf(Ai.charAt(i))) 108 | * Integer.parseInt(Wi[i]); 109 | } 110 | int modValue = TotalmulAiWi % 11; 111 | String strVerifyCode = ValCodeArr[modValue]; 112 | Ai = Ai + strVerifyCode; 113 | 114 | if (IDStr.length() == 18) { 115 | if (Ai.equals(IDStr) == false) { 116 | errorInfo = "身份证无效,不是合法的身份证号码"; 117 | return errorInfo; 118 | } 119 | } else { 120 | return ""; 121 | } 122 | // =====================(end)===================== 123 | return ""; 124 | } 125 | 126 | /** 127 | * 功能:设置地区编码 128 | * 129 | * @return Hashtable 对象 130 | */ 131 | @SuppressWarnings("unchecked") 132 | private static Hashtable GetAreaCode() { 133 | Hashtable hashtable = new Hashtable(); 134 | hashtable.put("11", "北京"); 135 | hashtable.put("12", "天津"); 136 | hashtable.put("13", "河北"); 137 | hashtable.put("14", "山西"); 138 | hashtable.put("15", "内蒙古"); 139 | hashtable.put("21", "辽宁"); 140 | hashtable.put("22", "吉林"); 141 | hashtable.put("23", "黑龙江"); 142 | hashtable.put("31", "上海"); 143 | hashtable.put("32", "江苏"); 144 | hashtable.put("33", "浙江"); 145 | hashtable.put("34", "安徽"); 146 | hashtable.put("35", "福建"); 147 | hashtable.put("36", "江西"); 148 | hashtable.put("37", "山东"); 149 | hashtable.put("41", "河南"); 150 | hashtable.put("42", "湖北"); 151 | hashtable.put("43", "湖南"); 152 | hashtable.put("44", "广东"); 153 | hashtable.put("45", "广西"); 154 | hashtable.put("46", "海南"); 155 | hashtable.put("50", "重庆"); 156 | hashtable.put("51", "四川"); 157 | hashtable.put("52", "贵州"); 158 | hashtable.put("53", "云南"); 159 | hashtable.put("54", "西藏"); 160 | hashtable.put("61", "陕西"); 161 | hashtable.put("62", "甘肃"); 162 | hashtable.put("63", "青海"); 163 | hashtable.put("64", "宁夏"); 164 | hashtable.put("65", "新疆"); 165 | hashtable.put("71", "台湾"); 166 | hashtable.put("81", "香港"); 167 | hashtable.put("82", "澳门"); 168 | hashtable.put("91", "国外"); 169 | return hashtable; 170 | } 171 | 172 | /** 173 | * 功能:判断字符串是否为数字 174 | * 175 | * @param str 176 | * @return 177 | */ 178 | private static boolean isNumeric(String str) { 179 | Pattern pattern = Pattern.compile("[0-9]*"); 180 | Matcher isNum = pattern.matcher(str); 181 | if (isNum.matches()) { 182 | return true; 183 | } else { 184 | return false; 185 | } 186 | } 187 | 188 | /** 189 | * 功能:判断字符串是否为日期格式 190 | * 191 | * @param strDate 192 | * @return 193 | */ 194 | public static boolean isDate(String strDate) { 195 | Pattern pattern = Pattern 196 | .compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$"); 197 | Matcher m = pattern.matcher(strDate); 198 | if (m.matches()) { 199 | return true; 200 | } else { 201 | return false; 202 | } 203 | } 204 | 205 | /** 206 | * @param args 207 | * @throws ParseException 208 | */ 209 | @SuppressWarnings("static-access") 210 | public static void main(String[] args) throws ParseException { 211 | // String IDCardNum="210102820826411"; 212 | // String IDCardNum="210102198208264114"; 213 | String IDCardNum = "210181198807193116"; 214 | IDCard cc = new IDCard(); 215 | System.out.println(cc.IDCardValidate(IDCardNum)); 216 | // System.out.println(cc.isDate("1996-02-29")); 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/IdCardView.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.Rect; 9 | import android.view.View; 10 | import android.view.WindowManager; 11 | 12 | /** 13 | * Created by panda on 2018/1/15. 14 | */ 15 | 16 | public class IdCardView extends View { 17 | 18 | private int panelWidth; 19 | private int panelHeght; 20 | 21 | private int viewWidth; 22 | private int viewHeight; 23 | 24 | public int rectWidth; 25 | public int rectHeght; 26 | 27 | private int rectTop; 28 | private int rectLeft; 29 | private int rectRight; 30 | private int rectBottom; 31 | 32 | private int lineLen; 33 | private int lineWidht; 34 | private static final int LINE_WIDTH = 5; 35 | private static final int TOP_BAR_HEIGHT = 50; 36 | private static final int BOTTOM_BTN_HEIGHT = 66; 37 | 38 | // private static final int TOP_BAR_HEIGHT = Constant.RECT_VIEW_TOP; 39 | // private static final int BOTTOM_BTN_HEIGHT = Constant.RECT_VIEW_BOTTOM; 40 | 41 | private static final int LEFT_PADDING = 10; 42 | private static final int RIGHT_PADDING = 10; 43 | private static final String TIPS = "请将身份证放入到方框中"; 44 | 45 | private Paint linePaint; 46 | private Paint wordPaint; 47 | private Rect rect; 48 | private int baseline; 49 | 50 | public IdCardView(Context context) { 51 | super(context); 52 | 53 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 54 | panelWidth = wm.getDefaultDisplay().getWidth();//拿到屏幕的宽 55 | panelHeght = wm.getDefaultDisplay().getHeight();//拿到屏幕的高 56 | 57 | //高度不需要dp转换px,不然整体相机会向上移动一小节 58 | // viewHeight = panelHeght - (int) DisplayUtil.dp2px(activity,TOP_BAR_HEIGHT + BOTTOM_BTN_HEIGHT); 59 | 60 | viewHeight = panelHeght; 61 | //viewHeight,界面的高,viewWidth,界面的宽 62 | viewWidth = panelWidth; 63 | 64 | /*rectWidth = panelWidth 65 | - UnitUtils.getInstance(activity).dip2px( 66 | LEFT_PADDING + RIGHT_PADDING);*/ 67 | 68 | rectWidth = panelWidth - (int) DisplayUtil.dp2px(context,LEFT_PADDING + RIGHT_PADDING); 69 | 70 | rectHeght = (int) (rectWidth * 54 / 85.6); 71 | // 相对于此view 72 | rectTop = (viewHeight - rectHeght) / 2; 73 | rectLeft = (viewWidth - rectWidth) / 2; 74 | rectBottom = rectTop + rectHeght; 75 | rectRight = rectLeft + rectWidth; 76 | 77 | lineLen = panelWidth / 8; 78 | 79 | linePaint = new Paint(); 80 | linePaint.setAntiAlias(true); 81 | linePaint.setColor(Color.rgb(0xdd, 0x42, 0x2f)); 82 | linePaint.setStyle(Paint.Style.STROKE); 83 | linePaint.setStrokeWidth(LINE_WIDTH);// 设置线宽 84 | linePaint.setAlpha(255); 85 | 86 | wordPaint = new Paint(); 87 | wordPaint.setAntiAlias(true); 88 | wordPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 89 | wordPaint.setStrokeWidth(3); 90 | wordPaint.setTextSize(35); 91 | 92 | rect = new Rect(rectLeft, rectTop - 80, rectRight, rectTop - 10); 93 | Paint.FontMetricsInt fontMetrics = wordPaint.getFontMetricsInt(); 94 | baseline = rect.top + (rect.bottom - rect.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top; 95 | wordPaint.setTextAlign(Paint.Align.CENTER); 96 | } 97 | 98 | @Override 99 | public void onDraw(Canvas canvas) { 100 | super.onDraw(canvas); 101 | wordPaint.setColor(Color.TRANSPARENT); 102 | canvas.drawRect(rect, wordPaint); 103 | 104 | //画蒙层 105 | wordPaint.setColor(0xa0000000); 106 | rect = new Rect(0, viewHeight/2+rectHeght/2, viewWidth, viewHeight); 107 | canvas.drawRect(rect, wordPaint); 108 | 109 | rect = new Rect(0, 0, viewWidth, viewHeight/2-rectHeght/2); 110 | canvas.drawRect(rect, wordPaint); 111 | 112 | rect = new Rect(0, viewHeight/2-rectHeght/2, (viewWidth-rectWidth)/2, viewHeight/2+rectHeght/2); 113 | canvas.drawRect(rect, wordPaint); 114 | 115 | rect = new Rect(viewWidth-(viewWidth-rectWidth)/2, viewHeight/2-rectHeght/2, viewWidth, viewHeight/2+rectHeght/2); 116 | canvas.drawRect(rect, wordPaint); 117 | 118 | 119 | //重制rect 并画文字 吧文字置于rect中间 120 | rect = new Rect(rectLeft, rectTop - 80, rectRight, rectTop - 10); 121 | wordPaint.setColor(Color.WHITE); 122 | canvas.drawText(TIPS, rect.centerX(), baseline, wordPaint); 123 | canvas.drawLine(rectLeft, rectTop, rectLeft + lineLen, rectTop, 124 | linePaint); 125 | canvas.drawLine(rectRight - lineLen, rectTop, rectRight, rectTop, 126 | linePaint); 127 | canvas.drawLine(rectLeft, rectTop, rectLeft, rectTop + lineLen, 128 | linePaint); 129 | canvas.drawLine(rectRight, rectTop, rectRight, rectTop + lineLen, 130 | linePaint); 131 | canvas.drawLine(rectLeft, rectBottom, rectLeft + lineLen, rectBottom, 132 | linePaint); 133 | canvas.drawLine(rectRight - lineLen, rectBottom, rectRight, rectBottom, 134 | linePaint); 135 | canvas.drawLine(rectLeft, rectBottom - lineLen, rectLeft, rectBottom, 136 | linePaint); 137 | canvas.drawLine(rectRight, rectBottom - lineLen, rectRight, rectBottom, 138 | linePaint); 139 | } 140 | 141 | public int getRectLeft() { 142 | return rectLeft; 143 | } 144 | 145 | public int getRectTop() { 146 | return rectTop; 147 | } 148 | 149 | public int getRectRight() { 150 | return rectRight; 151 | } 152 | 153 | public int getRectBottom() { 154 | return rectBottom; 155 | } 156 | 157 | public int getViewWidth() { 158 | return viewWidth; 159 | } 160 | 161 | public int getViewHeight() { 162 | return viewHeight; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/ImageFilter.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Bitmap.Config; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.ColorMatrix; 8 | import android.graphics.ColorMatrixColorFilter; 9 | import android.graphics.Paint; 10 | import android.util.Log; 11 | 12 | public class ImageFilter { 13 | 14 | /** 15 | * 截取中间的图像 16 | * @param bitmap 17 | * @return 18 | */ 19 | public static Bitmap curtImage(Bitmap bitmap, double pt){ 20 | int w = bitmap.getWidth(); // 得到图片的宽,高 21 | int h = bitmap.getHeight(); 22 | 23 | int wh = (int)(h * pt);// 裁切后所取的正方形区域边长 24 | 25 | int retX = 0;// 基于原图,取截图左上角x坐标 26 | int retY = (int)(h * (1 - pt))/2; 27 | 28 | Bitmap bmp = Bitmap.createBitmap(bitmap, retX, retY, w, wh, null, false); 29 | return bmp; 30 | } 31 | 32 | /** 33 | * 获取姓名区域 34 | * @param bitmap 35 | * @return 36 | */ 37 | public static Bitmap getName(Bitmap bitmap){ 38 | int w = bitmap.getWidth(); // 得到图片的宽,高 39 | int h = bitmap.getHeight(); 40 | 41 | int cw = (int)(w * 0.4); 42 | int ch = (int)(h * 0.25);// 裁切后所取的区域边长 43 | 44 | int retX = 0;// 基于原图,取截图左上角x坐标 45 | int retY = 0; 46 | 47 | Bitmap bmp = Bitmap.createBitmap(bitmap, retX, retY, cw, ch, null, false); 48 | return bmp; 49 | } 50 | 51 | /** 52 | * 获取身份证区域 53 | * @param bitmap 54 | * @return 55 | */ 56 | public static Bitmap getID(Bitmap bitmap){ 57 | int w = bitmap.getWidth(); // 得到图片的宽,高 58 | int h = bitmap.getHeight(); 59 | 60 | int ch = (int)(h * 0.25);// 裁切后所取的正方形区域边长 61 | 62 | int retX = 0;// 基于原图,取截图左上角x坐标 63 | int retY = (int)(h * (0.75)); 64 | 65 | Bitmap bmp = Bitmap.createBitmap(bitmap, retX, retY, w, ch, null, false); 66 | return bmp; 67 | } 68 | 69 | // 图像灰度化 70 | public static Bitmap bitmap2Gray(Bitmap bmSrc) { 71 | // 得到图片的长和宽 72 | int width = bmSrc.getWidth(); 73 | int height = bmSrc.getHeight(); 74 | // 创建目标灰度图像 75 | Bitmap bmpGray = null; 76 | bmpGray = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 77 | // 创建画布 78 | Canvas c = new Canvas(bmpGray); 79 | Paint paint = new Paint(); 80 | ColorMatrix cm = new ColorMatrix(); 81 | cm.setSaturation(0); 82 | ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm); 83 | paint.setColorFilter(f); 84 | c.drawBitmap(bmSrc, 0, 0, paint); 85 | return bmpGray; 86 | } 87 | 88 | // 图像灰度化 89 | public static Bitmap grayScaleImage(Bitmap src) { 90 | // constant factors 91 | 92 | final double GS_RED = 0.2973; 93 | final double GS_GREEN = 0.6274; 94 | final double GS_BLUE = 0.0753; 95 | 96 | // final double GS_RED = 0.299; 97 | // final double GS_GREEN = 0.587; 98 | // final double GS_BLUE = 0.114; 99 | 100 | // final double GS_RED = 0.235; 101 | // final double GS_GREEN = 0.589; 102 | // final double GS_BLUE = 0.119; 103 | 104 | // create output bitmap 105 | Bitmap bmOut = Bitmap.createBitmap(src.getWidth(), src.getHeight(), src.getConfig()); 106 | // pixel information 107 | int A, R, G, B; 108 | int pixel; 109 | 110 | // get image size 111 | int width = src.getWidth(); 112 | int height = src.getHeight(); 113 | 114 | // scan through every single pixel 115 | for(int x = 0; x < width; ++x) { 116 | for(int y = 0; y < height; ++y) { 117 | // get one pixel color 118 | pixel = src.getPixel(x, y); 119 | // retrieve color of all channels 120 | A = Color.alpha(pixel); 121 | R = Color.red(pixel); 122 | G = Color.green(pixel); 123 | B = Color.blue(pixel); 124 | // take conversion up to one single value 125 | R = G = B = (int)(GS_RED * R + GS_GREEN * G + GS_BLUE * B); 126 | // set new pixel color to output bitmap 127 | bmOut.setPixel(x, y, Color.argb(A, R, G, B)); 128 | } 129 | } 130 | 131 | // return final image 132 | return bmOut; 133 | } 134 | 135 | // 对图像进行线性灰度变化 136 | public static Bitmap lineGrey(Bitmap image) { 137 | // 得到图像的宽度和长度 138 | int width = image.getWidth(); 139 | int height = image.getHeight(); 140 | // 创建线性拉升灰度图像 141 | Bitmap linegray = null; 142 | linegray = image.copy(Config.ARGB_8888, true); 143 | // 依次循环对图像的像素进行处理 144 | for (int i = 0; i < width; i++) { 145 | for (int j = 0; j < height; j++) { 146 | // 得到每点的像素值 147 | int col = image.getPixel(i, j); 148 | int alpha = col & 0xFF000000; 149 | int red = (col & 0x00FF0000) >> 16; 150 | int green = (col & 0x0000FF00) >> 8; 151 | int blue = (col & 0x000000FF); 152 | // 增加了图像的亮度 153 | red = (int) (1.1 * red + 30); 154 | green = (int) (1.1 * green + 30); 155 | blue = (int) (1.1 * blue + 30); 156 | // 对图像像素越界进行处理 157 | if (red >= 255) { 158 | red = 255; 159 | } 160 | 161 | if (green >= 255) { 162 | green = 255; 163 | } 164 | 165 | if (blue >= 255) { 166 | blue = 255; 167 | } 168 | // 新的ARGB 169 | int newColor = alpha | (red << 16) | (green << 8) | blue; 170 | // 设置新图像的RGB值 171 | linegray.setPixel(i, j, newColor); 172 | } 173 | } 174 | return linegray; 175 | } 176 | 177 | // 该函数实现对图像进行二值化处理 178 | public static Bitmap gray2Binary(Bitmap graymap) { 179 | // 得到图形的宽度和长度 180 | int width = graymap.getWidth(); 181 | int height = graymap.getHeight(); 182 | // 创建二值化图像 183 | Bitmap binarymap = null; 184 | binarymap = graymap.copy(Config.ARGB_8888, true); 185 | // 依次循环,对图像的像素进行处理 186 | for (int i = 0; i < width; i++) { 187 | for (int j = 0; j < height; j++) { 188 | // 得到当前像素的值 189 | int col = binarymap.getPixel(i, j); 190 | // 得到alpha通道的值 191 | int alpha = col & 0xFF000000; 192 | // 得到图像的像素RGB的值 193 | int red = (col & 0x00FF0000) >> 16; 194 | int green = (col & 0x0000FF00) >> 8; 195 | int blue = (col & 0x000000FF); 196 | // 用公式X = 0.3×R+0.59×G+0.11×B计算出X代替原来的RGB 197 | int gray = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11); 198 | // 对图像进行二值化处理 199 | if (gray <= 95) { 200 | gray = 0; 201 | } else { 202 | gray = 255; 203 | } 204 | // 新的ARGB 205 | int newColor = alpha | (gray << 16) | (gray << 8) | gray; 206 | // 设置新图像的当前像素值 207 | binarymap.setPixel(i, j, newColor); 208 | } 209 | } 210 | return binarymap; 211 | } 212 | 213 | /** 214 | * 将彩色图转换为黑白图 215 | * 216 | * @param bmp 位图 217 | * @return 返回转换好的位图 218 | */ 219 | public static Bitmap convertToBlackWhite(Bitmap bmp) { 220 | int width = bmp.getWidth(); // 获取位图的宽 221 | int height = bmp.getHeight(); // 获取位图的高 222 | int[] pixels = new int[width * height]; // 通过位图的大小创建像素点数组 223 | bmp.getPixels(pixels, 0, width, 0, 0, width, height); 224 | int alpha = 0xFF << 24; 225 | for (int i = 0; i < height; i++) { 226 | for (int j = 0; j < width; j++) { 227 | int grey = pixels[width * i + j]; 228 | int red = ((grey & 0x00FF0000) >> 16); 229 | int green = ((grey & 0x0000FF00) >> 8); 230 | int blue = (grey & 0x000000FF); 231 | grey = (int) (red * 0.3 + green * 0.59 + blue * 0.11); 232 | grey = alpha | (grey << 16) | (grey << 8) | grey; 233 | pixels[width * i + j] = grey; 234 | } 235 | } 236 | Bitmap newBmp = Bitmap.createBitmap(width, height, Config.ARGB_8888); 237 | newBmp.setPixels(pixels, 0, width, 0, 0, width, height); 238 | return newBmp; 239 | } 240 | 241 | /** 242 | * 图片锐化(拉普拉斯变换) 243 | * 244 | * @param bmp 245 | * @return 246 | */ 247 | public static Bitmap sharpenImageAmeliorate(Bitmap bmp) { 248 | // 拉普拉斯矩阵 249 | int[] laplacian = new int[] { -1, -1, -1, -1, 9, -1, -1, -1, -1 }; 250 | int width = bmp.getWidth(); 251 | int height = bmp.getHeight(); 252 | Bitmap bitmap = Bitmap.createBitmap(width, height, 253 | Bitmap.Config.ARGB_8888); 254 | int pixR = 0; 255 | int pixG = 0; 256 | int pixB = 0; 257 | int pixColor = 0; 258 | int newR = 0; 259 | int newG = 0; 260 | int newB = 0; 261 | int idx = 0; 262 | float alpha = 0.3F; 263 | int[] pixels = new int[width * height]; 264 | bmp.getPixels(pixels, 0, width, 0, 0, width, height); 265 | for (int i = 1, length = height - 1; i < length; i++) { 266 | for (int k = 1, len = width - 1; k < len; k++) { 267 | idx = 0; 268 | for (int m = -1; m <= 1; m++) { 269 | for (int n = -1; n <= 1; n++) { 270 | pixColor = pixels[(i + n) * width + k + m]; 271 | pixR = Color.red(pixColor); 272 | pixG = Color.green(pixColor); 273 | pixB = Color.blue(pixColor); 274 | newR = newR + (int) (pixR * laplacian[idx] * alpha); 275 | newG = newG + (int) (pixG * laplacian[idx] * alpha); 276 | newB = newB + (int) (pixB * laplacian[idx] * alpha); 277 | idx++; 278 | } 279 | } 280 | newR = Math.min(255, Math.max(0, newR)); 281 | newG = Math.min(255, Math.max(0, newG)); 282 | newB = Math.min(255, Math.max(0, newB)); 283 | pixels[i * width + k] = Color.argb(255, newR, newG, newB); 284 | newR = 0; 285 | newG = 0; 286 | newB = 0; 287 | } 288 | } 289 | bitmap.setPixels(pixels, 0, width, 0, 0, width, height); 290 | return bitmap; 291 | } 292 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "ScanIdCard"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.facebook.react.ReactNativeHost; 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.shell.MainReactPackage; 9 | import com.facebook.soloader.SoLoader; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | public class MainApplication extends Application implements ReactApplication { 15 | 16 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return BuildConfig.DEBUG; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | return Arrays.asList( 25 | new MainReactPackage(), 26 | new ScanPackage() 27 | ); 28 | } 29 | }; 30 | 31 | @Override 32 | public ReactNativeHost getReactNativeHost() { 33 | return mReactNativeHost; 34 | } 35 | 36 | @Override 37 | public void onCreate() { 38 | super.onCreate(); 39 | SoLoader.init(this, /* native exopackage */ false); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/ScanPackage.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by mmjbds999 on 2017/6/2. 15 | */ 16 | public class ScanPackage implements ReactPackage { 17 | @Override 18 | public List createNativeModules(ReactApplicationContext reactContext) { 19 | return Collections.emptyList(); 20 | } 21 | 22 | public List> createJSModules() { 23 | return Collections.emptyList(); 24 | } 25 | 26 | @Override 27 | public List createViewManagers(ReactApplicationContext reactContext) { 28 | return Arrays.asList( 29 | new ScanViewManager() 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/ScanView.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Matrix; 7 | import android.hardware.Camera; 8 | import android.os.Environment; 9 | import android.support.annotation.Nullable; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.FrameLayout; 13 | 14 | import com.facebook.react.bridge.Arguments; 15 | import com.facebook.react.bridge.ReactContext; 16 | import com.facebook.react.bridge.WritableMap; 17 | import com.facebook.react.modules.core.DeviceEventManagerModule; 18 | import com.ym.idcard.reg.engine.OcrEngine; 19 | 20 | import java.io.ByteArrayOutputStream; 21 | import java.io.File; 22 | import java.io.FileNotFoundException; 23 | import java.io.FileOutputStream; 24 | import java.io.IOException; 25 | import java.text.SimpleDateFormat; 26 | import java.util.Date; 27 | import java.util.regex.Matcher; 28 | import java.util.regex.Pattern; 29 | 30 | /** 31 | * Created by mmjbds999 on 2017/6/5. 32 | */ 33 | public class ScanView extends FrameLayout implements Camera.PictureCallback{ 34 | 35 | private CameraPreview cameraPreview;//相机预览组件 36 | 37 | private View idCardView; 38 | 39 | private static final String TAG = "ScanView"; 40 | 41 | private static boolean isStop = false; 42 | 43 | /** 44 | * 默认构造函数 45 | * @param context 46 | */ 47 | public ScanView(Context context) { 48 | super(context); 49 | 50 | cameraPreview = new CameraPreview(context, this); 51 | idCardView = new IdCardView(context); 52 | 53 | this.addView(cameraPreview); 54 | this.addView(idCardView); 55 | } 56 | 57 | public void onResume() { 58 | cameraPreview.startCamera(); 59 | } 60 | 61 | public void onPause() { 62 | cameraPreview.stopCamera(); 63 | } 64 | 65 | public void setCameraType(String cameraType) { 66 | cameraPreview.setCameraType(cameraType); 67 | } 68 | 69 | public void setFlash(boolean flag) { 70 | cameraPreview.setFlash(flag); 71 | } 72 | 73 | public void stopCamera() { 74 | cameraPreview.stopCamera(); 75 | } 76 | 77 | /** 保存方法 */ 78 | public void saveBitmap(Bitmap bm) { 79 | Log.e(TAG, "保存图片"); 80 | getContext().getExternalFilesDir(null).getAbsolutePath(); 81 | File f = new File(Environment.getExternalStorageDirectory()+"/Android/data/"+getContext().getPackageName()+"/files/test.jpg"); 82 | try { 83 | f.createNewFile(); 84 | FileOutputStream out = new FileOutputStream(f); 85 | bm.compress(Bitmap.CompressFormat.JPEG, 100, out); 86 | out.flush(); 87 | out.close(); 88 | Log.i(TAG, "已经保存"); 89 | } catch (FileNotFoundException e) { 90 | e.printStackTrace(); 91 | } catch (IOException e) { 92 | e.printStackTrace(); 93 | } 94 | } 95 | 96 | @Override 97 | public void onPictureTaken(byte[] data, Camera camera) { 98 | if(isStop){ 99 | cameraPreview.stopCamera(); 100 | isStop = false; 101 | return; 102 | } 103 | camera.startPreview(); 104 | try { 105 | Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length); 106 | 107 | Matrix m = new Matrix(); 108 | //图片高宽压缩一半 109 | //m.setScale(0.5f, 0.5f); 110 | //bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); 111 | 112 | //旋转90度 113 | if(bmp.getWidth()>bmp.getHeight()){ 114 | m.setRotate(90, (float) bmp.getWidth(), (float) bmp.getHeight()); 115 | bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true); 116 | } 117 | 118 | bmp = ImageFilter.curtImage(bmp, 0.30);//截取中间部分 119 | 120 | ByteArrayOutputStream cropStream = new ByteArrayOutputStream(); 121 | // // 参数0,30 122 | bmp.compress(Bitmap.CompressFormat.JPEG, 30, cropStream); 123 | 124 | //保存下来看看 125 | // saveBitmap(bmp); 126 | 127 | /*身份证扫描核心代码*/ 128 | OcrEngine ocrEngine = new OcrEngine(); 129 | com.ym.idcard.reg.bean.IDCard idCard = ocrEngine.recognize(getContext(), 2, cropStream.toByteArray(), null); 130 | 131 | if(idCard.getCardNo()!=null && idCard.getCardNo().length()==18 && IDCard.IDCardValidate(idCard.getCardNo()).equals("") 132 | && !idCard.getName().isEmpty() && validateName(idCard.getName())){ 133 | isStop = true; 134 | WritableMap event = Arguments.createMap(); 135 | event.putString("name", idCard.getName()); 136 | event.putString("id", idCard.getCardNo()); 137 | event.putInt("age", getAge(idCard.getCardNo())); 138 | event.putString("sex", getSex(idCard.getCardNo())); 139 | 140 | ReactContext reactContext = (ReactContext)getContext(); 141 | sendEvent(reactContext, "scanCallBack", event); 142 | } 143 | 144 | }catch (Exception e){ 145 | Log.e(TAG, e.toString(), e); 146 | } 147 | } 148 | 149 | /** 150 | * 校验姓名是否是中文 151 | * @return 152 | */ 153 | public boolean validateName(String str){ 154 | Pattern pattern = Pattern.compile("[\\u4E00-\\u9FA5]{2,5}(?:·[\\u4E00-\\u9FA5]{2,5})*"); 155 | Matcher matcher = pattern.matcher(str); 156 | return matcher.matches(); 157 | } 158 | 159 | /** 160 | * 根据身份证获取性别 161 | * @param IdNO 162 | * @return 163 | * @throws Exception 164 | */ 165 | public String getSex(String IdNO) 166 | throws Exception { 167 | String sex; 168 | if (Integer.parseInt(IdNO.substring(16).substring(0, 1)) % 2 == 0) {// 判断性别 169 | sex = "女"; 170 | } else { 171 | sex = "男"; 172 | } 173 | return sex; 174 | } 175 | 176 | /** 177 | * 根据身份证获取年龄 178 | * @param IdNO 179 | * @return 180 | */ 181 | public int getAge(String IdNO){ 182 | int leh = IdNO.length(); 183 | String dates=""; 184 | if (leh == 18) { 185 | int se = Integer.valueOf(IdNO.substring(leh - 1)) % 2; 186 | dates = IdNO.substring(6, 10); 187 | SimpleDateFormat df = new SimpleDateFormat("yyyy"); 188 | String year=df.format(new Date()); 189 | int u=Integer.parseInt(year)-Integer.parseInt(dates); 190 | return u; 191 | }else{ 192 | dates = IdNO.substring(6, 8); 193 | return Integer.parseInt(dates); 194 | } 195 | 196 | } 197 | 198 | /** 199 | * 发送事件 200 | * @param reactContext 201 | * @param eventName 202 | * @param params 203 | */ 204 | private void sendEvent(ReactContext reactContext, 205 | String eventName, 206 | @Nullable WritableMap params) { 207 | reactContext 208 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 209 | .emit(eventName, params); 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/scanidcard/ScanViewManager.java: -------------------------------------------------------------------------------- 1 | package com.scanidcard; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | import android.widget.FrameLayout; 6 | 7 | import com.facebook.react.bridge.LifecycleEventListener; 8 | import com.facebook.react.uimanager.SimpleViewManager; 9 | import com.facebook.react.uimanager.ThemedReactContext; 10 | import com.facebook.react.uimanager.ViewGroupManager; 11 | import com.facebook.react.uimanager.annotations.ReactProp; 12 | 13 | import javax.annotation.Nullable; 14 | 15 | /** 16 | * Created by mmjbds999 on 2017/6/2. 17 | */ 18 | public class ScanViewManager extends ViewGroupManager implements LifecycleEventListener { 19 | 20 | private static final String REACT_CLASS = "RCTScanView"; 21 | 22 | private static final String DEFAULT_TORCH_MODE = "off"; 23 | private static final String DEFAULT_CAMERA_TYPE = "back"; 24 | 25 | private ScanView scanView; 26 | private boolean scanViewVisible; 27 | 28 | @Override 29 | public String getName() { 30 | return REACT_CLASS; 31 | } 32 | 33 | @ReactProp(name = "cameraType") 34 | public void setCameraType(ScanView view, @Nullable String cameraType) { 35 | if (cameraType != null) { 36 | view.setCameraType(cameraType); 37 | } 38 | } 39 | 40 | @ReactProp(name = "torchMode") 41 | public void setTorchMode(ScanView view, @Nullable String torchMode) { 42 | if (torchMode != null) { 43 | view.setFlash(torchMode.equals("on")); 44 | } 45 | } 46 | 47 | @Override 48 | protected ScanView createViewInstance(ThemedReactContext reactContext) { 49 | reactContext.addLifecycleEventListener(this); 50 | scanView = new ScanView(reactContext); 51 | scanView.setCameraType(DEFAULT_CAMERA_TYPE); 52 | scanView.setFlash(DEFAULT_TORCH_MODE.equals("on")); 53 | scanViewVisible = true; 54 | return scanView; 55 | } 56 | 57 | @Override 58 | public void onHostResume() { 59 | scanView.onResume(); 60 | } 61 | 62 | @Override 63 | public void onHostPause() { 64 | scanView.onPause(); 65 | } 66 | 67 | @Override 68 | public void onHostDestroy() { 69 | scanView.stopCamera(); 70 | } 71 | 72 | @Override 73 | public void addView(ScanView parent, View child, int index) { 74 | parent.addView(child, index + 1); // index 0 for camera preview reserved 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjbds999/react-native-scanidcard/35d30b89ab0185f1a08a40a4f4d8c2e2ff50222f/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjbds999/react-native-scanidcard/35d30b89ab0185f1a08a40a4f4d8c2e2ff50222f/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjbds999/react-native-scanidcard/35d30b89ab0185f1a08a40a4f4d8c2e2ff50222f/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjbds999/react-native-scanidcard/35d30b89ab0185f1a08a40a4f4d8c2e2ff50222f/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ScanIdCard 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjbds999/react-native-scanidcard/35d30b89ab0185f1a08a40a4f4d8c2e2ff50222f/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/idcard-library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android/idcard-library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 22 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | <<<<<<< HEAD 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile "com.android.support:appcompat-v7:23.0.1" 25 | ======= 26 | >>>>>>> ee76d4b4b26c8065f3be554b6de68fb421481e4e 27 | } 28 | -------------------------------------------------------------------------------- /android/idcard-library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /android/idcard-library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | <<<<<<< HEAD 4 | 6 | 7 | 8 | 9 | ======= 10 | >>>>>>> ee76d4b4b26c8065f3be554b6de68fb421481e4e 11 | 12 | -------------------------------------------------------------------------------- /android/idcard-library/src/main/assets/license.info: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjbds999/react-native-scanidcard/35d30b89ab0185f1a08a40a4f4d8c2e2ff50222f/android/idcard-library/src/main/assets/license.info -------------------------------------------------------------------------------- /android/idcard-library/src/main/java/com/ym/idcard/reg/NativeImage.java: -------------------------------------------------------------------------------- 1 | package com.ym.idcard.reg; 2 | 3 | import android.util.Log; 4 | 5 | public class NativeImage 6 | { 7 | private static final String LIB = "imageengine"; 8 | private static final String TAG = "NativeImage"; 9 | 10 | static 11 | { 12 | try 13 | { 14 | System.loadLibrary("imageengine"); 15 | } 16 | catch (Exception localException) 17 | { 18 | Log.e("imageengine", "", localException); 19 | } 20 | } 21 | 22 | public native int closeEngine(long paramLong); 23 | 24 | public native long createEngine(); 25 | 26 | public void finalize() 27 | { 28 | } 29 | 30 | public native int freeImage(long paramLong); 31 | 32 | public native int getImageComponent(long paramLong); 33 | 34 | public native long getImageDataEx(long paramLong); 35 | 36 | public native int getImageHeight(long paramLong); 37 | 38 | public native int getImageWidth(long paramLong); 39 | 40 | public native int initImage(long paramLong, int paramInt1, int paramInt2); 41 | 42 | public native int loadmemjpg(long paramLong, byte[] paramArrayOfByte, int paramInt); 43 | } 44 | 45 | /* Location: D:\document\bsd_work\一体机资料\测试app\com.newland.activity\classes_dex2jar.jar 46 | * Qualified Name: com.ym.idcard.reg.NativeImage 47 | * JD-Core Version: 0.5.4 48 | */ -------------------------------------------------------------------------------- /android/idcard-library/src/main/java/com/ym/idcard/reg/NativeOcr.java: -------------------------------------------------------------------------------- 1 | 2 | package com.ym.idcard.reg; 3 | 4 | import android.util.Log; 5 | 6 | public class NativeOcr 7 | { 8 | private static final String LIB = "IDCardengine"; 9 | private static final String TAG = "NativeOcr"; 10 | private static boolean mCancel; 11 | private static int mProgress; 12 | 13 | static 14 | { 15 | try 16 | { 17 | System.loadLibrary("IDCardengine"); 18 | mProgress = 0; 19 | mCancel = false; 20 | Log.v(TAG, "load lib end"); 21 | } catch (Exception localException) 22 | { 23 | Log.e("ocrengine", "", localException); 24 | } 25 | } 26 | 27 | public static int Progress(int progress, int relative) 28 | { 29 | if (relative != 0) 30 | mProgress = progress + mProgress; 31 | else { 32 | mProgress = progress; 33 | } 34 | return mProgress; 35 | } 36 | 37 | public static int getProgress() 38 | { 39 | return mProgress; 40 | } 41 | 42 | public native int closeBCR(long[] paramArrayOfLong); 43 | 44 | public native int codeConvert(long paramLong, byte[] paramArrayOfByte, int paramInt); 45 | 46 | public native int doImageBCR(long paramLong1, long paramLong2, long[] paramArrayOfLong); 47 | 48 | public void finalize() 49 | { 50 | } 51 | 52 | public native void freeBField(long paramLong1, long paramLong2, int paramInt); 53 | 54 | public native int freeImage(long paramLong, long[] paramArrayOfLong); 55 | 56 | public native int getFieldId(long paramLong); 57 | 58 | public native int getFieldRect(long paramLong, int[] paramArrayOfInt); 59 | 60 | public native int getFieldText(long paramLong, byte[] paramArrayOfByte, int paramInt); 61 | 62 | public native long getNextField(long paramLong); 63 | 64 | public native int imageChecking(long paramLong1, long paramLong2, int paramInt); 65 | 66 | public native long loadImageMem(long paramLong1, long paramLong2, int paramInt1, int paramInt2, 67 | int paramInt3); 68 | 69 | public native void setProgressFunc(long paramLong, boolean paramBoolean); 70 | 71 | public native int setoption(long paramLong, byte[] paramArrayOfByte1, byte[] paramArrayOfByte2); 72 | 73 | public native int startBCR(long[] paramArrayOfLong, byte[] paramArrayOfByte1, 74 | byte[] paramArrayOfByte2, int paramInt, byte[] paramArrayOfByte3); 75 | } 76 | 77 | /* 78 | * Location: 79 | * D:\document\bsd_work\一体机资料\测试app\com.newland.activity\classes_dex2jar.jar 80 | * Qualified Name: com.ym.idcard.reg.NativeOcr JD-Core Version: 0.5.4 81 | */ 82 | -------------------------------------------------------------------------------- /android/idcard-library/src/main/java/com/ym/idcard/reg/bean/IDCard.java: -------------------------------------------------------------------------------- 1 | package com.ym.idcard.reg.bean; 2 | 3 | 4 | import com.ym.idcard.reg.engine.OcrEngine; 5 | 6 | public class IDCard 7 | { 8 | private int recogStatus = OcrEngine.RECOG_FAIL; 9 | private String ymAddress; 10 | private String ymAuthority; 11 | private String ymBirth; 12 | private String ymCardNo; 13 | private String ymEthnicity; 14 | private String ymMemo; 15 | private String ymName; 16 | private String ymPeriod; 17 | private String ymSex; 18 | 19 | public String getAddress() 20 | { 21 | return this.ymAddress; 22 | } 23 | 24 | public String getAuthority() 25 | { 26 | return this.ymAuthority; 27 | } 28 | 29 | public String getBirth() 30 | { 31 | return this.ymBirth; 32 | } 33 | 34 | public String getCardNo() 35 | { 36 | return this.ymCardNo; 37 | } 38 | 39 | public String getEthnicity() 40 | { 41 | return this.ymEthnicity; 42 | } 43 | 44 | public String getMemo() 45 | { 46 | return this.ymMemo; 47 | } 48 | 49 | public String getName() 50 | { 51 | return this.ymName; 52 | } 53 | 54 | public String getPeriod() 55 | { 56 | return this.ymPeriod; 57 | } 58 | 59 | public int getRecogStatus() 60 | { 61 | return this.recogStatus; 62 | } 63 | 64 | public String getSex() 65 | { 66 | return this.ymSex; 67 | } 68 | 69 | public void setAddress(String paramString) 70 | { 71 | this.ymAddress = paramString; 72 | } 73 | 74 | public void setAuthority(String paramString) 75 | { 76 | this.ymAuthority = paramString; 77 | } 78 | 79 | public void setBirth(String paramString) 80 | { 81 | this.ymBirth = paramString; 82 | } 83 | 84 | public void setCardNo(String paramString) 85 | { 86 | this.ymCardNo = paramString; 87 | } 88 | 89 | public void setEthnicity(String paramString) 90 | { 91 | this.ymEthnicity = paramString; 92 | } 93 | 94 | public void setMemo(String paramString) 95 | { 96 | this.ymMemo = paramString; 97 | } 98 | 99 | public void setName(String paramString) 100 | { 101 | this.ymName = paramString; 102 | } 103 | 104 | public void setPeriod(String paramString) 105 | { 106 | this.ymPeriod = paramString; 107 | } 108 | 109 | public void setRecogStatus(int paramInt) 110 | { 111 | this.recogStatus = paramInt; 112 | } 113 | 114 | public void setSex(String paramString) 115 | { 116 | this.ymSex = paramString; 117 | } 118 | 119 | public String toString() 120 | { 121 | StringBuffer localStringBuffer = new StringBuffer(); 122 | localStringBuffer.append("姓名:").append(this.ymName).append("\n"); 123 | localStringBuffer.append("身份号码:").append(this.ymCardNo).append("\n"); 124 | localStringBuffer.append("性别:").append(this.ymSex).append("\n"); 125 | localStringBuffer.append("民族:").append(this.ymEthnicity).append("\n"); 126 | localStringBuffer.append("出生:").append(this.ymBirth).append("\n"); 127 | localStringBuffer.append("住址:").append(this.ymAddress).append("\n"); 128 | localStringBuffer.append("签发机关:").append(this.ymAuthority).append("\n"); 129 | localStringBuffer.append("有效期限:").append(this.ymPeriod).append("\n"); 130 | return localStringBuffer.toString(); 131 | } 132 | } 133 | 134 | /* Location: D:\document\bsd_work\一体机资料\测试app\com.newland.activity\classes_dex2jar.jar 135 | * Qualified Name: com.yunmai.android.vo.IDCard 136 | * JD-Core Version: 0.5.4 137 | */ -------------------------------------------------------------------------------- /android/idcard-library/src/main/java/com/ym/idcard/reg/engine/ImageEngine.java: -------------------------------------------------------------------------------- 1 | 2 | package com.ym.idcard.reg.engine; 3 | 4 | import com.ym.idcard.reg.NativeImage; 5 | 6 | public class ImageEngine 7 | { 8 | public static final int IMG_COMPONENT_GRAY = 1; 9 | public static final int IMG_COMPONENT_RGB = 3; 10 | public static final int IMG_FMT_BMP = 1; 11 | public static final int IMG_FMT_JPG = 2; 12 | public static final int IMG_FMT_UNK = 0; 13 | public static final int RET_ERR_ARG = -2; 14 | public static final int RET_ERR_MEM = -3; 15 | public static final int RET_ERR_PTR = -1; 16 | public static final int RET_ERR_UNK = 0; 17 | public static final int RET_OK = 1; 18 | protected long mEngine = 0L; 19 | protected NativeImage mNativeImage = null; 20 | 21 | ImageEngine(){ 22 | mNativeImage = new NativeImage(); 23 | mEngine = mNativeImage.createEngine(); 24 | } 25 | 26 | public void finalize() 27 | { 28 | if ((this.mNativeImage == null) || (this.mEngine == 0L)) 29 | return; 30 | this.mNativeImage.freeImage(this.mEngine); 31 | this.mNativeImage.closeEngine(this.mEngine); 32 | this.mEngine = 0L; 33 | } 34 | 35 | public int getComponent() 36 | { 37 | if (this.mNativeImage != null) 38 | return mNativeImage.getImageComponent(mEngine); 39 | return 0; 40 | } 41 | 42 | public long getDataEx() 43 | { 44 | long data = 0L; 45 | if (this.mNativeImage != null) 46 | data = this.mNativeImage.getImageDataEx(this.mEngine); 47 | return data; 48 | } 49 | 50 | public int getHeight() 51 | { 52 | if (this.mNativeImage != null) 53 | return mNativeImage.getImageHeight(this.mEngine); 54 | return 0; 55 | } 56 | 57 | public int getWidth() 58 | { 59 | if (this.mNativeImage != null) 60 | return mNativeImage.getImageWidth(this.mEngine); 61 | return 0; 62 | } 63 | 64 | public boolean init(int components, int quality) 65 | { 66 | if ((this.mNativeImage != null) 67 | && (this.mNativeImage.initImage(this.mEngine, components, quality) == 1)) 68 | { 69 | return true; 70 | } 71 | return false; 72 | } 73 | 74 | public boolean load(byte[] imgbuffer) 75 | { 76 | if ((this.mNativeImage != null) 77 | && (this.mNativeImage.loadmemjpg(this.mEngine, imgbuffer, 78 | imgbuffer.length) == 1)) 79 | return true; 80 | return false; 81 | } 82 | } 83 | 84 | /* 85 | * Location: 86 | * D:\document\bsd_work\一体机资料\测试app\com.newland.activity\classes_dex2jar.jar 87 | * Qualified Name: com.yunmai.android.engine.ImageEngine JD-Core Version: 0.5.4 88 | */ 89 | -------------------------------------------------------------------------------- /android/idcard-library/src/main/java/com/ym/idcard/reg/engine/OcrEngine.java: -------------------------------------------------------------------------------- 1 | package com.ym.idcard.reg.engine; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | import android.graphics.Rect; 6 | import android.util.Log; 7 | 8 | import com.ym.idcard.reg.NativeOcr; 9 | import com.ym.idcard.reg.bean.IDCard; 10 | import com.ym.idcard.reg.util.FileUtil; 11 | import com.ym.idcard.reg.util.StringUtil; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | 17 | public class OcrEngine { 18 | private static final int BIDC_ADDRESS = 6; 19 | private static final int BIDC_BIRTHDAY = 5; 20 | private static final int BIDC_CARDNO = 3; 21 | private static final int BIDC_FOLK = 11; 22 | private static final int BIDC_ISSUE_AUTHORITY = 7; 23 | private static final int BIDC_MEMO = 99; 24 | private static final int BIDC_NAME = 1; 25 | private static final int BIDC_NON = 0; 26 | private static final int BIDC_SEX = 4; 27 | private static final int BIDC_VALID_PERIOD = 9; 28 | private static final int MIN_HEIGHT_LIMIT = 720; 29 | private static final int MIN_WIDTH_LIMIT = 1024; 30 | private static final int OCR_CODE_B5 = 2; 31 | private static final int OCR_CODE_GB = 1; 32 | private static final int OCR_CODE_GB2B5 = 3; 33 | private static final int OCR_CODE_NIL = 0; 34 | private static final int OCR_LAN_CENTEURO = 7; 35 | private static final int OCR_LAN_CHINESE_SIMPLE = 2; 36 | private static final int OCR_LAN_CHINESE_TRADITIONAL = 21; 37 | private static final int OCR_LAN_ENGLISH = 1; 38 | private static final int OCR_LAN_EUROPEAN = 3; 39 | private static final int OCR_LAN_JAPAN = 6; 40 | private static final int OCR_LAN_NIL = 0; 41 | private static final int OCR_LAN_RUSSIAN = 4; 42 | private static boolean OPT_CANCEL = false; 43 | public static final int RECOG_BLUR = 3; 44 | public static final int RECOG_BLUR_TIP = 5; 45 | public static final int RECOG_CANCEL = -1; 46 | public static final int RECOG_FAIL = -2; 47 | public static final int RECOG_LANGUAGE = 4; 48 | public static final int RECOG_NONE = 0; 49 | public static final int RECOG_OK = 1; 50 | public static final int RECOG_SMALL = 2; 51 | protected boolean mBeCancel = false; 52 | protected NativeOcr mNativeOcr = new NativeOcr(); 53 | protected long pEngine = 0L; 54 | protected long pField = 0L; 55 | protected long pImage = 0L; 56 | protected long[] ppEngine = new long[1]; 57 | protected long[] ppField = new long[1]; 58 | protected long[] ppImage = new long[1]; 59 | private static final String TAG = "OcrEngine"; 60 | 61 | private void closeBCR() { 62 | if ((this.ppEngine == null) || (this.mNativeOcr == null)) 63 | return; 64 | this.mNativeOcr.closeBCR(this.ppEngine); 65 | this.ppEngine[0] = 0L; 66 | this.pEngine = 0L; 67 | } 68 | 69 | public static void doCancel() { 70 | OPT_CANCEL = true; 71 | } 72 | 73 | private boolean doImageBCR() { 74 | this.mBeCancel = false; 75 | this.mNativeOcr.setoption(this.pEngine, 76 | StringUtil.convertToUnicode("-fmt"), null); 77 | int result = this.mNativeOcr.doImageBCR(this.pEngine, this.pImage, 78 | this.ppField); 79 | if (result == RECOG_OK) { 80 | this.pField = this.ppField[0]; 81 | return true; 82 | } else if (result == RECOG_BLUR) { 83 | this.mBeCancel = true; 84 | } 85 | return false; 86 | } 87 | 88 | private boolean fields2Object(IDCard paramIDCard, int keyLanguage) { 89 | if (paramIDCard == null) 90 | return false; 91 | while (!isFieldEnd()) { 92 | switch (getFieldId()) { 93 | case BIDC_NAME: 94 | paramIDCard.setName(getFieldText(keyLanguage)); 95 | break; 96 | case BIDC_SEX: 97 | paramIDCard.setSex(getFieldText(keyLanguage)); 98 | break; 99 | case BIDC_CARDNO: 100 | paramIDCard.setCardNo(getFieldText(keyLanguage)); 101 | break; 102 | case BIDC_FOLK: 103 | paramIDCard.setEthnicity(getFieldText(keyLanguage)); 104 | break; 105 | case BIDC_BIRTHDAY: 106 | paramIDCard.setBirth(getFieldText(keyLanguage)); 107 | break; 108 | case BIDC_ADDRESS: 109 | paramIDCard.setAddress(getFieldText(keyLanguage)); 110 | break; 111 | case BIDC_ISSUE_AUTHORITY: 112 | paramIDCard.setAuthority(getFieldText(keyLanguage)); 113 | break; 114 | case BIDC_VALID_PERIOD: 115 | paramIDCard.setPeriod(getFieldText(keyLanguage)); 116 | break; 117 | case BIDC_MEMO: 118 | paramIDCard.setMemo(getFieldText(keyLanguage)); 119 | break; 120 | } 121 | getNextField(); 122 | } 123 | return true; 124 | 125 | } 126 | 127 | private void freeBFields() { 128 | if (this.mNativeOcr == null) 129 | return; 130 | this.mNativeOcr.freeBField(this.pEngine, this.ppField[0], 0); 131 | this.ppField[0] = 0L; 132 | this.pField = 0L; 133 | } 134 | 135 | private void freeImage() { 136 | if (this.mNativeOcr == null) 137 | return; 138 | this.mNativeOcr.freeImage(this.pEngine, this.ppImage); 139 | this.ppImage[0] = 0L; 140 | this.pImage = 0L; 141 | } 142 | 143 | private int getFieldId() { 144 | long l = this.pField; 145 | return this.mNativeOcr.getFieldId(l); 146 | } 147 | 148 | private Rect getFieldRect() { 149 | Rect localRect = new Rect(); 150 | long l = this.pField; 151 | int[] arrayOfInt = new int[4]; 152 | this.mNativeOcr.getFieldRect(l, arrayOfInt); 153 | localRect.left = arrayOfInt[0]; 154 | localRect.top = arrayOfInt[1]; 155 | localRect.right = arrayOfInt[2]; 156 | localRect.bottom = arrayOfInt[3]; 157 | return localRect; 158 | } 159 | 160 | private String getFieldText(int keyLanguage) { 161 | byte[] arrayOfByte = new byte[256]; 162 | this.mNativeOcr.getFieldText(this.pField, arrayOfByte, 163 | arrayOfByte.length); 164 | if ((keyLanguage == OCR_CODE_GB2B5)) { 165 | this.mNativeOcr.codeConvert(this.pEngine, arrayOfByte, keyLanguage); 166 | return StringUtil.convertBig5ToUnicode(arrayOfByte); 167 | } else { 168 | return StringUtil.convertGbkToUnicode(arrayOfByte); 169 | } 170 | } 171 | 172 | private void getNextField() { 173 | if (isFieldEnd()) 174 | return; 175 | this.pField = this.mNativeOcr.getNextField(this.pField); 176 | } 177 | 178 | private boolean isBlurImage() { 179 | if (mNativeOcr == null) 180 | return false; 181 | if (mNativeOcr.imageChecking(pEngine, pImage, 0) == 2) { 182 | return true; 183 | } 184 | return false; 185 | } 186 | 187 | private boolean isCancel() { 188 | return this.mBeCancel; 189 | } 190 | 191 | private boolean isFieldEnd() { 192 | return pField == 0; 193 | } 194 | 195 | private boolean loadImageMem(long pBuffer, int width, int height, 196 | int component) { 197 | if (pBuffer != 0) { 198 | this.pImage = this.mNativeOcr.loadImageMem(this.pEngine, pBuffer, 199 | width, height, component); 200 | if (this.pImage != 0L) { 201 | this.ppImage[0] = this.pImage; 202 | return true; 203 | } 204 | } 205 | return false; 206 | } 207 | 208 | private IDCard recognize(Context context, int ocrLanguage, String imagePath) 209 | throws IOException { 210 | return recognize(context, ocrLanguage, 211 | FileUtil.getBytesFromFile(new File(imagePath)), null); 212 | } 213 | 214 | public IDCard recognize(Context context, int ocrLanguage, 215 | byte[] idCardDataA, byte[] idCardDataB) { 216 | IDCard idCard = new IDCard(); 217 | int keyLanguage = OCR_CODE_GB; 218 | boolean blurDetection = false; 219 | if (ocrLanguage == OCR_LAN_CHINESE_TRADITIONAL) 220 | keyLanguage = OCR_LAN_EUROPEAN; 221 | OPT_CANCEL = false; 222 | byte[] license = new byte[256]; 223 | AssetManager localAssetManager = context.getAssets(); 224 | try { 225 | InputStream localInputStream = localAssetManager 226 | .open("license.info"); 227 | localInputStream.read(license); 228 | localInputStream.close(); 229 | } catch (IOException localIOException) { 230 | 231 | } 232 | if (startBCR("", "", ocrLanguage, license)) { 233 | if (idCardDataA != null) 234 | idCard = recognizing(idCardDataA, blurDetection, keyLanguage); 235 | if (idCardDataB != null) { 236 | IDCard idCardB = recognizing(idCardDataB, blurDetection, 237 | keyLanguage); 238 | idCard.setAuthority(idCardB.getAuthority()); 239 | idCard.setPeriod(idCardB.getPeriod()); 240 | } 241 | closeBCR(); 242 | } 243 | return idCard; 244 | } 245 | 246 | private IDCard recognizing(byte[] imgBuffer, boolean blurDetection, 247 | int keyLanguage) { 248 | IDCard idCard = new IDCard(); 249 | ImageEngine imageEngine = new ImageEngine(); 250 | if (imageEngine.init(1, 90) && imageEngine.load(imgBuffer)) { 251 | int width = imageEngine.getWidth(); 252 | int height = imageEngine.getHeight(); 253 | int component = imageEngine.getComponent(); 254 | long pBuffer = imageEngine.getDataEx(); 255 | boolean result = loadImageMem(pBuffer, width, height, component); 256 | imageEngine.finalize(); 257 | if (result) { 258 | if (!blurDetection || !isBlurImage() || OPT_CANCEL) { 259 | if (doImageBCR()) { 260 | if (fields2Object(idCard, keyLanguage)) { 261 | idCard.setRecogStatus(RECOG_OK); 262 | } 263 | } else { 264 | if (isCancel()) { 265 | idCard.setRecogStatus(RECOG_CANCEL); 266 | } 267 | } 268 | freeBFields(); 269 | } else { 270 | idCard.setRecogStatus(RECOG_BLUR); 271 | } 272 | } 273 | freeImage(); 274 | } 275 | return idCard; 276 | } 277 | 278 | private void setProgressFunc(boolean paramBoolean) { 279 | if ((this.pEngine == 0L) || (this.mNativeOcr == null)) 280 | return; 281 | this.mNativeOcr.setProgressFunc(this.pEngine, paramBoolean); 282 | } 283 | 284 | public String byteToHexString(byte[] b) { 285 | String str = ""; 286 | for (int i = 0; i < b.length; i++) { 287 | String hex = Integer.toHexString(b[i] & 0xFF); 288 | if (hex.length() == 1) { 289 | hex = '0' + hex; 290 | } 291 | 292 | str += hex; 293 | } 294 | return str; 295 | } 296 | 297 | private boolean startBCR(String cfgPath, String dataPath, int lanuage, 298 | byte[] license) { 299 | Log.v(TAG, "before navtive startBCR"); 300 | Log.v(TAG, "dataPath:" + dataPath); 301 | Log.v(TAG, "cfgPath:" + cfgPath); 302 | Log.v(TAG, "license:" + byteToHexString(license)); 303 | 304 | if (this.mNativeOcr.startBCR(this.ppEngine, 305 | StringUtil.convertUnicodeToAscii(dataPath), 306 | StringUtil.convertUnicodeToAscii(cfgPath), lanuage, license) == RECOG_OK) { 307 | Log.v(TAG, "after navtive startBCR"); 308 | this.pEngine = this.ppEngine[0]; 309 | return true; 310 | } 311 | Log.v(TAG, "after navtive startBCR"); 312 | return false; 313 | } 314 | 315 | public void finalize() { 316 | this.ppEngine = null; 317 | this.ppImage = null; 318 | this.ppField = null; 319 | this.mNativeOcr = null; 320 | this.pEngine = 0L; 321 | this.pImage = 0L; 322 | } 323 | 324 | public IDCard recognize(Context paramContext, String paramString) 325 | throws IOException { 326 | return recognize(paramContext, 2, paramString); 327 | } 328 | 329 | public IDCard recognize(Context paramContext, byte[] paramArrayOfByte) { 330 | return recognize(paramContext, 2, paramArrayOfByte, null); 331 | } 332 | 333 | public IDCard recognize(Context paramContext, byte[] paramArrayOfByte1, 334 | byte[] paramArrayOfByte2) { 335 | return recognize(paramContext, 2, paramArrayOfByte1, paramArrayOfByte2); 336 | } 337 | } 338 | 339 | -------------------------------------------------------------------------------- /android/idcard-library/src/main/java/com/ym/idcard/reg/util/FileUtil.java: -------------------------------------------------------------------------------- 1 | 2 | package com.ym.idcard.reg.util; 3 | 4 | import java.io.BufferedReader; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | import java.util.UUID; 11 | 12 | public class FileUtil 13 | { 14 | public static boolean copyFile(String src, String dst) 15 | { 16 | boolean bresult = false; 17 | try 18 | { 19 | File in = new File(src); 20 | File out = new File(dst); 21 | FileInputStream inFile = new FileInputStream(in); 22 | FileOutputStream outFile = new FileOutputStream(out); 23 | byte[] buffer = new byte[1024]; 24 | 25 | int len = 0; 26 | while ((len = inFile.read(buffer)) != -1) { 27 | outFile.write(buffer, 0, len); 28 | } 29 | inFile.close(); 30 | outFile.close(); 31 | bresult = true; 32 | 33 | } catch (IOException localIOException) 34 | { 35 | bresult = false; 36 | } 37 | return bresult; 38 | } 39 | 40 | public static boolean deleteFile(String filepath) 41 | { 42 | File file = new File(filepath); 43 | if (!file.exists()) 44 | return true; 45 | return file.delete(); 46 | } 47 | 48 | public static boolean exist(String filepath) 49 | { 50 | if (filepath == null) 51 | return false; 52 | return new File(filepath).exists(); 53 | } 54 | 55 | public static void generateOtherImg(String imagePath) 56 | { 57 | } 58 | 59 | public static byte[] getBytesFromFile(File file) 60 | throws IOException 61 | { 62 | FileInputStream is = new FileInputStream(file); 63 | long length = file.length(); 64 | if (length > Integer.MAX_VALUE) 65 | { 66 | is.close(); 67 | throw new IOException("File is to large " + file.getName()); 68 | } 69 | byte[] bytes = new byte[(int) length]; 70 | int offset = 0; 71 | int numRead = 0; 72 | try 73 | { 74 | while ((numRead = is.read(bytes, offset, bytes.length - offset)) > 0) { 75 | offset += numRead; 76 | } 77 | if (offset < length) { 78 | throw new IOException("Could not completely read file " + file.getName()); 79 | } 80 | } catch (Exception localException) 81 | { 82 | } finally 83 | { 84 | is.close(); 85 | } 86 | return bytes; 87 | } 88 | 89 | public static byte[] getBytesFromFile(String path) 90 | throws IOException 91 | { 92 | return getBytesFromFile(new File(path)); 93 | } 94 | 95 | public static int getFileLength(String filepath) 96 | { 97 | File file = new File(filepath); 98 | if (!file.exists()) 99 | return -1; 100 | return (int) file.length(); 101 | } 102 | 103 | public static String getStrFromFile(File file) 104 | throws IOException 105 | { 106 | String result = ""; 107 | FileInputStream is = new FileInputStream(file); 108 | if (file.length() > Integer.MAX_VALUE) 109 | { 110 | is.close(); 111 | throw new IOException("File is too large " + file.getName()); 112 | } 113 | StringBuffer localStringBuffer = new StringBuffer(); 114 | BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader( 115 | is, "GBK")); 116 | String str1 = null; 117 | while ((str1 = localBufferedReader.readLine()) != null) 118 | { 119 | localStringBuffer.append(str1); 120 | localStringBuffer.append("\n"); 121 | } 122 | result = localStringBuffer.toString(); 123 | is.close(); 124 | return result; 125 | } 126 | 127 | public static boolean isDirectory(String filepath) 128 | { 129 | return new File(filepath).isDirectory(); 130 | } 131 | 132 | public static boolean makeSureDirExist(String dirpath) 133 | { 134 | boolean bool = true; 135 | File file = new File(dirpath); 136 | if (!file.exists()) 137 | bool = file.mkdir(); 138 | return bool; 139 | } 140 | 141 | public static boolean makeSureFileExist(String filepath) 142 | { 143 | boolean result = false; 144 | File localFile = new File(filepath); 145 | if (localFile.exists()) 146 | return true; 147 | try 148 | { 149 | result = localFile.createNewFile(); 150 | } catch (IOException localIOException) 151 | { 152 | result = false; 153 | } 154 | return result; 155 | } 156 | 157 | public static int makeSureFileExistEx(String filepath) 158 | { 159 | File file = new File(filepath); 160 | if (!file.exists()) { 161 | try { 162 | if (file.createNewFile()) { 163 | return 0; 164 | } 165 | } catch (IOException e) { 166 | } 167 | return -1; 168 | } 169 | return (int) file.length(); 170 | } 171 | 172 | public static String newImageName() 173 | { 174 | return UUID.randomUUID().toString().replaceAll("-", "") + ".jpg"; 175 | } 176 | 177 | public void finalize() 178 | { 179 | } 180 | } 181 | 182 | /* 183 | * Location: 184 | * D:\document\bsd_work\一体机资料\测试app\com.newland.activity\classes_dex2jar.jar 185 | * Qualified Name: com.yunmai.android.other.FileUtil JD-Core Version: 0.5.4 186 | */ 187 | -------------------------------------------------------------------------------- /android/idcard-library/src/main/java/com/ym/idcard/reg/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.ym.idcard.reg.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | public class StringUtil 6 | { 7 | public static String convertAscIIToUnicode(byte[] array) 8 | { 9 | String str = ""; 10 | try 11 | { 12 | byte[] text = filterAndCut(array); 13 | if (text != null) 14 | { 15 | str = new String(text, "ISO-8859-1"); 16 | } 17 | } 18 | catch (UnsupportedEncodingException localUnsupportedEncodingException) 19 | { 20 | } 21 | return str.trim(); 22 | } 23 | 24 | public static String convertBig5ToUnicode(byte[] array) 25 | { 26 | String str = ""; 27 | try 28 | { 29 | byte[] text = filterAndCut(array); 30 | if (text != null) 31 | { 32 | str = new String(text, "big5"); 33 | } 34 | } 35 | catch (UnsupportedEncodingException localUnsupportedEncodingException) 36 | { 37 | } 38 | return str.trim(); 39 | } 40 | 41 | public static String convertGbkToUnicode(byte[] array) 42 | { 43 | String str = ""; 44 | try 45 | { 46 | byte[] text = filterAndCut(array); 47 | if (text != null) 48 | { 49 | str = new String(text, "GBK"); 50 | } 51 | } 52 | catch (UnsupportedEncodingException localUnsupportedEncodingException) 53 | { 54 | } 55 | return str.trim(); 56 | } 57 | 58 | public static byte[] convertToUnicode(String str) 59 | { 60 | byte[] result = null; 61 | try 62 | { 63 | byte[] res = str.getBytes("utf-8"); 64 | result = new byte[res.length + 1]; 65 | for(int i = 0; i 2 | IdCardLibrary 3 | 4 | -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ScanIdCard' 2 | 3 | include ':app', ':idcard-library' 4 | 5 | include ':app' 6 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ScanIdCard", 3 | "displayName": "ScanIdCard" 4 | } -------------------------------------------------------------------------------- /debug.log: -------------------------------------------------------------------------------- 1 | [0627/140842:ERROR:tcp_listen_socket.cc(76)] Could not bind socket to 127.0.0.1:6004 2 | [0627/140842:ERROR:node_debugger.cc(86)] Cannot start debugger server 3 | -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | import { 2 | AppRegistry, 3 | } from 'react-native'; 4 | import Scan from './js/scan.js' 5 | AppRegistry.registerComponent('ScanIdCard', () => Scan); -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | export default class ScanIdCard extends Component { 16 | render() { 17 | return ( 18 | 19 | 20 | Welcome to React Native! 21 | 22 | 23 | To get started, edit index.ios.js 24 | 25 | 26 | Press Cmd+R to reload,{'\n'} 27 | Cmd+D or shake for dev menu 28 | 29 | 30 | ); 31 | } 32 | } 33 | 34 | const styles = StyleSheet.create({ 35 | container: { 36 | flex: 1, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | backgroundColor: '#F5FCFF', 40 | }, 41 | welcome: { 42 | fontSize: 20, 43 | textAlign: 'center', 44 | margin: 10, 45 | }, 46 | instructions: { 47 | textAlign: 'center', 48 | color: '#333333', 49 | marginBottom: 5, 50 | }, 51 | }); 52 | 53 | AppRegistry.registerComponent('ScanIdCard', () => ScanIdCard); 54 | -------------------------------------------------------------------------------- /ios/ScanIdCard-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ios/ScanIdCard-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/ScanIdCard.xcodeproj/xcshareddata/xcschemes/ScanIdCard-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/ScanIdCard.xcodeproj/xcshareddata/xcschemes/ScanIdCard.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/ScanIdCard/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/ScanIdCard/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"ScanIdCard" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ios/ScanIdCard/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/ScanIdCard/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /ios/ScanIdCard/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ScanIdCard 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UIViewControllerBasedStatusBarAppearance 40 | 41 | NSLocationWhenInUseUsageDescription 42 | 43 | NSAppTransportSecurity 44 | 45 | 46 | NSExceptionDomains 47 | 48 | localhost 49 | 50 | NSExceptionAllowsInsecureHTTPLoads 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ios/ScanIdCard/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/ScanIdCardTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/ScanIdCardTests/ScanIdCardTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface ScanIdCardTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation ScanIdCardTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /js/scan.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { 3 | AppRegistry, 4 | StyleSheet, 5 | Text, 6 | Vibration, 7 | View, 8 | TextInput, 9 | DeviceEventEmitter 10 | } from 'react-native'; 11 | 12 | import ScanView from '../native_ui/ScanView.js'; 13 | import TextInputWidget from './TextInputWidget.js'; 14 | import {Dimensions} from 'react-native' 15 | 16 | const w = Dimensions.get('window').width 17 | 18 | class ScanScreen extends Component { 19 | constructor(props) { 20 | super(props); 21 | 22 | this.state = { 23 | torchMode: 'off', 24 | cameraType: 'back', 25 | idcard: '身份证号', 26 | name: '', 27 | sex: '', 28 | age: '' 29 | }; 30 | } 31 | 32 | componentWillMount() { 33 | this.listener = DeviceEventEmitter.addListener('scanCallBack', this.scanCallBack.bind(this)); //对应了原生端的名字 34 | } 35 | 36 | componentWillUnmount() { 37 | this.listener && this.listener.remove(); //记得remove哦 38 | this.listener = null; 39 | } 40 | 41 | scanCallBack(e) { 42 | alert(e.name+":"+e.id); 43 | //this.setState({ 44 | // idcard : e.id, 45 | // name : e.name, 46 | // sex: e.sex, 47 | // age: e.age 48 | //}) 49 | } 50 | 51 | render() { 52 | return ( 53 | 57 | 58 | ); 59 | } 60 | 61 | } 62 | 63 | export default ScanScreen; -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true 5 | }, 6 | "exclude": [ 7 | "node_modules" 8 | ] 9 | } -------------------------------------------------------------------------------- /native_ui/ScanView.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { 4 | Component 5 | } from 'react'; 6 | import { 7 | requireNativeComponent, 8 | StyleSheet, 9 | View, 10 | Text, 11 | } from 'react-native'; 12 | import PropTypes from 'prop-types'; 13 | 14 | import Viewfinder from './Viewfinder'; 15 | 16 | class ScanView extends Component { 17 | constructor(props) { 18 | super(props); 19 | 20 | } 21 | 22 | render() { 23 | 24 | return ( 25 | 26 | 27 | 28 | ); 29 | } 30 | } 31 | 32 | ScanView.propTypes = { 33 | ...View.propTypes, 34 | cameraType: PropTypes.string, 35 | torchMode: PropTypes.string, 36 | 37 | }; 38 | 39 | ScanView.defaultProps = { 40 | showViewFinder: true, 41 | }; 42 | 43 | var RCTScanView = requireNativeComponent('RCTScanView', ScanView, { 44 | nativeOnly: {onChange: true} 45 | }); 46 | 47 | module.exports = ScanView; 48 | -------------------------------------------------------------------------------- /native_ui/Viewfinder.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | Component, 3 | PropTypes, 4 | } from 'react'; 5 | import { 6 | ActivityIndicator, 7 | Platform, 8 | StyleSheet, 9 | View, 10 | } from 'react-native'; 11 | 12 | class Viewfinder extends Component { 13 | constructor(props) { 14 | super(props); 15 | 16 | this.getBackgroundColor = this.getBackgroundColor.bind(this); 17 | this.getSizeStyles = this.getSizeStyles.bind(this); 18 | this.getEdgeSizeStyles = this.getEdgeSizeStyles.bind(this); 19 | this.renderLoadingIndicator = this.renderLoadingIndicator.bind(this); 20 | } 21 | 22 | getBackgroundColor() { 23 | return ({ 24 | backgroundColor: this.props.backgroundColor, 25 | }); 26 | } 27 | 28 | getEdgeColor() { 29 | return ({ 30 | borderColor: this.props.color, 31 | }); 32 | } 33 | 34 | getSizeStyles() { 35 | return ({ 36 | height: this.props.height, 37 | width: this.props.width, 38 | }); 39 | } 40 | 41 | getEdgeSizeStyles() { 42 | return ({ 43 | height: this.props.borderLength, 44 | width: this.props.borderLength, 45 | }); 46 | } 47 | 48 | renderLoadingIndicator() { 49 | if (!this.props.isLoading) { 50 | return null; 51 | } 52 | 53 | return ( 54 | 59 | ); 60 | } 61 | 62 | render() { 63 | return ( 64 | 65 | 66 | 75 | 84 | {this.renderLoadingIndicator()} 85 | 94 | 103 | 104 | 105 | ); 106 | } 107 | }; 108 | 109 | Viewfinder.propTypes = { 110 | backgroundColor: PropTypes.string, 111 | borderWidth: PropTypes.number, 112 | borderLength: PropTypes.number, 113 | color: PropTypes.string, 114 | height: PropTypes.number, 115 | isLoading: PropTypes.bool, 116 | width: PropTypes.number, 117 | }; 118 | 119 | Viewfinder.defaultProps = { 120 | backgroundColor: 'transparent', 121 | borderWidth: 2, 122 | borderLength: 30, 123 | color: 'white', 124 | height: 200, 125 | isLoading: false, 126 | width: 200, 127 | }; 128 | 129 | var styles = StyleSheet.create({ 130 | container: { 131 | alignItems: 'center', 132 | justifyContent: 'center', 133 | position: 'absolute', 134 | top: 0, 135 | right: 0, 136 | bottom: 0, 137 | left: 0, 138 | }, 139 | viewfinder: { 140 | alignItems: 'center', 141 | justifyContent: 'center', 142 | }, 143 | topLeftEdge: { 144 | position: 'absolute', 145 | top: 0, 146 | left: 0, 147 | }, 148 | topRightEdge: { 149 | position: 'absolute', 150 | top: 0, 151 | right: 0, 152 | }, 153 | bottomLeftEdge: { 154 | position: 'absolute', 155 | bottom: 0, 156 | left: 0, 157 | }, 158 | bottomRightEdge: { 159 | position: 'absolute', 160 | bottom: 0, 161 | right: 0, 162 | }, 163 | }); 164 | 165 | module.exports = Viewfinder; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-scanidcard", 3 | "version": "0.0.1", 4 | "description": "身份证扫描识别", 5 | "keywords": [ 6 | "react-native", 7 | "scanidcard", 8 | "scan", 9 | "idcard", 10 | "react-native-scanidcard" 11 | ], 12 | "author": "mmjbds999", 13 | "main": "index.android.js", 14 | "dependencies": { 15 | "abab": "^1.0.3", 16 | "absolute-path": "^0.0.0", 17 | "accepts": "^1.2.13", 18 | "acorn": "^4.0.13", 19 | "align-text": "^0.1.4", 20 | "acorn-globals": "^3.1.0", 21 | "ajv": "^4.11.8", 22 | "amdefine": "^1.0.1", 23 | "ansi": "^0.3.1", 24 | "ansi-escapes": "^1.4.0", 25 | "ansi-regex": "^2.1.1", 26 | "ansi-styles": "^2.2.1", 27 | "anymatch": "^1.3.0", 28 | "are-we-there-yet": "^1.1.4", 29 | "append-transform": "^0.4.0", 30 | "arr-flatten": "^1.0.3", 31 | "argparse": "^1.0.9", 32 | "array-differ": "^1.0.0", 33 | "arr-diff": "^2.0.0", 34 | "array-equal": "^1.0.0", 35 | "array-filter": "^0.0.1", 36 | "array-map": "^0.0.0", 37 | "array-reduce": "^0.0.0", 38 | "arrify": "^1.0.1", 39 | "array-uniq": "^1.0.3", 40 | "array-unique": "^0.2.1", 41 | "art": "^0.10.1", 42 | "asn1": "^0.2.3", 43 | "asap": "^2.0.5", 44 | "assert-plus": "^0.2.0", 45 | "asynckit": "^0.4.0", 46 | "async": "^2.4.1", 47 | "aws4": "^1.6.0", 48 | "babel-code-frame": "^6.22.0", 49 | "babel-core": "^6.24.1", 50 | "aws-sign2": "^0.6.0", 51 | "babel-generator": "^6.24.1", 52 | "babel-helper-call-delegate": "^6.24.1", 53 | "babel-helper-builder-react-jsx": "^6.24.1", 54 | "babel-helper-function-name": "^6.24.1", 55 | "babel-helper-hoist-variables": "^6.24.1", 56 | "babel-helper-define-map": "^6.24.1", 57 | "babel-helper-get-function-arity": "^6.24.1", 58 | "babel-helper-optimise-call-expression": "^6.24.1", 59 | "babel-helper-regex": "^6.24.1", 60 | "babel-helper-remap-async-to-generator": "^6.24.1", 61 | "babel-helper-replace-supers": "^6.24.1", 62 | "babel-jest": "^20.0.3", 63 | "babel-helpers": "^6.24.1", 64 | "babel-plugin-check-es2015-constants": "^6.22.0", 65 | "babel-messages": "^6.23.0", 66 | "babel-plugin-external-helpers": "^6.22.0", 67 | "babel-plugin-istanbul": "^4.1.4", 68 | "babel-plugin-jest-hoist": "^20.0.3", 69 | "babel-plugin-react-transform": "^2.0.2", 70 | "babel-plugin-syntax-async-functions": "^6.13.0", 71 | "babel-plugin-syntax-class-properties": "^6.13.0", 72 | "babel-plugin-syntax-flow": "^6.18.0", 73 | "babel-plugin-syntax-jsx": "^6.18.0", 74 | "babel-plugin-syntax-object-rest-spread": "^6.13.0", 75 | "babel-plugin-syntax-trailing-function-commas": "^6.22.0", 76 | "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", 77 | "babel-plugin-transform-async-to-generator": "^6.16.0", 78 | "babel-plugin-transform-es2015-block-scoping": "^6.24.1", 79 | "babel-plugin-transform-class-properties": "^6.24.1", 80 | "babel-plugin-transform-es2015-classes": "^6.24.1", 81 | "babel-plugin-transform-es2015-computed-properties": "^6.24.1", 82 | "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", 83 | "babel-plugin-transform-es2015-destructuring": "^6.23.0", 84 | "babel-plugin-transform-es2015-for-of": "^6.23.0", 85 | "babel-plugin-transform-es2015-function-name": "^6.24.1", 86 | "babel-plugin-transform-es2015-literals": "^6.22.0", 87 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 88 | "babel-plugin-transform-es2015-object-super": "^6.24.1", 89 | "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", 90 | "babel-plugin-transform-es2015-parameters": "^6.24.1", 91 | "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", 92 | "babel-plugin-transform-es2015-spread": "^6.22.0", 93 | "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", 94 | "babel-plugin-transform-es2015-template-literals": "^6.22.0", 95 | "babel-plugin-transform-es3-member-expression-literals": "^6.22.0", 96 | "babel-plugin-transform-flow-strip-types": "^6.22.0", 97 | "babel-plugin-transform-object-rest-spread": "^6.23.0", 98 | "babel-plugin-transform-es3-property-literals": "^6.22.0", 99 | "babel-plugin-transform-react-display-name": "^6.23.0", 100 | "babel-plugin-transform-object-assign": "^6.22.0", 101 | "babel-plugin-transform-react-jsx": "^6.24.1", 102 | "babel-plugin-transform-react-jsx-source": "^6.22.0", 103 | "babel-plugin-transform-strict-mode": "^6.24.1", 104 | "babel-plugin-transform-regenerator": "^6.24.1", 105 | "babel-polyfill": "^6.23.0", 106 | "babel-preset-es2015-node": "^6.1.1", 107 | "babel-preset-fbjs": "^2.1.2", 108 | "babel-preset-react-native": "^1.9.2", 109 | "babel-preset-jest": "^20.0.3", 110 | "babel-runtime": "^6.23.0", 111 | "babel-register": "^6.24.1", 112 | "babel-template": "^6.24.1", 113 | "babel-traverse": "^6.24.1", 114 | "babel-types": "^6.24.1", 115 | "babylon": "^6.17.2", 116 | "balanced-match": "^0.4.2", 117 | "base64-js": "^1.2.0", 118 | "base64-url": "^1.2.1", 119 | "basic-auth": "^1.0.4", 120 | "basic-auth-connect": "^1.0.0", 121 | "bcrypt-pbkdf": "^1.0.1", 122 | "batch": "^0.5.3", 123 | "beeper": "^1.1.1", 124 | "big-integer": "^1.6.23", 125 | "body-parser": "^1.13.3", 126 | "boom": "^2.10.1", 127 | "bplist-creator": "^0.0.7", 128 | "bplist-parser": "^0.1.1", 129 | "brace-expansion": "^1.1.7", 130 | "braces": "^1.8.5", 131 | "browser-resolve": "^1.11.2", 132 | "bytes": "^2.1.0", 133 | "bser": "^1.0.3", 134 | "callsites": "^2.0.0", 135 | "builtin-modules": "^1.1.1", 136 | "camelcase": "^3.0.0", 137 | "caseless": "^0.12.0", 138 | "center-align": "^0.1.3", 139 | "ci-info": "^1.0.0", 140 | "chalk": "^1.1.3", 141 | "cli-width": "^2.1.0", 142 | "cliui": "^3.2.0", 143 | "cli-cursor": "^1.0.2", 144 | "clone": "^1.0.2", 145 | "clone-stats": "^0.0.1", 146 | "co": "^4.6.0", 147 | "code-point-at": "^1.1.0", 148 | "color-convert": "^1.9.0", 149 | "color-name": "^1.1.2", 150 | "combined-stream": "^1.0.5", 151 | "commander": "^2.9.0", 152 | "compressible": "^2.0.10", 153 | "compression": "^1.5.2", 154 | "concat-map": "^0.0.1", 155 | "concat-stream": "^1.6.0", 156 | "connect": "^2.30.2", 157 | "connect-timeout": "^1.6.2", 158 | "content-type-parser": "^1.0.1", 159 | "content-type": "^1.0.2", 160 | "convert-source-map": "^1.5.0", 161 | "cookie": "^0.1.3", 162 | "cookie-parser": "^1.3.5", 163 | "core-js": "^2.4.1", 164 | "cookie-signature": "^1.0.6", 165 | "core-util-is": "^1.0.2", 166 | "crc": "^3.3.0", 167 | "cross-spawn": "^3.0.1", 168 | "csrf": "^3.0.6", 169 | "cryptiles": "^2.0.5", 170 | "cssom": "^0.3.2", 171 | "csurf": "^1.8.3", 172 | "cssstyle": "^0.2.37", 173 | "debug": "^2.6.8", 174 | "dashdash": "^1.14.1", 175 | "dateformat": "^2.0.0", 176 | "decamelize": "^1.2.0", 177 | "default-require-extensions": "^1.0.0", 178 | "deep-is": "^0.1.3", 179 | "delegates": "^1.0.0", 180 | "delayed-stream": "^1.0.0", 181 | "denodeify": "^1.2.1", 182 | "depd": "^1.0.1", 183 | "destroy": "^1.0.4", 184 | "detect-indent": "^4.0.0", 185 | "diff": "^3.2.0", 186 | "dom-walk": "^0.1.1", 187 | "duplexer2": "^0.0.2", 188 | "ecc-jsbn": "^0.1.1", 189 | "ee-first": "^1.1.1", 190 | "encoding": "^0.1.12", 191 | "error-ex": "^1.3.1", 192 | "errno": "^0.1.4", 193 | "escape-html": "^1.0.2", 194 | "errorhandler": "^1.4.3", 195 | "escape-string-regexp": "^1.0.5", 196 | "escodegen": "^1.8.1", 197 | "esutils": "^2.0.2", 198 | "estraverse": "^1.9.3", 199 | "esprima": "^3.1.3", 200 | "etag": "^1.7.0", 201 | "event-target-shim": "^1.1.1", 202 | "exec-sh": "^0.2.0", 203 | "expand-brackets": "^0.1.5", 204 | "exit-hook": "^1.1.1", 205 | "expand-range": "^1.8.2", 206 | "express-session": "^1.11.3", 207 | "extsprintf": "^1.0.2", 208 | "extglob": "^0.3.2", 209 | "extend": "^3.0.1", 210 | "fancy-log": "^1.3.0", 211 | "fast-levenshtein": "^2.0.6", 212 | "fb-watchman": "^1.9.2", 213 | "fbjs": "^0.8.12", 214 | "fbjs-scripts": "^0.7.1", 215 | "figures": "^1.7.0", 216 | "fileset": "^2.0.3", 217 | "filename-regex": "^2.0.1", 218 | "fill-range": "^2.2.3", 219 | "finalhandler": "^0.4.0", 220 | "find-up": "^2.1.0", 221 | "for-in": "^1.0.2", 222 | "forever-agent": "^0.6.1", 223 | "form-data": "^2.1.4", 224 | "fresh": "^0.3.0", 225 | "for-own": "^0.1.5", 226 | "fs-extra": "^1.0.0", 227 | "fs.realpath": "^1.0.0", 228 | "get-caller-file": "^1.0.2", 229 | "gauge": "^1.2.7", 230 | "glob": "^7.1.2", 231 | "getpass": "^0.1.7", 232 | "glob-base": "^0.3.0", 233 | "global": "^4.3.2", 234 | "glob-parent": "^2.0.0", 235 | "globals": "^9.17.0", 236 | "graceful-fs": "^4.1.11", 237 | "glogg": "^1.0.0", 238 | "growly": "^1.3.0", 239 | "gulp-util": "^3.0.8", 240 | "graceful-readlink": "^1.0.1", 241 | "gulplog": "^1.0.0", 242 | "handlebars": "^4.0.10", 243 | "har-schema": "^1.0.5", 244 | "har-validator": "^4.2.1", 245 | "has-ansi": "^2.0.0", 246 | "has-gulplog": "^0.1.0", 247 | "has-unicode": "^2.0.1", 248 | "has-flag": "^1.0.0", 249 | "hoek": "^2.16.3", 250 | "hawk": "^3.1.3", 251 | "home-or-tmp": "^2.0.0", 252 | "hosted-git-info": "^2.4.2", 253 | "html-encoding-sniffer": "^1.0.1", 254 | "http-errors": "^1.3.1", 255 | "http-signature": "^1.1.1", 256 | "iconv-lite": "^0.4.11", 257 | "image-size": "^0.3.5", 258 | "imurmurhash": "^0.1.4", 259 | "inflight": "^1.0.6", 260 | "immutable": "^3.7.6", 261 | "inquirer": "^0.12.0", 262 | "inherits": "^2.0.3", 263 | "invariant": "^2.2.2", 264 | "invert-kv": "^1.0.0", 265 | "is-arrayish": "^0.2.1", 266 | "is-buffer": "^1.1.5", 267 | "is-builtin-module": "^1.0.0", 268 | "is-ci": "^1.0.10", 269 | "is-dotfile": "^1.0.3", 270 | "is-equal-shallow": "^0.1.3", 271 | "is-extglob": "^1.0.0", 272 | "is-extendable": "^0.1.1", 273 | "is-finite": "^1.0.2", 274 | "is-fullwidth-code-point": "^1.0.0", 275 | "is-number": "^2.1.0", 276 | "is-posix-bracket": "^0.1.1", 277 | "is-primitive": "^2.0.0", 278 | "is-glob": "^2.0.1", 279 | "is-stream": "^1.1.0", 280 | "is-typedarray": "^1.0.0", 281 | "isarray": "^1.0.0", 282 | "is-utf8": "^0.2.1", 283 | "isemail": "^1.2.0", 284 | "isexe": "^2.0.0", 285 | "isobject": "^2.1.0", 286 | "isomorphic-fetch": "^2.2.1", 287 | "isstream": "^0.1.2", 288 | "istanbul-api": "^1.1.9", 289 | "istanbul-lib-coverage": "^1.1.1", 290 | "istanbul-lib-hook": "^1.0.7", 291 | "istanbul-lib-instrument": "^1.7.2", 292 | "istanbul-lib-report": "^1.1.1", 293 | "istanbul-lib-source-maps": "^1.2.1", 294 | "istanbul-reports": "^1.1.1", 295 | "jest": "^20.0.4", 296 | "jest-changed-files": "^20.0.3", 297 | "jest-cli": "^20.0.4", 298 | "jest-config": "^20.0.4", 299 | "jest-diff": "^20.0.3", 300 | "jest-docblock": "^20.0.3", 301 | "jest-environment-jsdom": "^20.0.3", 302 | "jest-environment-node": "^20.0.3", 303 | "jest-haste-map": "^20.0.4", 304 | "jest-jasmine2": "^20.0.4", 305 | "jest-matchers": "^20.0.3", 306 | "jest-matcher-utils": "^20.0.3", 307 | "jest-message-util": "^20.0.3", 308 | "jest-mock": "^20.0.3", 309 | "jest-resolve": "^20.0.4", 310 | "jest-regex-util": "^20.0.3", 311 | "jest-resolve-dependencies": "^20.0.3", 312 | "jest-runtime": "^20.0.4", 313 | "jest-snapshot": "^20.0.3", 314 | "jest-util": "^20.0.3", 315 | "jodid25519": "^1.0.2", 316 | "jest-validate": "^20.0.3", 317 | "joi": "^6.10.1", 318 | "js-tokens": "^3.0.1", 319 | "js-yaml": "^3.8.4", 320 | "jsbn": "^0.1.1", 321 | "jsesc": "^1.3.0", 322 | "jsdom": "^9.12.0", 323 | "json-schema": "^0.2.3", 324 | "json-stable-stringify": "^1.0.1", 325 | "json-stringify-safe": "^5.0.1", 326 | "json5": "^0.4.0", 327 | "jsonfile": "^2.4.0", 328 | "jsonify": "^0.0.0", 329 | "jsprim": "^1.4.0", 330 | "kind-of": "^3.2.2", 331 | "lazy-cache": "^1.0.4", 332 | "klaw": "^1.3.1", 333 | "lcid": "^1.0.0", 334 | "left-pad": "^1.1.3", 335 | "leven": "^2.1.0", 336 | "levn": "^0.3.0", 337 | "load-json-file": "^1.1.0", 338 | "locate-path": "^2.0.0", 339 | "lodash": "^4.17.4", 340 | "lodash._basecopy": "^3.0.1", 341 | "lodash._basetostring": "^3.0.1", 342 | "lodash._getnative": "^3.9.1", 343 | "lodash._basevalues": "^3.0.0", 344 | "lodash._isiterateecall": "^3.0.9", 345 | "lodash._reevaluate": "^3.0.0", 346 | "lodash._reescape": "^3.0.0", 347 | "lodash._root": "^3.0.1", 348 | "lodash._reinterpolate": "^3.0.0", 349 | "lodash.escape": "^3.2.0", 350 | "lodash.isarguments": "^3.1.0", 351 | "lodash.keys": "^3.1.2", 352 | "lodash.isarray": "^3.0.4", 353 | "lodash.pad": "^4.5.1", 354 | "lodash.padstart": "^4.6.1", 355 | "lodash.restparam": "^3.6.1", 356 | "lodash.padend": "^4.6.1", 357 | "lodash.template": "^3.6.2", 358 | "lodash.templatesettings": "^3.1.1", 359 | "longest": "^1.0.1", 360 | "loose-envify": "^1.3.1", 361 | "lru-cache": "^4.0.2", 362 | "media-typer": "^0.3.0", 363 | "makeerror": "^1.0.11", 364 | "method-override": "^2.3.9", 365 | "merge": "^1.2.0", 366 | "methods": "^1.1.2", 367 | "mime": "^1.3.6", 368 | "micromatch": "^2.3.11", 369 | "mime-db": "^1.23.0", 370 | "mime-types": "^2.1.11", 371 | "min-document": "^2.19.0", 372 | "minimatch": "^3.0.4", 373 | "minimist": "^1.2.0", 374 | "mkdirp": "^0.5.1", 375 | "moment": "^2.18.1", 376 | "morgan": "^1.6.1", 377 | "ms": "^2.0.0", 378 | "multiparty": "^3.3.2", 379 | "multipipe": "^0.1.2", 380 | "mute-stream": "^0.0.5", 381 | "natural-compare": "^1.4.0", 382 | "node-fetch": "^1.7.0", 383 | "negotiator": "^0.5.3", 384 | "node-int64": "^0.4.0", 385 | "node-notifier": "^5.1.2", 386 | "normalize-package-data": "^2.3.8", 387 | "normalize-path": "^2.1.1", 388 | "npmlog": "^2.0.4", 389 | "number-is-nan": "^1.0.1", 390 | "nwmatcher": "^1.4.0", 391 | "oauth-sign": "^0.8.2", 392 | "object.omit": "^2.0.1", 393 | "object-assign": "^4.1.1", 394 | "on-finished": "^2.3.0", 395 | "on-headers": "^1.0.1", 396 | "once": "^1.4.0", 397 | "onetime": "^1.1.0", 398 | "opn": "^3.0.3", 399 | "optionator": "^0.8.2", 400 | "optimist": "^0.6.1", 401 | "os-homedir": "^1.0.2", 402 | "options": "^0.0.6", 403 | "os-locale": "^1.4.0", 404 | "p-limit": "^1.1.0", 405 | "os-tmpdir": "^1.0.2", 406 | "p-locate": "^2.0.0", 407 | "p-map": "^1.1.1", 408 | "parse-glob": "^3.0.4", 409 | "parse-json": "^2.2.0", 410 | "parse5": "^1.5.1", 411 | "parseurl": "^1.3.1", 412 | "path-exists": "^2.1.0", 413 | "path-is-absolute": "^1.0.1", 414 | "path-parse": "^1.0.5", 415 | "path-type": "^1.1.0", 416 | "pause": "^0.1.0", 417 | "pegjs": "^0.10.0", 418 | "performance-now": "^0.2.0", 419 | "pinkie": "^2.0.4", 420 | "pify": "^2.3.0", 421 | "plist": "^1.2.0", 422 | "pinkie-promise": "^2.0.1", 423 | "prelude-ls": "^1.1.2", 424 | "preserve": "^0.2.0", 425 | "pretty-format": "^4.3.1", 426 | "private": "^0.1.7", 427 | "process": "^0.5.2", 428 | "process-nextick-args": "^1.0.7", 429 | "promise": "^7.1.1", 430 | "pseudomap": "^1.0.2", 431 | "punycode": "^1.4.1", 432 | "prr": "^0.0.0", 433 | "qs": "^4.0.0", 434 | "random-bytes": "^1.0.0", 435 | "randomatic": "^1.1.6", 436 | "range-parser": "^1.0.3", 437 | "raw-body": "^2.1.7", 438 | "react": "^16.0.0-alpha.6", 439 | "react-clone-referenced-element": "^1.0.1", 440 | "react-deep-force-update": "^1.0.1", 441 | "react-devtools-core": "^2.2.1", 442 | "react-native": "^0.44.2", 443 | "react-navigation": "^1.0.0-beta.11", 444 | "react-test-renderer": "^16.0.0-alpha.6", 445 | "react-proxy": "^1.1.8", 446 | "react-transform-hmr": "^1.0.4", 447 | "react-timer-mixin": "^0.13.3", 448 | "read-pkg": "^1.1.0", 449 | "read-pkg-up": "^1.0.1", 450 | "readable-stream": "^2.2.10", 451 | "readline2": "^1.0.1", 452 | "regenerate": "^1.3.2", 453 | "rebound": "^0.0.13", 454 | "regenerator-runtime": "^0.9.6", 455 | "regenerator-transform": "^0.9.11", 456 | "regex-cache": "^0.4.3", 457 | "regexpu-core": "^2.0.0", 458 | "regjsgen": "^0.2.0", 459 | "regjsparser": "^0.1.5", 460 | "remove-trailing-separator": "^1.0.1", 461 | "repeat-element": "^1.1.2", 462 | "repeat-string": "^1.6.1", 463 | "repeating": "^2.0.1", 464 | "request": "^2.81.0", 465 | "replace-ext": "^0.0.1", 466 | "require-directory": "^2.1.1", 467 | "require-main-filename": "^1.0.1", 468 | "resolve": "^1.3.3", 469 | "response-time": "^2.3.2", 470 | "restore-cursor": "^1.0.1", 471 | "right-align": "^0.1.3", 472 | "rimraf": "^2.6.1", 473 | "rndm": "^1.2.0", 474 | "rx-lite": "^3.1.2", 475 | "run-async": "^0.1.0", 476 | "safe-buffer": "^5.0.1", 477 | "sane": "^1.4.1", 478 | "sax": "^1.1.6", 479 | "semver": "^5.3.0", 480 | "send": "^0.13.2", 481 | "serve-index": "^1.7.3", 482 | "serve-favicon": "^2.3.2", 483 | "serve-static": "^1.10.3", 484 | "setimmediate": "^1.0.5", 485 | "set-blocking": "^2.0.0", 486 | "shell-quote": "^1.6.1", 487 | "shellwords": "^0.1.0", 488 | "simple-plist": "^0.2.1", 489 | "slash": "^1.0.0", 490 | "slide": "^1.1.6", 491 | "sntp": "^1.0.9", 492 | "source-map": "^0.5.6", 493 | "source-map-support": "^0.4.15", 494 | "sparkles": "^1.0.0", 495 | "spdx-correct": "^1.0.2", 496 | "spdx-expression-parse": "^1.0.4", 497 | "sprintf-js": "^1.0.3", 498 | "spdx-license-ids": "^1.2.2", 499 | "sshpk": "^1.13.0", 500 | "stacktrace-parser": "^0.1.4", 501 | "statuses": "^1.3.1", 502 | "stream-counter": "^0.2.0", 503 | "stream-buffers": "^2.2.0", 504 | "string-length": "^1.0.1", 505 | "string-width": "^1.0.2", 506 | "string_decoder": "^1.0.1", 507 | "stringstream": "^0.0.5", 508 | "strip-bom": "^3.0.0", 509 | "strip-ansi": "^3.0.1", 510 | "supports-color": "^2.0.0", 511 | "symbol-tree": "^3.2.2", 512 | "temp": "^0.8.3", 513 | "throat": "^3.0.0", 514 | "test-exclude": "^4.1.1", 515 | "through": "^2.3.8", 516 | "through2": "^2.0.3", 517 | "time-stamp": "^1.1.0", 518 | "tmpl": "^1.0.4", 519 | "to-fast-properties": "^1.0.3", 520 | "topo": "^1.1.0", 521 | "tough-cookie": "^2.3.2", 522 | "tr46": "^0.0.3", 523 | "tsscmp": "^1.0.5", 524 | "trim-right": "^1.0.1", 525 | "tweetnacl": "^0.14.5", 526 | "tunnel-agent": "^0.6.0", 527 | "type-check": "^0.3.2", 528 | "type-is": "^1.6.15", 529 | "ua-parser-js": "^0.7.12", 530 | "typedarray": "^0.0.6", 531 | "uglify-to-browserify": "^1.0.2", 532 | "uglify-js": "^2.7.5", 533 | "uid-safe": "^2.0.0", 534 | "unpipe": "^1.0.0", 535 | "ultron": "^1.0.2", 536 | "util-deprecate": "^1.0.2", 537 | "uuid": "^3.0.1", 538 | "utils-merge": "^1.0.0", 539 | "validate-npm-package-license": "^3.0.1", 540 | "vary": "^1.0.1", 541 | "verror": "^1.3.6", 542 | "vhost": "^3.0.2", 543 | "vinyl": "^0.5.3", 544 | "walker": "^1.0.7", 545 | "watch": "^0.10.0", 546 | "webidl-conversions": "^4.0.1", 547 | "whatwg-encoding": "^1.0.1", 548 | "whatwg-fetch": "^1.1.1", 549 | "whatwg-url": "^4.8.0", 550 | "which": "^1.2.14", 551 | "window-size": "^0.1.0", 552 | "which-module": "^1.0.0", 553 | "wordwrap": "^1.0.0", 554 | "wrap-ansi": "^2.1.0", 555 | "wrappy": "^1.0.2", 556 | "worker-farm": "^1.3.1", 557 | "write-file-atomic": "^1.3.4", 558 | "ws": "^1.1.4", 559 | "xcode": "^0.9.3", 560 | "xml-name-validator": "^2.0.1", 561 | "xmlbuilder": "^4.0.0", 562 | "xmldoc": "^0.4.0", 563 | "xmldom": "^0.1.27", 564 | "xpipe": "^1.0.5", 565 | "y18n": "^3.2.1", 566 | "xtend": "^4.0.1", 567 | "yallist": "^2.1.2", 568 | "yargs": "^6.6.0", 569 | "yargs-parser": "^4.2.1" 570 | }, 571 | "devDependencies": {}, 572 | "scripts": { 573 | "test": "echo \"Error: no test specified\" && exit 1" 574 | }, 575 | "repository": { 576 | "type": "git", 577 | "url": "git+https://github.com/mmjbds999/react-native-scanidcard.git" 578 | }, 579 | "license": "ISC", 580 | "bugs": { 581 | "url": "https://github.com/mmjbds999/react-native-scanidcard/issues" 582 | }, 583 | "homepage": "https://github.com/mmjbds999/react-native-scanidcard#readme" 584 | } 585 | --------------------------------------------------------------------------------