├── Example ├── .watchmanconfig ├── assets │ ├── ic_stop_36pt.png │ ├── ic_stop_36pt@2x.png │ ├── ic_stop_36pt@3x.png │ ├── ic_videocam_36pt.png │ ├── ic_flash_off_white.png │ ├── ic_flash_on_white.png │ ├── ic_camera_front_white.png │ ├── ic_camera_rear_white.png │ ├── ic_flash_auto_white.png │ ├── ic_flash_off_white@2x.png │ ├── ic_flash_off_white@3x.png │ ├── ic_flash_on_white@2x.png │ ├── ic_flash_on_white@3x.png │ ├── ic_photo_camera_36pt.png │ ├── ic_videocam_36pt@2x.png │ ├── ic_videocam_36pt@3x.png │ ├── ic_camera_rear_white@2x.png │ ├── ic_camera_rear_white@3x.png │ ├── ic_flash_auto_white@2x.png │ ├── ic_flash_auto_white@3x.png │ ├── ic_photo_camera_36pt@2x.png │ ├── ic_photo_camera_36pt@3x.png │ ├── ic_camera_front_white@2x.png │ └── ic_camera_front_white@3x.png ├── android │ ├── app │ │ ├── src │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ └── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── MainActivity.java │ │ ├── BUCK │ │ ├── proguard-rules.pro │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── keystores │ │ ├── debug.keystore.properties │ │ └── BUCK │ ├── settings.gradle │ ├── build.gradle │ ├── gradle.properties │ ├── gradlew.bat │ └── gradlew ├── .buckconfig ├── index.ios.js ├── index.android.js ├── package.json ├── README.md ├── ios │ ├── Example │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── AppDelegate.m │ │ └── Base.lproj │ │ │ └── LaunchScreen.xib │ ├── ExampleTests │ │ ├── Info.plist │ │ └── ExampleTests.m │ └── Example.xcodeproj │ │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Example.xcscheme │ │ └── project.pbxproj ├── .gitignore ├── .flowconfig └── Example.js ├── ios ├── CameraFocusSquare.h ├── RCTCamera.h ├── RCTSensorOrientationChecker.h ├── CameraFocusSquare.m ├── RCTSensorOrientationChecker.m ├── NSMutableDictionary+ImageMetadata.m ├── RCTCameraManager.h ├── RCTCamera.m └── RCTCamera.xcodeproj │ └── project.pbxproj ├── .gitignore ├── issue_template.md ├── package.json ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── lwansbrough │ └── RCTCamera │ ├── RCTCameraPackage.java │ ├── RCTCameraViewManager.java │ ├── RCTSensorOrientationChecker.java │ ├── RCTCameraViewFinder.java │ ├── RCTCameraView.java │ ├── RCTCamera.java │ └── RCTCameraModule.java ├── react-native-camera.podspec ├── LICENSE ├── index.js └── README.md /Example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /ios/CameraFocusSquare.h: -------------------------------------------------------------------------------- 1 | #import 2 | @interface RCTCameraFocusSquare : UIView 3 | @end -------------------------------------------------------------------------------- /Example/assets/ic_stop_36pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_stop_36pt.png -------------------------------------------------------------------------------- /Example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example 4 | 5 | -------------------------------------------------------------------------------- /Example/assets/ic_stop_36pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_stop_36pt@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_stop_36pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_stop_36pt@3x.png -------------------------------------------------------------------------------- /Example/assets/ic_videocam_36pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_videocam_36pt.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_off_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_off_white.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_on_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_on_white.png -------------------------------------------------------------------------------- /Example/assets/ic_camera_front_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_camera_front_white.png -------------------------------------------------------------------------------- /Example/assets/ic_camera_rear_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_camera_rear_white.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_auto_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_auto_white.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_off_white@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_off_white@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_off_white@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_off_white@3x.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_on_white@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_on_white@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_on_white@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_on_white@3x.png -------------------------------------------------------------------------------- /Example/assets/ic_photo_camera_36pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_photo_camera_36pt.png -------------------------------------------------------------------------------- /Example/assets/ic_videocam_36pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_videocam_36pt@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_videocam_36pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_videocam_36pt@3x.png -------------------------------------------------------------------------------- /Example/assets/ic_camera_rear_white@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_camera_rear_white@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_camera_rear_white@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_camera_rear_white@3x.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_auto_white@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_auto_white@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_flash_auto_white@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_flash_auto_white@3x.png -------------------------------------------------------------------------------- /Example/assets/ic_photo_camera_36pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_photo_camera_36pt@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_photo_camera_36pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_photo_camera_36pt@3x.png -------------------------------------------------------------------------------- /Example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /Example/assets/ic_camera_front_white@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_camera_front_white@2x.png -------------------------------------------------------------------------------- /Example/assets/ic_camera_front_white@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/assets/ic_camera_front_white@3x.png -------------------------------------------------------------------------------- /Example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcejohnson/react-native-camera/HEAD/Example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Example/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /Example/index.ios.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AppRegistry } from 'react-native'; 3 | 4 | import Example from './Example'; 5 | 6 | AppRegistry.registerComponent('Example', () => Example); 7 | -------------------------------------------------------------------------------- /Example/index.android.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AppRegistry } from 'react-native'; 3 | 4 | import Example from './Example'; 5 | 6 | AppRegistry.registerComponent('Example', () => Example); 7 | -------------------------------------------------------------------------------- /Example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Example' 2 | 3 | include ':app' 4 | include ':react-native-camera' 5 | project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android') 6 | -------------------------------------------------------------------------------- /Example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 3 | node_modules 4 | ios/RCTCamera.xcodeproj/xcuserdata 5 | ios/RCTCamera.xcodeproj/project.xcworkspace 6 | .DS_Store 7 | .idea 8 | *.iml 9 | android/build 10 | -------------------------------------------------------------------------------- /ios/RCTCamera.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "CameraFocusSquare.h" 4 | 5 | @class RCTCameraManager; 6 | 7 | @interface RCTCamera : UIView 8 | 9 | - (id)initWithManager:(RCTCameraManager*)manager bridge:(RCTBridge *)bridge; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "react": "15.0.2", 10 | "react-native": "^0.26.2", 11 | "react-native-camera": "file:../" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Example/README.md: -------------------------------------------------------------------------------- 1 | #### `Run example` 2 | 3 | From project root run through cli: 4 | - `cd Example/` 5 | - `npm install` 6 | 7 | For Android: 8 | - `adb reverse tcp:8081 tcp:8081` or in Dev Settings input COMPUTER_IP:8081 for debug server 9 | - `react-native run-android` 10 | 11 | For iOS build: 12 | - Open Example.xcodeproj with XCode 13 | - Change IP for jsCodeLocation in AppDelegate.m file 14 | - Run from XCode 15 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | ### Steps to reproduce 2 | 1. 3 | 2. 4 | 3. 5 | 6 | ### Expected behaviour 7 | Tell us what should happen 8 | 9 | ### Actual behaviour 10 | Tell us what happens instead 11 | 12 | ### Environment 13 | - **Node.js version**: 14 | - **React Native version**: 15 | - **React Native platform + platform version**: iOS 9.0, Android 5.0, etc 16 | 17 | ### react-native-camera 18 | **Version**: npm version or "master" 19 | -------------------------------------------------------------------------------- /Example/ios/Example/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 | -------------------------------------------------------------------------------- /Example/ios/Example/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 | -------------------------------------------------------------------------------- /Example/.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/IJ 26 | # 27 | .idea 28 | .gradle 29 | local.properties 30 | 31 | # node.js 32 | # 33 | node_modules/ 34 | npm-debug.log 35 | 36 | # BUCK 37 | buck-out/ 38 | \.buckd/ 39 | android/app/libs 40 | android/keystores/debug.keystore 41 | -------------------------------------------------------------------------------- /ios/RCTSensorOrientationChecker.h: -------------------------------------------------------------------------------- 1 | // 2 | // RCTSensorOrientationChecker.h 3 | // RCTCamera 4 | // 5 | // Created by Radu Popovici on 24/03/16. 6 | // 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void (^RCTSensorCallback) (UIInterfaceOrientation orientation); 13 | 14 | @interface RCTSensorOrientationChecker : NSObject 15 | 16 | @property (assign, nonatomic) UIInterfaceOrientation orientation; 17 | 18 | - (void)getDeviceOrientationWithBlock:(RCTSensorCallback)callback; 19 | - (AVCaptureVideoOrientation)convertToAVCaptureVideoOrientation:(UIInterfaceOrientation)orientation; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-camera", 3 | "repository": { 4 | "type" : "git", 5 | "url" : "https://github.com/lwansbrough/react-native-camera.git" 6 | }, 7 | "version": "0.3.8", 8 | "description": "A Camera component for React Native. Also reads barcodes.", 9 | "author": "Lochlan Wansbrough (http://lwansbrough.com)", 10 | "nativePackage": true, 11 | "license": "MIT", 12 | "homepage": "https://github.com/lwansbrough/react-native-camera", 13 | "keywords": [ 14 | "react-native", 15 | "react", 16 | "native", 17 | "camera", 18 | "qr", 19 | "code", 20 | "barcode" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.2.3' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.library' 12 | 13 | android { 14 | compileSdkVersion 23 15 | buildToolsVersion "23.0.1" 16 | 17 | defaultConfig { 18 | minSdkVersion 16 19 | targetSdkVersion 22 20 | versionCode 1 21 | versionName "1.0" 22 | } 23 | lintOptions { 24 | abortOnError false 25 | warning 'InvalidPackage' 26 | } 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | dependencies { 34 | compile "com.facebook.react:react-native:0.19.+" 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/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 "$projectDir/../../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /react-native-camera.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'react-native-camera' 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | s.description = package['description'] 10 | s.license = package['license'] 11 | s.author = package['author'] 12 | s.homepage = package['homepage'] 13 | s.source = { :git => 'https://github.com/lwansbrough/react-native-camera', :tag => s.version } 14 | 15 | s.requires_arc = true 16 | s.platform = :ios, '8.0' 17 | 18 | s.preserve_paths = 'LICENSE', 'README.md', 'package.json', 'index.js' 19 | s.source_files = 'ios/*.{h,m}' 20 | 21 | s.dependency 'React' 22 | end 23 | -------------------------------------------------------------------------------- /Example/ios/Example/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 | } -------------------------------------------------------------------------------- /Example/ios/ExampleTests/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 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /ios/CameraFocusSquare.m: -------------------------------------------------------------------------------- 1 | #import "CameraFocusSquare.h" 2 | #import 3 | 4 | const float squareLength = 80.0f; 5 | @implementation RCTCameraFocusSquare 6 | 7 | - (id)initWithFrame:(CGRect)frame 8 | { 9 | self = [super initWithFrame:frame]; 10 | if (self) { 11 | // Initialization code 12 | 13 | [self setBackgroundColor:[UIColor clearColor]]; 14 | [self.layer setBorderWidth:2.0]; 15 | [self.layer setCornerRadius:4.0]; 16 | [self.layer setBorderColor:[UIColor whiteColor].CGColor]; 17 | 18 | CABasicAnimation* selectionAnimation = [CABasicAnimation 19 | animationWithKeyPath:@"borderColor"]; 20 | selectionAnimation.toValue = (id)[UIColor blueColor].CGColor; 21 | selectionAnimation.repeatCount = 8; 22 | [self.layer addAnimation:selectionAnimation 23 | forKey:@"selectionAnimation"]; 24 | 25 | } 26 | return self; 27 | } 28 | @end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Loch Wansbrough 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraPackage.java: -------------------------------------------------------------------------------- 1 | package com.lwansbrough.RCTCamera; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.bridge.NativeModule; 9 | import com.facebook.react.bridge.ReactApplicationContext; 10 | import com.facebook.react.uimanager.ViewManager; 11 | import com.facebook.react.bridge.JavaScriptModule; 12 | 13 | public class RCTCameraPackage implements ReactPackage { 14 | 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactApplicationContext) { 17 | return Collections.singletonList(new RCTCameraModule(reactApplicationContext)); 18 | } 19 | 20 | @Override 21 | public List> createJSModules() { 22 | return Collections.emptyList(); 23 | } 24 | 25 | @Override 26 | public List createViewManagers(ReactApplicationContext reactApplicationContext) { 27 | //noinspection ArraysAsListWithZeroOrOneArgument 28 | return Collections.singletonList(new RCTCameraViewManager()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Example/android/app/src/main/java/com/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.lwansbrough.RCTCamera.RCTCameraPackage; 5 | import com.facebook.react.ReactPackage; 6 | import com.facebook.react.shell.MainReactPackage; 7 | 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | public class MainActivity extends ReactActivity { 12 | 13 | /** 14 | * Returns the name of the main component registered from JavaScript. 15 | * This is used to schedule rendering of the component. 16 | */ 17 | @Override 18 | protected String getMainComponentName() { 19 | return "Example"; 20 | } 21 | 22 | /** 23 | * Returns whether dev mode should be enabled. 24 | * This enables e.g. the dev menu. 25 | */ 26 | @Override 27 | protected boolean getUseDeveloperSupport() { 28 | return BuildConfig.DEBUG; 29 | } 30 | 31 | /** 32 | * A list of packages used by the app. If the app uses additional views 33 | * or modules besides the default ones, add more packages here. 34 | */ 35 | @Override 36 | protected List getPackages() { 37 | return Arrays.asList( 38 | new MainReactPackage(), 39 | new RCTCameraPackage() 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Example/ios/Example/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 | NSAllowsArbitraryLoads 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Example/android/app/BUCK: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | # To learn about Buck see [Docs](https://buckbuild.com/). 4 | # To run your application with Buck: 5 | # - install Buck 6 | # - `npm start` - to start the packager 7 | # - `cd android` 8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US` 9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 10 | # - `buck install -r android/app` - compile, install and run application 11 | # 12 | 13 | lib_deps = [] 14 | for jarfile in glob(['libs/*.jar']): 15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) 16 | lib_deps.append(':' + name) 17 | prebuilt_jar( 18 | name = name, 19 | binary_jar = jarfile, 20 | ) 21 | 22 | for aarfile in glob(['libs/*.aar']): 23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) 24 | lib_deps.append(':' + name) 25 | android_prebuilt_aar( 26 | name = name, 27 | aar = aarfile, 28 | ) 29 | 30 | android_library( 31 | name = 'all-libs', 32 | exported_deps = lib_deps 33 | ) 34 | 35 | android_library( 36 | name = 'app-code', 37 | srcs = glob([ 38 | 'src/main/java/**/*.java', 39 | ]), 40 | deps = [ 41 | ':all-libs', 42 | ':build_config', 43 | ':res', 44 | ], 45 | ) 46 | 47 | android_build_config( 48 | name = 'build_config', 49 | package = 'com.example', 50 | ) 51 | 52 | android_resource( 53 | name = 'res', 54 | res = 'src/main/res', 55 | package = 'com.example', 56 | ) 57 | 58 | android_binary( 59 | name = 'app', 60 | package_type = 'debug', 61 | manifest = 'src/main/AndroidManifest.xml', 62 | keystore = '//android/keystores:debug', 63 | deps = [ 64 | ':app-code', 65 | ], 66 | ) 67 | -------------------------------------------------------------------------------- /android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewManager.java: -------------------------------------------------------------------------------- 1 | package com.lwansbrough.RCTCamera; 2 | 3 | import android.support.annotation.Nullable; 4 | import com.facebook.react.uimanager.*; 5 | import com.facebook.react.uimanager.annotations.ReactProp; 6 | 7 | public class RCTCameraViewManager extends ViewGroupManager { 8 | private static final String REACT_CLASS = "RCTCamera"; 9 | 10 | @Override 11 | public String getName() { 12 | return REACT_CLASS; 13 | } 14 | 15 | @Override 16 | public RCTCameraView createViewInstance(ThemedReactContext context) { 17 | return new RCTCameraView(context); 18 | } 19 | 20 | @ReactProp(name = "aspect") 21 | public void setAspect(RCTCameraView view, int aspect) { 22 | view.setAspect(aspect); 23 | } 24 | 25 | @ReactProp(name = "captureMode") 26 | public void setCaptureMode(RCTCameraView view, int captureMode) { 27 | // TODO - implement video mode 28 | } 29 | 30 | @ReactProp(name = "captureTarget") 31 | public void setCaptureTarget(RCTCameraView view, int captureTarget) { 32 | // No reason to handle this props value here since it's passed again to the RCTCameraModule capture method 33 | } 34 | 35 | @ReactProp(name = "type") 36 | public void setType(RCTCameraView view, int type) { 37 | view.setCameraType(type); 38 | } 39 | 40 | @ReactProp(name = "captureQuality") 41 | public void setCaptureQuality(RCTCameraView view, String captureQuality) { 42 | view.setCaptureQuality(captureQuality); 43 | } 44 | 45 | @ReactProp(name = "torchMode") 46 | public void setTorchMode(RCTCameraView view, int torchMode) { 47 | view.setTorchMode(torchMode); 48 | } 49 | 50 | @ReactProp(name = "flashMode") 51 | public void setFlashMode(RCTCameraView view, int flashMode) { 52 | view.setFlashMode(flashMode); 53 | } 54 | 55 | @ReactProp(name = "orientation") 56 | public void setOrientation(RCTCameraView view, int orientation) { 57 | view.setOrientation(orientation); 58 | } 59 | 60 | @ReactProp(name = "captureAudio") 61 | public void setCaptureAudio(RCTCameraView view, boolean captureAudio) { 62 | // TODO - implement video mode 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Example/ios/ExampleTests/ExampleTests.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 "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface ExampleTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation ExampleTests 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 = [[[[UIApplication sharedApplication] 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 | -------------------------------------------------------------------------------- /Example/ios/Example/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 "RCTRootView.h" 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | NSURL *jsCodeLocation; 19 | 20 | /** 21 | * Loading JavaScript code - uncomment the one you want. 22 | * 23 | * OPTION 1 24 | * Load from development server. Start the server from the repository root: 25 | * 26 | * $ npm start 27 | * 28 | * To run on device, change `localhost` to the IP address of your computer 29 | * (you can get this by typing `ifconfig` into the terminal and selecting the 30 | * `inet` value under `en0:`) and make sure your computer and iOS device are 31 | * on the same Wi-Fi network. 32 | */ 33 | 34 | // jsCodeLocation = [NSURL URLWithString:@"http://192.168.1.15:8081/index.ios.bundle?platform=ios&dev=true"]; 35 | jsCodeLocation = [NSURL URLWithString:@"http://127.0.0.1:8081/index.ios.bundle?platform=ios&dev=true"]; 36 | 37 | /** 38 | * OPTION 2 39 | * Load from pre-bundled file on disk. The static bundle is automatically 40 | * generated by the "Bundle React Native code and images" build step when 41 | * running the project on an actual device or running the project on the 42 | * simulator in the "Release" build configuration. 43 | */ 44 | 45 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 46 | 47 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 48 | moduleName:@"Example" 49 | initialProperties:nil 50 | launchOptions:launchOptions]; 51 | 52 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 53 | UIViewController *rootViewController = [UIViewController new]; 54 | rootViewController.view = rootView; 55 | self.window.rootViewController = rootViewController; 56 | [self.window makeKeyAndVisible]; 57 | return YES; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Example/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 | 30 | # Do not strip any method/class that is annotated with @DoNotStrip 31 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 32 | -keepclassmembers class * { 33 | @com.facebook.proguard.annotations.DoNotStrip *; 34 | } 35 | 36 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 37 | void set*(***); 38 | *** get*(); 39 | } 40 | 41 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 42 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 43 | -keepclassmembers,includedescriptorclasses class * { native ; } 44 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 45 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 46 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 47 | 48 | -dontwarn com.facebook.react.** 49 | 50 | # okhttp 51 | 52 | -keepattributes Signature 53 | -keepattributes *Annotation* 54 | -keep class com.squareup.okhttp.** { *; } 55 | -keep interface com.squareup.okhttp.** { *; } 56 | -dontwarn com.squareup.okhttp.** 57 | 58 | # okio 59 | 60 | -keep class sun.misc.Unsafe { *; } 61 | -dontwarn java.nio.file.* 62 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 63 | -dontwarn okio.** 64 | -------------------------------------------------------------------------------- /Example/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/src/main/java/com/lwansbrough/RCTCamera/RCTSensorOrientationChecker.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by rpopovici on 23/03/16. 3 | */ 4 | 5 | package com.lwansbrough.RCTCamera; 6 | 7 | import android.content.Context; 8 | import android.hardware.Sensor; 9 | import android.hardware.SensorEvent; 10 | import android.hardware.SensorEventListener; 11 | import android.hardware.SensorManager; 12 | import android.view.Surface; 13 | 14 | import com.facebook.react.bridge.ReactApplicationContext; 15 | 16 | interface RCTSensorOrientationListener { 17 | void orientationEvent(); 18 | } 19 | 20 | public class RCTSensorOrientationChecker { 21 | 22 | int mOrientation = 0; 23 | private SensorEventListener mSensorEventListener; 24 | private SensorManager mSensorManager; 25 | private RCTSensorOrientationListener mListener = null; 26 | 27 | public RCTSensorOrientationChecker( ReactApplicationContext reactContext) { 28 | mSensorEventListener = new Listener(); 29 | mSensorManager = (SensorManager) reactContext.getSystemService(Context.SENSOR_SERVICE); 30 | 31 | } 32 | 33 | /** 34 | * Call on activity onResume() 35 | */ 36 | public void onResume() { 37 | mSensorManager.registerListener(mSensorEventListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); 38 | } 39 | 40 | /** 41 | * Call on activity onPause() 42 | */ 43 | public void onPause() { 44 | mSensorManager.unregisterListener(mSensorEventListener); 45 | } 46 | 47 | private class Listener implements SensorEventListener { 48 | 49 | @Override 50 | public void onSensorChanged(SensorEvent event) { 51 | float x = event.values[0]; 52 | float y = event.values[1]; 53 | 54 | if (x<5 && x>-5 && y > 5) 55 | mOrientation = Surface.ROTATION_0; // portrait 56 | else if (x<-5 && y<5 && y>-5) 57 | mOrientation = Surface.ROTATION_270; // right 58 | else if (x<5 && x>-5 && y<-5) 59 | mOrientation = Surface.ROTATION_180; // upside down 60 | else if (x>5 && y<5 && y>-5) 61 | mOrientation = Surface.ROTATION_90; // left 62 | 63 | if (mListener != null) { 64 | mListener.orientationEvent(); 65 | } 66 | } 67 | 68 | @Override 69 | public void onAccuracyChanged(Sensor sensor, int accuracy) { 70 | 71 | } 72 | } 73 | 74 | public int getOrientation() { 75 | return mOrientation; 76 | } 77 | 78 | public void registerOrientationListener(RCTSensorOrientationListener listener) { 79 | this.mListener = listener; 80 | } 81 | 82 | public void unregisterOrientationListener() { 83 | mListener = null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.web.js 5 | .*/*.android.js 6 | 7 | # Some modules have their own node_modules with overlap 8 | .*/node_modules/node-haste/.* 9 | 10 | # Ugh 11 | .*/node_modules/babel.* 12 | .*/node_modules/babylon.* 13 | .*/node_modules/invariant.* 14 | 15 | # Ignore react and fbjs where there are overlaps, but don't ignore 16 | # anything that react-native relies on 17 | .*/node_modules/fbjs/lib/Map.js 18 | .*/node_modules/fbjs/lib/ErrorUtils.js 19 | 20 | # Flow has a built-in definition for the 'react' module which we prefer to use 21 | # over the currently-untyped source 22 | .*/node_modules/react/react.js 23 | .*/node_modules/react/lib/React.js 24 | .*/node_modules/react/lib/ReactDOM.js 25 | 26 | .*/__mocks__/.* 27 | .*/__tests__/.* 28 | 29 | .*/commoner/test/source/widget/share.js 30 | 31 | # Ignore commoner tests 32 | .*/node_modules/commoner/test/.* 33 | 34 | # See https://github.com/facebook/flow/issues/442 35 | .*/react-tools/node_modules/commoner/lib/reader.js 36 | 37 | # Ignore jest 38 | .*/node_modules/jest-cli/.* 39 | 40 | # Ignore Website 41 | .*/website/.* 42 | 43 | # Ignore generators 44 | .*/local-cli/generator.* 45 | 46 | # Ignore BUCK generated folders 47 | .*\.buckd/ 48 | 49 | .*/node_modules/is-my-json-valid/test/.*\.json 50 | .*/node_modules/iconv-lite/encodings/tables/.*\.json 51 | .*/node_modules/y18n/test/.*\.json 52 | .*/node_modules/spdx-license-ids/spdx-license-ids.json 53 | .*/node_modules/spdx-exceptions/index.json 54 | .*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json 55 | .*/node_modules/resolve/lib/core.json 56 | .*/node_modules/jsonparse/samplejson/.*\.json 57 | .*/node_modules/json5/test/.*\.json 58 | .*/node_modules/ua-parser-js/test/.*\.json 59 | .*/node_modules/builtin-modules/builtin-modules.json 60 | .*/node_modules/binary-extensions/binary-extensions.json 61 | .*/node_modules/url-regex/tlds.json 62 | .*/node_modules/joi/.*\.json 63 | .*/node_modules/isemail/.*\.json 64 | .*/node_modules/tr46/.*\.json 65 | 66 | 67 | [include] 68 | 69 | [libs] 70 | node_modules/react-native/Libraries/react-native/react-native-interface.js 71 | node_modules/react-native/flow 72 | flow/ 73 | 74 | [options] 75 | module.system=haste 76 | 77 | esproposal.class_static_fields=enable 78 | esproposal.class_instance_fields=enable 79 | 80 | munge_underscores=true 81 | 82 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 83 | 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' 84 | 85 | suppress_type=$FlowIssue 86 | suppress_type=$FlowFixMe 87 | suppress_type=$FixMe 88 | 89 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-4]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 90 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-4]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 91 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 92 | 93 | [version] 94 | 0.24.0 95 | -------------------------------------------------------------------------------- /ios/RCTSensorOrientationChecker.m: -------------------------------------------------------------------------------- 1 | // 2 | // RCTSensorOrientationChecker.m 3 | // RCTCamera 4 | // 5 | // Created by Radu Popovici on 24/03/16. 6 | // 7 | // 8 | 9 | #import "RCTSensorOrientationChecker.h" 10 | #import 11 | 12 | 13 | @interface RCTSensorOrientationChecker () 14 | 15 | @property (strong, nonatomic) CMMotionManager * motionManager; 16 | @property (strong, nonatomic) RCTSensorCallback orientationCallback; 17 | 18 | @end 19 | 20 | @implementation RCTSensorOrientationChecker 21 | 22 | - (instancetype)init 23 | { 24 | self = [super init]; 25 | if (self) { 26 | // Initialization code 27 | self.motionManager = [[CMMotionManager alloc] init]; 28 | self.motionManager.accelerometerUpdateInterval = 0.2; 29 | self.motionManager.gyroUpdateInterval = 0.2; 30 | self.orientationCallback = nil; 31 | } 32 | return self; 33 | } 34 | 35 | - (void)dealloc 36 | { 37 | [self pause]; 38 | } 39 | 40 | - (void)resume 41 | { 42 | __weak __typeof(self) weakSelf = self; 43 | [self.motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue new] 44 | withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { 45 | if (!error) { 46 | self.orientation = [weakSelf getOrientationBy:accelerometerData.acceleration]; 47 | } 48 | if (self.orientationCallback) { 49 | self.orientationCallback(self.orientation); 50 | } 51 | }]; 52 | } 53 | 54 | - (void)pause 55 | { 56 | [self.motionManager stopAccelerometerUpdates]; 57 | } 58 | 59 | - (void)getDeviceOrientationWithBlock:(RCTSensorCallback)callback 60 | { 61 | __weak __typeof(self) weakSelf = self; 62 | self.orientationCallback = ^(UIInterfaceOrientation orientation) { 63 | if (callback) { 64 | callback(orientation); 65 | } 66 | weakSelf.orientationCallback = nil; 67 | [weakSelf pause]; 68 | }; 69 | [self resume]; 70 | } 71 | 72 | - (UIInterfaceOrientation)getOrientationBy:(CMAcceleration)acceleration 73 | { 74 | if(acceleration.x >= 0.75) { 75 | return UIInterfaceOrientationLandscapeLeft; 76 | } 77 | if(acceleration.x <= -0.75) { 78 | return UIInterfaceOrientationLandscapeRight; 79 | } 80 | if(acceleration.y >= -0.75) { 81 | return UIInterfaceOrientationPortrait; 82 | } 83 | if(acceleration.y >= 0.75) { 84 | return UIInterfaceOrientationPortraitUpsideDown; 85 | } 86 | return [[UIApplication sharedApplication] statusBarOrientation]; 87 | } 88 | 89 | - (AVCaptureVideoOrientation)convertToAVCaptureVideoOrientation:(UIInterfaceOrientation)orientation 90 | { 91 | switch (orientation) { 92 | case UIInterfaceOrientationPortrait: 93 | return AVCaptureVideoOrientationPortrait; 94 | case UIInterfaceOrientationPortraitUpsideDown: 95 | return AVCaptureVideoOrientationPortraitUpsideDown; 96 | case UIInterfaceOrientationLandscapeLeft: 97 | return AVCaptureVideoOrientationLandscapeLeft; 98 | case UIInterfaceOrientationLandscapeRight: 99 | return AVCaptureVideoOrientationLandscapeRight; 100 | default: 101 | return 0; // unknown 102 | } 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /ios/NSMutableDictionary+ImageMetadata.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableDictionary+ImageMetadata.m 3 | // RCTCamera 4 | // 5 | // Created by Jehan Tremback on 7/10/15. 6 | // 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface NSMutableDictionary(ImageMetadata) 13 | - (void)mergeMetadata:(NSDictionary *)inputMetadata; 14 | @end 15 | 16 | @implementation NSMutableDictionary(ImageMetadata) 17 | 18 | - (void)mergeMetadata:(NSDictionary *)inputMetadata { 19 | NSDictionary *inputMetadataLocation = [inputMetadata objectForKey:@"location"]; 20 | if (inputMetadataLocation) { 21 | // Add GPS stuff 22 | [self setObject:[self getGPSDictionaryForLocation:inputMetadataLocation] forKey:(NSString *)kCGImagePropertyGPSDictionary]; 23 | } 24 | } 25 | 26 | - (NSMutableDictionary *)getGPSDictionaryForLocation:(NSDictionary *)location { 27 | NSMutableDictionary *gps = [NSMutableDictionary dictionary]; 28 | NSDictionary *coords = [location objectForKey:@"coords"]; 29 | // GPS tag version 30 | [gps setObject:@"2.2.0.0" forKey:(NSString *)kCGImagePropertyGPSVersion]; 31 | 32 | // Timestamp 33 | double timestamp = floor([[location objectForKey:@"timestamp"] doubleValue]); 34 | NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp]; 35 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 36 | [formatter setDateFormat:@"HH:mm:ss.SSSSSS"]; 37 | [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; 38 | [gps setObject:[formatter stringFromDate:date] forKey:(NSString *)kCGImagePropertyGPSTimeStamp]; 39 | [formatter setDateFormat:@"yyyy:MM:dd"]; 40 | [gps setObject:[formatter stringFromDate:date] forKey:(NSString *)kCGImagePropertyGPSDateStamp]; 41 | 42 | // Latitude 43 | double latitude = [[coords objectForKey:@"latitude"] doubleValue]; 44 | if (latitude < 0) { 45 | latitude = -latitude; 46 | [gps setObject:@"S" forKey:(NSString *)kCGImagePropertyGPSLatitudeRef]; 47 | } else { 48 | [gps setObject:@"N" forKey:(NSString *)kCGImagePropertyGPSLatitudeRef]; 49 | } 50 | [gps setObject:[NSNumber numberWithFloat:latitude] forKey:(NSString *)kCGImagePropertyGPSLatitude]; 51 | 52 | // Longitude 53 | double longitude = [[coords objectForKey:@"longitude"] doubleValue]; 54 | if (longitude < 0) { 55 | longitude = -longitude; 56 | [gps setObject:@"W" forKey:(NSString *)kCGImagePropertyGPSLongitudeRef]; 57 | } else { 58 | [gps setObject:@"E" forKey:(NSString *)kCGImagePropertyGPSLongitudeRef]; 59 | } 60 | [gps setObject:[NSNumber numberWithFloat:longitude] forKey:(NSString *)kCGImagePropertyGPSLongitude]; 61 | 62 | // Altitude 63 | double altitude = [[coords objectForKey:@"altitude"] doubleValue]; 64 | if (!isnan(altitude)){ 65 | if (altitude < 0) { 66 | altitude = -altitude; 67 | [gps setObject:@"1" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; 68 | } else { 69 | [gps setObject:@"0" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef]; 70 | } 71 | [gps setObject:[NSNumber numberWithFloat:altitude] forKey:(NSString *)kCGImagePropertyGPSAltitude]; 72 | } 73 | 74 | // Speed, must be converted from m/s to km/h 75 | double speed = [[coords objectForKey:@"speed"] doubleValue]; 76 | if (speed >= 0){ 77 | [gps setObject:@"K" forKey:(NSString *)kCGImagePropertyGPSSpeedRef]; 78 | [gps setObject:[NSNumber numberWithFloat:speed*3.6] forKey:(NSString *)kCGImagePropertyGPSSpeed]; 79 | } 80 | 81 | // Heading 82 | double heading = [[coords objectForKey:@"heading"] doubleValue]; 83 | if (heading >= 0){ 84 | [gps setObject:@"T" forKey:(NSString *)kCGImagePropertyGPSTrackRef]; 85 | [gps setObject:[NSNumber numberWithFloat:heading] forKey:(NSString *)kCGImagePropertyGPSTrack]; 86 | } 87 | 88 | return gps; 89 | } 90 | @end 91 | -------------------------------------------------------------------------------- /Example/ios/Example/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/RCTCameraManager.h: -------------------------------------------------------------------------------- 1 | #import "RCTViewManager.h" 2 | #import 3 | 4 | @class RCTCamera; 5 | 6 | typedef NS_ENUM(NSInteger, RCTCameraAspect) { 7 | RCTCameraAspectFill = 0, 8 | RCTCameraAspectFit = 1, 9 | RCTCameraAspectStretch = 2 10 | }; 11 | 12 | typedef NS_ENUM(NSInteger, RCTCameraCaptureSessionPreset) { 13 | RCTCameraCaptureSessionPresetLow = 0, 14 | RCTCameraCaptureSessionPresetMedium = 1, 15 | RCTCameraCaptureSessionPresetHigh = 2, 16 | RCTCameraCaptureSessionPresetPhoto = 3 17 | }; 18 | 19 | typedef NS_ENUM(NSInteger, RCTCameraCaptureMode) { 20 | RCTCameraCaptureModeStill = 0, 21 | RCTCameraCaptureModeVideo = 1 22 | }; 23 | 24 | typedef NS_ENUM(NSInteger, RCTCameraCaptureTarget) { 25 | RCTCameraCaptureTargetMemory = 0, 26 | RCTCameraCaptureTargetDisk = 1, 27 | RCTCameraCaptureTargetTemp = 2, 28 | RCTCameraCaptureTargetCameraRoll = 3 29 | }; 30 | 31 | typedef NS_ENUM(NSInteger, RCTCameraOrientation) { 32 | RCTCameraOrientationAuto = 0, 33 | RCTCameraOrientationLandscapeLeft = AVCaptureVideoOrientationLandscapeLeft, 34 | RCTCameraOrientationLandscapeRight = AVCaptureVideoOrientationLandscapeRight, 35 | RCTCameraOrientationPortrait = AVCaptureVideoOrientationPortrait, 36 | RCTCameraOrientationPortraitUpsideDown = AVCaptureVideoOrientationPortraitUpsideDown 37 | }; 38 | 39 | typedef NS_ENUM(NSInteger, RCTCameraType) { 40 | RCTCameraTypeFront = AVCaptureDevicePositionFront, 41 | RCTCameraTypeBack = AVCaptureDevicePositionBack 42 | }; 43 | 44 | typedef NS_ENUM(NSInteger, RCTCameraFlashMode) { 45 | RCTCameraFlashModeOff = AVCaptureFlashModeOff, 46 | RCTCameraFlashModeOn = AVCaptureFlashModeOn, 47 | RCTCameraFlashModeAuto = AVCaptureFlashModeAuto 48 | }; 49 | 50 | typedef NS_ENUM(NSInteger, RCTCameraTorchMode) { 51 | RCTCameraTorchModeOff = AVCaptureTorchModeOff, 52 | RCTCameraTorchModeOn = AVCaptureTorchModeOn, 53 | RCTCameraTorchModeAuto = AVCaptureTorchModeAuto 54 | }; 55 | 56 | @interface RCTCameraManager : RCTViewManager 57 | 58 | @property (nonatomic, strong) dispatch_queue_t sessionQueue; 59 | @property (nonatomic, strong) AVCaptureSession *session; 60 | @property (nonatomic, strong) AVCaptureDeviceInput *audioCaptureDeviceInput; 61 | @property (nonatomic, strong) AVCaptureDeviceInput *videoCaptureDeviceInput; 62 | @property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput; 63 | @property (nonatomic, strong) AVCaptureMovieFileOutput *movieFileOutput; 64 | @property (nonatomic, strong) AVCaptureMetadataOutput *metadataOutput; 65 | @property (nonatomic, strong) id runtimeErrorHandlingObserver; 66 | @property (nonatomic, assign) NSInteger presetCamera; 67 | @property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; 68 | @property (nonatomic, assign) NSInteger videoTarget; 69 | @property (nonatomic, assign) NSInteger orientation; 70 | @property (nonatomic, assign) BOOL mirrorImage; 71 | @property (nonatomic, strong) NSArray* barCodeTypes; 72 | @property (nonatomic, strong) RCTPromiseResolveBlock videoResolve; 73 | @property (nonatomic, strong) RCTPromiseRejectBlock videoReject; 74 | @property (nonatomic, strong) RCTCamera *camera; 75 | 76 | 77 | - (void)changeOrientation:(NSInteger)orientation; 78 | - (AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position; 79 | - (void)capture:(NSDictionary*)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; 80 | - (void)getFOV:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; 81 | - (void)hasFlash:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; 82 | - (void)initializeCaptureSessionInput:(NSString*)type; 83 | - (void)stopCapture; 84 | - (void)startSession; 85 | - (void)stopSession; 86 | - (void)focusAtThePoint:(CGPoint) atPoint; 87 | - (void)zoom:(CGFloat)velocity reactTag:(NSNumber *)reactTag; 88 | 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /Example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewFinder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Fabrice Armisen (farmisen@gmail.com) on 1/3/16. 3 | */ 4 | 5 | package com.lwansbrough.RCTCamera; 6 | 7 | import android.content.Context; 8 | import android.graphics.SurfaceTexture; 9 | import android.hardware.Camera; 10 | import android.view.TextureView; 11 | 12 | import java.util.List; 13 | 14 | class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceTextureListener { 15 | private int _cameraType; 16 | private SurfaceTexture _surfaceTexture; 17 | private boolean _isStarting; 18 | private boolean _isStopping; 19 | private Camera _camera; 20 | 21 | public RCTCameraViewFinder(Context context, int type) { 22 | super(context); 23 | this.setSurfaceTextureListener(this); 24 | this._cameraType = type; 25 | } 26 | 27 | @Override 28 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 29 | _surfaceTexture = surface; 30 | startCamera(); 31 | } 32 | 33 | @Override 34 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 35 | } 36 | 37 | @Override 38 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 39 | _surfaceTexture = null; 40 | stopCamera(); 41 | return true; 42 | } 43 | 44 | @Override 45 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { 46 | } 47 | 48 | public double getRatio() { 49 | int width = RCTCamera.getInstance().getPreviewWidth(this._cameraType); 50 | int height = RCTCamera.getInstance().getPreviewHeight(this._cameraType); 51 | return ((float) width) / ((float) height); 52 | } 53 | 54 | public void setCameraType(final int type) { 55 | if (this._cameraType == type) { 56 | return; 57 | } 58 | new Thread(new Runnable() { 59 | @Override 60 | public void run() { 61 | stopPreview(); 62 | _cameraType = type; 63 | startPreview(); 64 | } 65 | }).start(); 66 | } 67 | 68 | public void setCaptureQuality(String captureQuality) { 69 | RCTCamera.getInstance().setCaptureQuality(_cameraType, captureQuality); 70 | } 71 | 72 | public void setTorchMode(int torchMode) { 73 | RCTCamera.getInstance().setTorchMode(_cameraType, torchMode); 74 | } 75 | 76 | public void setFlashMode(int flashMode) { 77 | RCTCamera.getInstance().setTorchMode(_cameraType, flashMode); 78 | } 79 | 80 | private void startPreview() { 81 | if (_surfaceTexture != null) { 82 | startCamera(); 83 | } 84 | } 85 | 86 | private void stopPreview() { 87 | if (_camera != null) { 88 | stopCamera(); 89 | } 90 | } 91 | 92 | synchronized private void startCamera() { 93 | if (!_isStarting) { 94 | _isStarting = true; 95 | try { 96 | _camera = RCTCamera.getInstance().acquireCameraInstance(_cameraType); 97 | Camera.Parameters parameters = _camera.getParameters(); 98 | // set autofocus 99 | List focusModes = parameters.getSupportedFocusModes(); 100 | if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { 101 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 102 | } 103 | // set picture size 104 | // defaults to max available size 105 | Camera.Size optimalPictureSize = RCTCamera.getInstance().getBestSize( 106 | parameters.getSupportedPictureSizes(), 107 | Integer.MAX_VALUE, 108 | Integer.MAX_VALUE 109 | ); 110 | parameters.setPictureSize(optimalPictureSize.width, optimalPictureSize.height); 111 | 112 | _camera.setParameters(parameters); 113 | _camera.setPreviewTexture(_surfaceTexture); 114 | _camera.startPreview(); 115 | } catch (NullPointerException e) { 116 | e.printStackTrace(); 117 | } catch (Exception e) { 118 | e.printStackTrace(); 119 | stopCamera(); 120 | } finally { 121 | _isStarting = false; 122 | } 123 | } 124 | } 125 | 126 | synchronized private void stopCamera() { 127 | if (!_isStopping) { 128 | _isStopping = true; 129 | try { 130 | if (_camera != null) { 131 | _camera.stopPreview(); 132 | RCTCamera.getInstance().releaseCameraInstance(_cameraType); 133 | _camera = null; 134 | } 135 | 136 | } catch (Exception e) { 137 | e.printStackTrace(); 138 | } finally { 139 | _isStopping = false; 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Example/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 | */ 61 | 62 | apply from: "../../node_modules/react-native/react.gradle" 63 | 64 | /** 65 | * Set this to true to create two separate APKs instead of one: 66 | * - An APK that only works on ARM devices 67 | * - An APK that only works on x86 devices 68 | * The advantage is the size of the APK is reduced by about 4MB. 69 | * Upload all the APKs to the Play Store and people will download 70 | * the correct one based on the CPU architecture of their device. 71 | */ 72 | def enableSeparateBuildPerCPUArchitecture = false 73 | 74 | /** 75 | * Run Proguard to shrink the Java bytecode in release builds. 76 | */ 77 | def enableProguardInReleaseBuilds = false 78 | 79 | android { 80 | compileSdkVersion 23 81 | buildToolsVersion "23.0.1" 82 | 83 | defaultConfig { 84 | applicationId "com.example" 85 | minSdkVersion 16 86 | targetSdkVersion 22 87 | versionCode 1 88 | versionName "1.0" 89 | ndk { 90 | abiFilters "armeabi-v7a", "x86" 91 | } 92 | } 93 | splits { 94 | abi { 95 | reset() 96 | enable enableSeparateBuildPerCPUArchitecture 97 | universalApk false // If true, also generate a universal APK 98 | include "armeabi-v7a", "x86" 99 | } 100 | } 101 | buildTypes { 102 | release { 103 | minifyEnabled enableProguardInReleaseBuilds 104 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 105 | } 106 | } 107 | // applicationVariants are e.g. debug, release 108 | applicationVariants.all { variant -> 109 | variant.outputs.each { output -> 110 | // For each separate APK per architecture, set a unique version code as described here: 111 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 112 | def versionCodes = ["armeabi-v7a":1, "x86":2] 113 | def abi = output.getFilter(OutputFile.ABI) 114 | if (abi != null) { // null for the universal-debug, universal-release variants 115 | output.versionCodeOverride = 116 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 117 | } 118 | } 119 | } 120 | } 121 | 122 | dependencies { 123 | compile project(':react-native-camera') 124 | compile fileTree(dir: "libs", include: ["*.jar"]) 125 | compile "com.android.support:appcompat-v7:23.0.1" 126 | compile "com.facebook.react:react-native:+" // From node_modules 127 | } 128 | 129 | // Run this once to be able to run the application with BUCK 130 | // puts all compile dependencies into folder libs for BUCK to use 131 | task copyDownloadableDepsToLibs(type: Copy) { 132 | from configurations.compile 133 | into 'libs' 134 | } 135 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /ios/RCTCamera.m: -------------------------------------------------------------------------------- 1 | #import "RCTBridge.h" 2 | #import "RCTCamera.h" 3 | #import "RCTCameraManager.h" 4 | #import "RCTLog.h" 5 | #import "RCTUtils.h" 6 | #import "RCTEventDispatcher.h" 7 | 8 | #import "UIView+React.h" 9 | 10 | #import 11 | #import "CameraFocusSquare.h" 12 | 13 | @interface RCTCamera () 14 | 15 | @property (nonatomic, weak) RCTCameraManager *manager; 16 | @property (nonatomic, weak) RCTBridge *bridge; 17 | @property (nonatomic, strong) RCTCameraFocusSquare *camFocus; 18 | 19 | @end 20 | 21 | @implementation RCTCamera 22 | { 23 | BOOL _multipleTouches; 24 | BOOL _onFocusChanged; 25 | BOOL _defaultOnFocusComponent; 26 | BOOL _onZoomChanged; 27 | BOOL _previousIdleTimerDisabled; 28 | } 29 | 30 | - (void)setOrientation:(NSInteger)orientation 31 | { 32 | [self.manager changeOrientation:orientation]; 33 | 34 | if (orientation == RCTCameraOrientationAuto) { 35 | [self changePreviewOrientation:[UIApplication sharedApplication].statusBarOrientation]; 36 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil]; 37 | } 38 | else { 39 | [[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; 40 | [self changePreviewOrientation:orientation]; 41 | } 42 | } 43 | 44 | - (void)setOnFocusChanged:(BOOL)enabled 45 | { 46 | if (_onFocusChanged != enabled) { 47 | _onFocusChanged = enabled; 48 | } 49 | } 50 | 51 | - (void)setDefaultOnFocusComponent:(BOOL)enabled 52 | { 53 | if (_defaultOnFocusComponent != enabled) { 54 | _defaultOnFocusComponent = enabled; 55 | } 56 | } 57 | 58 | - (void)setOnZoomChanged:(BOOL)enabled 59 | { 60 | if (_onZoomChanged != enabled) { 61 | _onZoomChanged = enabled; 62 | } 63 | } 64 | 65 | - (id)initWithManager:(RCTCameraManager*)manager bridge:(RCTBridge *)bridge 66 | { 67 | 68 | if ((self = [super init])) { 69 | self.manager = manager; 70 | self.bridge = bridge; 71 | UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchToZoomRecognizer:)]; 72 | [self addGestureRecognizer:pinchGesture]; 73 | [self.manager initializeCaptureSessionInput:AVMediaTypeVideo]; 74 | [self.manager startSession]; 75 | _multipleTouches = NO; 76 | _onFocusChanged = NO; 77 | _defaultOnFocusComponent = YES; 78 | _onZoomChanged = NO; 79 | _previousIdleTimerDisabled = [UIApplication sharedApplication].idleTimerDisabled; 80 | } 81 | return self; 82 | } 83 | 84 | - (void)layoutSubviews 85 | { 86 | [super layoutSubviews]; 87 | self.manager.previewLayer.frame = self.bounds; 88 | [self setBackgroundColor:[UIColor blackColor]]; 89 | [self.layer insertSublayer:self.manager.previewLayer atIndex:0]; 90 | } 91 | 92 | - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex 93 | { 94 | [self insertSubview:view atIndex:atIndex + 1]; 95 | return; 96 | } 97 | 98 | - (void)removeReactSubview:(UIView *)subview 99 | { 100 | [subview removeFromSuperview]; 101 | return; 102 | } 103 | 104 | - (void)removeFromSuperview 105 | { 106 | [self.manager stopSession]; 107 | [super removeFromSuperview]; 108 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; 109 | [UIApplication sharedApplication].idleTimerDisabled = _previousIdleTimerDisabled; 110 | } 111 | 112 | - (void)orientationChanged:(NSNotification *)notification{ 113 | UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 114 | [self changePreviewOrientation:orientation]; 115 | } 116 | 117 | 118 | - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 119 | { 120 | // Update the touch state. 121 | if ([[event touchesForView:self] count] > 1) { 122 | _multipleTouches = YES; 123 | } 124 | 125 | } 126 | 127 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 128 | { 129 | if (!_onFocusChanged) return; 130 | 131 | BOOL allTouchesEnded = ([touches count] == [[event touchesForView:self] count]); 132 | 133 | // Do not conflict with zooming and etc. 134 | if (allTouchesEnded && !_multipleTouches) { 135 | UITouch *touch = [[event allTouches] anyObject]; 136 | CGPoint touchPoint = [touch locationInView:touch.view]; 137 | // Focus camera on this point 138 | [self.manager focusAtThePoint:touchPoint]; 139 | 140 | if (self.camFocus) 141 | { 142 | [self.camFocus removeFromSuperview]; 143 | } 144 | NSDictionary *event = @{ 145 | @"target": self.reactTag, 146 | @"touchPoint": @{ 147 | @"x": [NSNumber numberWithDouble:touchPoint.x], 148 | @"y": [NSNumber numberWithDouble:touchPoint.y] 149 | } 150 | }; 151 | [self.bridge.eventDispatcher sendInputEventWithName:@"focusChanged" body:event]; 152 | 153 | // Show animated rectangle on the touched area 154 | if (_defaultOnFocusComponent) { 155 | self.camFocus = [[RCTCameraFocusSquare alloc]initWithFrame:CGRectMake(touchPoint.x-40, touchPoint.y-40, 80, 80)]; 156 | [self.camFocus setBackgroundColor:[UIColor clearColor]]; 157 | [self addSubview:self.camFocus]; 158 | [self.camFocus setNeedsDisplay]; 159 | 160 | [UIView beginAnimations:nil context:NULL]; 161 | [UIView setAnimationDuration:1.0]; 162 | [self.camFocus setAlpha:0.0]; 163 | [UIView commitAnimations]; 164 | } 165 | } 166 | 167 | if (allTouchesEnded) { 168 | _multipleTouches = NO; 169 | } 170 | 171 | } 172 | 173 | 174 | -(void) handlePinchToZoomRecognizer:(UIPinchGestureRecognizer*)pinchRecognizer { 175 | if (!_onZoomChanged) return; 176 | 177 | if (pinchRecognizer.state == UIGestureRecognizerStateChanged) { 178 | [self.manager zoom:pinchRecognizer.velocity reactTag:self.reactTag]; 179 | } 180 | } 181 | 182 | - (void)changePreviewOrientation:(NSInteger)orientation 183 | { 184 | dispatch_async(self.manager.sessionQueue, ^{ 185 | if (self.manager.previewLayer.connection.isVideoOrientationSupported) { 186 | self.manager.previewLayer.connection.videoOrientation = orientation; 187 | } 188 | }); 189 | } 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraView.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Fabrice Armisen (farmisen@gmail.com) on 1/3/16. 3 | */ 4 | 5 | package com.lwansbrough.RCTCamera; 6 | 7 | import android.content.Context; 8 | import android.hardware.SensorManager; 9 | import android.view.OrientationEventListener; 10 | import android.view.ViewGroup; 11 | import android.view.WindowManager; 12 | import android.view.View; 13 | 14 | public class RCTCameraView extends ViewGroup { 15 | private final OrientationEventListener _orientationListener; 16 | private final Context _context; 17 | private RCTCameraViewFinder _viewFinder = null; 18 | private int _actualDeviceOrientation = -1; 19 | private int _aspect = RCTCameraModule.RCT_CAMERA_ASPECT_FIT; 20 | private String _captureQuality = "high"; 21 | private int _torchMode = -1; 22 | private int _flashMode = -1; 23 | 24 | public RCTCameraView(Context context) { 25 | super(context); 26 | this._context = context; 27 | setActualDeviceOrientation(context); 28 | 29 | _orientationListener = new OrientationEventListener(context, SensorManager.SENSOR_DELAY_NORMAL) { 30 | @Override 31 | public void onOrientationChanged(int orientation) { 32 | if (setActualDeviceOrientation(_context)) { 33 | layoutViewFinder(); 34 | } 35 | } 36 | }; 37 | 38 | if (_orientationListener.canDetectOrientation()) { 39 | _orientationListener.enable(); 40 | } else { 41 | _orientationListener.disable(); 42 | } 43 | } 44 | 45 | @Override 46 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 47 | layoutViewFinder(left, top, right, bottom); 48 | } 49 | 50 | @Override 51 | public void onViewAdded(View child) { 52 | if (this._viewFinder == child) return; 53 | // remove and readd view to make sure it is in the back. 54 | // @TODO figure out why there was a z order issue in the first place and fix accordingly. 55 | this.removeView(this._viewFinder); 56 | this.addView(this._viewFinder, 0); 57 | } 58 | 59 | public void setAspect(int aspect) { 60 | this._aspect = aspect; 61 | layoutViewFinder(); 62 | } 63 | 64 | public void setCameraType(final int type) { 65 | if (null != this._viewFinder) { 66 | this._viewFinder.setCameraType(type); 67 | RCTCamera.getInstance().adjustPreviewLayout(type); 68 | } else { 69 | _viewFinder = new RCTCameraViewFinder(_context, type); 70 | if (-1 != this._flashMode) { 71 | _viewFinder.setFlashMode(this._flashMode); 72 | } 73 | if (-1 != this._torchMode) { 74 | _viewFinder.setFlashMode(this._torchMode); 75 | } 76 | addView(_viewFinder); 77 | } 78 | } 79 | 80 | public void setCaptureQuality(String captureQuality) { 81 | this._captureQuality = captureQuality; 82 | if (this._viewFinder != null) { 83 | this._viewFinder.setCaptureQuality(captureQuality); 84 | } 85 | } 86 | 87 | public void setTorchMode(int torchMode) { 88 | this._torchMode = torchMode; 89 | if (this._viewFinder != null) { 90 | this._viewFinder.setTorchMode(torchMode); 91 | } 92 | } 93 | 94 | public void setFlashMode(int flashMode) { 95 | this._flashMode = flashMode; 96 | if (this._viewFinder != null) { 97 | this._viewFinder.setFlashMode(flashMode); 98 | } 99 | } 100 | 101 | public void setOrientation(int orientation) { 102 | RCTCamera.getInstance().setOrientation(orientation); 103 | if (this._viewFinder != null) { 104 | layoutViewFinder(); 105 | } 106 | } 107 | 108 | private boolean setActualDeviceOrientation(Context context) { 109 | int actualDeviceOrientation = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getOrientation(); 110 | if (_actualDeviceOrientation != actualDeviceOrientation) { 111 | _actualDeviceOrientation = actualDeviceOrientation; 112 | RCTCamera.getInstance().setActualDeviceOrientation(_actualDeviceOrientation); 113 | return true; 114 | } else { 115 | return false; 116 | } 117 | } 118 | 119 | private void layoutViewFinder() { 120 | layoutViewFinder(this.getLeft(), this.getTop(), this.getRight(), this.getBottom()); 121 | } 122 | 123 | private void layoutViewFinder(int left, int top, int right, int bottom) { 124 | if (null == _viewFinder) { 125 | return; 126 | } 127 | float width = right - left; 128 | float height = bottom - top; 129 | int viewfinderWidth; 130 | int viewfinderHeight; 131 | double ratio; 132 | switch (this._aspect) { 133 | case RCTCameraModule.RCT_CAMERA_ASPECT_FIT: 134 | ratio = this._viewFinder.getRatio(); 135 | if (ratio * height > width) { 136 | viewfinderHeight = (int) (width / ratio); 137 | viewfinderWidth = (int) width; 138 | } else { 139 | viewfinderWidth = (int) (ratio * height); 140 | viewfinderHeight = (int) height; 141 | } 142 | break; 143 | case RCTCameraModule.RCT_CAMERA_ASPECT_FILL: 144 | ratio = this._viewFinder.getRatio(); 145 | if (ratio * height < width) { 146 | viewfinderHeight = (int) (width / ratio); 147 | viewfinderWidth = (int) width; 148 | } else { 149 | viewfinderWidth = (int) (ratio * height); 150 | viewfinderHeight = (int) height; 151 | } 152 | break; 153 | default: 154 | viewfinderWidth = (int) width; 155 | viewfinderHeight = (int) height; 156 | } 157 | 158 | int viewFinderPaddingX = (int) ((width - viewfinderWidth) / 2); 159 | int viewFinderPaddingY = (int) ((height - viewfinderHeight) / 2); 160 | 161 | this._viewFinder.layout(viewFinderPaddingX, viewFinderPaddingY, viewFinderPaddingX + viewfinderWidth, viewFinderPaddingY + viewfinderHeight); 162 | this.postInvalidate(this.getLeft(), this.getTop(), this.getRight(), this.getBottom()); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /Example/Example.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Image, 4 | StatusBar, 5 | StyleSheet, 6 | TouchableOpacity, 7 | View, 8 | } from 'react-native'; 9 | import Camera from 'react-native-camera'; 10 | 11 | const styles = StyleSheet.create({ 12 | container: { 13 | flex: 1, 14 | }, 15 | preview: { 16 | flex: 1, 17 | justifyContent: 'flex-end', 18 | alignItems: 'center', 19 | }, 20 | overlay: { 21 | position: 'absolute', 22 | padding: 16, 23 | right: 0, 24 | left: 0, 25 | alignItems: 'center', 26 | }, 27 | topOverlay: { 28 | top: 0, 29 | flex: 1, 30 | flexDirection: 'row', 31 | justifyContent: 'space-between', 32 | alignItems: 'center', 33 | }, 34 | bottomOverlay: { 35 | bottom: 0, 36 | backgroundColor: 'rgba(0,0,0,0.4)', 37 | flexDirection: 'row', 38 | justifyContent: 'center', 39 | alignItems: 'center', 40 | }, 41 | captureButton: { 42 | padding: 15, 43 | backgroundColor: 'white', 44 | borderRadius: 40, 45 | }, 46 | typeButton: { 47 | padding: 5, 48 | }, 49 | flashButton: { 50 | padding: 5, 51 | }, 52 | buttonsSpace: { 53 | width: 10, 54 | }, 55 | }); 56 | 57 | export default class Example extends React.Component { 58 | constructor(props) { 59 | super(props); 60 | 61 | this.camera = null; 62 | 63 | this.state = { 64 | camera: { 65 | aspect: Camera.constants.Aspect.fill, 66 | captureTarget: Camera.constants.CaptureTarget.cameraRoll, 67 | type: Camera.constants.Type.back, 68 | orientation: Camera.constants.Orientation.auto, 69 | flashMode: Camera.constants.FlashMode.auto, 70 | }, 71 | isRecording: false 72 | }; 73 | 74 | this.takePicture = this.takePicture.bind(this); 75 | this.startRecording = this.startRecording.bind(this); 76 | this.stopRecording = this.stopRecording.bind(this); 77 | this.switchType = this.switchType.bind(this); 78 | this.switchFlash = this.switchFlash.bind(this); 79 | } 80 | 81 | takePicture() { 82 | if (this.camera) { 83 | this.camera.capture() 84 | .then((data) => console.log(data)) 85 | .catch(err => console.error(err)); 86 | } 87 | } 88 | 89 | startRecording() { 90 | if (this.camera) { 91 | this.camera.capture({mode: Camera.constants.CaptureMode.video}) 92 | .then((data) => console.log(data)) 93 | .catch(err => console.error(err)); 94 | this.setState({ 95 | isRecording: true 96 | }); 97 | } 98 | } 99 | 100 | stopRecording() { 101 | if (this.camera) { 102 | this.camera.stopCapture(); 103 | this.setState({ 104 | isRecording: false 105 | }); 106 | } 107 | } 108 | 109 | switchType() { 110 | let newType; 111 | const { back, front } = Camera.constants.Type; 112 | 113 | if (this.state.camera.type === back) { 114 | newType = front; 115 | } else if (this.state.camera.type === front) { 116 | newType = back; 117 | } 118 | 119 | this.setState({ 120 | camera: { 121 | ...this.state.camera, 122 | type: newType, 123 | }, 124 | }); 125 | } 126 | 127 | get typeIcon() { 128 | let icon; 129 | const { back, front } = Camera.constants.Type; 130 | 131 | if (this.state.camera.type === back) { 132 | icon = require('./assets/ic_camera_rear_white.png'); 133 | } else if (this.state.camera.type === front) { 134 | icon = require('./assets/ic_camera_front_white.png'); 135 | } 136 | 137 | return icon; 138 | } 139 | 140 | switchFlash() { 141 | let newFlashMode; 142 | const { auto, on, off } = Camera.constants.FlashMode; 143 | 144 | if (this.state.camera.flashMode === auto) { 145 | newFlashMode = on; 146 | } else if (this.state.camera.flashMode === on) { 147 | newFlashMode = off; 148 | } else if (this.state.camera.flashMode === off) { 149 | newFlashMode = auto; 150 | } 151 | 152 | this.setState({ 153 | camera: { 154 | ...this.state.camera, 155 | flashMode: newFlashMode, 156 | }, 157 | }); 158 | } 159 | 160 | get flashIcon() { 161 | let icon; 162 | const { auto, on, off } = Camera.constants.FlashMode; 163 | 164 | if (this.state.camera.flashMode === auto) { 165 | icon = require('./assets/ic_flash_auto_white.png'); 166 | } else if (this.state.camera.flashMode === on) { 167 | icon = require('./assets/ic_flash_on_white.png'); 168 | } else if (this.state.camera.flashMode === off) { 169 | icon = require('./assets/ic_flash_off_white.png'); 170 | } 171 | 172 | return icon; 173 | } 174 | 175 | render() { 176 | return ( 177 | 178 |