Compare commits

..

No commits in common. "master" and "feat/hooks" have entirely different histories.

329 changed files with 10568 additions and 55339 deletions

View File

@ -1,56 +1,57 @@
version: 2.1
orbs:
react-native: react-native-community/react-native@4.4.0
commands:
checkout-attach-workspace:
description: "Checkout and attach workspace"
version: 2
executorType: docker
jobs:
build-app:
resource_class: large
environment:
- GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"'
- REACT_NATIVE_MAX_WORKERS: 2
- ANDROID_BUILD_TOOLS_VERSION: '28.0.3'
working_directory: ~/app
docker:
- image: reactnativecommunity/react-native-android
steps:
- checkout
- attach_workspace:
at: .
jobs:
install:
executor: react-native/linux_js
steps:
- checkout-attach-workspace
- react-native/yarn_install
- persist_to_workspace:
root: .
paths:
- node_modules
lint:
executor: react-native/linux_android
steps:
- checkout-attach-workspace
- restore_cache:
keys:
- v1-npm-{{ .Branch }}-{{ checksum "yarn.lock" }}
- v1-npm
- run:
name: Install Dependencies
command: yarn install --ignore-engines
- run:
name: Lint
command: yarn lint
build-app:
executor: react-native/linux_android
steps:
- checkout-attach-workspace
- run:
name: Run Checks
command: |
cd android
chmod +x ./gradlew && ./gradlew check
- store_artifacts:
path: android/build/reports
- run:
name: Run Yarn to Generate react.gradle
command: cd examples/basic/android && yarn
- react-native/android_build:
project_path: ./examples/basic/android
name: Build Sample App
command: |
cd examples/basic/android
yarn
chmod +x ./gradlew && ./gradlew build
- deploy:
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
yarn ci:publish
fi
- save_cache:
key: v1-npm
paths:
- node_modules/
- save_cache:
key: v1-npm-{{ .Branch }}-{{ checksum "yarn.lock" }}
paths:
- node_modules/
deploy-docs:
executor: react-native/linux_js
working_directory: ~/app
docker:
- image: circleci/node:8.11.1
steps:
- checkout-attach-workspace
- checkout
- run:
name: Deploying to GitHub Pages
command: |
@ -58,46 +59,12 @@ jobs:
git config --global user.name "${GH_NAME}"
echo "machine github.com login $GH_NAME password $GH_TOKEN_DOCS" > ~/.netrc
cd website && yarn install && GIT_USER=${GH_NAME} yarn run publish-gh-pages
publish-version:
executor: react-native/linux_js
steps:
- checkout-attach-workspace
- run:
name: Run semantic-release
command: yarn ci:publish
workflows:
version: 2
develop:
build-and-deploy-docs:
jobs:
- install:
filters:
branches:
ignore: master
- lint:
requires:
- install
- build-app:
requires:
- install
release:
jobs:
- install:
- build-app
- deploy-docs:
filters:
branches:
only: master
- deploy-docs:
requires:
- install
- publish-version:
requires:
- install

View File

@ -1 +0,0 @@
tests

3
.gitignore vendored
View File

@ -49,6 +49,3 @@ package-json.lock
examples/mlkit/android/app/google-services.json
examples/mlkit/ios/Pods
examples/mlkit/ios/mlkit/GoogleService-Info.plist
!debug.keystore
/ios/Pods/

View File

@ -3,5 +3,3 @@
circle.yml
commitlint.config.js
/android/build
/website
/docs

View File

@ -1,11 +1,7 @@
# React Native Camera [![Backers on Open Collective](https://opencollective.com/react-native-camera/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/react-native-camera/sponsors/badge.svg)](#sponsors) [![npm version](https://badge.fury.io/js/react-native-camera.svg)](http://badge.fury.io/js/react-native-camera) [![npm downloads](https://img.shields.io/npm/dm/react-native-camera.svg)](https://www.npmjs.com/package/react-native-camera)
[Looking for Maintainers](https://github.com/react-native-community/react-native-camera/issues/3000)
We are looking for maintainers for this package, or to deprecated this in favor of expo-camera, it nobody want to maintain this
## Docs
Follow our docs here [https://react-native-camera.github.io/react-native-camera/](https://react-native-camera.github.io/react-native-camera/)
Follow our docs here [https://react-native-community.github.io/react-native-camera/](https://react-native-community.github.io/react-native-camera/)
## Sponsors
@ -15,12 +11,6 @@ This gives you the power to prioritize our work and support the project contribu
[![issuehunt-image](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/33218414)
## react-native-camera for enterprise
Available as part of the Tidelift Subscription
The maintainers of react-native-camera and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
## Open Collective
You can also fund this project using open collective
@ -85,6 +75,12 @@ Supports:
- barcode scanning
- text recognition (optional installation for iOS using CocoaPods)
## Tidelift
[Get supported react-native-camera with the Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=readme)
![tidelift](https://tidelift.com/badges/github/react-native-community/react-native-camera)
### Example import
```jsx
@ -129,7 +125,7 @@ To enable `video recording` feature you have to add the following code to the `A
2) On iOS, you must update Info.plist with a usage description for camera
```xml
```
...
<key>NSCameraUsageDescription</key>
<string>Your own description of the purpose</string>
@ -139,11 +135,3 @@ To enable `video recording` feature you have to add the following code to the `A
For more information on installation, please refer to [installation requirements](./docs/installation.md#requirements).
For general introduction, please take a look into this [RNCamera](./docs/RNCamera.md).
## Security contact information
To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.

View File

@ -3,19 +3,13 @@ def safeExtGet(prop, fallback) {
}
buildscript {
// The Android Gradle plugin is only required when opening the android folder stand-alone.
// This avoids unnecessary downloads and potential conflicts when the library is included as a
// module dependency in an application project.
if (project == rootProject) {
repositories {
google()
jcenter()
}
repositories {
google()
jcenter()
}
dependencies {
//noinspection GradleDependency
classpath("com.android.tools.build:gradle:3.6.3")
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
}
}
@ -41,6 +35,18 @@ android {
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
general {
java.srcDirs = ['src/general/java']
}
mlkit {
java.srcDirs = ['src/mlkit/java']
}
}
lintOptions {
abortOnError false
warning 'InvalidPackage'
@ -66,8 +72,7 @@ repositories {
dependencies {
def googlePlayServicesVisionVersion = safeExtGet('googlePlayServicesVisionVersion', safeExtGet('googlePlayServicesVersion', '17.0.2'))
//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+' // From node_modules
implementation 'com.facebook.react:react-native:+'
implementation "com.google.zxing:core:3.3.3"
implementation "com.drewnoakes:metadata-extractor:2.11.0"
generalImplementation "com.google.android.gms:play-services-vision:$googlePlayServicesVisionVersion"

Binary file not shown.

View File

@ -1,5 +1,6 @@
#Wed Jan 23 23:35:17 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

120
android/gradlew vendored
View File

@ -1,20 +1,4 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#!/usr/bin/env bash
##############################################################################
##
@ -22,6 +6,42 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@ -40,46 +60,6 @@ cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@ -105,7 +85,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@ -125,8 +105,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
@ -170,19 +150,11 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
APP_ARGS=$(save "$@")
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

30
android/gradlew.bat vendored
View File

@ -1,19 +1,3 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -24,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@ -62,9 +46,10 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@ -75,6 +60,11 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

View File

@ -29,18 +29,19 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, S
private int mPaddingTop;
public BarcodeDetectorAsyncTask(
BarcodeDetectorAsyncTaskDelegate delegate,
RNBarcodeDetector barcodeDetector,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop) {
BarcodeDetectorAsyncTaskDelegate delegate,
RNBarcodeDetector barcodeDetector,
byte[] imageData,
int width,
int height,
int rotation,
float density,
int facing,
int viewWidth,
int viewHeight,
int viewPaddingLeft,
int viewPaddingTop
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
@ -72,7 +73,7 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, S
mDelegate.onBarcodeDetectionError(mBarcodeDetector);
} else {
if (barcodes.size() > 0) {
mDelegate.onBarcodesDetected(serializeEventData(barcodes), mWidth, mHeight, mImageData);
mDelegate.onBarcodesDetected(serializeEventData(barcodes));
}
mDelegate.onBarcodeDetectingTaskCompleted();
}

View File

@ -37,14 +37,12 @@ import android.media.CamcorderProfile;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.media.MediaActionSound;
import androidx.annotation.NonNull;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.Surface;
import android.os.Handler;
import android.os.Looper;
import android.os.Build;
import com.facebook.react.bridge.ReadableMap;
@ -52,17 +50,10 @@ import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import org.reactnative.camera.utils.ObjectUtils;
@SuppressWarnings("MissingPermission")
@TargetApi(21)
class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, MediaRecorder.OnErrorListener {
@ -208,14 +199,11 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private String mCameraId;
private String _mCameraId;
private CameraCharacteristics mCameraCharacteristics;
CameraDevice mCamera;
MediaActionSound sound = new MediaActionSound();
CameraCaptureSession mCaptureSession;
CaptureRequest.Builder mPreviewRequestBuilder;
@ -250,7 +238,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private int mFlash;
private float mExposure;
private int mExposure;
private int mCameraOrientation;
@ -266,14 +254,12 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private boolean mIsScanning;
private Boolean mPlaySoundOnCapture = false;
private Surface mPreviewSurface;
private Rect mInitialCropRegion;
Camera2(Callback callback, PreviewImpl preview, Context context, Handler bgHandler) {
super(callback, preview, bgHandler);
Camera2(Callback callback, PreviewImpl preview, Context context) {
super(callback, preview);
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
mCameraManager.registerAvailabilityCallback(new CameraManager.AvailabilityCallback() {
@Override
@ -306,7 +292,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
boolean start() {
if (!chooseCameraIdByFacing()) {
mAspectRatio = mInitialRatio;
mCallback.onMountError();
return false;
}
collectCameraInfo();
@ -345,8 +330,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mMediaRecorder = null;
if (mIsRecording) {
mCallback.onRecordingEnd();
// @TODO: implement videoOrientation and deviceOrientation calculation
mCallback.onVideoRecorded(mVideoPath, 0, 0);
mIsRecording = false;
@ -376,65 +359,11 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
return mFacing;
}
@Override
public ArrayList<int[]> getSupportedPreviewFpsRange() {
Log.e("CAMERA_2:: ", "getSupportedPreviewFpsRange is not currently supported for Camera2");
ArrayList<int[]> validValues = new ArrayList<int[]>();
return validValues;
}
@Override
void setCameraId(String id) {
if(!ObjectUtils.equals(_mCameraId, id)){
_mCameraId = id;
// only update if our camera ID actually changes
// from what we currently have.
// Passing null will always yield true
if(!ObjectUtils.equals(_mCameraId, mCameraId)){
// this will call chooseCameraIdByFacing
if (isCameraOpened()) {
stop();
start();
}
}
}
}
@Override
String getCameraId() {
return _mCameraId;
}
@Override
Set<AspectRatio> getSupportedAspectRatios() {
return mPreviewSizes.ratios();
}
@Override
List<Properties> getCameraIds() {
try{
List<Properties> ids = new ArrayList<>();
String[] cameraIds = mCameraManager.getCameraIdList();
for (String id : cameraIds) {
Properties p = new Properties();
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
p.put("id", id);
p.put("type", String.valueOf(internal == CameraCharacteristics.LENS_FACING_FRONT ? Constants.FACING_FRONT : Constants.FACING_BACK));
ids.add(p);
}
return ids;
}
catch (CameraAccessException e) {
throw new RuntimeException("Failed to get a list of camera ids", e);
}
}
@Override
SortedSet<Size> getAvailablePictureSizes(AspectRatio ratio) {
return mPictureSizes.sizes(ratio);
@ -455,7 +384,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mStillImageReader.close();
}
if (size == null) {
if (mAspectRatio == null || mPictureSize == null) {
if (mAspectRatio == null) {
return;
}
mPictureSizes.sizes(mAspectRatio).last();
@ -548,12 +477,12 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
}
@Override
float getExposureCompensation() {
int getExposureCompensation() {
return mExposure;
}
@Override
void setExposureCompensation(float exposure) {
void setExposureCompensation(int exposure) {
Log.e("CAMERA_2:: ", "Adjusting exposure is not currently supported for Camera2");
}
@ -570,7 +499,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
}
@Override
boolean record(String path, int maxDuration, int maxFileSize, boolean recordAudio, CamcorderProfile profile, int orientation, int fps) {
boolean record(String path, int maxDuration, int maxFileSize, boolean recordAudio, CamcorderProfile profile, int orientation) {
if (!mIsRecording) {
setUpMediaRecorder(path, maxDuration, maxFileSize, recordAudio, profile);
try {
@ -593,11 +522,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mSessionCallback, null);
mMediaRecorder.start();
mIsRecording = true;
// @TODO: implement videoOrientation and deviceOrientation calculation
// same TODO as onVideoRecorded
mCallback.onRecordingStart(mVideoPath, 0, 0);
return true;
} catch (CameraAccessException | IOException e) {
e.printStackTrace();
@ -620,16 +544,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
}
}
@Override
void pauseRecording() {
pauseMediaRecorder();
}
@Override
void resumeRecording() {
resumeMediaRecorder();
}
@Override
public void setFocusDepth(float value) {
if (mFocusDepth == value) {
@ -699,16 +613,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
return mWhiteBalance;
}
@Override
void setPlaySoundOnCapture(boolean playSoundOnCapture) {
mPlaySoundOnCapture = playSoundOnCapture;
}
@Override
public boolean getPlaySoundOnCapture(){
return mPlaySoundOnCapture;
}
@Override
void setScanning(boolean isScanning) {
if (mIsScanning == isScanning) {
@ -747,34 +651,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
@Override
void setDeviceOrientation(int deviceOrientation) {
mDeviceOrientation = deviceOrientation;
//mPreview.setDisplayOrientation(deviceOrientation); // this is not needed and messes up the display orientation
}
// This is a helper method to query Camera2 legacy status so we don't need
// to instantiate and set all its props in order to check if it is legacy or not
// and then fallback to Camera1. This way, legacy devices can fall back to Camera1 right away
// This method makes sure all cameras are not legacy, so further checks are not needed.
public static boolean isLegacy(Context context){
try{
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String[] ids = manager.getCameraIdList();
for (String id : ids) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
Integer level = characteristics.get(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null ||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
Log.w(TAG, "Camera2 can only run in legacy mode and should not be used.");
return true;
}
}
return false;
}
catch(CameraAccessException ex){
Log.e(TAG, "Failed to check camera legacy status, returning true.", ex);
return true;
}
mPreview.setDisplayOrientation(mDeviceOrientation);
}
/**
@ -783,79 +660,55 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
* {@link #mFacing}.</p>
*/
private boolean chooseCameraIdByFacing() {
if(_mCameraId == null){
try {
int internalFacing = INTERNAL_FACINGS.get(mFacing);
final String[] ids = mCameraManager.getCameraIdList();
if (ids.length == 0) { // No camera
Log.e(TAG, "No cameras available.");
return false;
try {
int internalFacing = INTERNAL_FACINGS.get(mFacing);
final String[] ids = mCameraManager.getCameraIdList();
if (ids.length == 0) { // No camera
throw new RuntimeException("No camera available.");
}
for (String id : ids) {
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
Integer level = characteristics.get(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null ||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
continue;
}
for (String id : ids) {
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
Log.e(TAG, "Unexpected state: LENS_FACING null");
continue;
}
if (internal == internalFacing) {
mCameraId = id;
mCameraCharacteristics = characteristics;
return true;
}
}
// Not found
mCameraId = ids[0];
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
Log.e(TAG, "Unexpected state: LENS_FACING null");
return false;
throw new NullPointerException("Unexpected state: LENS_FACING null");
}
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
if (INTERNAL_FACINGS.valueAt(i) == internal) {
mFacing = INTERNAL_FACINGS.keyAt(i);
return true;
}
if (internal == internalFacing) {
mCameraId = id;
mCameraCharacteristics = characteristics;
return true;
}
// The operation can reach here when the only camera device is an external one.
// We treat it as facing back.
mFacing = Constants.FACING_BACK;
return true;
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to get a list of camera devices", e);
}
// Not found
mCameraId = ids[0];
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
Integer level = mCameraCharacteristics.get(
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null ||
level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
return false;
}
}
else{
try{
// need to set the mCameraCharacteristics variable as above and also do the same checks
// for legacy hardware
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(_mCameraId);
// set our facing variable so orientation also works as expected
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
Log.e(TAG, "Unexpected state: LENS_FACING null");
return false;
}
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
if (INTERNAL_FACINGS.valueAt(i) == internal) {
mFacing = INTERNAL_FACINGS.keyAt(i);
break;
}
}
mCameraId = _mCameraId;
return true;
Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (internal == null) {
throw new NullPointerException("Unexpected state: LENS_FACING null");
}
catch(Exception e){
Log.e(TAG, "Failed to get camera characteristics", e);
return false;
for (int i = 0, count = INTERNAL_FACINGS.size(); i < count; i++) {
if (INTERNAL_FACINGS.valueAt(i) == internal) {
mFacing = INTERNAL_FACINGS.keyAt(i);
return true;
}
}
// The operation can reach here when the only camera device is an external one.
// We treat it as facing back.
mFacing = Constants.FACING_BACK;
return true;
} catch (CameraAccessException e) {
throw new RuntimeException("Failed to get a list of camera devices", e);
}
}
@ -955,7 +808,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mCamera.createCaptureSession(Arrays.asList(surface, mStillImageReader.getSurface(),
mScanImageReader.getSurface()), mSessionCallback, null);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to start capture session", e);
mCallback.onMountError();
}
}
@ -1198,9 +1050,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
// Much credit - https://gist.github.com/royshil/8c760c2485257c85a11cafd958548482
void setFocusArea(float x, float y) {
if (mCaptureSession == null) {
return;
}
CameraCaptureSession.CaptureCallback captureCallbackHandler = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
@ -1225,6 +1074,7 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
try {
mCaptureSession.stopRepeating();
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to manual focus.", e);
}
@ -1315,13 +1165,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
break;
}
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOutputRotation());
if(mCaptureCallback.getOptions().hasKey("quality")){
int quality = (int) (mCaptureCallback.getOptions().getDouble("quality") * 100);
captureRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte)quality);
}
captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, mPreviewRequestBuilder.get(CaptureRequest.SCALER_CROP_REGION));
// Stop preview and capture a still picture.
mCaptureSession.stopRepeating();
@ -1335,9 +1178,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
&& !mCaptureCallback.getOptions().getBoolean("pauseAfterCapture")) {
unlockFocus();
}
if (mPlaySoundOnCapture) {
sound.play(MediaActionSound.SHUTTER_CLICK);
}
}
}, null);
} catch (CameraAccessException e) {
@ -1348,25 +1188,9 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
private int getOutputRotation() {
@SuppressWarnings("ConstantConditions")
int sensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
// updated and copied from Camera1
if (mFacing == Constants.FACING_BACK) {
return (sensorOrientation + mDeviceOrientation) % 360;
} else {
final int landscapeFlip = isLandscape(mDeviceOrientation) ? 180 : 0;
return (sensorOrientation + mDeviceOrientation + landscapeFlip) % 360;
}
}
/**
* Test if the supplied orientation is in landscape.
*
* @param orientationDegrees Orientation in degrees (0,90,180,270)
* @return True if in landscape, false if portrait
*/
private boolean isLandscape(int orientationDegrees) {
return (orientationDegrees == Constants.LANDSCAPE_90 ||
orientationDegrees == Constants.LANDSCAPE_270);
return (sensorOrientation +
mDisplayOrientation * (mFacing == Constants.FACING_FRONT ? 1 : -1) +
360) % 360;
}
private void setUpMediaRecorder(String path, int maxDuration, int maxFileSize, boolean recordAudio, CamcorderProfile profile) {
@ -1427,8 +1251,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mMediaRecorder.release();
mMediaRecorder = null;
mCallback.onRecordingEnd();
if (mVideoPath == null || !new File(mVideoPath).exists()) {
// @TODO: implement videoOrientation and deviceOrientation calculation
mCallback.onVideoRecorded(null, 0 , 0);
@ -1439,18 +1261,6 @@ class Camera2 extends CameraViewImpl implements MediaRecorder.OnInfoListener, Me
mVideoPath = null;
}
private void pauseMediaRecorder() {
if (Build.VERSION.SDK_INT >= 24) {
mMediaRecorder.pause();
}
}
private void resumeMediaRecorder() {
if (Build.VERSION.SDK_INT >= 24) {
mMediaRecorder.resume();
}
}
/**
* Unlocks the auto-focus and restart camera preview. This is supposed to be called after
* capturing a still picture.

View File

@ -20,14 +20,13 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Handler;
@TargetApi(23)
class Camera2Api23 extends Camera2 {
Camera2Api23(Callback callback, PreviewImpl preview, Context context, Handler bgHandler) {
super(callback, preview, context, bgHandler);
Camera2Api23(Callback callback, PreviewImpl preview, Context context) {
super(callback, preview, context);
}
@Override

View File

@ -22,8 +22,6 @@ import android.graphics.Rect;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.os.Build;
import android.os.HandlerThread;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.IntDef;
@ -43,8 +41,6 @@ import com.facebook.react.bridge.ReadableMap;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
@ -93,10 +89,6 @@ public class CameraView extends FrameLayout {
private final DisplayOrientationDetector mDisplayOrientationDetector;
protected HandlerThread mBgThread;
protected Handler mBgHandler;
public CameraView(Context context, boolean fallbackToOldApi) {
this(context, null, fallbackToOldApi);
}
@ -108,13 +100,6 @@ public class CameraView extends FrameLayout {
@SuppressWarnings("WrongConstant")
public CameraView(Context context, AttributeSet attrs, int defStyleAttr, boolean fallbackToOldApi) {
super(context, attrs, defStyleAttr);
// bg hanadler for non UI heavy work
mBgThread = new HandlerThread("RNCamera-Handler-Thread");
mBgThread.start();
mBgHandler = new Handler(mBgThread.getLooper());
if (isInEditMode()){
mCallbacks = null;
mDisplayOrientationDetector = null;
@ -126,12 +111,12 @@ public class CameraView extends FrameLayout {
// Internal setup
final PreviewImpl preview = createPreviewImpl(context);
mCallbacks = new CallbackBridge();
if (fallbackToOldApi || Build.VERSION.SDK_INT < 21 || Camera2.isLegacy(context)) {
mImpl = new Camera1(mCallbacks, preview, mBgHandler);
if (fallbackToOldApi || Build.VERSION.SDK_INT < 21) {
mImpl = new Camera1(mCallbacks, preview);
} else if (Build.VERSION.SDK_INT < 23) {
mImpl = new Camera2(mCallbacks, preview, context, mBgHandler);
mImpl = new Camera2(mCallbacks, preview, context);
} else {
mImpl = new Camera2Api23(mCallbacks, preview, context, mBgHandler);
mImpl = new Camera2Api23(mCallbacks, preview, context);
}
// Display orientation detector
@ -144,19 +129,6 @@ public class CameraView extends FrameLayout {
};
}
public void cleanup(){
if(mBgThread != null){
if(Build.VERSION.SDK_INT < 18){
mBgThread.quit();
}
else{
mBgThread.quitSafely();
}
mBgThread = null;
}
}
@NonNull
private PreviewImpl createPreviewImpl(Context context) {
PreviewImpl preview;
@ -248,7 +220,6 @@ public class CameraView extends FrameLayout {
protected Parcelable onSaveInstanceState() {
SavedState state = new SavedState(super.onSaveInstanceState());
state.facing = getFacing();
state.cameraId = getCameraId();
state.ratio = getAspectRatio();
state.autoFocus = getAutoFocus();
state.flash = getFlash();
@ -256,7 +227,6 @@ public class CameraView extends FrameLayout {
state.focusDepth = getFocusDepth();
state.zoom = getZoom();
state.whiteBalance = getWhiteBalance();
state.playSoundOnCapture = getPlaySoundOnCapture();
state.scanning = getScanning();
state.pictureSize = getPictureSize();
return state;
@ -271,7 +241,6 @@ public class CameraView extends FrameLayout {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setFacing(ss.facing);
setCameraId(ss.cameraId);
setAspectRatio(ss.ratio);
setAutoFocus(ss.autoFocus);
setFlash(ss.flash);
@ -279,7 +248,6 @@ public class CameraView extends FrameLayout {
setFocusDepth(ss.focusDepth);
setZoom(ss.zoom);
setWhiteBalance(ss.whiteBalance);
setPlaySoundOnCapture(ss.playSoundOnCapture);
setScanning(ss.scanning);
setPictureSize(ss.pictureSize);
}
@ -292,17 +260,15 @@ public class CameraView extends FrameLayout {
boolean wasOpened = isCameraOpened();
Parcelable state = onSaveInstanceState();
if (useCamera2 && !Camera2.isLegacy(mContext)) {
if (useCamera2) {
if (wasOpened) {
stop();
}
if (Build.VERSION.SDK_INT < 23) {
mImpl = new Camera2(mCallbacks, mImpl.mPreview, mContext, mBgHandler);
mImpl = new Camera2(mCallbacks, mImpl.mPreview, mContext);
} else {
mImpl = new Camera2Api23(mCallbacks, mImpl.mPreview, mContext, mBgHandler);
mImpl = new Camera2Api23(mCallbacks, mImpl.mPreview, mContext);
}
onRestoreInstanceState(state);
} else {
if (mImpl instanceof Camera1) {
return;
@ -311,11 +277,9 @@ public class CameraView extends FrameLayout {
if (wasOpened) {
stop();
}
mImpl = new Camera1(mCallbacks, mImpl.mPreview, mBgHandler);
}
if(wasOpened){
start();
mImpl = new Camera1(mCallbacks, mImpl.mPreview);
}
start();
}
/**
@ -323,20 +287,17 @@ public class CameraView extends FrameLayout {
* {@link Activity#onResume()}.
*/
public void start() {
mImpl.start();
// this fallback is no longer needed and was too buggy/slow
// if (!mImpl.start()) {
// if (mImpl.getView() != null) {
// this.removeView(mImpl.getView());
// }
// //store the state and restore this state after fall back to Camera1
// Parcelable state = onSaveInstanceState();
// // Camera2 uses legacy hardware layer; fall back to Camera1
// mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()), mBgHandler);
// onRestoreInstanceState(state);
// mImpl.start();
// }
if (!mImpl.start()) {
if (mImpl.getView() != null) {
this.removeView(mImpl.getView());
}
//store the state and restore this state after fall back to Camera1
Parcelable state=onSaveInstanceState();
// Camera2 uses legacy hardware layer; fall back to Camera1
mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()));
onRestoreInstanceState(state);
mImpl.start();
}
}
/**
@ -423,24 +384,6 @@ public class CameraView extends FrameLayout {
return mImpl.getFacing();
}
/**
* Chooses camera by its camera iD
*
* @param id The camera ID
*/
public void setCameraId(String id) {
mImpl.setCameraId(id);
}
/**
* Gets the currently set camera ID
*
* @return The camera facing.
*/
public String getCameraId() {
return mImpl.getCameraId();
}
/**
* Gets all the aspect ratios supported by the current camera.
*/
@ -448,13 +391,6 @@ public class CameraView extends FrameLayout {
return mImpl.getSupportedAspectRatios();
}
/**
* Gets all the camera IDs supported by the phone as a String
*/
public List<Properties> getCameraIds() {
return mImpl.getCameraIds();
}
/**
* Sets the aspect ratio of camera.
*
@ -475,7 +411,7 @@ public class CameraView extends FrameLayout {
public AspectRatio getAspectRatio() {
return mImpl.getAspectRatio();
}
/**
* Gets all the picture sizes for particular ratio supported by the current camera.
*
@ -484,7 +420,7 @@ public class CameraView extends FrameLayout {
public SortedSet<Size> getAvailablePictureSizes(@NonNull AspectRatio ratio) {
return mImpl.getAvailablePictureSizes(ratio);
}
/**
* Sets the size of taken pictures.
*
@ -493,7 +429,7 @@ public class CameraView extends FrameLayout {
public void setPictureSize(@NonNull Size size) {
mImpl.setPictureSize(size);
}
/**
* Gets the size of pictures that will be taken.
*/
@ -531,10 +467,6 @@ public class CameraView extends FrameLayout {
mImpl.setFlash(flash);
}
public ArrayList<int[]> getSupportedPreviewFpsRange() {
return mImpl.getSupportedPreviewFpsRange();
}
/**
* Gets the current flash mode.
*
@ -546,11 +478,11 @@ public class CameraView extends FrameLayout {
return mImpl.getFlash();
}
public void setExposureCompensation(float exposure) {
public void setExposureCompensation(int exposure) {
mImpl.setExposureCompensation(exposure);
}
public float getExposureCompensation() {
public int getExposureCompensation() {
return mImpl.getExposureCompensation();
}
@ -563,7 +495,7 @@ public class CameraView extends FrameLayout {
public int getCameraOrientation() {
return mImpl.getCameraOrientation();
}
/**
* Sets the auto focus point.
*
@ -596,14 +528,6 @@ public class CameraView extends FrameLayout {
return mImpl.getWhiteBalance();
}
public void setPlaySoundOnCapture(boolean playSoundOnCapture) {
mImpl.setPlaySoundOnCapture(playSoundOnCapture);
}
public boolean getPlaySoundOnCapture() {
return mImpl.getPlaySoundOnCapture();
}
public void setScanning(boolean isScanning) { mImpl.setScanning(isScanning);}
public boolean getScanning() { return mImpl.getScanning(); }
@ -623,30 +547,20 @@ public class CameraView extends FrameLayout {
* @param maxDuration Maximum duration of the recording, in seconds.
* @param maxFileSize Maximum recording file size, in bytes.
* @param profile Quality profile of the recording.
*
* fires {@link Callback#onRecordingStart(CameraView, String, int, int)} and {@link Callback#onRecordingEnd(CameraView)}.
*/
public boolean record(String path, int maxDuration, int maxFileSize,
boolean recordAudio, CamcorderProfile profile, int orientation, int fps) {
return mImpl.record(path, maxDuration, maxFileSize, recordAudio, profile, orientation, fps);
boolean recordAudio, CamcorderProfile profile, int orientation) {
return mImpl.record(path, maxDuration, maxFileSize, recordAudio, profile, orientation);
}
public void stopRecording() {
mImpl.stopRecording();
}
public void pauseRecording() {
mImpl.pauseRecording();
}
public void resumeRecording() {
mImpl.resumeRecording();
}
public void resumePreview() {
mImpl.resumePreview();
}
public void pausePreview() {
mImpl.pausePreview();
}
@ -701,20 +615,6 @@ public class CameraView extends FrameLayout {
}
}
@Override
public void onRecordingStart(String path, int videoOrientation, int deviceOrientation) {
for (Callback callback : mCallbacks) {
callback.onRecordingStart(CameraView.this, path, videoOrientation, deviceOrientation);
}
}
@Override
public void onRecordingEnd() {
for (Callback callback : mCallbacks) {
callback.onRecordingEnd(CameraView.this);
}
}
@Override
public void onVideoRecorded(String path, int videoOrientation, int deviceOrientation) {
for (Callback callback : mCallbacks) {
@ -746,8 +646,6 @@ public class CameraView extends FrameLayout {
@Facing
int facing;
String cameraId;
AspectRatio ratio;
boolean autoFocus;
@ -755,7 +653,7 @@ public class CameraView extends FrameLayout {
@Flash
int flash;
float exposure;
int exposure;
float focusDepth;
@ -763,25 +661,21 @@ public class CameraView extends FrameLayout {
int whiteBalance;
boolean playSoundOnCapture;
boolean scanning;
Size pictureSize;
@SuppressWarnings("WrongConstant")
public SavedState(Parcel source, ClassLoader loader) {
super(source);
facing = source.readInt();
cameraId = source.readString();
ratio = source.readParcelable(loader);
autoFocus = source.readByte() != 0;
flash = source.readInt();
exposure = source.readFloat();
exposure = source.readInt();
focusDepth = source.readFloat();
zoom = source.readFloat();
whiteBalance = source.readInt();
playSoundOnCapture = source.readByte() != 0;
scanning = source.readByte() != 0;
pictureSize = source.readParcelable(loader);
}
@ -794,15 +688,13 @@ public class CameraView extends FrameLayout {
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(facing);
out.writeString(cameraId);
out.writeParcelable(ratio, 0);
out.writeByte((byte) (autoFocus ? 1 : 0));
out.writeInt(flash);
out.writeFloat(exposure);
out.writeInt(exposure);
out.writeFloat(focusDepth);
out.writeFloat(zoom);
out.writeInt(whiteBalance);
out.writeByte((byte) (playSoundOnCapture ? 1 : 0));
out.writeByte((byte) (scanning ? 1 : 0));
out.writeParcelable(pictureSize, flags);
}
@ -835,14 +727,16 @@ public class CameraView extends FrameLayout {
*
* @param cameraView The associated {@link CameraView}.
*/
public void onCameraOpened(CameraView cameraView) {}
public void onCameraOpened(CameraView cameraView) {
}
/**
* Called when camera is closed.
*
* @param cameraView The associated {@link CameraView}.
*/
public void onCameraClosed(CameraView cameraView) {}
public void onCameraClosed(CameraView cameraView) {
}
/**
* Called when a picture is taken.
@ -850,23 +744,8 @@ public class CameraView extends FrameLayout {
* @param cameraView The associated {@link CameraView}.
* @param data JPEG data.
*/
public void onPictureTaken(CameraView cameraView, byte[] data, int deviceOrientation) {}
/**
* Called when a video recording starts
*
* @param cameraView The associated {@link CameraView}.
* @param path Path to recoredd video file.
*/
public void onRecordingStart(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {}
/**
* Called when a video recording ends, but before video is saved/processed.
*
* @param cameraView The associated {@link CameraView}.
* @param path Path to recoredd video file.
*/
public void onRecordingEnd(CameraView cameraView){}
public void onPictureTaken(CameraView cameraView, byte[] data, int deviceOrientation) {
}
/**
* Called when a video is recorded.
@ -874,9 +753,11 @@ public class CameraView extends FrameLayout {
* @param cameraView The associated {@link CameraView}.
* @param path Path to recoredd video file.
*/
public void onVideoRecorded(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {}
public void onVideoRecorded(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {
}
public void onFramePreview(CameraView cameraView, byte[] data, int width, int height, int orientation) {}
public void onFramePreview(CameraView cameraView, byte[] data, int width, int height, int orientation) {
}
public void onMountError(CameraView cameraView) {}
}

View File

@ -19,33 +19,21 @@ package com.google.android.cameraview;
import android.media.CamcorderProfile;
import android.view.View;
import android.graphics.SurfaceTexture;
import android.os.Handler;
import com.facebook.react.bridge.ReadableMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
abstract class CameraViewImpl {
protected final Callback mCallback;
protected final PreviewImpl mPreview;
// Background handler that the implementation an use to run heavy tasks in background
// in a thread/looper provided by the view.
// Most calls should not require this since the view will already schedule it
// on the bg thread. However, the implementation might need to do some heavy work
// by itself.
protected final Handler mBgHandler;
CameraViewImpl(Callback callback, PreviewImpl preview, Handler bgHandler) {
CameraViewImpl(Callback callback, PreviewImpl preview) {
mCallback = callback;
mPreview = preview;
mBgHandler = bgHandler;
}
View getView() {
@ -62,21 +50,15 @@ abstract class CameraViewImpl {
abstract boolean isCameraOpened();
abstract void setFacing(int facing);
abstract int getFacing();
abstract void setCameraId(String id);
abstract String getCameraId();
abstract Set<AspectRatio> getSupportedAspectRatios();
abstract List<Properties> getCameraIds();
abstract SortedSet<Size> getAvailablePictureSizes(AspectRatio ratio);
abstract void setPictureSize(Size size);
abstract Size getPictureSize();
/**
@ -94,27 +76,23 @@ abstract class CameraViewImpl {
abstract int getFlash();
abstract void setExposureCompensation(float exposure);
abstract void setExposureCompensation(int exposure);
abstract float getExposureCompensation();
abstract int getExposureCompensation();
abstract void takePicture(ReadableMap options);
abstract boolean record(String path, int maxDuration, int maxFileSize,
boolean recordAudio, CamcorderProfile profile, int orientation, int fps);
boolean recordAudio, CamcorderProfile profile, int orientation);
abstract void stopRecording();
abstract void pauseRecording();
abstract void resumeRecording();
abstract int getCameraOrientation();
abstract void setDisplayOrientation(int displayOrientation);
abstract void setDeviceOrientation(int deviceOrientation);
abstract void setFocusArea(float x, float y);
abstract void setFocusDepth(float value);
@ -125,22 +103,16 @@ abstract class CameraViewImpl {
abstract float getZoom();
abstract public ArrayList<int[]> getSupportedPreviewFpsRange();
abstract void setWhiteBalance(int whiteBalance);
abstract int getWhiteBalance();
abstract void setPlaySoundOnCapture(boolean playSoundOnCapture);
abstract boolean getPlaySoundOnCapture();
abstract void setScanning(boolean isScanning);
abstract boolean getScanning();
abstract public void resumePreview();
abstract public void pausePreview();
abstract public void setPreviewTexture(SurfaceTexture surfaceTexture);
@ -157,10 +129,6 @@ abstract class CameraViewImpl {
void onVideoRecorded(String path, int videoOrientation, int deviceOrientation);
void onRecordingStart(String path, int videoOrientation, int deviceOrientation);
void onRecordingEnd();
void onFramePreview(byte[] data, int width, int height, int orientation);
void onMountError();

View File

@ -20,16 +20,12 @@ import com.google.android.cameraview.Size;
import javax.annotation.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Properties;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
public class CameraModule extends ReactContextBaseJavaModule {
private static final String TAG = "CameraModule";
@ -212,7 +208,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
}
});
}
@ReactMethod
public void pausePreview(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
@ -221,7 +217,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
@ -233,7 +229,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
}
});
}
@ReactMethod
public void resumePreview(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
@ -242,7 +238,7 @@ public class CameraModule extends ReactContextBaseJavaModule {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
@ -265,15 +261,14 @@ public class CameraModule extends ReactContextBaseJavaModule {
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
RNCameraView cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
try {
if (cameraView.isCameraOpened()) {
cameraView.takePicture(options, promise, cacheDirectory);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
}
catch (Exception e) {
promise.reject("E_TAKE_PICTURE_FAILED", e.getMessage());
}
if (cameraView.isCameraOpened()) {
cameraView.takePicture(options, promise, cacheDirectory);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
} catch (Exception e) {
promise.reject("E_CAMERA_BAD_VIEWTAG", "takePictureAsync: Expected a Camera component");
}
}
});
}
@ -324,48 +319,6 @@ public class CameraModule extends ReactContextBaseJavaModule {
});
}
@ReactMethod
public void pauseRecording(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
cameraView.pauseRecording();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@ReactMethod
public void resumeRecording(final int viewTag) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
if (cameraView.isCameraOpened()) {
cameraView.resumeRecording();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@ReactMethod
public void getSupportedRatios(final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
@ -392,104 +345,49 @@ public class CameraModule extends ReactContextBaseJavaModule {
}
});
}
@ReactMethod
public void getAvailablePictureSizes(final String ratio, final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
if (cameraView.isCameraOpened()) {
SortedSet<Size> sizes = cameraView.getAvailablePictureSizes(AspectRatio.parse(ratio));
for (Size size : sizes) {
result.pushString(size.toString());
}
promise.resolve(result);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
} catch (Exception e) {
promise.reject("E_CAMERA_BAD_VIEWTAG", "getAvailablePictureSizesAsync: Expected a Camera component");
}
}
});
}
@ReactMethod
public void getCameraIds(final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
List<Properties> ids = cameraView.getCameraIds();
for (Properties p : ids) {
WritableMap m = new WritableNativeMap();
m.putString("id", p.getProperty("id"));
m.putInt("type", Integer.valueOf(p.getProperty("type")));
result.pushMap(m);
}
promise.resolve(result);
} catch (Exception e) {
e.printStackTrace();
promise.reject("E_CAMERA_FAILED", e.getMessage());
}
}
});
}
@ReactMethod
public void getAvailablePictureSizes(final String ratio, final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
if (cameraView.isCameraOpened()) {
SortedSet<Size> sizes = cameraView.getAvailablePictureSizes(AspectRatio.parse(ratio));
for (Size size : sizes) {
result.pushString(size.toString());
}
promise.resolve(result);
} else {
promise.reject("E_CAMERA_UNAVAILABLE", "Camera is not running");
}
} catch (Exception e) {
promise.reject("E_CAMERA_BAD_VIEWTAG", "getAvailablePictureSizesAsync: Expected a Camera component");
}
}
});
}
@ReactMethod
public void checkIfRecordAudioPermissionsAreDefined(final Promise promise) {
try {
PackageInfo info = getCurrentActivity().getPackageManager().getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.equals(Manifest.permission.RECORD_AUDIO)) {
promise.resolve(true);
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
promise.resolve(false);
}
@ReactMethod
public void getSupportedPreviewFpsRange(final int viewTag, final Promise promise) {
final ReactApplicationContext context = getReactApplicationContext();
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
uiManager.addUIBlock(new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
final RNCameraView cameraView;
try {
cameraView = (RNCameraView) nativeViewHierarchyManager.resolveView(viewTag);
WritableArray result = Arguments.createArray();
ArrayList<int[]> ranges = cameraView.getSupportedPreviewFpsRange();
for (int[] range : ranges) {
WritableMap m = new WritableNativeMap();
m.putInt("MAXIMUM_FPS", range[0]);
m.putInt("MINIMUM_FPS", range[1]);
result.pushMap(m);
}
promise.resolve(result);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@ReactMethod
public void checkIfRecordAudioPermissionsAreDefined(final Promise promise) {
try {
PackageInfo info = getCurrentActivity().getPackageManager().getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.equals(Manifest.permission.RECORD_AUDIO)) {
promise.resolve(true);
return;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
promise.resolve(false);
}
}

View File

@ -25,11 +25,7 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
EVENT_ON_BARCODE_DETECTION_ERROR("onGoogleVisionBarcodeDetectionError"),
EVENT_ON_TEXT_RECOGNIZED("onTextRecognized"),
EVENT_ON_PICTURE_TAKEN("onPictureTaken"),
EVENT_ON_PICTURE_SAVED("onPictureSaved"),
EVENT_ON_RECORDING_START("onRecordingStart"),
EVENT_ON_RECORDING_END("onRecordingEnd"),
EVENT_ON_TOUCH("onTouch");
EVENT_ON_PICTURE_SAVED("onPictureSaved");
private final String mName;
@ -47,7 +43,7 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
@Override
public void onDropViewInstance(RNCameraView view) {
view.onHostDestroy();
view.stop();
super.onDropViewInstance(view);
}
@ -77,11 +73,6 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setFacing(type);
}
@ReactProp(name = "cameraId")
public void setCameraId(RNCameraView view, String id) {
view.setCameraId(id);
}
@ReactProp(name = "ratio")
public void setRatio(RNCameraView view, String ratio) {
view.setAspectRatio(AspectRatio.parse(ratio));
@ -93,7 +84,7 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
}
@ReactProp(name = "exposure")
public void setExposureCompensation(RNCameraView view, float exposure){
public void setExposureCompensation(RNCameraView view, int exposure){
view.setExposureCompensation(exposure);
}
@ -109,11 +100,9 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
@ReactProp(name = "autoFocusPointOfInterest")
public void setAutoFocusPointOfInterest(RNCameraView view, ReadableMap coordinates) {
if(coordinates != null){
float x = (float) coordinates.getDouble("x");
float y = (float) coordinates.getDouble("y");
view.setAutoFocusPointOfInterest(x, y);
}
float x = (float) coordinates.getDouble("x");
float y = (float) coordinates.getDouble("y");
view.setAutoFocusPointOfInterest(x, y);
}
@ReactProp(name = "zoom")
@ -121,10 +110,6 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setZoom(zoom);
}
@ReactProp(name = "useNativeZoom")
public void setUseNativeZoom(RNCameraView view, boolean useNativeZoom) {
view.setUseNativeZoom(useNativeZoom);
}
@ReactProp(name = "whiteBalance")
public void setWhiteBalance(RNCameraView view, int whiteBalance) {
view.setWhiteBalance(whiteBalance);
@ -135,11 +120,6 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setPictureSize(size.equals("None") ? null : Size.parse(size));
}
@ReactProp(name = "playSoundOnCapture")
public void setPlaySoundOnCapture(RNCameraView view, boolean playSoundOnCapture) {
view.setPlaySoundOnCapture(playSoundOnCapture);
}
@ReactProp(name = "barCodeTypes")
public void setBarCodeTypes(RNCameraView view, ReadableArray barCodeTypes) {
if (barCodeTypes == null) {
@ -152,11 +132,6 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setBarCodeTypes(result);
}
@ReactProp(name = "detectedImageInEvent")
public void setDetectedImageInEvent(RNCameraView view, boolean detectedImageInEvent) {
view.setDetectedImageInEvent(detectedImageInEvent);
}
@ReactProp(name = "barCodeScannerEnabled")
public void setBarCodeScanning(RNCameraView view, boolean barCodeScannerEnabled) {
view.setShouldScanBarCodes(barCodeScannerEnabled);
@ -167,9 +142,9 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
view.setUsingCamera2Api(useCamera2Api);
}
@ReactProp(name = "touchDetectorEnabled")
public void setTouchDetectorEnabled(RNCameraView view, boolean touchDetectorEnabled) {
view.setShouldDetectTouches(touchDetectorEnabled);
@ReactProp(name = "playSoundOnCapture")
public void setPlaySoundOnCapture(RNCameraView view, boolean playSoundOnCapture) {
view.setPlaySoundOnCapture(playSoundOnCapture);
}
@ReactProp(name = "faceDetectorEnabled")
@ -196,7 +171,7 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
public void setTracking(RNCameraView view, boolean trackingEnabled) {
view.setTracking(trackingEnabled);
}
@ReactProp(name = "googleVisionBarcodeDetectorEnabled")
public void setGoogleVisionBarcodeDetecting(RNCameraView view, boolean googleBarcodeDetectorEnabled) {
view.setShouldGoogleDetectBarcodes(googleBarcodeDetectorEnabled);
@ -216,26 +191,4 @@ public class CameraViewManager extends ViewGroupManager<RNCameraView> {
public void setTextRecognizing(RNCameraView view, boolean textRecognizerEnabled) {
view.setShouldRecognizeText(textRecognizerEnabled);
}
/**---limit scan area addition---**/
@ReactProp(name = "rectOfInterest")
public void setRectOfInterest(RNCameraView view, ReadableMap coordinates) {
if(coordinates != null){
float x = (float) coordinates.getDouble("x");
float y = (float) coordinates.getDouble("y");
float width = (float) coordinates.getDouble("width");
float height = (float) coordinates.getDouble("height");
view.setRectOfInterest(x, y, width, height);
}
}
@ReactProp(name = "cameraViewDimensions")
public void setCameraViewDimensions(RNCameraView view, ReadableMap dimensions) {
if(dimensions != null){
int cameraViewWidth = (int) dimensions.getDouble("width");
int cameraViewHeight = (int) dimensions.getDouble("height");
view.setCameraViewDimensions(cameraViewWidth, cameraViewHeight);
}
}
/**---limit scan area addition---**/
}

View File

@ -3,20 +3,11 @@ package org.reactnative.camera;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.CamcorderProfile;
import android.media.MediaActionSound;
import android.os.Build;
import androidx.core.content.ContextCompat;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.os.AsyncTask;
import com.facebook.react.bridge.*;
@ -31,7 +22,6 @@ import org.reactnative.camera.tasks.*;
import org.reactnative.camera.utils.RNFileUtils;
import org.reactnative.facedetector.RNFaceDetector;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;
@ -46,18 +36,13 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
private Map<Promise, File> mPictureTakenDirectories = new ConcurrentHashMap<>();
private Promise mVideoRecordedPromise;
private List<String> mBarCodeTypes = null;
private boolean mDetectedImageInEvent = false;
private ScaleGestureDetector mScaleGestureDetector;
private GestureDetector mGestureDetector;
private Boolean mPlaySoundOnCapture = false;
private boolean mIsPaused = false;
private boolean mIsNew = true;
private boolean invertImageData = false;
private Boolean mIsRecording = false;
private Boolean mIsRecordingInterrupted = false;
private boolean mUseNativeZoom=false;
// Concurrency lock for scanners to avoid flooding the runtime
public volatile boolean barCodeScannerTaskLock = false;
@ -73,7 +58,6 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
private boolean mShouldGoogleDetectBarcodes = false;
private boolean mShouldScanBarCodes = false;
private boolean mShouldRecognizeText = false;
private boolean mShouldDetectTouches = false;
private int mFaceDetectorMode = RNFaceDetector.FAST_MODE;
private int mFaceDetectionLandmarks = RNFaceDetector.NO_LANDMARKS;
private int mFaceDetectionClassifications = RNFaceDetector.NO_CLASSIFICATIONS;
@ -83,15 +67,6 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
private int mPaddingX;
private int mPaddingY;
// Limit Android Scan Area
private boolean mLimitScanArea = false;
private float mScanAreaX = 0.0f;
private float mScanAreaY = 0.0f;
private float mScanAreaWidth = 0.0f;
private float mScanAreaHeight = 0.0f;
private int mCameraViewWidth = 0;
private int mCameraViewHeight = 0;
public RNCameraView(ThemedReactContext themedReactContext) {
super(themedReactContext, true);
mThemedReactContext = themedReactContext;
@ -126,20 +101,6 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
RNCameraViewHelper.emitPictureTakenEvent(cameraView);
}
@Override
public void onRecordingStart(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {
WritableMap result = Arguments.createMap();
result.putInt("videoOrientation", videoOrientation);
result.putInt("deviceOrientation", deviceOrientation);
result.putString("uri", RNFileUtils.uriFromFile(new File(path)).toString());
RNCameraViewHelper.emitRecordingStartEvent(cameraView, result);
}
@Override
public void onRecordingEnd(CameraView cameraView) {
RNCameraViewHelper.emitRecordingEndEvent(cameraView);
}
@Override
public void onVideoRecorded(CameraView cameraView, String path, int videoOrientation, int deviceOrientation) {
if (mVideoRecordedPromise != null) {
@ -177,7 +138,7 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
if (willCallBarCodeTask) {
barCodeScannerTaskLock = true;
BarCodeScannerAsyncTaskDelegate delegate = (BarCodeScannerAsyncTaskDelegate) cameraView;
new BarCodeScannerAsyncTask(delegate, mMultiFormatReader, data, width, height, mLimitScanArea, mScanAreaX, mScanAreaY, mScanAreaWidth, mScanAreaHeight, mCameraViewWidth, mCameraViewHeight, getAspectRatio().toFloat()).execute();
new BarCodeScannerAsyncTask(delegate, mMultiFormatReader, data, width, height).execute();
}
if (willCallFaceTask) {
@ -201,9 +162,7 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
}
}
BarcodeDetectorAsyncTaskDelegate delegate = (BarcodeDetectorAsyncTaskDelegate) cameraView;
new BarcodeDetectorAsyncTask(delegate, mGoogleBarcodeDetector, data, width, height,
correctRotation, getResources().getDisplayMetrics().density, getFacing(),
getWidth(), getHeight(), mPaddingX, mPaddingY).execute();
new BarcodeDetectorAsyncTask(delegate, mGoogleBarcodeDetector, data, width, height, correctRotation, getResources().getDisplayMetrics().density, getFacing(), getWidth(), getHeight(), mPaddingX, mPaddingY).execute();
}
if (willCallTextTask) {
@ -263,29 +222,26 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
initBarcodeReader();
}
public void setDetectedImageInEvent(boolean detectedImageInEvent) {
this.mDetectedImageInEvent = detectedImageInEvent;
public void setPlaySoundOnCapture(Boolean playSoundOnCapture) {
mPlaySoundOnCapture = playSoundOnCapture;
}
public void takePicture(final ReadableMap options, final Promise promise, final File cacheDirectory) {
mBgHandler.post(new Runnable() {
@Override
public void run() {
mPictureTakenPromises.add(promise);
mPictureTakenOptions.put(promise, options);
mPictureTakenDirectories.put(promise, cacheDirectory);
try {
RNCameraView.super.takePicture(options);
} catch (Exception e) {
mPictureTakenPromises.remove(promise);
mPictureTakenOptions.remove(promise);
mPictureTakenDirectories.remove(promise);
promise.reject("E_TAKE_PICTURE_FAILED", e.getMessage());
}
}
});
public void takePicture(ReadableMap options, final Promise promise, File cacheDirectory) {
mPictureTakenPromises.add(promise);
mPictureTakenOptions.put(promise, options);
mPictureTakenDirectories.put(promise, cacheDirectory);
if (mPlaySoundOnCapture) {
MediaActionSound sound = new MediaActionSound();
sound.play(MediaActionSound.SHUTTER_CLICK);
}
try {
super.takePicture(options);
} catch (Exception e) {
mPictureTakenPromises.remove(promise);
mPictureTakenOptions.remove(promise);
mPictureTakenDirectories.remove(promise);
throw e;
}
}
@Override
@ -293,45 +249,39 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
RNCameraViewHelper.emitPictureSavedEvent(this, response);
}
public void record(final ReadableMap options, final Promise promise, final File cacheDirectory) {
mBgHandler.post(new Runnable() {
@Override
public void run() {
try {
String path = options.hasKey("path") ? options.getString("path") : RNFileUtils.getOutputFilePath(cacheDirectory, ".mp4");
int maxDuration = options.hasKey("maxDuration") ? options.getInt("maxDuration") : -1;
int maxFileSize = options.hasKey("maxFileSize") ? options.getInt("maxFileSize") : -1;
int fps = options.hasKey("fps") ? options.getInt("fps") : -1;
public void record(ReadableMap options, final Promise promise, File cacheDirectory) {
try {
String path = options.hasKey("path") ? options.getString("path") : RNFileUtils.getOutputFilePath(cacheDirectory, ".mp4");
int maxDuration = options.hasKey("maxDuration") ? options.getInt("maxDuration") : -1;
int maxFileSize = options.hasKey("maxFileSize") ? options.getInt("maxFileSize") : -1;
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
if (options.hasKey("quality")) {
profile = RNCameraViewHelper.getCamcorderProfile(options.getInt("quality"));
}
if (options.hasKey("videoBitrate")) {
profile.videoBitRate = options.getInt("videoBitrate");
}
boolean recordAudio = true;
if (options.hasKey("mute")) {
recordAudio = !options.getBoolean("mute");
}
int orientation = Constants.ORIENTATION_AUTO;
if (options.hasKey("orientation")) {
orientation = options.getInt("orientation");
}
if (RNCameraView.super.record(path, maxDuration * 1000, maxFileSize, recordAudio, profile, orientation, fps)) {
mIsRecording = true;
mVideoRecordedPromise = promise;
} else {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed. Another recording might be in progress.");
}
} catch (IOException e) {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed - could not create video file.");
}
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
if (options.hasKey("quality")) {
profile = RNCameraViewHelper.getCamcorderProfile(options.getInt("quality"));
}
});
if (options.hasKey("videoBitrate")) {
profile.videoBitRate = options.getInt("videoBitrate");
}
boolean recordAudio = true;
if (options.hasKey("mute")) {
recordAudio = !options.getBoolean("mute");
}
int orientation = Constants.ORIENTATION_AUTO;
if (options.hasKey("orientation")) {
orientation = options.getInt("orientation");
}
if (super.record(path, maxDuration * 1000, maxFileSize, recordAudio, profile, orientation)) {
mIsRecording = true;
mVideoRecordedPromise = promise;
} else {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed. Another recording might be in progress.");
}
} catch (IOException e) {
promise.reject("E_RECORDING_FAILED", "Starting video recording failed - could not create video file.");
}
}
/**
@ -365,28 +315,13 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
setScanning(mShouldDetectFaces || mShouldGoogleDetectBarcodes || mShouldScanBarCodes || mShouldRecognizeText);
}
public void onBarCodeRead(Result barCode, int width, int height, byte[] imageData) {
public void onBarCodeRead(Result barCode, int width, int height) {
String barCodeType = barCode.getBarcodeFormat().toString();
if (!mShouldScanBarCodes || !mBarCodeTypes.contains(barCodeType)) {
return;
}
final byte[] compressedImage;
if (mDetectedImageInEvent) {
try {
// https://stackoverflow.com/a/32793908/122441
final YuvImage yuvImage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
final ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, imageStream);
compressedImage = imageStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(String.format("Error decoding imageData from NV21 format (%d bytes)", imageData.length), e);
}
} else {
compressedImage = null;
}
RNCameraViewHelper.emitBarCodeReadEvent(this, barCode, width, height, compressedImage);
RNCameraViewHelper.emitBarCodeReadEvent(this, barCode, width, height);
}
public void onBarCodeScanningTaskCompleted() {
@ -396,49 +331,6 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
}
}
// Limit Scan Area
public void setRectOfInterest(float x, float y, float width, float height) {
this.mLimitScanArea = true;
this.mScanAreaX = x;
this.mScanAreaY = y;
this.mScanAreaWidth = width;
this.mScanAreaHeight = height;
}
public void setCameraViewDimensions(int width, int height) {
this.mCameraViewWidth = width;
this.mCameraViewHeight = height;
}
public void setShouldDetectTouches(boolean shouldDetectTouches) {
if(!mShouldDetectTouches && shouldDetectTouches){
mGestureDetector=new GestureDetector(mThemedReactContext,onGestureListener);
}else{
mGestureDetector=null;
}
this.mShouldDetectTouches = shouldDetectTouches;
}
public void setUseNativeZoom(boolean useNativeZoom){
if(!mUseNativeZoom && useNativeZoom){
mScaleGestureDetector = new ScaleGestureDetector(mThemedReactContext,onScaleGestureListener);
}else{
mScaleGestureDetector=null;
}
mUseNativeZoom=useNativeZoom;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(mUseNativeZoom) {
mScaleGestureDetector.onTouchEvent(event);
}
if(mShouldDetectTouches){
mGestureDetector.onTouchEvent(event);
}
return true;
}
/**
* Initial setup of the face detector
*/
@ -534,28 +426,11 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
mGoogleVisionBarCodeMode = barcodeMode;
}
public void onBarcodesDetected(WritableArray barcodesDetected, int width, int height, byte[] imageData) {
public void onBarcodesDetected(WritableArray barcodesDetected) {
if (!mShouldGoogleDetectBarcodes) {
return;
}
// See discussion in https://github.com/react-native-community/react-native-camera/issues/2786
final byte[] compressedImage;
if (mDetectedImageInEvent) {
try {
// https://stackoverflow.com/a/32793908/122441
final YuvImage yuvImage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
final ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, imageStream);
compressedImage = imageStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(String.format("Error decoding imageData from NV21 format (%d bytes)", imageData.length), e);
}
} else {
compressedImage = null;
}
RNCameraViewHelper.emitBarcodesDetectedEvent(this, barcodesDetected, compressedImage);
RNCameraViewHelper.emitBarcodesDetectedEvent(this, barcodesDetected);
}
public void onBarcodeDetectionError(RNBarcodeDetector barcodeDetector) {
@ -601,16 +476,11 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
@Override
public void onHostResume() {
if (hasCameraPermissions()) {
mBgHandler.post(new Runnable() {
@Override
public void run() {
if ((mIsPaused && !isCameraOpened()) || mIsNew) {
mIsPaused = false;
mIsNew = false;
start();
}
}
});
if ((mIsPaused && !isCameraOpened()) || mIsNew) {
mIsPaused = false;
mIsNew = false;
start();
}
} else {
RNCameraViewHelper.emitMountErrorEvent(this, "Camera permissions not granted - component could not be rendered.");
}
@ -636,28 +506,8 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
mGoogleBarcodeDetector.release();
}
mMultiFormatReader = null;
stop();
mThemedReactContext.removeLifecycleEventListener(this);
// camera release can be quite expensive. Run in on bg handler
// and cleanup last once everything has finished
mBgHandler.post(new Runnable() {
@Override
public void run() {
stop();
cleanup();
}
});
}
private void onZoom(float scale){
float currentZoom=getZoom();
float nextZoom=currentZoom+(scale-1.0f);
if(nextZoom > currentZoom){
setZoom(Math.min(nextZoom,1.0f));
}else{
setZoom(Math.max(nextZoom,0.0f));
}
}
private boolean hasCameraPermissions() {
@ -668,43 +518,4 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
return true;
}
}
private int scalePosition(float raw){
Resources resources = getResources();
Configuration config = resources.getConfiguration();
DisplayMetrics dm = resources.getDisplayMetrics();
return (int)(raw/ dm.density);
}
private GestureDetector.SimpleOnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onSingleTapUp(MotionEvent e) {
RNCameraViewHelper.emitTouchEvent(RNCameraView.this,false,scalePosition(e.getX()),scalePosition(e.getY()));
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
RNCameraViewHelper.emitTouchEvent(RNCameraView.this,true,scalePosition(e.getX()),scalePosition(e.getY()));
return true;
}
};
private ScaleGestureDetector.OnScaleGestureListener onScaleGestureListener = new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
onZoom(scaleGestureDetector.getScaleFactor());
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
onZoom(scaleGestureDetector.getScaleFactor());
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
}
};
}

View File

@ -10,7 +10,7 @@ import androidx.exifinterface.media.ExifInterface;
import android.view.ViewGroup;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.uimanager.UIManagerModule;
@ -156,182 +156,80 @@ public class RNCameraViewHelper {
{"int", ExifInterface.TAG_RW2_SENSOR_TOP_BORDER},
{"int", ExifInterface.TAG_RW2_ISO},
};
// Run all events on native modules queue thread since they might be fired
// from other non RN threads.
// Mount error event
public static void emitMountErrorEvent(final ViewGroup view, final String error) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
CameraMountErrorEvent event = CameraMountErrorEvent.obtain(view.getId(), error);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitMountErrorEvent(ViewGroup view, String error) {
CameraMountErrorEvent event = CameraMountErrorEvent.obtain(view.getId(), error);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// Camera ready event
public static void emitCameraReadyEvent(final ViewGroup view) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
CameraReadyEvent event = CameraReadyEvent.obtain(view.getId());
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitCameraReadyEvent(ViewGroup view) {
CameraReadyEvent event = CameraReadyEvent.obtain(view.getId());
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// Picture saved event
public static void emitPictureSavedEvent(final ViewGroup view, final WritableMap response) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
PictureSavedEvent event = PictureSavedEvent.obtain(view.getId(), response);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitPictureSavedEvent(ViewGroup view, WritableMap response) {
PictureSavedEvent event = PictureSavedEvent.obtain(view.getId(), response);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// Picture taken event
public static void emitPictureTakenEvent(final ViewGroup view) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
PictureTakenEvent event = PictureTakenEvent.obtain(view.getId());
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitPictureTakenEvent(ViewGroup view) {
PictureTakenEvent event = PictureTakenEvent.obtain(view.getId());
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// video recording start/end events
public static void emitRecordingStartEvent(final ViewGroup view, final WritableMap response) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
RecordingStartEvent event = RecordingStartEvent.obtain(view.getId(), response);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
public static void emitRecordingEndEvent(final ViewGroup view) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
RecordingEndEvent event = RecordingEndEvent.obtain(view.getId());
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Touch event
public static void emitTouchEvent(final ViewGroup view, final boolean isDoubleTap, final int x, final int y) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
TouchEvent event = TouchEvent.obtain(view.getId(), isDoubleTap, x, y);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
}
// Face detection events
public static void emitFacesDetectedEvent(final ViewGroup view, final WritableArray data) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
FacesDetectedEvent event = FacesDetectedEvent.obtain(view.getId(), data);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitFacesDetectedEvent(ViewGroup view, WritableArray data) {
FacesDetectedEvent event = FacesDetectedEvent.obtain(view.getId(), data);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
public static void emitFaceDetectionErrorEvent(final ViewGroup view, final RNFaceDetector faceDetector) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
FaceDetectionErrorEvent event = FaceDetectionErrorEvent.obtain(view.getId(), faceDetector);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitFaceDetectionErrorEvent(ViewGroup view, RNFaceDetector faceDetector) {
FaceDetectionErrorEvent event = FaceDetectionErrorEvent.obtain(view.getId(), faceDetector);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// Barcode detection events
public static void emitBarcodesDetectedEvent(final ViewGroup view, final WritableArray barcodes, final byte[] compressedImage) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
BarcodesDetectedEvent event = BarcodesDetectedEvent.obtain(view.getId(), barcodes, compressedImage);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitBarcodesDetectedEvent(ViewGroup view, WritableArray barcodes) {
BarcodesDetectedEvent event = BarcodesDetectedEvent.obtain(view.getId(), barcodes);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
public static void emitBarcodeDetectionErrorEvent(final ViewGroup view, final RNBarcodeDetector barcodeDetector) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
BarcodeDetectionErrorEvent event = BarcodeDetectionErrorEvent.obtain(view.getId(), barcodeDetector);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitBarcodeDetectionErrorEvent(ViewGroup view, RNBarcodeDetector barcodeDetector) {
BarcodeDetectionErrorEvent event = BarcodeDetectionErrorEvent.obtain(view.getId(), barcodeDetector);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// Bar code read event
public static void emitBarCodeReadEvent(final ViewGroup view, final Result barCode, final int width, final int height, final byte[] compressedImage) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
BarCodeReadEvent event = BarCodeReadEvent.obtain(view.getId(), barCode, width, height, compressedImage);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitBarCodeReadEvent(ViewGroup view, Result barCode, int width, int height) {
BarCodeReadEvent event = BarCodeReadEvent.obtain(view.getId(), barCode, width, height);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// Text recognition event
public static void emitTextRecognizedEvent(final ViewGroup view, final WritableArray data) {
final ReactContext reactContext = (ReactContext) view.getContext();
reactContext.runOnNativeModulesQueueThread(new Runnable() {
@Override
public void run() {
TextRecognizedEvent event = TextRecognizedEvent.obtain(view.getId(), data);
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
});
public static void emitTextRecognizedEvent(ViewGroup view, WritableArray data) {
TextRecognizedEvent event = TextRecognizedEvent.obtain(view.getId(), data);
ReactContext reactContext = (ReactContext) view.getContext();
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher().dispatchEvent(event);
}
// Utilities
@ -411,46 +309,25 @@ public class RNCameraViewHelper {
return exifMap;
}
public static void setExifData(ExifInterface exifInterface, ReadableMap exifMap) {
for (String[] tagInfo : exifTags) {
String name = tagInfo[1];
if (exifMap.hasKey(name)) {
String type = tagInfo[0];
switch (type) {
case "string":
exifInterface.setAttribute(name, exifMap.getString(name));
break;
case "int":
exifInterface.setAttribute(name, Integer.toString(exifMap.getInt(name)));
exifMap.getInt(name);
break;
case "double":
exifInterface.setAttribute(name, Double.toString(exifMap.getDouble(name)));
exifMap.getDouble(name);
break;
}
public static void setExifData(ExifInterface exifInterface, WritableMap exifMap) {
ReadableMapKeySetIterator iterator = exifMap.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
switch (exifMap.getType(key)) {
case Null:
exifInterface.setAttribute(key, null);
break;
case Boolean:
exifInterface.setAttribute(key, Boolean.toString(exifMap.getBoolean(key)));
break;
case Number:
exifInterface.setAttribute(key, Double.toString(exifMap.getDouble(key)));
break;
case String:
exifInterface.setAttribute(key, exifMap.getString(key));
break;
}
}
if (exifMap.hasKey(ExifInterface.TAG_GPS_LATITUDE) && exifMap.hasKey(ExifInterface.TAG_GPS_LONGITUDE)) {
exifInterface.setLatLong(exifMap.getDouble(ExifInterface.TAG_GPS_LATITUDE),
exifMap.getDouble(ExifInterface.TAG_GPS_LONGITUDE));
}
if(exifMap.hasKey(ExifInterface.TAG_GPS_ALTITUDE)){
exifInterface.setAltitude(exifMap.getDouble(ExifInterface.TAG_GPS_ALTITUDE));
}
}
// clears exif values in place
public static void clearExifData(ExifInterface exifInterface) {
for (String[] tagInfo : exifTags) {
exifInterface.setAttribute(tagInfo[1], null);
}
// these are not part of our tag list, remove by hand
exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE, null);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, null);
exifInterface.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, null);
}
public static Bitmap generateSimulatorPhoto(int width, int height) {

View File

@ -1,7 +1,5 @@
package org.reactnative.camera.events;
import android.util.Base64;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
@ -22,25 +20,23 @@ public class BarCodeReadEvent extends Event<BarCodeReadEvent> {
private Result mBarCode;
private int mWidth;
private int mHeight;
private byte[] mCompressedImage;
private BarCodeReadEvent() {}
public static BarCodeReadEvent obtain(int viewTag, Result barCode, int width, int height, byte[] compressedImage) {
public static BarCodeReadEvent obtain(int viewTag, Result barCode, int width, int height) {
BarCodeReadEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new BarCodeReadEvent();
}
event.init(viewTag, barCode, width, height, compressedImage);
event.init(viewTag, barCode, width, height);
return event;
}
private void init(int viewTag, Result barCode, int width, int height, byte[] compressedImage) {
private void init(int viewTag, Result barCode, int width, int height) {
super.init(viewTag);
mBarCode = barCode;
mWidth = width;
mHeight = height;
mCompressedImage = compressedImage;
}
/**
@ -99,9 +95,6 @@ public class BarCodeReadEvent extends Event<BarCodeReadEvent> {
eventOrigin.putInt("height", mHeight);
eventOrigin.putInt("width", mWidth);
event.putMap("bounds", eventOrigin);
if (mCompressedImage != null) {
event.putString("image", Base64.encodeToString(mCompressedImage, Base64.NO_WRAP));
}
return event;
}
}

View File

@ -1,9 +1,7 @@
package org.reactnative.camera.events;
import android.util.Base64;
import androidx.core.util.Pools;
import android.util.SparseArray;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
@ -17,30 +15,28 @@ public class BarcodesDetectedEvent extends Event<BarcodesDetectedEvent> {
new Pools.SynchronizedPool<>(3);
private WritableArray mBarcodes;
private byte[] mCompressedImage;
private BarcodesDetectedEvent() {
}
public static BarcodesDetectedEvent obtain(
int viewTag,
WritableArray barcodes,
byte[] compressedImage) {
int viewTag,
WritableArray barcodes
) {
BarcodesDetectedEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new BarcodesDetectedEvent();
}
event.init(viewTag, barcodes, compressedImage);
event.init(viewTag, barcodes);
return event;
}
private void init(
int viewTag,
WritableArray barcodes,
byte[] compressedImage) {
int viewTag,
WritableArray barcodes
) {
super.init(viewTag);
mBarcodes = barcodes;
mCompressedImage = compressedImage;
}
/**
@ -72,9 +68,6 @@ public class BarcodesDetectedEvent extends Event<BarcodesDetectedEvent> {
event.putString("type", "barcode");
event.putArray("barcodes", mBarcodes);
event.putInt("target", getViewTag());
if (mCompressedImage != null) {
event.putString("image", Base64.encodeToString(mCompressedImage, Base64.NO_WRAP));
}
return event;
}
}

View File

@ -1,42 +0,0 @@
package org.reactnative.camera.events;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
public class RecordingEndEvent extends Event<RecordingEndEvent> {
private static final Pools.SynchronizedPool<RecordingEndEvent> EVENTS_POOL = new Pools.SynchronizedPool<>(3);
private RecordingEndEvent() {}
public static RecordingEndEvent obtain(int viewTag) {
RecordingEndEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new RecordingEndEvent();
}
event.init(viewTag);
return event;
}
@Override
public short getCoalescingKey() {
return 0;
}
@Override
public String getEventName() {
return CameraViewManager.Events.EVENT_ON_RECORDING_END.toString();
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
}
private WritableMap serializeEventData() {
return Arguments.createMap();
}
}

View File

@ -1,46 +0,0 @@
package org.reactnative.camera.events;
import androidx.core.util.Pools;
import org.reactnative.camera.CameraViewManager;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
public class RecordingStartEvent extends Event<RecordingStartEvent> {
private static final Pools.SynchronizedPool<RecordingStartEvent> EVENTS_POOL = new Pools.SynchronizedPool<>(3);
private RecordingStartEvent() {}
private WritableMap mResponse;
public static RecordingStartEvent obtain(int viewTag, WritableMap response) {
RecordingStartEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new RecordingStartEvent();
}
event.init(viewTag, response);
return event;
}
private void init(int viewTag, WritableMap response) {
super.init(viewTag);
mResponse = response;
}
// @Override
// public short getCoalescingKey() {
// int hashCode = mResponse.getString("uri").hashCode() % Short.MAX_VALUE;
// return (short) hashCode;
// }
@Override
public String getEventName() {
return CameraViewManager.Events.EVENT_ON_RECORDING_START.toString();
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mResponse);
}
}

View File

@ -1,69 +0,0 @@
package org.reactnative.camera.events;
import androidx.core.util.Pools;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import org.reactnative.camera.CameraViewManager;
public class TouchEvent extends Event<TouchEvent> {
private static final Pools.SynchronizedPool<TouchEvent> EVENTS_POOL =
new Pools.SynchronizedPool<>(3);
private int mX;
private int mY;
private boolean mIsDoubleTap;
private TouchEvent() {}
public static TouchEvent obtain(int viewTag, boolean isDoubleTap, int x, int y) {
TouchEvent event = EVENTS_POOL.acquire();
if (event == null) {
event = new TouchEvent();
}
event.init(viewTag, isDoubleTap, x, y);
return event;
}
private void init(int viewTag, boolean isDoubleTap, int x, int y) {
super.init(viewTag);
mX = x;
mY = y;
mIsDoubleTap=isDoubleTap;
}
@Override
public short getCoalescingKey() {
return 0;
}
@Override
public String getEventName() {
return CameraViewManager.Events.EVENT_ON_TOUCH.toString();
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData());
}
private WritableMap serializeEventData() {
WritableMap event = Arguments.createMap();
event.putInt("target", getViewTag());
WritableMap touchOrigin = Arguments.createMap();
touchOrigin.putInt("x", mX);
touchOrigin.putInt("y",mY);
event.putBoolean("isDoubleTap", mIsDoubleTap);
event.putMap("touchOrigin", touchOrigin);
return event;
}
}

View File

@ -13,14 +13,6 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
private int mHeight;
private BarCodeScannerAsyncTaskDelegate mDelegate;
private final MultiFormatReader mMultiFormatReader;
private boolean mLimitScanArea;
private float mScanAreaX;
private float mScanAreaY;
private float mScanAreaWidth;
private float mScanAreaHeight;
private int mCameraViewWidth;
private int mCameraViewHeight;
private float mRatio;
// note(sjchmiela): From my short research it's ok to ignore rotation of the image.
public BarCodeScannerAsyncTask(
@ -28,29 +20,13 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
MultiFormatReader multiFormatReader,
byte[] imageData,
int width,
int height,
boolean limitScanArea,
float scanAreaX,
float scanAreaY,
float scanAreaWidth,
float scanAreaHeight,
int cameraViewWidth,
int cameraViewHeight,
float ratio
int height
) {
mImageData = imageData;
mWidth = width;
mHeight = height;
mDelegate = delegate;
mMultiFormatReader = multiFormatReader;
mLimitScanArea = limitScanArea;
mScanAreaX = scanAreaX;
mScanAreaY = scanAreaY;
mScanAreaWidth = scanAreaWidth;
mScanAreaHeight = scanAreaHeight;
mCameraViewWidth = cameraViewWidth;
mCameraViewHeight = cameraViewHeight;
mRatio = ratio;
}
@Override
@ -60,29 +36,13 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
}
Result result = null;
/**
* mCameraViewWidth and mCameraViewHeight are obtained from portait orientation
* mWidth and mHeight are measured with landscape orientation with Home button to the right
* adjustedCamViewWidth is the adjusted width from the Aspect ratio setting
*/
int adjustedCamViewWidth = (int) (mCameraViewHeight / mRatio);
float adjustedScanY = (((adjustedCamViewWidth - mCameraViewWidth) / 2) + (mScanAreaY * mCameraViewWidth)) / adjustedCamViewWidth;
int left = (int) (mScanAreaX * mWidth);
int top = (int) (adjustedScanY * mHeight);
int scanWidth = (int) (mScanAreaWidth * mWidth);
int scanHeight = (int) (((mScanAreaHeight * mCameraViewWidth) / adjustedCamViewWidth) * mHeight);
try {
BinaryBitmap bitmap = generateBitmapFromImageData(
mImageData,
mWidth,
mHeight,
false,
left,
top,
scanWidth,
scanHeight
false
);
result = mMultiFormatReader.decodeWithState(bitmap);
} catch (NotFoundException e) {
@ -90,11 +50,7 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
rotateImage(mImageData,mWidth, mHeight),
mHeight,
mWidth,
false,
mHeight - scanHeight - top,
left,
scanHeight,
scanWidth
false
);
try {
result = mMultiFormatReader.decodeWithState(bitmap);
@ -103,11 +59,7 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
mImageData,
mWidth,
mHeight,
true,
mWidth - scanWidth - left,
mHeight - scanHeight - top,
scanWidth,
scanHeight
true
);
try {
result = mMultiFormatReader.decodeWithState(invertedBitmap);
@ -116,11 +68,7 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
rotateImage(mImageData,mWidth, mHeight),
mHeight,
mWidth,
true,
top,
mWidth - scanWidth - left,
scanHeight,
scanWidth
true
);
try {
result = mMultiFormatReader.decodeWithState(invertedRotatedBitmap);
@ -148,26 +96,13 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
protected void onPostExecute(Result result) {
super.onPostExecute(result);
if (result != null) {
mDelegate.onBarCodeRead(result, mWidth, mHeight, mImageData);
mDelegate.onBarCodeRead(result, mWidth, mHeight);
}
mDelegate.onBarCodeScanningTaskCompleted();
}
private BinaryBitmap generateBitmapFromImageData(byte[] imageData, int width, int height, boolean inverse, int left, int top, int sWidth, int sHeight) {
PlanarYUVLuminanceSource source;
if (mLimitScanArea) {
source = new PlanarYUVLuminanceSource(
imageData, // byte[] yuvData
width, // int dataWidth
height, // int dataHeight
left, // int left
top, // int top
sWidth, // int width
sHeight, // int height
false // boolean reverseHorizontal
);
} else {
source = new PlanarYUVLuminanceSource(
private BinaryBitmap generateBitmapFromImageData(byte[] imageData, int width, int height, boolean inverse) {
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
imageData, // byte[] yuvData
width, // int dataWidth
height, // int dataHeight
@ -176,8 +111,7 @@ public class BarCodeScannerAsyncTask extends android.os.AsyncTask<Void, Void, Re
width, // int width
height, // int height
false // boolean reverseHorizontal
);
}
);
if (inverse) {
return new BinaryBitmap(new HybridBinarizer(source.invert()));
} else {

View File

@ -3,6 +3,6 @@ package org.reactnative.camera.tasks;
import com.google.zxing.Result;
public interface BarCodeScannerAsyncTaskDelegate {
void onBarCodeRead(Result barCode, int width, int height, byte[] imageData);
void onBarCodeRead(Result barCode, int width, int height);
void onBarCodeScanningTaskCompleted();
}

View File

@ -5,7 +5,7 @@ import org.reactnative.barcodedetector.RNBarcodeDetector;
public interface BarcodeDetectorAsyncTaskDelegate {
void onBarcodesDetected(WritableArray barcodes, int width, int height, byte[] imageData);
void onBarcodesDetected(WritableArray barcodes);
void onBarcodeDetectionError(RNBarcodeDetector barcodeDetector);

View File

@ -15,7 +15,6 @@ import org.reactnative.camera.utils.RNFileUtils;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import java.io.ByteArrayInputStream;
@ -27,10 +26,10 @@ import java.io.IOException;
public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, WritableMap> {
private static final String ERROR_TAG = "E_TAKING_PICTURE_FAILED";
private Promise mPromise;
private Bitmap mBitmap;
private byte[] mImageData;
private ReadableMap mOptions;
private File mCacheDirectory;
private Bitmap mBitmap;
private int mDeviceOrientation;
private PictureSavedDelegate mPictureSavedDelegate;
@ -47,109 +46,95 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
return (int) (mOptions.getDouble("quality") * 100);
}
// loads bitmap only if necessary
private void loadBitmap() throws IOException {
if(mBitmap == null){
mBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
}
if(mBitmap == null){
throw new IOException("Failed to decode Image Bitmap");
}
}
@Override
protected WritableMap doInBackground(Void... voids) {
WritableMap response = Arguments.createMap();
ByteArrayInputStream inputStream = null;
ExifInterface exifInterface = null;
WritableMap exifData = null;
ReadableMap exifExtraData = null;
boolean orientationChanged = false;
response.putInt("deviceOrientation", mDeviceOrientation);
response.putInt("pictureOrientation", mOptions.hasKey("orientation") ? mOptions.getInt("orientation") : mDeviceOrientation);
if (mOptions.hasKey("skipProcessing")) {
try {
// Prepare file output
File imageFile = new File(RNFileUtils.getOutputFilePath(mCacheDirectory, ".jpg"));
imageFile.createNewFile();
FileOutputStream fOut = new FileOutputStream(imageFile);
try{
// this replaces the skipProcessing flag, we will process only if needed, and in
// an orderly manner, so that skipProcessing is the default behaviour if no options are given
// and this behaves more like the iOS version.
// We will load all data lazily only when needed.
// Save byte array (it is already a JPEG)
fOut.write(mImageData);
// this should not incurr in any overhead if not read/used
// get image size
if (mBitmap == null) {
mBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
}
response.putInt("width", mBitmap.getWidth());
response.putInt("height", mBitmap.getHeight());
// Return file system URI
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
} catch (Resources.NotFoundException e) {
mPromise.reject(ERROR_TAG, "Documents directory of the app could not be found.", e);
e.printStackTrace();
} catch (IOException e) {
mPromise.reject(ERROR_TAG, "An unknown I/O exception has occurred.", e);
e.printStackTrace();
}
return response;
}
// we need the stream only for photos from a device
if (mBitmap == null) {
mBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
inputStream = new ByteArrayInputStream(mImageData);
}
try {
WritableMap fileExifData = null;
// Rotate the bitmap to the proper orientation if requested
if(mOptions.hasKey("fixOrientation") && mOptions.getBoolean("fixOrientation")){
exifInterface = new ExifInterface(inputStream);
if (inputStream != null) {
ExifInterface exifInterface = new ExifInterface(inputStream);
// Get orientation of the image from mImageData via inputStream
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
if(orientation != ExifInterface.ORIENTATION_UNDEFINED){
loadBitmap();
// Rotate the bitmap to the proper orientation if needed
boolean fixOrientation = mOptions.hasKey("fixOrientation")
&& mOptions.getBoolean("fixOrientation")
&& orientation != ExifInterface.ORIENTATION_UNDEFINED;
if (fixOrientation) {
mBitmap = rotateBitmap(mBitmap, getImageRotation(orientation));
orientationChanged = true;
}
}
if (mOptions.hasKey("width")) {
loadBitmap();
mBitmap = resizeBitmap(mBitmap, mOptions.getInt("width"));
}
if (mOptions.hasKey("mirrorImage") && mOptions.getBoolean("mirrorImage")) {
loadBitmap();
mBitmap = flipHorizontally(mBitmap);
}
// EXIF code - we will adjust exif info later if we manipulated the bitmap
boolean writeExifToResponse = mOptions.hasKey("exif") && mOptions.getBoolean("exif");
// default to true if not provided so it is consistent with iOS and with what happens if no
// processing is done and the image is saved as is.
boolean writeExifToFile = true;
if (mOptions.hasKey("writeExif")) {
switch (mOptions.getType("writeExif")) {
case Boolean:
writeExifToFile = mOptions.getBoolean("writeExif");
break;
case Map:
exifExtraData = mOptions.getMap("writeExif");
writeExifToFile = true;
break;
if (mOptions.hasKey("width")) {
mBitmap = resizeBitmap(mBitmap, mOptions.getInt("width"));
}
}
// Read Exif data if needed
if (writeExifToResponse || writeExifToFile) {
if (mOptions.hasKey("mirrorImage") && mOptions.getBoolean("mirrorImage")) {
mBitmap = flipHorizontally(mBitmap);
}
// if we manipulated the image, or need to add extra data, or need to add it to the response,
// then we need to load the actual exif data.
// Otherwise we can just use w/e exif data we have right now in our byte array
if(mBitmap != null || exifExtraData != null || writeExifToResponse){
if(exifInterface == null){
exifInterface = new ExifInterface(inputStream);
}
WritableMap exifData = null;
boolean writeExifToResponse = mOptions.hasKey("exif") && mOptions.getBoolean("exif");
boolean writeExifToFile = mOptions.hasKey("writeExif") && mOptions.getBoolean("writeExif");
// Read Exif data if needed
if (writeExifToResponse || writeExifToFile) {
exifData = RNCameraViewHelper.getExifData(exifInterface);
if(exifExtraData != null){
exifData.merge(exifExtraData);
}
}
// if we did anything to the bitmap, adjust exif
if(mBitmap != null){
exifData.putInt("width", mBitmap.getWidth());
exifData.putInt("height", mBitmap.getHeight());
if(orientationChanged){
exifData.putInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
// Write Exif data to output file if requested
if (writeExifToFile) {
fileExifData = Arguments.createMap();
fileExifData.merge(exifData);
fileExifData.putInt("width", mBitmap.getWidth());
fileExifData.putInt("height", mBitmap.getHeight());
if (fixOrientation) {
fileExifData.putInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
}
}
@ -159,110 +144,47 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
}
}
// Upon rotating, write the image's dimensions to the response
response.putInt("width", mBitmap.getWidth());
response.putInt("height", mBitmap.getHeight());
// Cache compressed image in imageStream
ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.JPEG, getQuality(), imageStream);
// final processing
// Based on whether or not we loaded the full bitmap into memory, final processing differs
if(mBitmap == null){
// set response dimensions. If we haven't read our bitmap, get it efficiently
// without loading the actual bitmap into memory
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length, options);
if(options != null){
response.putInt("width", options.outWidth);
response.putInt("height", options.outHeight);
// Write compressed image to file in cache directory unless otherwise specified
if (!mOptions.hasKey("doNotSave") || !mOptions.getBoolean("doNotSave")) {
String filePath = writeStreamToFile(imageStream);
if (fileExifData != null) {
ExifInterface fileExifInterface = new ExifInterface(filePath);
RNCameraViewHelper.setExifData(fileExifInterface, fileExifData);
fileExifInterface.saveAttributes();
}
// save to file if requested
if (!mOptions.hasKey("doNotSave") || !mOptions.getBoolean("doNotSave")) {
// Prepare file output
File imageFile = new File(getImagePath());
imageFile.createNewFile();
FileOutputStream fOut = new FileOutputStream(imageFile);
// Save byte array (it is already a JPEG)
fOut.write(mImageData);
fOut.flush();
fOut.close();
// update exif data if needed.
// Since we didn't modify the image, we only update if we have extra exif info
if (writeExifToFile && exifExtraData != null) {
ExifInterface fileExifInterface = new ExifInterface(imageFile.getAbsolutePath());
RNCameraViewHelper.setExifData(fileExifInterface, exifExtraData);
fileExifInterface.saveAttributes();
}
else if (!writeExifToFile){
// if we were requested to NOT store exif, we actually need to
// clear the exif tags
ExifInterface fileExifInterface = new ExifInterface(imageFile.getAbsolutePath());
RNCameraViewHelper.clearExifData(fileExifInterface);
fileExifInterface.saveAttributes();
}
// else: exif is unmodified, no need to update anything
// Return file system URI
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
}
if (mOptions.hasKey("base64") && mOptions.getBoolean("base64")) {
response.putString("base64", Base64.encodeToString(mImageData, Base64.NO_WRAP));
}
File imageFile = new File(filePath);
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
}
else{
// get response dimensions right from the bitmap if we have it
response.putInt("width", mBitmap.getWidth());
response.putInt("height", mBitmap.getHeight());
// Cache compressed image in imageStream
ByteArrayOutputStream imageStream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.JPEG, getQuality(), imageStream);
// Write compressed image to file in cache directory unless otherwise specified
if (!mOptions.hasKey("doNotSave") || !mOptions.getBoolean("doNotSave")) {
String filePath = writeStreamToFile(imageStream);
// since we lost any exif data on bitmap creation, we only need
// to add it if requested
if (writeExifToFile && exifData != null) {
ExifInterface fileExifInterface = new ExifInterface(filePath);
RNCameraViewHelper.setExifData(fileExifInterface, exifData);
fileExifInterface.saveAttributes();
}
File imageFile = new File(filePath);
String fileUri = Uri.fromFile(imageFile).toString();
response.putString("uri", fileUri);
}
// Write base64-encoded image to the response if requested
if (mOptions.hasKey("base64") && mOptions.getBoolean("base64")) {
response.putString("base64", Base64.encodeToString(imageStream.toByteArray(), Base64.NO_WRAP));
}
// Write base64-encoded image to the response if requested
if (mOptions.hasKey("base64") && mOptions.getBoolean("base64")) {
response.putString("base64", Base64.encodeToString(imageStream.toByteArray(), Base64.NO_WRAP));
}
// Cleanup
imageStream.close();
if (inputStream != null) {
inputStream.close();
inputStream = null;
}
return response;
}
catch (Resources.NotFoundException e) {
} catch (Resources.NotFoundException e) {
mPromise.reject(ERROR_TAG, "Documents directory of the app could not be found.", e);
e.printStackTrace();
}
catch (IOException e) {
} catch (IOException e) {
mPromise.reject(ERROR_TAG, "An unknown I/O exception has occurred.", e);
e.printStackTrace();
}
finally {
} finally {
try {
if (inputStream != null) {
inputStream.close();
@ -272,6 +194,7 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
}
}
// An exception had to occur, promise has already been rejected. Do not try to resolve it again.
return null;
}
@ -313,20 +236,13 @@ public class ResolveTakenPictureAsyncTask extends AsyncTask<Void, Void, Writable
return rotationDegrees;
}
private String getImagePath() throws IOException{
if(mOptions.hasKey("path")){
return mOptions.getString("path");
}
return RNFileUtils.getOutputFilePath(mCacheDirectory, ".jpg");
}
private String writeStreamToFile(ByteArrayOutputStream inputStream) throws IOException {
String outputPath = null;
IOException exception = null;
FileOutputStream outputStream = null;
try {
outputPath = getImagePath();
outputPath = RNFileUtils.getOutputFilePath(mCacheDirectory, ".jpg");
outputStream = new FileOutputStream(outputPath);
inputStream.writeTo(outputStream);
} catch (IOException e) {

View File

@ -1,15 +0,0 @@
package org.reactnative.camera.utils;
public class ObjectUtils {
/*
* Replacement for Objects.equals that is only available after Android API 19
*/
public static boolean equals(Object o1, Object o2) {
if (o1 == null && o2 == null) return true;
if (o1 == null) return false;
return o1.equals(o2);
}
}

View File

@ -17,7 +17,6 @@ public class BarcodeFormatUtils {
private static final int UNKNOWN_FORMAT_INT = FirebaseVisionBarcode.FORMAT_UNKNOWN;
private static final String UNKNOWN_TYPE_STRING = "UNKNOWN_TYPE";
private static final String UNKNOWN_FORMAT_STRING = "UNKNOWN_FORMAT";
static {
// Initialize integer to string map
@ -37,6 +36,7 @@ public class BarcodeFormatUtils {
map.put(FirebaseVisionBarcode.FORMAT_AZTEC, "AZTEC");
map.put(FirebaseVisionBarcode.FORMAT_ALL_FORMATS, "ALL");
map.put(FirebaseVisionBarcode.FORMAT_UPC_A, "UPC_A");
map.put(FirebaseVisionBarcode.FORMAT_ALL_FORMATS, "ALL");
map.put(-1, "None");
FORMATS = map;
@ -81,9 +81,6 @@ public class BarcodeFormatUtils {
public static String get(int format) {
return TYPES.get(format, UNKNOWN_TYPE_STRING);
}
public static String getFormat(int format) {
return FORMATS.get(format, UNKNOWN_FORMAT_STRING);
}
public static int get(String format) {
if (REVERSE_FORMATS.containsKey(format)) {

View File

@ -61,7 +61,7 @@ public class RNBarcodeDetector {
private void createBarcodeDetector() {
FirebaseVisionBarcodeDetectorOptions options = mBuilder.build();
mBarcodeDetector = FirebaseVision.getInstance()
.getVisionBarcodeDetector(options);
.getVisionBarcodeDetector();
}
}

View File

@ -57,7 +57,7 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, V
mBarcodeDetector = barcodeDetector;
mImageDimensions = new ImageDimensions(width, height, rotation, facing);
mScaleX = (double) (viewWidth) / (mImageDimensions.getWidth() * density);
mScaleY = 1 / density;
mScaleY = (double) (viewHeight) / (mImageDimensions.getHeight() * density);
mPaddingLeft = viewPaddingLeft;
mPaddingTop = viewPaddingTop;
}
@ -82,7 +82,7 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, V
@Override
public void onSuccess(List<FirebaseVisionBarcode> barcodes) {
WritableArray serializedBarcodes = serializeEventData(barcodes);
mDelegate.onBarcodesDetected(serializedBarcodes, mWidth, mHeight, mImageData);
mDelegate.onBarcodesDetected(serializedBarcodes);
mDelegate.onBarcodeDetectingTaskCompleted();
}
})
@ -130,7 +130,6 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, V
String rawValue = barcode.getRawValue();
int valueType = barcode.getValueType();
int valueFormat = barcode.getFormat();
WritableMap serializedBarcode = Arguments.createMap();
@ -279,7 +278,6 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, V
serializedBarcode.putString("data", barcode.getDisplayValue());
serializedBarcode.putString("dataRaw", rawValue);
serializedBarcode.putString("type", BarcodeFormatUtils.get(valueType));
serializedBarcode.putString("format", BarcodeFormatUtils.getFormat(valueFormat));
serializedBarcode.putMap("bounds", processBounds(bounds));
barcodesList.pushMap(serializedBarcode);
}
@ -336,7 +334,11 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, V
x = x - mPaddingLeft / 2;
}
y = y + mPaddingTop;
if (frame.top < mHeight / 2) {
y = y + mPaddingTop / 2;
} else if (frame.top > mHeight / 2) {
y = y - mPaddingTop / 2;
}
origin.putDouble("x", x * mScaleX);
origin.putDouble("y", y * mScaleY);

View File

@ -2,134 +2,19 @@
id: api
title: Work in progress
---
## Props Index
## API props
[**wip**]
- [`zoom`](API.md#zoom)
- [`maxZoom`](API.md#maxzoom)
- [`type`](API.md#type)
- [`cameraId`](API.md#cameraid)
- [`flashMode`](API.md#flashmode)
- [`exposure`](API.md#exposure)
- [`whiteBalance`](API.md#whiteBalance)
- [`autoFocus`](API.md#autoFocus)
- [`ratio`](API.md#ratio)
- [`pictureSize`](API.md#pictureSize)
- [`focusDepth`](API.md#focusDepth)
- [`onMountError`](API.md#onMountError)
- [`onCameraReady`](API.md#onCameraReady)
## Methods Index
- [`takePictureAsync`](API.md#takepictureasync)
- [`recordAsync`](API.md#recordasync)
- [`refreshAuthorizationStatus`](API.md#refreshauthorizationstatus)
- [`stopRecording`](API.md#stoprecording)
- [`pausePreview`](API.md#pausepreview)
- [`resumePreview`](API.md#resumepreview)
- [`getAvailablePictureSizes`](API.md#getavailablepicturesizes)
- [`getSupportedRatiosAsync`](API.md#getsupportedratiosasync-android-only)
- [`isRecording`](API.md#isrecording-ios-only)
- [`getSupportedPreviewFpsRange`](API.md#getsupportedpreviewfpsrange-android-only)
## Props
---
### `zoom`
This property specifies the zoom value of the camera. Ranges from 0 to 1. Default to 0.
| Type | Default Value |
| ------ | ------------- |
| number | 0 |
---
### `maxZoom`
The maximum zoom value of the camera. Defaults to 0.
| Type | Default Value |
| ------ | ------------- |
| number | 0 |
---
### `type`
This property defines which camera on the phone the component is using.
Possible values:
- `front`
- `back`
| Type | Default Value |
| ------ | ------------- |
| number | 'back' |
---
### `cameraId`
For selecting from multiple cameras on Android devices. See [2492](https://github.com/react-native-community/react-native-camera/pull/2492) for more info. Can be retrieved with `getCameraIds()`
| Type | Default Value | Platform |
| ------ | ------------- | -------- |
| String | `null` | Android |
---
### `flashMode`
Determines the state of the camera flash. Has the following possible states.
```off: '1',
on: 'auto',
auto: 'torch',
torch: 'off'
```
| Type | Default Value |
| ------ | ------------- |
| object | `{ off: 1 }` |
### `ratio`
A string representing the camera ratio in the format 'height:width'. Default is `"4:3"`.
Use `getSupportedRatiosAsync` method to get ratio strings supported by your camera on Android.
| Type | Default Value |
| ------ | ------------- |
| string | `4:3` |
### `pictureSize`
This prop has a different behaviour for Android and iOS and should rarely be set.
For Android, this prop attempts to control the camera sensor capture resolution, similar to how `ratio` behaves. This is useful for cases where a low resolution image is required, and makes further resizing less intensive on the device's memory. The list of possible values can be requested with `getAvailablePictureSizes`, and the value should be set in the format of `<width>x<height>`. Internally, the native code will attempt to get the best suited resolution for the given `pictureSize` value if the provided value is invalid, and will default to the highest resolution available.
For iOS, this prop controls the internal camera preset value and should rarely be changed. However, this value can be set to setup the sensor to match the video recording's quality in order to prevent flickering. The list of valid values can be gathered from https://developer.apple.com/documentation/avfoundation/avcapturesessionpreset and can also be requested with `getAvailablePictureSizes`.
| Type | Default Value |
| ------ | ------------- |
| string | `None` |
## Methods
## takePictureAsync()
Returns a promise with TakePictureResponse.
### Method type
```ts
takePictureAsync(options?: TakePictureOptions): Promise<TakePictureResponse>;
```
```ts
interface TakePictureOptions {
quality?: number;
@ -140,10 +25,11 @@ interface TakePictureOptions {
mirrorImage?: boolean;
doNotSave?: boolean;
pauseAfterCapture?: boolean;
writeExif?: boolean | { [name: string]: any };
/** Android only */
skipProcessing?: boolean;
fixOrientation?: boolean;
writeExif?: boolean;
/** iOS only */
forceUpOrientation?: boolean;
@ -170,7 +56,6 @@ takePicture = async () => {
}
};
```
---
## recordAsync()
@ -182,7 +67,6 @@ Returns a promise with RecordResponse.
```ts
recordAsync(options?: RecordOptions): Promise<RecordResponse>;
```
```ts
interface RecordOptions {
quality?: keyof VideoQuality;
@ -192,8 +76,9 @@ interface RecordOptions {
mute?: boolean;
mirrorVideo?: boolean;
path?: string;
/** Android only */
videoBitrate?: number;
fps?: number;
/** iOS only */
codec?: keyof VideoCodec | VideoCodec[keyof VideoCodec];
@ -208,6 +93,7 @@ interface RecordResponse {
/** iOS only */
codec: VideoCodec[keyof VideoCodec];
}
```
### Usage example
@ -233,6 +119,7 @@ takeVideo = async () => {
---
## refreshAuthorizationStatus()
Allows to make RNCamera check Permissions again and set status accordingly.
@ -275,6 +162,7 @@ stopRecording(): void;
---
## pausePreview()
Pauses the preview. The preview can be resumed again by using resumePreview().
@ -295,6 +183,7 @@ pausePreview(): void;
---
## resumePreview()
Resumes the preview after pausePreview() has been called.
@ -336,6 +225,7 @@ getAvailablePictureSizes(): Promise<string[]>;
---
## getSupportedRatiosAsync() - Android only
Android only. Returns a promise. The promise will be fulfilled with an object with an array containing strings with all camera aspect ratios supported by the device.
@ -356,12 +246,12 @@ getSupportedRatiosAsync(): Promise<string[]>;
---
## isRecording() - iOS only
iOS only. Returns a promise. The promise will be fulfilled with a boolean indicating if currently recording is started or stopped.
### Method type
```ts
isRecording(): Promise<boolean>;
@ -376,33 +266,4 @@ const isRecording = await isRecording();
} */
```
- [`getSupportedPreviewFpsRange`](API.md#getSupportedPreviewFpsRange`)
## getSupportedPreviewFpsRange - Android only
Android only. Returns a promise. The promise will be fulfilled with a json object including the fps ranges available for those devices ([android docs](<https://developer.android.com/reference/android/hardware/Camera.Parameters#getSupportedPreviewFpsRange()>))
### Method type
```ts
getSupportedPreviewFpsRange(): Promise<[{MINIMUM_FPS: string, MAXIMUM_FPS: string}]>;
```
### Usage example
```js
const previewRange = await this.camera.getSupportedPreviewFpsRange();
/* -> [
{
MINIMUM_FPS: "15000",
MAXIMUM_FPS: "15000"
},
{
MINIMUM_FPS: "20000",
MAXIMUM_FPS: "20000"
}
] */
```
---
---

View File

@ -83,12 +83,12 @@ dependencies {
## How can I resize captured images?
Currently, `RNCamera` does not allow for specifying the desired resolution of the captured image, nor does it natively expose any functionality to resize images.
One way to achieve this (without any additional dependencies ) is using [react-native.ImageEditor.cropImage](https://facebook.github.io/react-native/docs/imageeditor.html#cropimage).
One way to achieve this (without any additional dependencies )is using [react-native.ImageEditor.cropImage](https://facebook.github.io/react-native/docs/imageeditor.html#cropimage).
The strategy is:
1. Capture an image using `RNCamera`, which uses the device's max resolution.
2. Use `react-native.ImageEditor.cropImage()` to crop the image using the image's native size as the crop size (thus maintaining the original image), and the desired new size as the `displaySize` attribute (thus resizing the image).
2. Use `react-native.ImageEditor.cropImage()` to crop the image using the image's native size as the crop size (thus maintaiing the original image), and the desired new size as the `displaySize` attribute (thus resizing the image).
```javascript
import React, { PureComponent } from 'react';

View File

@ -51,7 +51,7 @@ class ExampleApp extends PureComponent {
);
}
takePicture = async () => {
takePicture = async() => {
if (this.camera) {
const options = { quality: 0.5, base64: true };
const data = await this.camera.takePictureAsync(options);
@ -82,7 +82,7 @@ const styles = StyleSheet.create({
},
});
AppRegistry.registerComponent('App', () => ExampleApp);
AppRegistry.registerComponent('ExampleApp', () => ExampleApp);
```
## FaCC (Function as Child Components)
@ -174,7 +174,7 @@ const styles = StyleSheet.create({
},
});
AppRegistry.registerComponent('App', () => ExampleApp);
AppRegistry.registerComponent('ExampleApp', () => ExampleApp);
```
### `camera`
@ -206,23 +206,14 @@ Use the `autoFocus` property to specify the auto focus setting of your camera. `
### `autoFocusPointOfInterest`
Values: Object `{ x: 0.5, y: 0.5 }`.
Values (iOS): Object `{ x: 0.5, y: 0.5, autoExposure }`.
Setting this property causes the auto focus feature of the camera to attempt to focus on the part of the image at this coordinate.
Setting this property causes the auto focus feature of the camera to attempt to focus on the part of the image at this coordiate.
Coordinates values are measured as floats from `0` to `1.0`. `{ x: 0, y: 0 }` will focus on the top left of the image, `{ x: 1, y: 1 }` will be the bottom right. Values are based on landscape mode with the home button on the right—this applies even if the device is in portrait mode.
On iOS, focusing will not change the exposure automatically unless autoExposure is also set to true.
Hint:
for portrait orientation, apply 90° clockwise rotation + translation: [Example](https://gist.github.com/Craigtut/6632a9ac7cfff55e74fb561862bc4edb)
### iOS `onSubjectAreaChanged`
iOS only.
if autoFocusPointOfInterest is set, this event will be fired when a substancial change is detected with the following object: `{ nativeEvent: { prevPoint: { x: number; y: number; } } }`
### `captureAudio`
Values: boolean `true` (default) | `false`
@ -230,12 +221,6 @@ Values: boolean `true` (default) | `false`
Specifies if audio recording permissions should be requested.
Make sure to follow README instructions for audio recording permissions [here](README.md).
### iOS `keepAudioSession`
Values: boolean `true` | `false` (false)
(iOS Only) When the camera is unmounted, it will release any audio session it acquired (if `captureAudio=true`) so other media can continue playing. However, this might not be always desirable (e.g., if video is played afterwards) and can be disabled by setting it to `true`. Setting this to `true`, means your app will not release the audio session. Note: other apps might still "steal" the audio session from your app.
### `flashMode`
Values: `RNCamera.Constants.FlashMode.off` (default), `RNCamera.Constants.FlashMode.on`, `RNCamera.Constants.FlashMode.auto` or `RNCamera.Constants.FlashMode.torch`.
@ -268,14 +253,6 @@ Values: `RNCamera.Constants.Type.front` or `RNCamera.Constants.Type.back` (defau
Use the `type` property to specify which camera to use.
### `Android` `cameraId`
Overrides the `type` property and uses the camera given by cameraId. Use `getCameraIds` to get the list of available IDs.
A common use case for this is to provide a "switch camera" button that loops through all available cameras.
Note: Variables such as flash might need to be resetted due to the camera not reporting an error when those values are not supported.
### `whiteBalance`
Values: `RNCamera.Constants.WhiteBalance.sunny`, `RNCamera.Constants.WhiteBalance.cloudy`, `RNCamera.Constants.WhiteBalance.shadow`, `RNCamera.Constants.WhiteBalance.incandescent`, `RNCamera.Constants.WhiteBalance.fluorescent` or `RNCamera.Constants.WhiteBalance.auto` (default)
@ -286,38 +263,12 @@ The idea is that you select the appropriate white balance setting for the type o
Use the `whiteBalance` property to specify which white balance setting the camera should use.
On iOS it's also possible to specify custom temperature, tint and rgb offset values instead of using one of the presets (auto, sunny, ...):
Value: Object (e.g. `{temperature: 4000, tint: -10.0, redGainOffset: 0.0, greenGainOffset: 0.0, blueGainOffset: 0.0}`)
The rgb offset values are applied to the calculated device specific white balance gains for the given temperature and tint values.
### `exposure`
Value: float from `0` to `1.0`, or `-1` (default) for auto.
Sets the camera's exposure value.
### `useNativeZoom`
Boolean to turn on native pinch to zoom. Works with the `maxZoom` property on iOS.
Warning: The Android Touch-Event-System causes childviews to catch the touch events. Therefore avoid using screenfilling touchables inside of the cameraview.
### `zoom`
Value: float from `0` to `1.0`
Specifies the zoom of your camera. The value 0 is no zoom, 1 is maximum zoom. For a medium zoom, for example, you could pass `0.5`.
### `iOS` `maxZoom`
iOS Only.
Value: optional float greater than `1.0` used to enforce a maximum zoom value on the camera. Setting a value to less than `1` (default) will make the camera use its own max zoom property.
Specifies the max zoom value used in zoom calculations. This is specifically useful for iOS where it reports arbitrary high values and using a 0 to 1 value as the zoom factor is not appropriate.
### `Android` `permissionDialogTitle` - Deprecated
Starting on android M individual permissions must be granted for certain services, the camera is one of them, you can use this to change the title of the dialog prompt requesting permissions.
@ -342,20 +293,6 @@ By default a `Camera not authorized` message will be displayed when access to th
By default a <ActivityIndicator> will be displayed while the component is waiting for the user to grant/deny access to the camera, if set displays the passed react element instead of the default one.
#### `rectOfInterest`
An `{x: , y:, width:, height: }` object which defines the rect of interst as normalized coordinates from `(0,0)` top left corner to `(1,1)` bottom right corner.
Note: Must also provide cameraViewDimensions prop for Android device
### `Android` `cameraViewDimensions`
An `{width:, height: }` object which defines the width and height of the cameraView. This prop is used to adjust the effect of Aspect Raio for rectOfInterest area on Android
### `Android` `playSoundOnCapture`
Boolean to turn on or off the camera's shutter sound (default false). Note that in some countries, the shutter sound cannot be turned off.
### `iOS` `videoStabilizationMode`
The video stabilization mode used for a video recording. The possible values are:
@ -367,7 +304,7 @@ The video stabilization mode used for a video recording. The possible values are
You can read more about each stabilization type here: https://developer.apple.com/documentation/avfoundation/avcapturevideostabilizationmode
### `defaultVideoQuality`
### `iOS` `defaultVideoQuality`
This option specifies the quality of the video to be taken. The possible values are:
@ -393,19 +330,11 @@ This option specifies the quality of the video to be taken. The possible values
If nothing is passed the device's highest camera quality will be used as default.
Note: This solve the flicker video recording issue for iOS
### `pictureSize`
This prop has a different behaviour for Android and iOS and should rarely be set.
For Android, this prop attempts to control the camera sensor capture resolution, similar to how `ratio` behaves. This is useful for cases where a low resolution image is required, and makes further resizing less intensive on the device's memory. The list of possible values can be requested with `getAvailablePictureSizes`, and the value should be set in the format of `<width>x<height>`. Internally, the native code will attempt to get the best suited resolution for the given `pictureSize` value if the provided value is invalid, and will default to the highest resolution available.
For iOS, this prop controls the internal camera preset value and should rarely be changed. However, this value can be set to setup the sensor to match the video recording's quality in order to prevent flickering. The list of valid values can be gathered from https://developer.apple.com/documentation/avfoundation/avcapturesessionpreset and can also be requested with `getAvailablePictureSizes`.
### Native Event callbacks props
### `onCameraReady`
Function to be called when native code emit onCameraReady event, when camera is ready. This event will also fire when changing cameras (by `type` or `cameraId`).
Function to be called when native code emit onCameraReady event, when camera is ready.
### `onMountError`
@ -420,47 +349,9 @@ Event contains the following fields:
- `cameraStatus` - one of the [CameraStatus](#status) values
- `recordAudioPermissionStatus` - one of the [RecordAudioPermissionStatus](#recordAudioPermissionStatus) values
### `iOS` `onAudioInterrupted`
### `Android` `onPictureTaken`
iOS only. Function to be called when the camera audio session is interrupted or fails to start for any reason (e.g., in use or not authorized). For example, this might happen due to another app taking exclusive control over the microphone (e.g., a phone call) if `captureAudio={true}`. When this happens, any active audio input will be temporarily disabled and cause a flicker on the preview screen. This will fire any time an attempt to connect the audio device fails. Use this to update your UI to indicate that audio recording is not currently possible.
### `iOS` `onAudioConnected`
iOS only. Function to be called when the camera audio session is connected. This will be fired the first time the camera is mounted with `captureAudio={true}`, and any time the audio device connection is established. Note that this event might not always fire after an interruption due to iOS' behavior. For example, if the audio was already interrupted before the camera was mounted, this event will only fire once a recording is attempted.
### `onPictureTaken`
Function to be called when native code emit onPictureTaken event, when camera has taken a picture, but before all extra processing happens. This can be useful to allow the UI to take other pictures while the processing of the current picture is still taking place.
### `onRecordingStart`
Function to be called when native code actually starts video recording. Note that video recording might take a few miliseconds to setup depending on the camera settings and hardware features. Use this event to detect when video is actually being recorded.
Event will contain the following fields:
- `uri` - Video file URI, as returned by `recordAsync`
- `videoOrientation` - Video orientation, as returned by `recordAsync`
- `deviceOrientation` - Video orientation, as returned by `recordAsync`
### `onRecordingEnd`
Function to be called when native code stops recording video, but before all video processing takes place. This event will only fire after a successful video recording, and it will not fire if video recording fails (use the error returned from `recordAsync` instead).
### `onTap`
Function to be called when a touch within the camera view is recognized.
The function is also called on the first touch of double tap.
Event will contain the following fields:
- `x`
- `y`
### `onDoubleTap`
Function to be called when a double touch within the camera view is recognized.
Event will contain the following fields:
- `x`
- `y`
Function to be called when native code emit onPictureTaken event, when camera has taken a picture.
### Bar Code Related props
@ -472,7 +363,6 @@ Event contains the following fields
- `data` - a textual representation of the barcode, if available
- `rawData` - The raw data encoded in the barcode, if available
- `uri`: (iOS only) string representing the path to the image saved on your app's cache directory. Applicable only for `onGoogleVisionBarcodesDetected`.
- `type` - the type of the barcode detected
- `bounds` -
@ -489,24 +379,18 @@ Event contains the following fields
}
}
- onAndroid: the `ResultPoint[]` (`bounds.origin`) is returned for scanned barcode origins. The number of `ResultPoint` returned depends on the type of Barcode.
- onAndroid:
bounds: {
width: number;
height: number;
origin: Array<{x: number, y: number}>
}
bounds:[{x:string,y:string}]
- on Android it just returns resultPoints:
- for barcodes:
1. **PDF417**: 8 ResultPoint, laid out as follow:
0 --- 4 ------ 6 --- 2
| ////////////////// |
1 --- 5 ------ 7 --- 3
bounds[0].x : left side of barcode.
bounds[1].x : right side of barcode
- counting for QRcodes:
2. **QR**: 4 ResultPoint, laid out as follow:
2 ------ 3
| //////
| //////
1 ------ 0
1 2
0
The following barcode types can be recognised:
@ -538,7 +422,6 @@ Like `onBarCodeRead`, but using Firebase MLKit to scan barcodes. More info can b
Like `barCodeTypes`, but applies to the Firebase MLKit barcode detector.
Example: `<RNCamera googleVisionBarcodeType={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeType.DATA_MATRIX} />`
Available settings:
- CODE_128
- CODE_39
- CODE_93
@ -554,18 +437,11 @@ Available settings:
- DATA_MATRIX
- ALL
### `googleVisionBarcodeMode`
### `Android` `googleVisionBarcodeMode`
Change the mode in order to scan "inverted" barcodes. You can either change it to `alternate`, which will inverted the image data every second screen and be able to read both normal and inverted barcodes, or `inverted`, which will only read inverted barcodes. Default is `normal`, which only reads "normal" barcodes. Note: this property only applies to the Google Vision barcode detector.
Example: `<RNCamera googleVisionBarcodeMode={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeMode.ALTERNATE} />`
### `detectedImageInEvent`
When `detectedImageInEvent` is `false` (default), `onBarCodeRead` / `onBarcodesDetected` only gives metadata, but not the image (bytes/base64) itself.
When `detectedImageInEvent` is `true`, `onBarCodeRead` / `onGoogleVisionBarcodesDetected` will fill the `image` field inside the object given to the callback handler.
It contains raw image bytes in JPEG format (quality 100) as Base64-encoded string.
### Face Detection Related props
RNCamera uses the Firebase MLKit for Face Detection, you can read more about it [here](https://firebase.google.com/docs/ml-kit/detect-faces).
@ -610,7 +486,7 @@ Method to be called when text is detected. Receives a Text Recognized Event obje
### `takePictureAsync([options]): Promise`
Takes a picture, saves in your app's cache directory and returns a promise. Note: additional image processing, such as mirror, orientation, and width, can be significantly slow on Android.
Takes a picture, saves in your app's cache directory and returns a promise.
Supported options:
@ -622,30 +498,20 @@ Supported options:
- `mirrorImage` (boolean true or false). Use this with `true` if you want the resulting rendered picture to be mirrored (inverted in the vertical axis). If no value is specified `mirrorImage:false` is used.
- `writeExif`: (boolean or object, defaults to true). Setting this to a boolean indicates if the image exif should be preserved after capture, or removed. Setting it to an object, merges any data with the final exif output. This is useful, for example, to add GPS metadata (note that GPS info is correctly transalted from double values to the EXIF format, so there's no need to read the EXIF protocol).
```js
writeExif = {
GPSLatitude: latitude,
GPSLongitude: longitude,
GPSAltitude: altitude,
};
```
- `exif` (boolean true or false) Use this with `true` if you want a exif data map of the picture taken on the return data of your promise. If no value is specified `exif:false` is used.
- `fixOrientation` (android only, boolean true or false) Use this with `true` if you want to fix incorrect image orientation (can take up to 5 seconds on some devices). Do not provide this if you only need EXIF based orientation.
- `forceUpOrientation` (iOS only, boolean true or false). This property allows to force portrait orientation based on actual data instead of exif data.
- `skipProcessing` (android only, boolean). This property skips all image processing on android, this makes taking photos super fast, but you loose some of the information, width, height and the ability to do some processing on the image (base64, width, quality, mirrorImage, exif, etc)
- `doNotSave` (boolean true or false). Use this with `true` if you do not want the picture to be saved as a file to cache. If no value is specified `doNotSave:false` is used. If you only need the base64 for the image, you can use this with `base64:true` and avoid having to save the file.
- `pauseAfterCapture` (boolean true or false). If true, pause the preview layer immediately after capturing the image. You will need to call `cameraRef.resumePreview()` before using the camera again. If no value is specified `pauseAfterCapture:false` is used.
- `orientation` (string or number). Specifies the orientation that us used for taking the picture. Possible values: `"portrait"`, `"portraitUpsideDown"`, `"landscapeLeft"` or `"landscapeRight"`.
- `path` (file path on disk). Specifies the path on disk to save picture to.
The promise will be fulfilled with an object with some of the following properties:
- `width`: returns the image's width (taking image orientation into account)
@ -685,7 +551,7 @@ Supported options:
- `videoBitrate`. (int greater than 0) This option specifies a desired video bitrate. For example, 5\*1000\*1000 would be 5Mbps.
- `ios` Supported however requires that the codec key is also set.
- `ios` Not supported.
- `android` Supported.
- `orientation` (string or number). Specifies the orientation that us used for recording the video. Possible values: `"portrait"`, `"portraitUpsideDown"`, `"landscapeLeft"` or `"landscapeRight"`.
@ -726,7 +592,7 @@ The promise will be fulfilled with an object with some of the following properti
### `refreshAuthorizationStatus: Promise<void>`
Allows to make RNCamera check Permissions again and set status accordingly.
Allows to make RNCamera check Permissions again and set status accordingly.
Making it possible to refresh status of RNCamera after user initially rejected the permissions.
### `stopRecording: void`
@ -745,20 +611,6 @@ Resumes the preview after pausePreview() has been called.
Android only. Returns a promise. The promise will be fulfilled with an object with an array containing strings with all camera aspect ratios supported by the device.
### `getCameraIdsAsync(): Promise`
Returns a promise. The promise will be fulfilled with an array containing objects with all camera IDs and type supported by the device.
The promise will be fulfilled with an array containing objects with some of the following properties:
- `id`: (string) the ID of the camera.
- `type`: One of `RNCamera.Constants.Type.front` | `RNCamera.Constants.Type.back`
- `deviceType`: iOS 10+ only. Returns the internal device string type used by the OS. Useful to identify camera types (e.g., wide). Constants match iOS' string values: `AVCaptureDeviceTypeBuiltInWideAngleCamera`, `AVCaptureDeviceTypeBuiltInTelephotoCamera`, `AVCaptureDeviceTypeBuiltInUltraWideCamera`. More info can be found at <a href="https://developer.apple.com/documentation/avfoundation/avcapturedevicetypebuiltinultrawidecamera" target="_blank">Apple Docs</a>
Note: iOS also allows for virtual cameras (e.g., a camera made of multiple cameras). However, only physical non-virtual cameras are returned by this method since advanced features (such as depth maps or auto switching on camera zoom) are not supported.
### `iOS` `isRecording(): Promise<boolean>`
iOS only. Returns a promise. The promise will be fulfilled with a boolean indicating if currently recording is started or stopped.
@ -775,15 +627,6 @@ A Barcode and QR code UI mask which can be use to render a scanning layout on ca
Read more about [react-native-barcode-mask](https://github.com/shahnawaz/react-native-barcode-mask) here.
### @nartc/react-native-barcode-mask
A rewritten version of `react-native-barcode-mask` using `Hooks` and `Reanimated`. If you're already using `react-native-reanimated` (`react-navigation` dependency) then you might benefit from this rewritten component.
- Customizable
- Provide custom hook to "scan barcode within finder area"
Read more about it here [@nartc/react-native-barcode-mask](https://github.com/nartc/react-native-barcode-mask)
## Testing
To learn about how to test components which uses `RNCamera` check its [documentation about testing](./tests.md).

View File

@ -24,7 +24,7 @@ Passing `null` to `onFaceDetected`, `onGoogleVisionBarcodesDetected`, `onTextRec
## Events continue if screen is mounted but not on top of stack
Lets say you use Face Detection, you take a picture and then takes the user to another screen to see that picture. Meanwhile, RNCamera is still mounted on the previous screen. `onFaceDetected` will still be called if you do not prevent it. For example (using [`react-navigation`](https://github.com/react-navigation/react-navigation)):
Lets say you use Face Detection, you take a picture and then takes the user to another screen to see that picture. Meanwhile, RNCamera is still mounted on the previous screen. `onFaceDetected` will still be called if you do not prevent it. For example (using [`react-navigation`](https://github.com/react-navigation/react-navigation):
```
const takePictureAndShow = () => {
@ -47,7 +47,7 @@ const { navigation } = this.props;
## Sending the image to a server
A good way is to get the base64 string representation of your image. You can get it from RNCamera by passing the `base64: true` option to `takePictureAsync` like:
A good way is to get the base64 string representation of your image. You can get it from RNCamera by passing the `base64: true` option lto `takePictureAsync` like:
```
if (this.camera) {
@ -85,7 +85,7 @@ Use this package https://github.com/phuochau/react-native-thumbnail
Because of different project requirements there is no gesture zoom (like pinch zoom or slide-up zoom) implemented in this package. All implementation should be done in user-land.
However we have some recipes for common zoom behaviours. If you implemented your own solution feel free to add it to the list!
However we have some recipies for common zoom behaviours. If you implemented your own solution feel free to add it to the list!
## SlideUp Zoom

View File

@ -1,56 +0,0 @@
---
id: Tidelift
title: React-Native-Camera for Enterprise
---
## React-Native-Camera for Enterprise
### Available as part of the Tidelift Subscription
**Tidelift** is working with the maintainers of **React-Native-Camera** and thousands of other open source projects to deliver
commercial support and maintenance for the open source dependencies you use to build your applications.
Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
[LEARN MORE](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)
[REQUEST A DEMO](https://tidelift.com/subscription/request-a-demo?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)
### Enterprise-ready open source software - managed for you
The Tidelift Subscription is a managed open source subscription for application dependencies covering millions
of open source projects across JavaScript, Python, Java, PHP, Ruby, .NET, and more.
Your subscription includes:
* **Security updates**<br />
Tidelifts security response team coordinates patches for new breaking security vulnerabilities and alerts
immediately through a private channel, so your software supply chain is always secure.
* **Licensing verification and indemnification**<br />
Tidelift verifies license information to enable easy policy enforcement and adds intellectual property
indemnification to cover creators and users in case something goes wrong. You always have a 100% up-to-date
bill of materials for your dependencies to share with your legal team, customers, or partners.
* **Maintenance and code improvement**<br />
Tidelift ensures the software you rely on keeps working as long as you need it to work.
Your managed dependencies are actively maintained and we recruit additional maintainers where required.
* **Package selection and version guidance**<br />
We help you choose the best open source packages from the start—and then guide you through updates to stay on
the best releases as new issues arise.
* **Roadmap input**<br />
Take a seat at the table with the creators behind the software you use. Tidelifts participating maintainers
earn more income as their software is used by more subscribers, so theyre interested in knowing what you need.
* **Tooling and cloud integration**<br />
Tidelift works with GitHub, GitLab, BitBucket, and more.
We support every cloud platform (and other deployment targets, too).
The end result? All of the capabilities you expect from commercial-grade software, for the full breadth
of open source you use. That means less time grappling with esoteric open source trivia, and more
time building your own applications—and your business.
[LEARN MORE](https://tidelift.com/subscription/pkg/npm-react-native-camera?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)
[REQUEST A DEMO](https://tidelift.com/subscription/request-a-demo?utm_source=npm-react-native-camera&utm_medium=referral&utm_campaign=enterprise)

View File

@ -1,468 +1,418 @@
---
id: installation
title: Installation
---
This document is split into two main sections:
1. Required installation steps for basic usage of `react-native-camera`
2. Additional installation steps for usage of Face Detection/Text Recognition/BarCode with [MLKit](https://developers.google.com/ml-kit)
# Required installation steps
_These steps assume installation for iOS/Android. To install it with Windows, see [Windows](#windows) below_
## Mostly automatic install with autolinking (RN > 0.60)
1. `npm install react-native-camera --save`
2. Run `cd ios && pod install && cd ..`
## Mostly automatic install with react-native link (RN < 0.60)
1. `npm install react-native-camera --save`
2. `react-native link react-native-camera`
## Manual install - iOS (not recommended)
1. `npm install react-native-camera --save`
2. In XCode, in the project navigator, right click `Libraries``Add Files to [your project's name]`
3. Go to `node_modules``react-native-camera` and add `RNCamera.xcodeproj`
4. Expand the `RNCamera.xcodeproj``Products` folder
5. In XCode, in the project navigator, select your project. Add `libRNCamera.a` to your project's `Build Phases``Link Binary With Libraries`
6. Click `RNCamera.xcodeproj` in the project navigator and go the `Build Settings` tab. Make sure 'All' is toggled on (instead of 'Basic'). In the `Search Paths` section, look for `Header Search Paths` and make sure it contains both `$(SRCROOT)/../../react-native/React` and `$(SRCROOT)/../../../React` - mark both as `recursive`.
## Manual install - Android (not recommended)
1. `npm install react-native-camera --save`
2. Open up `android/app/src/main/java/[...]/MainApplication.java`
- Add `import org.reactnative.camera.RNCameraPackage;` to the imports at the top of the file
- Add `new RNCameraPackage()` to the list returned by the `getPackages()` method. Add a comma to the previous item if there's already something there.
3. Append the following lines to `android/settings.gradle`:
```gradle
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
```
4. Insert the following lines in `android/app/build.gradle` inside the dependencies block:
```gradle
implementation project(':react-native-camera')
```
## iOS - other required steps
Add permissions with usage descriptions to your app `Info.plist`:
```xml
<!-- Required with iOS 10 and higher -->
<key>NSCameraUsageDescription</key>
<string>Your message to user when the camera is accessed for the first time</string>
<!-- Required with iOS 11 and higher: include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the microphone for video recording -->
<key>NSMicrophoneUsageDescription</key>
<string>Your message to user when the microphone is accessed for the first time</string>
```
<details>
<summary>Additional information in case of problems</summary>
You might need to adjust your Podfile following the example below:
```ruby
target 'yourTargetName' do
# See http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#configuring-cocoapods-dependencies
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # Needed for debugging
'RCTAnimation', # Needed for FlatList and animations running on native UI thread
# Add any other subspecs you want to use in your project
]
# Explicitly include Yoga if you are using RN >= 0.42.0
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
# Third party deps podspec link
pod 'react-native-camera', path: '../node_modules/react-native-camera'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == "React"
target.remove_from_project
end
end
end
```
</details>
## Android - other required steps
Add permissions to your app `android/app/src/main/AndroidManifest.xml` file:
```xml
<!-- Required -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- Include this only if you are planning to use the camera roll -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Include this only if you are planning to use the microphone for video recording -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
```
Insert the following lines in `android/app/build.gradle`:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'general' // <--- insert this line
}
}
```
<details>
<summary>Additional information in case of problems</summary>
1. Make sure you use `JDK >= 1.7` and your `buildToolsVersion >= 25.0.2`
2. Make sure you have jitpack added in `android/build.gradle`
```gradle
allprojects {
repositories {
maven { url "https://www.jitpack.io" }
maven { url "https://maven.google.com" }
}
}
```
</details>
# Additional installation steps
Follow these optional steps if you want to use Face Detection/Text Recognition/BarCode with [MLKit](https://developers.google.com/ml-kit).
You will need to set-up Firebase project for your app (detailed steps below).
_Note:_ Installing [react-native-firebase](https://github.com/invertase/react-native-firebase) package is NOT necessary.
## iOS
If you want any of these optional features, you will need to use CocoaPods.
### Modifying Podfile
Add dependency towards `react-native-camera` in your `Podfile` with `subspecs` using one of the following:
- For Face Detection:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'FaceDetectorMLKit'
]
```
- For Text Recognition:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector'
]
```
- For BarCode Recognition:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'BarcodeDetectorMLKit'
]
```
- For all possible detections:
```ruby
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector',
'FaceDetectorMLKit',
'BarcodeDetectorMLKit'
]
```
Then run `cd ios && pod install && cd ..`
### Setting up Firebase
Text/Face recognition for iOS uses Firebase MLKit which requires setting up Firebase project for your app.
If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/ios/setup).
In short, you would need to
1. Register your app in Firebase console.
2. Download `GoogleService-Info.plist` and add it to your project
3. Add `pod 'Firebase/Core'` to your podfile
4. In your `AppDelegate.m` file add the following lines:
```objective-c
#import <Firebase.h> // <--- add this
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure]; // <--- add this
...
}
```
<details>
<summary>Additional information in case of problems</summary>
- If you have issues with duplicate symbols you will need to enable dead code stripping option in your Xcode (Target > Build Settings > search for "Dead code stripping") [see here](https://github.com/firebase/quickstart-ios/issues/487#issuecomment-415313053).
- If you are using `pod Firebase/Core` with a version set below 5.13 you might want to add `pod 'GoogleAppMeasurement', '~> 5.3.0'` to your podfile
</details>
## Android
### Modifying build.gradle
Modify the following lines in `android/app/build.gradle`:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'mlkit' // <--- replace general with mlkit
}
}
```
### Setting up Firebase
Using Firebase MLKit requires seting up Firebase project for your app. If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/android/setup).
In short, you would need to
1. Register your app in Firebase console.
2. Download google-services.json and place it in `android/app/`
3. Add the folowing to project level `build.gradle`:
```gradle
buildscript {
dependencies {
// Add this line
classpath 'com.google.gms:google-services:4.0.1' // <--- you might want to use different version
}
}
```
4. add to the bottom of `android/app/build.gradle` file
```gradle
apply plugin: 'com.google.gms.google-services'
```
5. Configure your app to automatically download the ML model to the device after your app is installed from the Play Store. If you do not enable install-time model downloads, the model will be downloaded the first time you run the on-device detector. Requests you make before the download has completed will produce no results.
```xml
<application ...>
...
<meta-data
android:name="com.google.firebase.ml.vision.DEPENDENCIES"
android:value="ocr, face" /> <!-- choose models that you will use -->
</application>
```
<details>
<summary>Additional information in case of problems</summary>
The current Android library defaults to the below values for the Google SDK and Libraries,
```gradle
def DEFAULT_COMPILE_SDK_VERSION = 26
def DEFAULT_BUILD_TOOLS_VERSION = "26.0.2"
def DEFAULT_TARGET_SDK_VERSION = 26
def DEFAULT_GOOGLE_PLAY_SERVICES_VERSION = "12.0.1"
def DEFAULT_SUPPORT_LIBRARY_VERSION = "27.1.0"
```
You can override this settings by adding a Project-wide gradle configuration properties for
use by all modules in your ReactNative project by adding the below to `android/build.gradle`
file,
```gradle
buildscript {...}
allprojects {...}
/**
* Project-wide gradle configuration properties for use by all modules
*/
ext {
compileSdkVersion = 26
targetSdkVersion = 26
buildToolsVersion = "26.0.2"
googlePlayServicesVersion = "12.0.1"
googlePlayServicesVisionVersion = "15.0.2"
supportLibVersion = "27.1.0"
}
```
The above settings in the ReactNative project over-rides the values present in the `react-native-camera`
module. For your reference below is the `android/build.gradle` file of the module.
```gradle
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
buildscript {
repositories {
google()
maven {
url 'https://maven.google.com'
}
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
}
flavorDimensions "react-native-camera"
productFlavors {
general {
dimension "react-native-camera"
}
mlkit {
dimension "react-native-camera"
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
general {
java.srcDirs = ['src/general/java']
}
mlkit {
java.srcDirs = ['src/mlkit/java']
}
}
lintOptions {
abortOnError false
warning 'InvalidPackage'
}
}
repositories {
google()
jcenter()
maven {
url 'https://maven.google.com'
}
maven { url "https://jitpack.io" }
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
dependencies {
def googlePlayServicesVisionVersion = safeExtGet('googlePlayServicesVisionVersion', safeExtGet('googlePlayServicesVersion', '17.0.2'))
implementation 'com.facebook.react:react-native:+'
implementation "com.google.zxing:core:3.3.3"
implementation "com.drewnoakes:metadata-extractor:2.11.0"
generalImplementation "com.google.android.gms:play-services-vision:$googlePlayServicesVisionVersion"
implementation "com.android.support:exifinterface:${safeExtGet('supportLibVersion', '28.0.0')}"
implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '28.0.0')}"
implementation "com.android.support:support-v4:${safeExtGet('supportLibVersion', '28.0.0')}"
mlkitImplementation "com.google.firebase:firebase-ml-vision:${safeExtGet('firebase-ml-vision', '19.0.3')}"
mlkitImplementation "com.google.firebase:firebase-ml-vision-face-model:${safeExtGet('firebase-ml-vision-face-model', '17.0.2')}"
}
```
If you are using a version of `googlePlayServicesVersion` that does not have `play-services-vision`, you can specify a different version of `play-services-vision` by adding `googlePlayServicesVisionVersion` to the project-wide properties
```gradle
ext {
compileSdkVersion = 26
targetSdkVersion = 26
buildToolsVersion = "26.0.2"
googlePlayServicesVersion = "16.0.1"
googlePlayServicesVisionVersion = "15.0.2"
supportLibVersion = "27.1.0"
}
```
</details>
# Windows
## Mostly automatic install with autolinking (RNW >= 0.63)
1. `npm install react-native-camera --save`
2. See [Additional steps - Windows](#additional-steps-windows) below
## Manual install - Windows (RNW 0.62)
1. `npm install react-native-camera --save`
2. Link the library as described below:
1. Add the _ReactNativeCameraCPP_ project to your solution (eg. `windows\yourapp.sln`)
1. Open your solution in Visual Studio 2019
2. Right-click Solution icon in Solution Explorer > Add > Existing Project...
3. Select `node_modules\react-native-camera\windows\ReactNativeCameraCPP\ReactNativeCameraCPP.vcxproj`
2. Add a reference to _ReactNativeCameraCPP_ to your main application project (eg. `windows\yourapp\yourapp.vcxproj`)
1. Open your solution in Visual Studio 2019
2. Right-click main application project > Add > Reference...
3. Check _ReactNativeCameraCPP_ from Solution Projects
3. Modify files below to add the package providers to your main application project
1. `pch.h`
1. Add `#include "winrt/ReactNativeCameraCPP.h"`
2. `App.cpp`
1. Add `PackageProviders().Append(winrt::ReactNativeCameraCPP::ReactPackageProvider());` before `InitializeComponent();`
4. See [Additional steps - Windows](#additional-steps-windows) below
## Manual install - Windows (RNW 0.61)
Follow [Manual install - Windows (RNW 0.62)](#manual-install-windows-rnw-062) above, but for step 2 substitute _ReactNativeCameraCPP61_ for _ReactNativeCameraCPP_.
## Additional steps - Windows
You need to declare that your app wants to access the camera:
1. Add the capabilities (permissions) for the webcam and microphone as described here: [Add capability declarations to the app manifest](https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/simple-camera-preview-access#add-capability-declarations-to-the-app-manifest)
2. If you plan on capturing images to the Pictures Library, or videos to the Videos Library, be sure to enable those capabilities too
Follow the [Q & A](QA.md) section if you are having compilation issues.
---
id: installation
title: Installation
---
## Requirements
1. JDK >= 1.7 (if you run on 1.6 you will get an error on "\_cameras = new HashMap<>();")
2. With iOS 10 and higher you need to add the "Privacy - Camera Usage Description" key to the Info.plist of your project. This should be found in 'your_project/ios/your_project/Info.plist'. Add the following code:
```
<key>NSCameraUsageDescription</key>
<string>Your message to user when the camera is accessed for the first time</string>
<!-- Include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
<!-- Include this only if you are planning to use the microphone for video recording -->
<key>NSMicrophoneUsageDescription</key>
<string>Your message to user when the microphone is accessed for the first time</string>
```
3. On Android, you require `buildToolsVersion` of `25.0.2+`. _This should easily and automatically be downloaded by Android Studio's SDK Manager._
4. On iOS 11 and later you need to add `NSPhotoLibraryAddUsageDescription` key to the Info.plist. This key lets you describe the reason your app seeks write-only access to the users photo library. Info.plist can be found in 'your_project/ios/your_project/Info.plist'. Add the following code:
```
<!-- Include this only if you are planning to use the camera roll -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Your message to user when the photo library is accessed for the first time</string>
```
## Mostly automatic install with react-native
1. `npm install react-native-camera --save`
2. `react-native link react-native-camera`
_To install it with Windows, see manual install below_
## Mostly automatic install with CocoaPods
1. `npm install react-native-camera --save`
2. Add the plugin dependency to your Podfile, pointing at the path where NPM installed it:
```obj-c
pod 'react-native-camera', path: '../node_modules/react-native-camera'
```
3. Run `pod install`
_Note:_ You might need to adjust your Podfile following the example below:
```ruby
target 'yourTargetName' do
# See http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#configuring-cocoapods-dependencies
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # Needed for debugging
'RCTAnimation', # Needed for FlatList and animations running on native UI thread
# Add any other subspecs you want to use in your project
]
# Explicitly include Yoga if you are using RN >= 0.42.0
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
# Third party deps podspec link
pod 'react-native-camera', path: '../node_modules/react-native-camera'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == "React"
target.remove_from_project
end
end
end
```
## Manual install
## iOS
1. `npm install react-native-camera --save`
2. In XCode, in the project navigator, right click `Libraries``Add Files to [your project's name]`
3. Go to `node_modules``react-native-camera` and add `RNCamera.xcodeproj`
4. Expand the `RNCamera.xcodeproj``Products` folder
5. In XCode, in the project navigator, select your project. Add `libRNCamera.a` to your project's `Build Phases``Link Binary With Libraries`
6. Click `RNCamera.xcodeproj` in the project navigator and go the `Build Settings` tab. Make sure 'All' is toggled on (instead of 'Basic'). In the `Search Paths` section, look for `Header Search Paths` and make sure it contains both `$(SRCROOT)/../../react-native/React` and `$(SRCROOT)/../../../React` - mark both as `recursive`.
### Face Detection/Text Recognition/BarCode(using MLKit) Steps
Face Detection/Text Recognition/BarCode(using MLKit) are optional on iOS. If you want them, you will need to use CocoaPods path and set-up Firebase project for your app (detailed steps below).
_Note:_ Installing react-native-firebase package is NOT necessary.
### Modifying Podfile
Modify the dependency towards `react-native-camera` in your
`Podfile`, from
```
pod 'react-native-camera', path: '../node_modules/react-native-camera'
```
to (for Face Detection)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'FaceDetectorMLKit'
]
```
or to (for Text Recognition)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector'
]
```
or to (for Barcode Recognition)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'BarcodeDetectorMLKit'
]
```
or to (all possible detections)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector',
'FaceDetectorMLKit',
'BarcodeDetectorMLKit'
]
```
## Setting up Firebase
Text/Face recognition for iOS uses Firebase MLKit which requires setting up Firebase project for your app.
If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/ios/setup).
In short, you would need to
1. Register your app in Firebase console.
2. Download `GoogleService-Info.plist` and add it to your project
3. Add `pod 'Firebase/Core'` to your podfile
4. In your `AppDelegate.m` file add the following lines:
```objective-c
#import <Firebase.h> // <--- add this
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure]; // <--- add this
...
}
```
- If you have issues with duplicate symbols you will need to enable dead code stripping option in your Xcode (Target > Build Settings > search for "Dead code stripping") [see here](https://github.com/firebase/quickstart-ios/issues/487#issuecomment-415313053).
- If you are using `pod Firebase/Core` with a version set below 5.13 you might want to add `pod 'GoogleAppMeasurement', '~> 5.3.0'` to your podfile
### Android
1. `npm install react-native-camera --save`
2. Open up `android/app/src/main/java/[...]/MainApplication.java`
- Add `import org.reactnative.camera.RNCameraPackage;` to the imports at the top of the file
- Add `new RNCameraPackage()` to the list returned by the `getPackages()` method. Add a comma to the previous item if there's already something there.
3. Append the following lines to `android/settings.gradle`:
```gradle
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
```
4. Insert the following lines in `android/app/build.gradle`:
inside the dependencies block:
```gradle
implementation project(':react-native-camera')
```
inside defaultConfig block insert either:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'general' <-- insert this line
}
}
```
or, if using MLKit for text/face/barcode recognition:
```gradle
android {
...
defaultConfig {
...
missingDimensionStrategy 'react-native-camera', 'mlkit' <-- insert this line
}
}
```
5. Declare the permissions in your Android Manifest (required for `video recording` feature)
```xml
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```
6. Add jitpack to android/build.gradle
```gradle
allprojects {
repositories {
maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" }
}
}
```
7. Additional steps for using MLKit for text/face/barcode recognition
7.1. Using Firebase MLKit requires seting up Firebase project for your app. If you have not already added Firebase to your app, please follow the steps described in [getting started guide](https://firebase.google.com/docs/android/setup).
In short, you would need to
- Register your app in Firebase console.
- Download google-services.json and place it in `android/app/`
- add the folowing to project level build.gradle:
```gradle
buildscript {
dependencies {
// Add this line
classpath 'com.google.gms:google-services:4.0.1' <-- you might want to use different version
}
}
```
- add to the bottom of `android/app/build.gradle` file
```gradle
apply plugin: 'com.google.gms.google-services'
```
7.2. Configure your app to automatically download the ML model to the device after your app is installed from the Play Store. If you do not enable install-time model downloads, the model will be downloaded the first time you run the on-device detector. Requests you make before the download has completed will produce no results.
```xml
<application ...>
...
<meta-data
android:name="com.google.firebase.ml.vision.DEPENDENCIES"
android:value="ocr" />
<!-- To use multiple models, list all needed models: android:value="ocr, face, barcode" -->
</application>
```
The current Android library defaults to the below values for the Google SDK and Libraries,
```gradle
def DEFAULT_COMPILE_SDK_VERSION = 26
def DEFAULT_BUILD_TOOLS_VERSION = "26.0.2"
def DEFAULT_TARGET_SDK_VERSION = 26
def DEFAULT_GOOGLE_PLAY_SERVICES_VERSION = "12.0.1"
def DEFAULT_SUPPORT_LIBRARY_VERSION = "27.1.0"
```
You can override this settings by adding a Project-wide gradle configuration properties for
use by all modules in your ReactNative project by adding the below to `android/build.gradle`
file,
```gradle
buildscript {...}
allprojects {...}
/**
* Project-wide gradle configuration properties for use by all modules
*/
ext {
compileSdkVersion = 26
targetSdkVersion = 26
buildToolsVersion = "26.0.2"
googlePlayServicesVersion = "12.0.1"
googlePlayServicesVisionVersion = "15.0.2"
supportLibVersion = "27.1.0"
}
```
The above settings in the ReactNative project over-rides the values present in the `react-native-camera`
module. For your reference below is the `android/build.gradle` file of the module.
```gradle
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
buildscript {
repositories {
google()
maven {
url 'https://maven.google.com'
}
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
}
flavorDimensions "react-native-camera"
productFlavors {
general {
dimension "react-native-camera"
}
mlkit {
dimension "react-native-camera"
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
general {
java.srcDirs = ['src/general/java']
}
mlkit {
java.srcDirs = ['src/mlkit/java']
}
}
lintOptions {
abortOnError false
warning 'InvalidPackage'
}
}
repositories {
google()
jcenter()
maven {
url 'https://maven.google.com'
}
maven { url "https://jitpack.io" }
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
}
dependencies {
def googlePlayServicesVisionVersion = safeExtGet('googlePlayServicesVisionVersion', safeExtGet('googlePlayServicesVersion', '17.0.2'))
implementation 'com.facebook.react:react-native:+'
implementation "com.google.zxing:core:3.3.3"
implementation "com.drewnoakes:metadata-extractor:2.11.0"
generalImplementation "com.google.android.gms:play-services-vision:$googlePlayServicesVisionVersion"
implementation "com.android.support:exifinterface:${safeExtGet('supportLibVersion', '28.0.0')}"
implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '28.0.0')}"
implementation "com.android.support:support-v4:${safeExtGet('supportLibVersion', '28.0.0')}"
mlkitImplementation "com.google.firebase:firebase-ml-vision:${safeExtGet('firebase-ml-vision', '19.0.3')}"
mlkitImplementation "com.google.firebase:firebase-ml-vision-face-model:${safeExtGet('firebase-ml-vision-face-model', '17.0.2')}"
}
```
If you are using a version of `googlePlayServicesVersion` that does not have `play-services-vision`, you can specify a different version of `play-services-vision` by adding `googlePlayServicesVisionVersion` to the project-wide properties
```
ext {
compileSdkVersion = 26
targetSdkVersion = 26
buildToolsVersion = "26.0.2"
googlePlayServicesVersion = "16.0.1"
googlePlayServicesVisionVersion = "15.0.2"
supportLibVersion = "27.1.0"
}
```
### Windows
1. `npm install react-native-camera --save`
2. Link the library as described here: [react-native-windows / LinkingLibrariesWindows.md](https://github.com/microsoft/react-native-windows/blob/master/current/docs/LinkingLibrariesWindows.md)
For the last step of this guide, you have to add the following things to your `MainReactNativeHost.cs`:
- in the import section at the very top: `using RNCamera;`
- in `protected override List<IReactPackage> Packages => new List<IReactPackage>` add a new line with `new RNCameraPackage()`
3. Add the capabilities (permissions) for the webcam and microphone as described here: [docs.microsoft / audio-video-camera](https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/simple-camera-preview-access#add-capability-declarations-to-the-app-manifest)
4. Use `RCTCamera` (RNCamera is not supported yet) like described above
Follow the [Q & A](QA.md) section if you are having compilation issues.

View File

@ -4,25 +4,29 @@ title: React Navigation
sidebar_label: React Navigation
---
React-navigation does not unmount components when switching between tabs. So when you leave and return back to the screen with the camera component it will just be black view. So a good solution is to use `withNavigationFocus`, which is a higher order component, and wrap it around your component. Then, you can have access to `isFocused` from `props`.
React-navigation does not unmount components when switching between tabs. So when you leave and return back to the screen with the camera component it will just be black view. So a good solution is to use `componentDidMount` and added two listeners `willFocus` and `willBlur` to help you mount and unmount the views.
```jsx
import { withNavigationFocus } from 'react-navigation'
render() {
const { isFocused } = this.props
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else if (isFocused){
return (this.cameraView());
} else {
return <View />;
}
componentDidMount() {
const { navigation } = this.props;
navigation.addListener('willFocus', () =>
this.setState({ focusedScreen: true })
);
navigation.addListener('willBlur', () =>
this.setState({ focusedScreen: false })
);
}
export default withNavigationFocus(YourComponent)
render() {
const { hasCameraPermission, focusedScreen } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else if (focusedScreen){
return (this.cameraView());
} else {
return <View />;
}
}
```

View File

@ -1,4 +0,0 @@
# OSX
#
.DS_Store
.vscode

View File

@ -1,6 +0,0 @@
[android]
target = Google Inc.:Google APIs:23
[maven_repositories]
central = https://repo1.maven.org/maven2

View File

@ -1,4 +0,0 @@
module.exports = {
root: true,
extends: '@react-native-community',
};

View File

@ -1,75 +0,0 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow/
[options]
emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
munge_underscores=true
module.name_mapper='^react-native$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/react-native/react-native-implementation'
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
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\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.105.0

View File

@ -1 +0,0 @@
*.pbxproj -text

View File

@ -1,59 +0,0 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle
# CocoaPods
/ios/Pods/

View File

@ -1,6 +0,0 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
};

View File

@ -1 +0,0 @@
{}

View File

@ -1,55 +0,0 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
lib_deps = []
create_aar_targets(glob(["libs/*.aar"]))
create_jar_targets(glob(["libs/*.jar"]))
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "com.advanced",
)
android_resource(
name = "res",
package = "com.advanced",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)

View File

@ -1,213 +0,0 @@
apply plugin: "com.android.application"
import com.android.build.OutputFile
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.android.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
project.ext.react = [
entryFile: "index.js"
enableHermes: false, // clean and rebuild if changing
]
apply from: "../../node_modules/react-native/react.gradle"
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore.
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and mirrored here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
android {
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "com.advanced"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
missingDimensionStrategy 'react-native-camera', 'general'
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://facebook.github.io/react-native/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.facebook.react:react-native:+" // From node_modules
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
task downloadDependencies() {
description 'Download all dependencies to the Gradle cache'
doLast {
configurations.findAll().each { config ->
if (config.name.contains("minReactNative") && config.canBeResolved) {
print config.name
print '\n'
config.files
}
}
}
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

View File

@ -1,19 +0,0 @@
"""Helper definitions to glob .aar and .jar targets"""
def create_aar_targets(aarfiles):
for aarfile in aarfiles:
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
lib_deps.append(":" + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
def create_jar_targets(jarfiles):
for jarfile in jarfiles:
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
lib_deps.append(":" + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)

View File

@ -1,10 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
</manifest>

View File

@ -1,69 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.advanced;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}

View File

@ -1,34 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.advanced">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

View File

@ -1,32 +0,0 @@
package com.advanced;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "advanced";
}
/**
For react-native-gesture-handler (used)
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected ReactRootView createRootView() {
return new RNGestureHandlerEnabledRootView(MainActivity.this);
}
};
}
}

View File

@ -1,74 +0,0 @@
package com.advanced;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
}
/**
* Loads Flipper in React Native templates.
*
* @param context
*/
private static void initializeFlipper(Context context) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,3 +0,0 @@
<resources>
<string name="app_name">RNCamera</string>
</resources>

View File

@ -1,10 +0,0 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:textColor">#000000</item>
<item name="android:editTextBackground">@android:color/transparent</item>
</style>
</resources>

View File

@ -1,38 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 16
compileSdkVersion = 28
targetSdkVersion = 28
}
repositories {
google()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:3.4.2")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}

View File

@ -1,21 +0,0 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useAndroidX=true
android.enableJetifier=true

View File

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1,188 +0,0 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View File

@ -1,100 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -1,3 +0,0 @@
rootProject.name = 'advanced'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

View File

@ -1,4 +0,0 @@
{
"name": "advanced",
"displayName": "RNCamera"
}

View File

@ -1,3 +0,0 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
};

View File

@ -1,6 +0,0 @@
import 'react-native-gesture-handler'; // required for correct initialization of this library
import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);

View File

@ -1,40 +0,0 @@
platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target 'advanced' do
# Pods for advanced
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/'
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
use_native_modules!
end

Some files were not shown because too many files have changed in this diff Show More