Compare commits
1 Commits
master
...
fix-exampl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1c9bd01d1 |
@ -24,4 +24,8 @@ jobs:
|
||||
name: Yarn Install
|
||||
command: |
|
||||
yarn install --frozen-lockfile --no-progress --non-interactive --cache-folder ~/.cache/yarn
|
||||
- run:
|
||||
name: Flow
|
||||
command: |
|
||||
yarn flow
|
||||
- save_cache: *save-cache-yarn
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
typings
|
||||
node_modules
|
||||
example/android-bundle.js
|
||||
example/ios-bundle.js
|
||||
|
||||
# generated by bob
|
||||
lib
|
||||
52
.eslintrc.js
52
.eslintrc.js
@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
const typescriptEslintRecommended = require('@typescript-eslint/eslint-plugin/dist/configs/recommended.json');
|
||||
const typescriptEslintPrettier = require('eslint-config-prettier/@typescript-eslint');
|
||||
|
||||
module.exports = {
|
||||
extends: ['@react-native-community'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
// Apply the recommended Typescript defaults and the prettier overrides to all Typescript files
|
||||
rules: Object.assign(
|
||||
typescriptEslintRecommended.rules,
|
||||
typescriptEslintPrettier.rules,
|
||||
{
|
||||
'@typescript-eslint/explicit-member-accessibility': 'off',
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
files: ['example/**/*.ts', 'example/**/*.tsx'],
|
||||
rules: {
|
||||
// Turn off rules which are useless and annoying for the example files files
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'react-native/no-inline-styles': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/__tests__/**/*.ts', '**/*.spec.ts'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
// Turn off rules which are useless and annoying for unit test files
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
rules: {
|
||||
'no-dupe-class-members': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
69
.flowconfig
Normal file
69
.flowconfig
Normal file
@ -0,0 +1,69 @@
|
||||
[ignore]
|
||||
; We fork some components by platform
|
||||
.*/*[.]android.js
|
||||
|
||||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; Ignore duplicate module providers
|
||||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; Ignore metro
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
[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.system=haste
|
||||
module.system.haste.use_name_reducers=true
|
||||
# get basename
|
||||
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1'
|
||||
# strip .js or .js.flow suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1'
|
||||
# strip .ios suffix
|
||||
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
|
||||
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
|
||||
module.system.haste.paths.blacklist=.*/__tests__/.*
|
||||
module.system.haste.paths.blacklist=.*/__mocks__/.*
|
||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
|
||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
module.file_ext=.native.js
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[version]
|
||||
^0.82.0
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +0,0 @@
|
||||
*.pbxproj -text
|
||||
41
.github/stale.yml
vendored
41
.github/stale.yml
vendored
@ -1,41 +0,0 @@
|
||||
# Configuration for probot-stale based on: https://github.com/facebook/react-native/blob/master/.github/stale.yml
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 60
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
daysUntilClose: 7
|
||||
|
||||
# Issues or Pull Requests.
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
- discussion
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions. You may also mark this issue as a "discussion" and I
|
||||
will leave this open.
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
closeComment: >
|
||||
Closing this issue after a prolonged period of inactivity. Fell free to reopen
|
||||
this issue, if this still affecting you.
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
69
.gitignore
vendored
69
.gitignore
vendored
@ -1,17 +1,15 @@
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
### Android Studio ###
|
||||
.idea/
|
||||
.gradle/
|
||||
local.properties
|
||||
|
||||
# node.js
|
||||
#
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
### Xcode ###
|
||||
|
||||
|
||||
# Xcode
|
||||
#
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
@ -20,42 +18,23 @@ build/
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
xcuserdata/
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
*.xccheckout
|
||||
*.xcscmblueprint
|
||||
|
||||
# CocoaPods
|
||||
/ios/Pods/
|
||||
### /Xcode ###
|
||||
|
||||
# Android/IntelliJ
|
||||
#
|
||||
build/
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
### OS X
|
||||
.DS_Store
|
||||
|
||||
### Node
|
||||
node_modules
|
||||
*.log
|
||||
|
||||
## Android iml
|
||||
*.iml
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
debug.keystore
|
||||
|
||||
# Editor config
|
||||
.vscode
|
||||
|
||||
# Outputs
|
||||
coverage
|
||||
|
||||
.tmp
|
||||
example/android-bundle.js
|
||||
example/ios-bundle.js
|
||||
index.android.bundle
|
||||
index.ios.bundle
|
||||
|
||||
# generated by bob
|
||||
lib/
|
||||
.vscode/
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
{
|
||||
"requirePragma": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": false,
|
||||
"jsxBracketSameLine": true
|
||||
"singleQuote": true,
|
||||
"arrowParens": "always"
|
||||
}
|
||||
|
||||
@ -1,3 +1 @@
|
||||
{
|
||||
"ignore_dirs": [".git", "node_modules", "example"]
|
||||
}
|
||||
{}
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
# Global owners
|
||||
* @johan-dutoit @janicduplessis
|
||||
@ -1,49 +0,0 @@
|
||||
# Contributing to React Native ImagePicker
|
||||
|
||||
## Development Process
|
||||
All work on React Native ImagePicker happens directly on GitHub. Contributors send pull requests which go through a review process.
|
||||
|
||||
> **Working on your first pull request?** You can learn how from this *free* series: [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
|
||||
|
||||
1. Fork the repo and create your branch from `master` (a guide on [how to fork a repository](https://help.github.com/articles/fork-a-repo/)).
|
||||
2. Run `yarn` or `npm install` to install all required dependencies.
|
||||
3. Now you are ready to make your changes!
|
||||
|
||||
## Tests & Verifications
|
||||
Currently we use `TypeScript` for typechecking, `eslint` with `prettier` for linting and formatting the code, and `jest` for unit testing.
|
||||
|
||||
* `yarn test`: Run all tests and validations.
|
||||
* `yarn validate:android`: Run Spotless style checker on the Java code.
|
||||
* `yarn validate:eslint`: Run `eslint`.
|
||||
* `yarn validate:eslint --fix`: Run `eslint` and automatically fix issues. This is useful for correcting code formatting.
|
||||
* `yarn validate:typescript`: Run `typescript` typechecking.
|
||||
* `yarn test:jest`: Run unit tests with `jest`.
|
||||
|
||||
## Sending a pull request
|
||||
When you're sending a pull request:
|
||||
|
||||
* Prefer small pull requests focused on one change.
|
||||
* Verify that all tests and validations are passing.
|
||||
* Follow the pull request template when opening a pull request.
|
||||
|
||||
## Commit message convention
|
||||
We prefix our commit messages with one of the following to signify the kind of change:
|
||||
|
||||
* **build**: Changes that affect the build system or external dependencies.
|
||||
* **ci**, **chore**: Changes to our CI configuration files and scripts.
|
||||
* **docs**: Documentation only changes.
|
||||
* **feat**: A new feature.
|
||||
* **fix**: A bug fix.
|
||||
* **perf**: A code change that improves performance.
|
||||
* **refactor**: A code change that neither fixes a bug nor adds a feature.
|
||||
* **style**: Changes that do not affect the meaning of the code.
|
||||
* **test**: Adding missing tests or correcting existing tests.
|
||||
|
||||
## Release process
|
||||
We use [Semantic Release](http://semantic-release.org) to automatically release new versions of the library when changes are merged into master. Using the commit message convention described above, it will detect if we need to release a patch, minor, or major version of the library.
|
||||
|
||||
## Reporting issues
|
||||
You can report issues on our [bug tracker](https://github.com/react-native-community/react-native-ImagePicker/issues). Please search for existing issues and follow the issue template when opening an issue.
|
||||
|
||||
## License
|
||||
By contributing to React Native ImagePicker, you agree that your contributions will be licensed under the **MIT** license.
|
||||
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-present, Facebook, Inc.
|
||||
Copyright (c) 2015 Marc Shilling
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
||||
21
README.md
21
README.md
@ -8,11 +8,6 @@
|
||||
|
||||
A React Native module that allows you to use native UI to select a photo/video from the device library or directly from the camera, like so:
|
||||
|
||||
🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
|
||||
|
||||
🚧🚧🚧🚧[Help & Input Wanted](https://github.com/react-native-community/react-native-image-picker/issues/1358) 🚧🚧🚧🚧
|
||||
|
||||
🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
|
||||
| iOS | Android |
|
||||
| --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| <img title="iOS" src="https://github.com/react-community/react-native-image-picker/blob/master/images/ios-image.png"> | <img title="Android" src="https://github.com/react-community/react-native-image-picker/blob/master/images/android-image.png"> |
|
||||
@ -21,26 +16,10 @@ A React Native module that allows you to use native UI to select a photo/video f
|
||||
|
||||
This library started as a basic bridge of the native iOS image picker, and I want to keep it that way. As such, functionality beyond what the native `UIImagePickerController` supports will not be supported here. **Multiple image selection, more control over the crop tool, and landscape support** are things missing from the native iOS functionality - **not issues with my library**. If you need these things, [react-native-image-crop-picker](https://github.com/ivpusic/react-native-image-crop-picker) might be a better choice for you.
|
||||
|
||||
## React Native Compatibility
|
||||
To use this library you need to ensure you match up with the correct version of React Native you are using.
|
||||
|
||||
p.s. React Native introduced AndroidX support in 0.60, which is a **breaking change** for most libraries (incl. this one) using native Android functionality.
|
||||
|
||||
| `@react-native-community/imagepicker` version | Required React Native Version |
|
||||
| ----------------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| `1.x.x` | `>= 0.60` or `>= 0.59` if using [Jetifier](https://github.com/mikehardy/jetifier) |
|
||||
| `0.x.x` | `<= 0.59` |
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
```
|
||||
yarn add react-native-image-picker
|
||||
|
||||
# RN >= 0.60
|
||||
npx pod-install
|
||||
|
||||
# RN < 0.60
|
||||
react-native link react-native-image-picker
|
||||
```
|
||||
|
||||
|
||||
@ -1,65 +1,63 @@
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
def computeVersionName() {
|
||||
// dynamically retrieve version from package.json
|
||||
def slurper = new JsonSlurper()
|
||||
def json = slurper.parse(file('../package.json'), "utf-8")
|
||||
return json.version
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.4.1'
|
||||
classpath 'com.android.tools.build:gradle:2.2.+'
|
||||
}
|
||||
}
|
||||
|
||||
def getExtOrDefault(name) {
|
||||
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeImagePicker_' + name]
|
||||
}
|
||||
|
||||
def getExtOrIntegerDefault(name) {
|
||||
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['ReactNativeImagePicker_' + name]).toInteger()
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
def DEFAULT_COMPILE_SDK_VERSION = 25
|
||||
def DEFAULT_BUILD_TOOLS_VERSION = "25.0.2"
|
||||
def DEFAULT_TARGET_SDK_VERSION = 25
|
||||
|
||||
android {
|
||||
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
|
||||
buildToolsVersion getExtOrDefault('buildToolsVersion')
|
||||
compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION
|
||||
buildToolsVersion rootProject.hasProperty('buildToolsVersion') ? rootProject.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion getExtOrIntegerDefault('minSdkVersion')
|
||||
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
|
||||
minSdkVersion 16
|
||||
targetSdkVersion rootProject.hasProperty('targetSdkVersion') ? rootProject.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION
|
||||
versionCode 1
|
||||
versionName computeVersionName()
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "$projectDir/../node_modules/react-native/android"
|
||||
url "$projectDir/../Example/node_modules/react-native/android"
|
||||
}
|
||||
maven {
|
||||
url "$projectDir/../node_modules/jsc-android/dist"
|
||||
url "$projectDir/../../react-native/android"
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api "com.facebook.react:react-native:+" // From node_modules
|
||||
compile "com.facebook.react:react-native:+" // From node_modules
|
||||
|
||||
testCompile "junit:junit:4.10"
|
||||
testCompile "org.assertj:assertj-core:1.7.0"
|
||||
testCompile "org.robolectric:robolectric:3.3.2"
|
||||
|
||||
testImplementation('org.robolectric:robolectric:4.3.1') {
|
||||
// https://github.com/robolectric/robolectric/issues/5245
|
||||
exclude group: 'com.google.auto.service', module: 'auto-service'
|
||||
}
|
||||
|
||||
testImplementation "org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}"
|
||||
testImplementation "org.powermock:powermock-module-junit4:${POWERMOCK_VERSION}"
|
||||
testImplementation "org.powermock:powermock-module-junit4-rule:${POWERMOCK_VERSION}"
|
||||
testImplementation "org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}"
|
||||
testCompile "org.easytesting:fest-assert-core:${FEST_ASSERT_CORE_VERSION}"
|
||||
testCompile "org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}"
|
||||
testCompile "org.powermock:powermock-module-junit4-rule:${POWERMOCK_VERSION}"
|
||||
testCompile "org.powermock:powermock-classloading-xstream:${POWERMOCK_VERSION}"
|
||||
testCompile "org.mockito:mockito-core:${MOCKITO_CORE_VERSION}"
|
||||
}
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
POWERMOCK_VERSION=1.6.6
|
||||
|
||||
ReactNativeImagePicker_compileSdkVersion=28
|
||||
ReactNativeImagePicker_buildToolsVersion=28.0.3
|
||||
ReactNativeImagePicker_targetSdkVersion=27
|
||||
ReactNativeImagePicker_minSdkVersion=16
|
||||
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
MOCKITO_CORE_VERSION=1.+
|
||||
POWERMOCK_VERSION=1.6.2
|
||||
FEST_ASSERT_CORE_VERSION=2.0M10
|
||||
@ -1,6 +1,6 @@
|
||||
#Mon Jun 24 15:04:47 BST 2019
|
||||
#Mon Dec 28 10:00:20 PST 2015
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.imagepicker;
|
||||
|
||||
public class FileProvider extends androidx.core.content.FileProvider {
|
||||
public class FileProvider extends android.support.v4.content.FileProvider {
|
||||
}
|
||||
|
||||
@ -12,11 +12,11 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.Settings;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StyleRes;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Patterns;
|
||||
@ -30,12 +30,10 @@ import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.imagepicker.media.ImageConfig;
|
||||
import com.imagepicker.permissions.PermissionUtils;
|
||||
import com.imagepicker.permissions.OnImagePickerPermissionsCallback;
|
||||
import com.imagepicker.utils.MediaUtils.ReadExifResult;
|
||||
import com.imagepicker.utils.ReadableMapUtils;
|
||||
import com.imagepicker.utils.RealPathUtil;
|
||||
import com.imagepicker.utils.UI;
|
||||
|
||||
@ -57,13 +55,9 @@ import static com.imagepicker.utils.MediaUtils.*;
|
||||
import static com.imagepicker.utils.MediaUtils.createNewFile;
|
||||
import static com.imagepicker.utils.MediaUtils.getResizedImage;
|
||||
|
||||
@ReactModule(name = ImagePickerModule.NAME)
|
||||
public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
implements ActivityEventListener
|
||||
{
|
||||
public static final String NAME = "ImagePickerManager";
|
||||
|
||||
public static final int DEFAULT_EXPLAINING_PERMISSION_DIALIOG_THEME = R.style.DefaultExplainingPermissionsTheme;
|
||||
|
||||
public static final int REQUEST_LAUNCH_IMAGE_CAPTURE = 13001;
|
||||
public static final int REQUEST_LAUNCH_IMAGE_LIBRARY = 13002;
|
||||
@ -76,13 +70,10 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
private final int dialogThemeId;
|
||||
|
||||
protected Callback callback;
|
||||
private Callback permissionRequestCallback;
|
||||
|
||||
private ReadableMap options;
|
||||
protected Uri cameraCaptureURI;
|
||||
private Boolean noData = false;
|
||||
private Boolean pickVideo = false;
|
||||
private Boolean pickBoth = false;
|
||||
private ImageConfig imageConfig = new ImageConfig(null, null, 0, 0, 100, 0, false);
|
||||
|
||||
@Deprecated
|
||||
@ -112,18 +103,18 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
|
||||
if (!permissionsGranted)
|
||||
{
|
||||
responseHelper.invokeError(permissionRequestCallback, "Permissions weren't granted");
|
||||
responseHelper.invokeError(callback, "Permissions weren't granted");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (requestCode)
|
||||
{
|
||||
case REQUEST_PERMISSIONS_FOR_CAMERA:
|
||||
launchCamera(options, permissionRequestCallback);
|
||||
launchCamera(options, callback);
|
||||
break;
|
||||
|
||||
case REQUEST_PERMISSIONS_FOR_LIBRARY:
|
||||
launchImageLibrary(options, permissionRequestCallback);
|
||||
launchImageLibrary(options, callback);
|
||||
break;
|
||||
|
||||
}
|
||||
@ -131,11 +122,6 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
}
|
||||
};
|
||||
|
||||
public ImagePickerModule(ReactApplicationContext reactContext)
|
||||
{
|
||||
this(reactContext, DEFAULT_EXPLAINING_PERMISSION_DIALIOG_THEME);
|
||||
}
|
||||
|
||||
public ImagePickerModule(ReactApplicationContext reactContext,
|
||||
@StyleRes final int dialogThemeId)
|
||||
{
|
||||
@ -148,7 +134,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
return "ImagePickerManager";
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
@ -228,8 +214,6 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
@ReactMethod
|
||||
public void launchCamera(final ReadableMap options, final Callback callback)
|
||||
{
|
||||
permissionRequestCallback = callback;
|
||||
|
||||
if (!isCameraAvailable())
|
||||
{
|
||||
responseHelper.invokeError(callback, "Camera not available");
|
||||
@ -324,8 +308,6 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
@ReactMethod
|
||||
public void launchImageLibrary(final ReadableMap options, final Callback callback)
|
||||
{
|
||||
permissionRequestCallback = callback;
|
||||
|
||||
final Activity currentActivity = getCurrentActivity();
|
||||
if (currentActivity == null) {
|
||||
responseHelper.invokeError(callback, "can't find current Activity");
|
||||
@ -355,11 +337,6 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
requestCode = REQUEST_LAUNCH_IMAGE_LIBRARY;
|
||||
libraryIntent = new Intent(Intent.ACTION_PICK,
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
|
||||
if (pickBoth)
|
||||
{
|
||||
libraryIntent.setType("image/* video/*");
|
||||
}
|
||||
}
|
||||
|
||||
if (libraryIntent.resolveActivity(reactContext.getPackageManager()) == null)
|
||||
@ -370,13 +347,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
|
||||
try
|
||||
{
|
||||
String chooseWhichLibraryTitle = null;
|
||||
if (ReadableMapUtils.hasAndNotEmptyString(options, "chooseWhichLibraryTitle"))
|
||||
{
|
||||
chooseWhichLibraryTitle = options.getString("chooseWhichLibraryTitle");
|
||||
}
|
||||
|
||||
currentActivity.startActivityForResult(Intent.createChooser(libraryIntent, chooseWhichLibraryTitle), requestCode);
|
||||
currentActivity.startActivityForResult(libraryIntent, requestCode);
|
||||
}
|
||||
catch (ActivityNotFoundException e)
|
||||
{
|
||||
@ -576,18 +547,10 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
final int cameraPermission = ActivityCompat
|
||||
.checkSelfPermission(activity, Manifest.permission.CAMERA);
|
||||
|
||||
boolean permissionsGranted = false;
|
||||
final boolean permissionsGrated = writePermission == PackageManager.PERMISSION_GRANTED &&
|
||||
cameraPermission == PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
switch (requestCode) {
|
||||
case REQUEST_PERMISSIONS_FOR_LIBRARY:
|
||||
permissionsGranted = writePermission == PackageManager.PERMISSION_GRANTED;
|
||||
break;
|
||||
case REQUEST_PERMISSIONS_FOR_CAMERA:
|
||||
permissionsGranted = cameraPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!permissionsGranted)
|
||||
if (!permissionsGrated)
|
||||
{
|
||||
final Boolean dontAskAgain = ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) && ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA);
|
||||
|
||||
@ -635,19 +598,7 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] PERMISSIONS;
|
||||
switch (requestCode) {
|
||||
case REQUEST_PERMISSIONS_FOR_LIBRARY:
|
||||
PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||
break;
|
||||
case REQUEST_PERMISSIONS_FOR_CAMERA:
|
||||
PERMISSIONS = new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||
break;
|
||||
default:
|
||||
PERMISSIONS = new String[]{};
|
||||
break;
|
||||
}
|
||||
|
||||
String[] PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
|
||||
if (activity instanceof ReactActivity)
|
||||
{
|
||||
((ReactActivity) activity).requestPermissions(PERMISSIONS, requestCode, listener);
|
||||
@ -742,26 +693,20 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
private void putExtraFileInfo(@NonNull final String path,
|
||||
@NonNull final ResponseHelper responseHelper)
|
||||
{
|
||||
// size && filename
|
||||
try {
|
||||
// size && filename
|
||||
File f = new File(path);
|
||||
responseHelper.putDouble("fileSize", f.length());
|
||||
responseHelper.putString("fileName", f.getName());
|
||||
// type
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(path);
|
||||
String fileName = f.getName();
|
||||
if (extension != "") {
|
||||
responseHelper.putString("type", MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension));
|
||||
} else {
|
||||
int i = fileName.lastIndexOf('.');
|
||||
if (i > 0) {
|
||||
extension = fileName.substring(i+1);
|
||||
responseHelper.putString("type", MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// type
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(path);
|
||||
if (extension != null) {
|
||||
responseHelper.putString("type", MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension));
|
||||
}
|
||||
}
|
||||
|
||||
private void parseOptions(final ReadableMap options) {
|
||||
@ -771,10 +716,6 @@ public class ImagePickerModule extends ReactContextBaseJavaModule
|
||||
}
|
||||
imageConfig = imageConfig.updateFromOptions(options);
|
||||
pickVideo = false;
|
||||
pickBoth = false;
|
||||
if (options.hasKey("mediaType") && options.getString("mediaType").equals("mixed")) {
|
||||
pickBoth = true;
|
||||
}
|
||||
if (options.hasKey("mediaType") && options.getString("mediaType").equals("video")) {
|
||||
pickVideo = true;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.imagepicker;
|
||||
|
||||
import androidx.annotation.StyleRes;
|
||||
import android.support.annotation.StyleRes;
|
||||
|
||||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.bridge.JavaScriptModule;
|
||||
@ -13,11 +13,12 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ImagePickerPackage implements ReactPackage {
|
||||
public static final int DEFAULT_EXPLAINING_PERMISSION_DIALIOG_THEME = R.style.DefaultExplainingPermissionsTheme;
|
||||
private @StyleRes final int dialogThemeId;
|
||||
|
||||
public ImagePickerPackage()
|
||||
{
|
||||
this.dialogThemeId = ImagePickerModule.DEFAULT_EXPLAINING_PERMISSION_DIALIOG_THEME;
|
||||
this.dialogThemeId = DEFAULT_EXPLAINING_PERMISSION_DIALIOG_THEME;
|
||||
}
|
||||
|
||||
public ImagePickerPackage(@StyleRes final int dialogThemeId)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.imagepicker;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
@ -73,9 +73,6 @@ public class ResponseHelper
|
||||
|
||||
public void invokeResponse(@NonNull final Callback callback)
|
||||
{
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
callback.invoke(response);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.imagepicker.media;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
@ -78,13 +78,11 @@ public class ImageConfig
|
||||
|
||||
public @NonNull ImageConfig withOriginalFile(@Nullable final File original)
|
||||
{
|
||||
if (original != null) {
|
||||
//if it is a GIF file, always set quality to 100 to prevent compression
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(original.getAbsolutePath());
|
||||
int quality = this.quality;
|
||||
if(extension.contains("gif")){
|
||||
quality = 100;
|
||||
}
|
||||
//if it is a GIF file, always set quality to 100 to prevent compression
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(original.getAbsolutePath());
|
||||
int quality = this.quality;
|
||||
if(extension.contains("gif")){
|
||||
quality = 100;
|
||||
}
|
||||
|
||||
return new ImageConfig(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.imagepicker.permissions;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.support.annotation.NonNull;
|
||||
import com.facebook.react.modules.core.PermissionListener;
|
||||
|
||||
/**
|
||||
|
||||
@ -2,15 +2,17 @@ package com.imagepicker.permissions;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableNativeMap;
|
||||
import com.imagepicker.ImagePickerModule;
|
||||
import com.imagepicker.R;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Created by rusfearuth on 03.03.17.
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.imagepicker.permissions;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by rusfearuth on 03.03.17.
|
||||
*/
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.imagepicker.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
@ -8,8 +8,8 @@ import android.media.ExifInterface;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
@ -20,6 +20,7 @@ import com.imagepicker.media.ImageConfig;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
@ -45,32 +46,11 @@ public class MediaUtils
|
||||
.append(".jpg")
|
||||
.toString();
|
||||
|
||||
// defaults to Public Pictures Directory
|
||||
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
||||
|
||||
if (ReadableMapUtils.hasAndNotNullReadableMap(options, "storageOptions"))
|
||||
{
|
||||
final ReadableMap storageOptions = options.getMap("storageOptions");
|
||||
|
||||
if (storageOptions.hasKey("privateDirectory"))
|
||||
{
|
||||
boolean saveToPrivateDirectory = storageOptions.getBoolean("privateDirectory");
|
||||
if (saveToPrivateDirectory)
|
||||
{
|
||||
// if privateDirectory is set then save to app's private files directory
|
||||
path = reactContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
}
|
||||
}
|
||||
|
||||
if (ReadableMapUtils.hasAndNotEmptyString(storageOptions, "path"))
|
||||
{
|
||||
path = new File(path, storageOptions.getString("path"));
|
||||
}
|
||||
}
|
||||
else if (forceLocal)
|
||||
{
|
||||
path = reactContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
}
|
||||
final File path = ReadableMapUtils.hasAndNotNullReadableMap(options, "storageOptions")
|
||||
&& ReadableMapUtils.hasAndNotEmptyString(options.getMap("storageOptions"), "path")
|
||||
? new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), options.getMap("storageOptions").getString("path"))
|
||||
: (!forceLocal ? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
|
||||
: reactContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES));
|
||||
|
||||
File result = new File(path, filename);
|
||||
|
||||
@ -122,7 +102,7 @@ public class MediaUtils
|
||||
|
||||
if (photo == null)
|
||||
{
|
||||
return imageConfig;
|
||||
return null;
|
||||
}
|
||||
|
||||
ImageConfig result = imageConfig;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.imagepicker.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.imagepicker.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
@ -9,9 +10,9 @@ import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.content.ContentUris;
|
||||
import android.os.Environment;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.FileProvider;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.FileProvider;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
@ -2,10 +2,10 @@ package com.imagepicker.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<files-path name="shared" path="."/>
|
||||
<external-path name="shared" path="."/>
|
||||
<external-files-path name="shared" path="."/>
|
||||
<root-path name="root" path="."/>
|
||||
</paths>
|
||||
<external-path name="app_images" path="."/>
|
||||
</paths>
|
||||
@ -45,7 +45,8 @@ import static org.powermock.api.mockito.PowerMockito.when;
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@SuppressStaticInitializationFor("com.facebook.react.common.build.ReactBuildConfig")
|
||||
@PrepareForTest({Arguments.class})
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*", "jdk.internal.reflect.*"})
|
||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
|
||||
@Config(manifest = Config.NONE)
|
||||
public class ImagePickerModuleTest
|
||||
{
|
||||
private static final int DEFAULT_THEME = R.style.DefaultExplainingPermissionsTheme;
|
||||
@ -110,4 +111,4 @@ public class ImagePickerModuleTest
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,16 @@
|
||||
package com.imagepicker.testing;
|
||||
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StyleRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StyleRes;
|
||||
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.imagepicker.ImagePickerModule;
|
||||
import com.imagepicker.ResponseHelper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Created by rusfearuth on 10.04.17.
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
};
|
||||
@ -2,11 +2,6 @@
|
||||
|
||||
```
|
||||
yarn add react-native-image-picker
|
||||
|
||||
# RN >= 0.60
|
||||
cd ios && pod install
|
||||
|
||||
# RN < 0.60
|
||||
react-native link react-native-image-picker
|
||||
```
|
||||
|
||||
@ -33,7 +28,7 @@ Add the `NSPhotoLibraryUsageDescription`, `NSCameraUsageDescription`, `NSPhotoLi
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>$(PRODUCT_NAME) would like to save photos to your photo gallery</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>$(PRODUCT_NAME) would like to use your microphone (for videos)</string>
|
||||
<string>$(PRODUCT_NAME) would like to your microphone (for videos)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
@ -98,7 +93,7 @@ Customization settings of dialog `android/app/res/values/themes.xml` (`android/a
|
||||
|
||||
1. In the XCode's "Project navigator", right click on your project's Libraries folder ➜ `Add Files to <...>`.
|
||||
1. Go to `node_modules` ➜ `react-native-image-picker` ➜ `ios` ➜ select `RNImagePicker.xcodeproj`.
|
||||
1. Add `libRNImagePicker.a` to `Build Phases -> Link Binary With Libraries`.
|
||||
1. Add `RNImagePicker.a` to `Build Phases -> Link Binary With Libraries`.
|
||||
1. Refer to [Post-install Steps](Install.md#post-install-steps).
|
||||
1. Compile and have fun.
|
||||
|
||||
@ -131,11 +126,11 @@ Customization settings of dialog `android/app/res/values/themes.xml` (`android/a
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||
```
|
||||
|
||||
4. Add the implementation line to the dependencies in `android/app/build.gradle`:
|
||||
4. Add the compile line to the dependencies in `android/app/build.gradle`:
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
implementation project(':react-native-image-picker')
|
||||
compile project(':react-native-image-picker')
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -44,33 +44,30 @@ The `callback` will be called with a response object, refer to [The Response Obj
|
||||
|
||||
| option | iOS | Android | Info |
|
||||
| ----------------------------- | --- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| title | OK | OK | Specify `null` or empty string to remove the title |
|
||||
| cancelButtonTitle | OK | OK | Specify `null` or empty string to remove this button |
|
||||
| takePhotoButtonTitle | OK | OK | Specify `null` or empty string to remove this button |
|
||||
| chooseFromLibraryButtonTitle | OK | OK | Specify `null` or empty string to remove this button |
|
||||
| chooseWhichLibraryTitle | - | OK | Specify `null` or empty string to use default Android title. Is shown when user has multiple apps that can open library. |
|
||||
| customButtons | OK | OK | An array containing objects with the name and title of buttons |
|
||||
| tintColor | OK | - | Text color to use on buttons |
|
||||
| cameraType | OK | - | 'front' or 'back' |
|
||||
| mediaType | OK | OK | 'photo', 'video', or 'mixed' |
|
||||
| maxWidth | OK | OK | Photos only |
|
||||
| maxHeight | OK | OK | Photos only |
|
||||
| quality | OK | OK | 0 to 1, photos only |
|
||||
| videoQuality | OK | OK | 'low', 'medium', or 'high' on iOS, 'low' or 'high' on Android |
|
||||
| durationLimit | OK | OK | Max video recording time, in seconds |
|
||||
| rotation | - | OK | Photos only, 0 to 360 degrees of rotation |
|
||||
| allowsEditing | OK | - | bool - enables built-in iOS functionality to resize the image after selection |
|
||||
| noData | OK | OK | If true, disables the base64 `data` field from being generated (greatly improves performance on large photos) |
|
||||
| storageOptions | OK | OK | If this key is provided, the image will be saved in your app's `Documents` directory on iOS (rather than a temporary directory). On Android this key does not affect the image location (Android always defaults to the public `Pictures` directory) |
|
||||
| storageOptions.skipBackup | OK | - | If true, the photo will NOT be backed up to iCloud |
|
||||
| storageOptions.path | OK | OK | If set, will save the image at `Documents/[path]/` rather than the root `Documents` for iOS, and `Pictures/[path]/` on Android. |
|
||||
| storageOptions.cameraRoll | OK | OK | If true, the cropped photo will be saved to the iOS Camera Roll or Android DCIM folder. |
|
||||
| storageOptions.waitUntilSaved | OK | - | If true, will delay the response callback until after the photo/video was saved to the Camera Roll. If the photo or video was just taken, then the file name and timestamp fields are only provided in the response object when this AND `cameraRoll` are both true. |
|
||||
| storageOptions.privateDirectory | - | OK | If true, the photo will be saved to the apps private files directory (Android/data/your_package/files/Pictures) |
|
||||
| permissionDenied.title | - | OK | Title of explaining permissions dialog. By default `Permission denied`. |
|
||||
| permissionDenied.text | - | OK | Message of explaining permissions dialog. By default `To be able to take pictures with your camera and choose images from your library.`. |
|
||||
| permissionDenied.reTryTitle | - | OK | Title of re-try button. By default `re-try` |
|
||||
| permissionDenied.okTitle | - | OK | Title of ok button. By default `I'm sure` |
|
||||
| title | OK | OK | Specify `null` or empty string to remove the title |
|
||||
| cancelButtonTitle | OK | OK | Specify `null` or empty string to remove this button |
|
||||
| takePhotoButtonTitle | OK | OK | Specify `null` or empty string to remove this button |
|
||||
| chooseFromLibraryButtonTitle | OK | OK | Specify `null` or empty string to remove this button |
|
||||
| customButtons | OK | OK | An array containing objects with the name and title of buttons |
|
||||
| cameraType | OK | - | 'front' or 'back' |
|
||||
| mediaType | OK | OK | 'photo', 'video', or 'mixed' on iOS, 'photo' or 'video' on Android |
|
||||
| maxWidth | OK | OK | Photos only |
|
||||
| maxHeight | OK | OK | Photos only |
|
||||
| quality | OK | OK | 0 to 1, photos only |
|
||||
| videoQuality | OK | OK | 'low', 'medium', or 'high' on iOS, 'low' or 'high' on Android |
|
||||
| durationLimit | OK | OK | Max video recording time, in seconds |
|
||||
| rotation | - | OK | Photos only, 0 to 360 degrees of rotation |
|
||||
| allowsEditing | OK | - | bool - enables built-in iOS functionality to resize the image after selection |
|
||||
| noData | OK | OK | If true, disables the base64 `data` field from being generated (greatly improves performance on large photos) |
|
||||
| storageOptions | OK | OK | If this key is provided, the image will be saved in your app's `Documents` directory on iOS, or your app's `Pictures` directory on Android (rather than a temporary directory) |
|
||||
| storageOptions.skipBackup | OK | - | If true, the photo will NOT be backed up to iCloud |
|
||||
| storageOptions.path | OK | OK | If set, will save the image at `Documents/[path]/` rather than the root `Documents` for iOS, and `Pictures/[path]/` on Android. |
|
||||
| storageOptions.cameraRoll | OK | OK | If true, the cropped photo will be saved to the iOS Camera Roll or Android DCIM folder. |
|
||||
| storageOptions.waitUntilSaved | OK | - | If true, will delay the response callback until after the photo/video was saved to the Camera Roll. If the photo or video was just taken, then the file name and timestamp fields are only provided in the response object when this AND `cameraRoll` are both true. |
|
||||
| permissionDenied.title | - | OK | Title of explaining permissions dialog. By default `Permission denied`. |
|
||||
| permissionDenied.text | - | OK | Message of explaining permissions dialog. By default `To be able to take pictures with your camera and choose images from your library.`. |
|
||||
| permissionDenied.reTryTitle | - | OK | Title of re-try button. By default `re-try` |
|
||||
| permissionDenied.okTitle | - | OK | Title of ok button. By default `I'm sure` |
|
||||
|
||||
## The Response Object
|
||||
|
||||
@ -86,7 +83,7 @@ The `callback` will be called with a response object, refer to [The Response Obj
|
||||
| width | OK | OK | Image dimensions (photos only) |
|
||||
| height | OK | OK | Image dimensions (photos only) |
|
||||
| fileSize | OK | OK | The file size (photos only) |
|
||||
| type | OK | OK | The file type (photos only) |
|
||||
| type | - | OK | The file type (photos only) |
|
||||
| fileName | OK (photos and videos) | OK (photos) | The file name, if available
|
||||
| path | - | OK | The file path |
|
||||
| latitude | OK | OK | Latitude metadata, if available |
|
||||
|
||||
@ -1 +1 @@
|
||||
{}
|
||||
{}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
AppRegistry,
|
||||
Image,
|
||||
PixelRatio,
|
||||
StyleSheet,
|
||||
@ -34,7 +35,7 @@ export default class App extends React.Component {
|
||||
},
|
||||
};
|
||||
|
||||
ImagePicker.showImagePicker(options, response => {
|
||||
ImagePicker.showImagePicker(options, (response) => {
|
||||
console.log('Response = ', response);
|
||||
|
||||
if (response.didCancel) {
|
||||
@ -44,7 +45,7 @@ export default class App extends React.Component {
|
||||
} else if (response.customButton) {
|
||||
console.log('User tapped custom button: ', response.customButton);
|
||||
} else {
|
||||
let source = {uri: response.uri};
|
||||
let source = { uri: response.uri };
|
||||
|
||||
// You can also display the image using data:
|
||||
// let source = { uri: 'data:image/jpeg;base64,' + response.data };
|
||||
@ -64,7 +65,7 @@ export default class App extends React.Component {
|
||||
videoQuality: 'medium',
|
||||
};
|
||||
|
||||
ImagePicker.showImagePicker(options, response => {
|
||||
ImagePicker.showImagePicker(options, (response) => {
|
||||
console.log('Response = ', response);
|
||||
|
||||
if (response.didCancel) {
|
||||
@ -86,7 +87,12 @@ export default class App extends React.Component {
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={this.selectPhotoTapped.bind(this)}>
|
||||
<View
|
||||
style={[styles.avatar, styles.avatarContainer, {marginBottom: 20}]}>
|
||||
style={[
|
||||
styles.avatar,
|
||||
styles.avatarContainer,
|
||||
{ marginBottom: 20 },
|
||||
]}
|
||||
>
|
||||
{this.state.avatarSource === null ? (
|
||||
<Text>Select a Photo</Text>
|
||||
) : (
|
||||
@ -102,7 +108,7 @@ export default class App extends React.Component {
|
||||
</TouchableOpacity>
|
||||
|
||||
{this.state.videoSource && (
|
||||
<Text style={{margin: 8, textAlign: 'center'}}>
|
||||
<Text style={{ margin: 8, textAlign: 'center' }}>
|
||||
{this.state.videoSource}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@ -16,4 +16,4 @@ Start the packager with:
|
||||
yarn start
|
||||
```
|
||||
|
||||
You will have to reinstall `react-native-image-picker` every time you do changes in the library: `rm -rf node_modules && yarn install` (from `./example` folder).
|
||||
You'll have to reinstall the dependencies each time you want to try a different version of react-native-image-picker.
|
||||
|
||||
@ -137,7 +137,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':react-native-image-picker')
|
||||
compile project(':react-native-image-picker')
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
|
||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Example</string>
|
||||
<string name="app_name">example</string>
|
||||
</resources>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
rootProject.name = 'Example'
|
||||
rootProject.name = 'example'
|
||||
include ':react-native-image-picker'
|
||||
project(':react-native-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-picker/android')
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/** @format */
|
||||
|
||||
import {AppRegistry} from 'react-native';
|
||||
import { AppRegistry } from 'react-native';
|
||||
import App from './App';
|
||||
import {name as appName} from './app.json';
|
||||
import { name as appName } from './app.json';
|
||||
|
||||
AppRegistry.registerComponent(appName, () => App);
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
|
||||
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
|
||||
00E356F31AD99517003FC87E /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ExampleTests.m */; };
|
||||
00E356F31AD99517003FC87E /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; };
|
||||
11D1A2F320CAFA9E000508D9 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
|
||||
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
|
||||
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
|
||||
@ -34,9 +34,9 @@
|
||||
2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; };
|
||||
2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; };
|
||||
2D16E6881FA4F8E400B85C8A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D16E6891FA4F8E400B85C8A /* libReact.a */; };
|
||||
2DCD954D1E0B4F2C00145EB5 /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ExampleTests.m */; };
|
||||
2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; };
|
||||
2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
|
||||
6ABE91CB479846A083DF7D5E /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C1EEBA50119241D39EA36627 /* libRNImagePicker.a */; };
|
||||
598CF0F9B4024A9691E77EB0 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F109B4AA08A74E2984C32E3F /* libRNImagePicker.a */; };
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
|
||||
ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -82,7 +82,7 @@
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
|
||||
remoteInfo = Example;
|
||||
remoteInfo = example;
|
||||
};
|
||||
139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
@ -105,9 +105,9 @@
|
||||
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
|
||||
remoteInfo = React;
|
||||
};
|
||||
1BAE1B2121BEEDA8006A28FB /* PBXContainerItemProxy */ = {
|
||||
1B73C9B821A87A36007D17CC /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5763CEC9783A4A4F83148F48 /* RNImagePicker.xcodeproj */;
|
||||
containerPortal = 3E14C3D2163E4C3082332CBF /* RNImagePicker.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 014A3B5C1C6CF33500B6D375;
|
||||
remoteInfo = RNImagePicker;
|
||||
@ -117,7 +117,7 @@
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
|
||||
remoteInfo = "Example-tvOS";
|
||||
remoteInfo = "example-tvOS";
|
||||
};
|
||||
2D16E6711FA4F8DC00B85C8A /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
@ -331,28 +331,28 @@
|
||||
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = "<group>"; };
|
||||
00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; };
|
||||
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = "<group>"; };
|
||||
00E356EE1AD99517003FC87E /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
00E356EE1AD99517003FC87E /* exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
00E356F21AD99517003FC87E /* ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleTests.m; sourceTree = "<group>"; };
|
||||
00E356F21AD99517003FC87E /* exampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleTests.m; sourceTree = "<group>"; };
|
||||
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Example/AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Example/AppDelegate.m; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = example/AppDelegate.m; sourceTree = "<group>"; };
|
||||
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Example/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Example/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Example/main.m; sourceTree = "<group>"; };
|
||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = "<group>"; };
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = "<group>"; };
|
||||
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
|
||||
2D02E47B1E0B4A5D006451C7 /* Example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2D02E4901E0B4A5D006451C7 /* Example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "example-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "example-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2D16E6891FA4F8E400B85C8A /* libReact.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libReact.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5763CEC9783A4A4F83148F48 /* RNImagePicker.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNImagePicker.xcodeproj; path = "../node_modules/react-native-image-picker/ios/RNImagePicker.xcodeproj"; sourceTree = "<group>"; };
|
||||
3E14C3D2163E4C3082332CBF /* RNImagePicker.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNImagePicker.xcodeproj; path = "../node_modules/react-native-image-picker/ios/RNImagePicker.xcodeproj"; sourceTree = "<group>"; };
|
||||
5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
|
||||
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
|
||||
ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = "<group>"; };
|
||||
C1EEBA50119241D39EA36627 /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = "<group>"; };
|
||||
F109B4AA08A74E2984C32E3F /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -380,7 +380,7 @@
|
||||
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
|
||||
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
|
||||
6ABE91CB479846A083DF7D5E /* libRNImagePicker.a in Frameworks */,
|
||||
598CF0F9B4024A9691E77EB0 /* libRNImagePicker.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -452,13 +452,13 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
00E356EF1AD99517003FC87E /* ExampleTests */ = {
|
||||
00E356EF1AD99517003FC87E /* exampleTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
00E356F21AD99517003FC87E /* ExampleTests.m */,
|
||||
00E356F21AD99517003FC87E /* exampleTests.m */,
|
||||
00E356F01AD99517003FC87E /* Supporting Files */,
|
||||
);
|
||||
path = ExampleTests;
|
||||
path = exampleTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
00E356F01AD99517003FC87E /* Supporting Files */ = {
|
||||
@ -489,7 +489,7 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13B07FAE1A68108700A75B9A /* Example */ = {
|
||||
13B07FAE1A68108700A75B9A /* example */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
|
||||
@ -500,7 +500,7 @@
|
||||
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
|
||||
13B07FB71A68108700A75B9A /* main.m */,
|
||||
);
|
||||
name = Example;
|
||||
name = example;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
146834001AC3E56700842450 /* Products */ = {
|
||||
@ -526,18 +526,18 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BAE1AF821BEEDA6006A28FB /* Recovered References */ = {
|
||||
1B69C68621A5B605001C5074 /* Recovered References */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C1EEBA50119241D39EA36627 /* libRNImagePicker.a */,
|
||||
F109B4AA08A74E2984C32E3F /* libRNImagePicker.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BAE1B1E21BEEDA8006A28FB /* Products */ = {
|
||||
1B73C9B521A87A36007D17CC /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BAE1B2221BEEDA8006A28FB /* libRNImagePicker.a */,
|
||||
1B73C9B921A87A36007D17CC /* libRNImagePicker.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@ -583,7 +583,7 @@
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
|
||||
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
|
||||
5763CEC9783A4A4F83148F48 /* RNImagePicker.xcodeproj */,
|
||||
3E14C3D2163E4C3082332CBF /* RNImagePicker.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@ -600,12 +600,12 @@
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07FAE1A68108700A75B9A /* Example */,
|
||||
13B07FAE1A68108700A75B9A /* example */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
00E356EF1AD99517003FC87E /* ExampleTests */,
|
||||
00E356EF1AD99517003FC87E /* exampleTests */,
|
||||
83CBBA001A601CBA00E9B192 /* Products */,
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */,
|
||||
1BAE1AF821BEEDA6006A28FB /* Recovered References */,
|
||||
1B69C68621A5B605001C5074 /* Recovered References */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
@ -615,10 +615,10 @@
|
||||
83CBBA001A601CBA00E9B192 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13B07F961A680F5B00A75B9A /* Example.app */,
|
||||
00E356EE1AD99517003FC87E /* ExampleTests.xctest */,
|
||||
2D02E47B1E0B4A5D006451C7 /* Example-tvOS.app */,
|
||||
2D02E4901E0B4A5D006451C7 /* Example-tvOSTests.xctest */,
|
||||
13B07F961A680F5B00A75B9A /* example.app */,
|
||||
00E356EE1AD99517003FC87E /* exampleTests.xctest */,
|
||||
2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */,
|
||||
2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@ -635,9 +635,9 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
00E356ED1AD99517003FC87E /* ExampleTests */ = {
|
||||
00E356ED1AD99517003FC87E /* exampleTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ExampleTests" */;
|
||||
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */;
|
||||
buildPhases = (
|
||||
00E356EA1AD99517003FC87E /* Sources */,
|
||||
00E356EB1AD99517003FC87E /* Frameworks */,
|
||||
@ -648,14 +648,14 @@
|
||||
dependencies = (
|
||||
00E356F51AD99517003FC87E /* PBXTargetDependency */,
|
||||
);
|
||||
name = ExampleTests;
|
||||
productName = ExampleTests;
|
||||
productReference = 00E356EE1AD99517003FC87E /* ExampleTests.xctest */;
|
||||
name = exampleTests;
|
||||
productName = exampleTests;
|
||||
productReference = 00E356EE1AD99517003FC87E /* exampleTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
13B07F861A680F5B00A75B9A /* Example */ = {
|
||||
13B07F861A680F5B00A75B9A /* example */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Example" */;
|
||||
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */;
|
||||
buildPhases = (
|
||||
13B07F871A680F5B00A75B9A /* Sources */,
|
||||
13B07F8C1A680F5B00A75B9A /* Frameworks */,
|
||||
@ -666,14 +666,14 @@
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Example;
|
||||
name = example;
|
||||
productName = "Hello World";
|
||||
productReference = 13B07F961A680F5B00A75B9A /* Example.app */;
|
||||
productReference = 13B07F961A680F5B00A75B9A /* example.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
2D02E47A1E0B4A5D006451C7 /* Example-tvOS */ = {
|
||||
2D02E47A1E0B4A5D006451C7 /* example-tvOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOS" */;
|
||||
buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */;
|
||||
buildPhases = (
|
||||
2D02E4771E0B4A5D006451C7 /* Sources */,
|
||||
2D02E4781E0B4A5D006451C7 /* Frameworks */,
|
||||
@ -684,14 +684,14 @@
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "Example-tvOS";
|
||||
productName = "Example-tvOS";
|
||||
productReference = 2D02E47B1E0B4A5D006451C7 /* Example-tvOS.app */;
|
||||
name = "example-tvOS";
|
||||
productName = "example-tvOS";
|
||||
productReference = 2D02E47B1E0B4A5D006451C7 /* example-tvOS.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
2D02E48F1E0B4A5D006451C7 /* Example-tvOSTests */ = {
|
||||
2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOSTests" */;
|
||||
buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */;
|
||||
buildPhases = (
|
||||
2D02E48C1E0B4A5D006451C7 /* Sources */,
|
||||
2D02E48D1E0B4A5D006451C7 /* Frameworks */,
|
||||
@ -702,9 +702,9 @@
|
||||
dependencies = (
|
||||
2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "Example-tvOSTests";
|
||||
productName = "Example-tvOSTests";
|
||||
productReference = 2D02E4901E0B4A5D006451C7 /* Example-tvOSTests.xctest */;
|
||||
name = "example-tvOSTests";
|
||||
productName = "example-tvOSTests";
|
||||
productReference = 2D02E4901E0B4A5D006451C7 /* example-tvOSTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
@ -731,7 +731,7 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Example" */;
|
||||
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
@ -792,16 +792,16 @@
|
||||
ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 1BAE1B1E21BEEDA8006A28FB /* Products */;
|
||||
ProjectRef = 5763CEC9783A4A4F83148F48 /* RNImagePicker.xcodeproj */;
|
||||
ProductGroup = 1B73C9B521A87A36007D17CC /* Products */;
|
||||
ProjectRef = 3E14C3D2163E4C3082332CBF /* RNImagePicker.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
13B07F861A680F5B00A75B9A /* Example */,
|
||||
00E356ED1AD99517003FC87E /* ExampleTests */,
|
||||
2D02E47A1E0B4A5D006451C7 /* Example-tvOS */,
|
||||
2D02E48F1E0B4A5D006451C7 /* Example-tvOSTests */,
|
||||
13B07F861A680F5B00A75B9A /* example */,
|
||||
00E356ED1AD99517003FC87E /* exampleTests */,
|
||||
2D02E47A1E0B4A5D006451C7 /* example-tvOS */,
|
||||
2D02E48F1E0B4A5D006451C7 /* example-tvOSTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@ -863,11 +863,11 @@
|
||||
remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
1BAE1B2221BEEDA8006A28FB /* libRNImagePicker.a */ = {
|
||||
1B73C9B921A87A36007D17CC /* libRNImagePicker.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRNImagePicker.a;
|
||||
remoteRef = 1BAE1B2121BEEDA8006A28FB /* PBXContainerItemProxy */;
|
||||
remoteRef = 1B73C9B821A87A36007D17CC /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
2D16E6721FA4F8DC00B85C8A /* libRCTBlob-tvOS.a */ = {
|
||||
@ -1145,7 +1145,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
00E356F31AD99517003FC87E /* ExampleTests.m in Sources */,
|
||||
00E356F31AD99517003FC87E /* exampleTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1171,7 +1171,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2DCD954D1E0B4F2C00145EB5 /* ExampleTests.m in Sources */,
|
||||
2DCD954D1E0B4F2C00145EB5 /* exampleTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1180,12 +1180,12 @@
|
||||
/* Begin PBXTargetDependency section */
|
||||
00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 13B07F861A680F5B00A75B9A /* Example */;
|
||||
target = 13B07F861A680F5B00A75B9A /* example */;
|
||||
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
|
||||
};
|
||||
2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 2D02E47A1E0B4A5D006451C7 /* Example-tvOS */;
|
||||
target = 2D02E47A1E0B4A5D006451C7 /* example-tvOS */;
|
||||
targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
@ -1197,7 +1197,7 @@
|
||||
13B07FB21A68108700A75B9A /* Base */,
|
||||
);
|
||||
name = LaunchScreen.xib;
|
||||
path = Example;
|
||||
path = example;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
@ -1215,7 +1215,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = ExampleTests/Info.plist;
|
||||
INFOPLIST_FILE = exampleTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
@ -1228,7 +1228,7 @@
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -1241,7 +1241,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = ExampleTests/Info.plist;
|
||||
INFOPLIST_FILE = exampleTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
@ -1254,7 +1254,7 @@
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example.app/example";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -1268,15 +1268,15 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = Example/Info.plist;
|
||||
INFOPLIST_FILE = example/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Example;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = react.native.image.picker.example;
|
||||
PRODUCT_NAME = example;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
@ -1290,15 +1290,15 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = Example/Info.plist;
|
||||
INFOPLIST_FILE = example/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = Example;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = react.native.image.picker.example;
|
||||
PRODUCT_NAME = example;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
@ -1319,7 +1319,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "Example-tvOS/Info.plist";
|
||||
INFOPLIST_FILE = "example-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -1329,7 +1329,7 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOS";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
@ -1353,7 +1353,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "Example-tvOS/Info.plist";
|
||||
INFOPLIST_FILE = "example-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -1363,7 +1363,7 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOS";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
@ -1386,7 +1386,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "Example-tvOSTests/Info.plist";
|
||||
INFOPLIST_FILE = "example-tvOSTests/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -1396,10 +1396,10 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOSTests";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-tvOS.app/Example-tvOS";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS";
|
||||
TVOS_DEPLOYMENT_TARGET = 10.1;
|
||||
};
|
||||
name = Debug;
|
||||
@ -1419,7 +1419,7 @@
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "Example-tvOSTests/Info.plist";
|
||||
INFOPLIST_FILE = "example-tvOSTests/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@ -1429,10 +1429,10 @@
|
||||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.Example-tvOSTests";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.example-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-tvOS.app/Example-tvOS";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/example-tvOS.app/example-tvOS";
|
||||
TVOS_DEPLOYMENT_TARGET = 10.1;
|
||||
};
|
||||
name = Release;
|
||||
@ -1539,7 +1539,7 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ExampleTests" */ = {
|
||||
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
00E356F61AD99517003FC87E /* Debug */,
|
||||
@ -1548,7 +1548,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Example" */ = {
|
||||
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
13B07F941A680F5B00A75B9A /* Debug */,
|
||||
@ -1557,7 +1557,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOS" */ = {
|
||||
2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2D02E4971E0B4A5E006451C7 /* Debug */,
|
||||
@ -1566,7 +1566,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "Example-tvOSTests" */ = {
|
||||
2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "example-tvOSTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2D02E4991E0B4A5E006451C7 /* Debug */,
|
||||
@ -1575,7 +1575,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Example" */ = {
|
||||
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
83CBBA201A601CBA00E9B192 /* Debug */,
|
||||
|
||||
@ -29,9 +29,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Example-tvOS.app"
|
||||
BlueprintName = "Example-tvOS"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example-tvOS.app"
|
||||
BlueprintName = "example-tvOS"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
@ -43,9 +43,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
|
||||
BuildableName = "Example-tvOSTests.xctest"
|
||||
BlueprintName = "Example-tvOSTests"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example-tvOSTests.xctest"
|
||||
BlueprintName = "example-tvOSTests"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
@ -61,9 +61,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
|
||||
BuildableName = "Example-tvOSTests.xctest"
|
||||
BlueprintName = "Example-tvOSTests"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example-tvOSTests.xctest"
|
||||
BlueprintName = "example-tvOSTests"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
@ -71,9 +71,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Example-tvOS.app"
|
||||
BlueprintName = "Example-tvOS"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example-tvOS.app"
|
||||
BlueprintName = "example-tvOS"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
@ -94,9 +94,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Example-tvOS.app"
|
||||
BlueprintName = "Example-tvOS"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example-tvOS.app"
|
||||
BlueprintName = "example-tvOS"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
@ -113,9 +113,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
|
||||
BuildableName = "Example-tvOS.app"
|
||||
BlueprintName = "Example-tvOS"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example-tvOS.app"
|
||||
BlueprintName = "example-tvOS"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
|
||||
@ -29,9 +29,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Example.app"
|
||||
BlueprintName = "Example"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example.app"
|
||||
BlueprintName = "example"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
@ -43,9 +43,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
BuildableName = "ExampleTests.xctest"
|
||||
BlueprintName = "ExampleTests"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "exampleTests.xctest"
|
||||
BlueprintName = "exampleTests"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
@ -61,9 +61,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
||||
BuildableName = "ExampleTests.xctest"
|
||||
BlueprintName = "ExampleTests"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "exampleTests.xctest"
|
||||
BlueprintName = "exampleTests"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
@ -71,9 +71,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Example.app"
|
||||
BlueprintName = "Example"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example.app"
|
||||
BlueprintName = "example"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
@ -94,9 +94,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Example.app"
|
||||
BlueprintName = "Example"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example.app"
|
||||
BlueprintName = "example"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
@ -113,9 +113,9 @@
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
||||
BuildableName = "Example.app"
|
||||
BlueprintName = "Example"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
BuildableName = "example.app"
|
||||
BlueprintName = "example"
|
||||
ReferencedContainer = "container:example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
@ -12,20 +15,20 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Example" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Example" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
|
||||
@ -1,38 +1,53 @@
|
||||
{
|
||||
"images" : [
|
||||
"images": [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
"idiom": "iphone",
|
||||
"size": "20x20",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
"idiom": "iphone",
|
||||
"size": "20x20",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
"idiom": "iphone",
|
||||
"size": "29x29",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
"idiom": "iphone",
|
||||
"size": "29x29",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
"idiom": "iphone",
|
||||
"size": "40x40",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
"idiom": "iphone",
|
||||
"size": "40x40",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "60x60",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"idiom": "iphone",
|
||||
"size": "60x60",
|
||||
"scale": "3x"
|
||||
},
|
||||
{
|
||||
"idiom": "ios-marketing",
|
||||
"size": "1024x1024",
|
||||
"scale": "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,11 +14,11 @@
|
||||
#define TIMEOUT_SECONDS 600
|
||||
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
|
||||
|
||||
@interface ExampleTests : XCTestCase
|
||||
@interface exampleTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation ExampleTests
|
||||
@implementation exampleTests
|
||||
|
||||
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
|
||||
{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Example",
|
||||
"name": "example",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@ -8,13 +8,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "16.6.1",
|
||||
"react-native": "0.57.7",
|
||||
"react-native": "0.57.5",
|
||||
"react-native-image-picker": "file:../"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "23.6.0",
|
||||
"jest": "23.6.0",
|
||||
"metro-react-native-babel-preset": "0.50.0",
|
||||
"metro-react-native-babel-preset": "0.49.2",
|
||||
"react-test-renderer": "16.6.1"
|
||||
},
|
||||
"jest": {
|
||||
|
||||
1892
example/yarn.lock
1892
example/yarn.lock
File diff suppressed because it is too large
Load Diff
62
index.d.ts
vendored
Normal file
62
index.d.ts
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
declare module "react-native-image-picker" {
|
||||
|
||||
interface Response {
|
||||
customButton: string;
|
||||
didCancel: boolean;
|
||||
error: string;
|
||||
data: string;
|
||||
uri: string;
|
||||
origURL?: string;
|
||||
isVertical: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
fileSize: number;
|
||||
type?: string;
|
||||
fileName?: string;
|
||||
path?: string;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
interface CustomButtonOptions {
|
||||
name?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
interface Options {
|
||||
title?: string;
|
||||
cancelButtonTitle?: string;
|
||||
takePhotoButtonTitle?: string;
|
||||
chooseFromLibraryButtonTitle?: string;
|
||||
customButtons?: Array<CustomButtonOptions>;
|
||||
cameraType?: 'front' | 'back';
|
||||
mediaType?: 'photo' | 'video' | 'mixed';
|
||||
maxWidth?: number;
|
||||
maxHeight?: number;
|
||||
quality?: number;
|
||||
videoQuality?: 'low' | 'medium' | 'high';
|
||||
durationLimit?: number;
|
||||
rotation?: number;
|
||||
allowsEditing?: boolean;
|
||||
noData?: boolean;
|
||||
storageOptions?: StorageOptions;
|
||||
}
|
||||
|
||||
interface StorageOptions {
|
||||
skipBackup?: boolean;
|
||||
path?: string;
|
||||
cameraRoll?: boolean;
|
||||
waitUntilSaved?: boolean;
|
||||
}
|
||||
|
||||
|
||||
class ImagePicker {
|
||||
static showImagePicker(options: Options, callback: (response: Response) => void): void;
|
||||
static launchCamera(options: Options, callback: (response: Response) => void): void;
|
||||
static launchImageLibrary(options: Options, callback: (response: Response) => void): void;
|
||||
}
|
||||
|
||||
export = ImagePicker;
|
||||
|
||||
}
|
||||
33
index.js
Normal file
33
index.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
const { ImagePickerManager } = NativeModules;
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
title: 'Select a Photo',
|
||||
cancelButtonTitle: 'Cancel',
|
||||
takePhotoButtonTitle: 'Take Photo…',
|
||||
chooseFromLibraryButtonTitle: 'Choose from Library…',
|
||||
quality: 1.0,
|
||||
allowsEditing: false,
|
||||
permissionDenied: {
|
||||
title: 'Permission denied',
|
||||
text:
|
||||
'To be able to take pictures with your camera and choose images from your library.',
|
||||
reTryTitle: 're-try',
|
||||
okTitle: "I'm sure",
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
...ImagePickerManager,
|
||||
showImagePicker: function showImagePicker(options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
return ImagePickerManager.showImagePicker(
|
||||
{ ...DEFAULT_OPTIONS, ...options },
|
||||
callback,
|
||||
);
|
||||
},
|
||||
};
|
||||
66
index.js.flow
Normal file
66
index.js.flow
Normal file
@ -0,0 +1,66 @@
|
||||
// @flow
|
||||
|
||||
export type Response = {
|
||||
customButton: string;
|
||||
didCancel: boolean;
|
||||
error: string;
|
||||
data: string;
|
||||
uri: string;
|
||||
origURL?: string;
|
||||
isVertical: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
fileSize: number;
|
||||
type?: string;
|
||||
fileName?: string;
|
||||
path?: string;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
export type CustomButtonOptions = {
|
||||
name?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export type Options = {
|
||||
title?: string;
|
||||
cancelButtonTitle?: string;
|
||||
takePhotoButtonTitle?: string;
|
||||
chooseFromLibraryButtonTitle?: string;
|
||||
customButtons?: Array<CustomButtonOptions>;
|
||||
cameraType?: 'front' | 'back';
|
||||
mediaType?: 'photo' | 'video' | 'mixed';
|
||||
maxWidth?: number;
|
||||
maxHeight?: number;
|
||||
quality?: number;
|
||||
videoQuality?: 'low' | 'medium' | 'high';
|
||||
durationLimit?: number;
|
||||
rotation?: number;
|
||||
allowsEditing?: boolean;
|
||||
noData?: boolean;
|
||||
storageOptions?: StorageOptions;
|
||||
}
|
||||
|
||||
export type StorageOptions = {
|
||||
skipBackup?: boolean;
|
||||
path?: string;
|
||||
cameraRoll?: boolean;
|
||||
waitUntilSaved?: boolean;
|
||||
}
|
||||
|
||||
declare export function showImagePicker(options: ?Options, callback: (response: Response) => any): void;
|
||||
declare export function showImagePicker(callback: (response: Response) => any): void;
|
||||
|
||||
declare export function launchCamera(options: ?Options, callback: (response: Response) => any): void;
|
||||
declare export function launchCamera(callback: (response: Response) => any): void;
|
||||
|
||||
declare export function launchImageLibrary(options: ?Options, callback: (response: Response) => any): void;
|
||||
declare export function launchImageLibrary(callback: (response: Response) => any): void;
|
||||
|
||||
declare export default {
|
||||
showImagePicker(options: ?Options, callback: (response: Response) => any): void,
|
||||
launchCamera(options: ?Options, callback: (response: Response) => any): void,
|
||||
launchImageLibrary(callback: (response: Response) => any): void,
|
||||
};
|
||||
@ -1,21 +1,19 @@
|
||||
#import "ImagePickerManager.h"
|
||||
#import <React/RCTConvert.h>
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <Photos/Photos.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#endif
|
||||
|
||||
@import MobileCoreServices;
|
||||
|
||||
@interface ImagePickerManager ()
|
||||
|
||||
@property (nonatomic, strong) UIAlertController *alertController;
|
||||
@property (nonatomic, strong) UIImagePickerController *picker;
|
||||
@property (nonatomic, strong) RCTResponseSenderBlock callback;
|
||||
@property (nonatomic, strong) NSDictionary *defaultOptions;
|
||||
@property (nonatomic, retain) NSDictionary *options;
|
||||
@property (nonatomic, retain) NSMutableDictionary *response;
|
||||
@property (nonatomic, retain) NSMutableDictionary *options, *response;
|
||||
@property (nonatomic, strong) NSArray *customButtons;
|
||||
|
||||
@end
|
||||
@ -27,85 +25,80 @@ RCT_EXPORT_MODULE();
|
||||
RCT_EXPORT_METHOD(launchCamera:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
self.callback = callback;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self launchImagePicker:RNImagePickerTargetCamera options:options];
|
||||
});
|
||||
[self launchImagePicker:RNImagePickerTargetCamera options:options];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(launchImageLibrary:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
self.callback = callback;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self launchImagePicker:RNImagePickerTargetLibrarySingleImage options:options];
|
||||
});
|
||||
[self launchImagePicker:RNImagePickerTargetLibrarySingleImage options:options];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
self.callback = callback; // Save the callback so we can use it from the delegate methods
|
||||
self.options = options;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
NSString *title = [self.options valueForKey:@"title"];
|
||||
if ([title isEqual:[NSNull null]] || title.length == 0) {
|
||||
title = nil; // A more visually appealing UIAlertControl is displayed with a nil title rather than title = @""
|
||||
}
|
||||
NSString *cancelTitle = [self.options valueForKey:@"cancelButtonTitle"];
|
||||
NSString *takePhotoButtonTitle = [self.options valueForKey:@"takePhotoButtonTitle"];
|
||||
NSString *chooseFromLibraryButtonTitle = [self.options valueForKey:@"chooseFromLibraryButtonTitle"];
|
||||
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
alertController.view.tintColor = [RCTConvert UIColor:options[@"tintColor"]];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
|
||||
self.callback(@[@{@"didCancel": @YES}]); // Return callback for 'cancel' action (if is required)
|
||||
|
||||
NSString *title = [self.options valueForKey:@"title"];
|
||||
if ([title isEqual:[NSNull null]] || title.length == 0) {
|
||||
title = nil; // A more visually appealing UIAlertControl is displayed with a nil title rather than title = @""
|
||||
}
|
||||
NSString *cancelTitle = [self.options valueForKey:@"cancelButtonTitle"];
|
||||
NSString *takePhotoButtonTitle = [self.options valueForKey:@"takePhotoButtonTitle"];
|
||||
NSString *chooseFromLibraryButtonTitle = [self.options valueForKey:@"chooseFromLibraryButtonTitle"];
|
||||
|
||||
|
||||
self.alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
|
||||
self.callback(@[@{@"didCancel": @YES}]); // Return callback for 'cancel' action (if is required)
|
||||
}];
|
||||
[self.alertController addAction:cancelAction];
|
||||
|
||||
if (![takePhotoButtonTitle isEqual:[NSNull null]] && takePhotoButtonTitle.length > 0) {
|
||||
UIAlertAction *takePhotoAction = [UIAlertAction actionWithTitle:takePhotoButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
||||
[self actionHandler:action];
|
||||
}];
|
||||
[alertController addAction:cancelAction];
|
||||
|
||||
if (![takePhotoButtonTitle isEqual:[NSNull null]] && takePhotoButtonTitle.length > 0) {
|
||||
UIAlertAction *takePhotoAction = [UIAlertAction actionWithTitle:takePhotoButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
||||
[self.alertController addAction:takePhotoAction];
|
||||
}
|
||||
if (![chooseFromLibraryButtonTitle isEqual:[NSNull null]] && chooseFromLibraryButtonTitle.length > 0) {
|
||||
UIAlertAction *chooseFromLibraryAction = [UIAlertAction actionWithTitle:chooseFromLibraryButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
||||
[self actionHandler:action];
|
||||
}];
|
||||
[self.alertController addAction:chooseFromLibraryAction];
|
||||
}
|
||||
|
||||
// Add custom buttons to action sheet
|
||||
if ([self.options objectForKey:@"customButtons"] && [[self.options objectForKey:@"customButtons"] isKindOfClass:[NSArray class]]) {
|
||||
self.customButtons = [self.options objectForKey:@"customButtons"];
|
||||
for (NSString *button in self.customButtons) {
|
||||
NSString *title = [button valueForKey:@"title"];
|
||||
UIAlertAction *customAction = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
||||
[self actionHandler:action];
|
||||
}];
|
||||
[alertController addAction:takePhotoAction];
|
||||
[self.alertController addAction:customAction];
|
||||
}
|
||||
if (![chooseFromLibraryButtonTitle isEqual:[NSNull null]] && chooseFromLibraryButtonTitle.length > 0) {
|
||||
UIAlertAction *chooseFromLibraryAction = [UIAlertAction actionWithTitle:chooseFromLibraryButtonTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
||||
[self actionHandler:action];
|
||||
}];
|
||||
[alertController addAction:chooseFromLibraryAction];
|
||||
}
|
||||
|
||||
// Add custom buttons to action sheet
|
||||
if ([self.options objectForKey:@"customButtons"] && [[self.options objectForKey:@"customButtons"] isKindOfClass:[NSArray class]]) {
|
||||
self.customButtons = [self.options objectForKey:@"customButtons"];
|
||||
for (NSString *button in self.customButtons) {
|
||||
NSString *title = [button valueForKey:@"title"];
|
||||
UIAlertAction *customAction = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
||||
[self actionHandler:action];
|
||||
}];
|
||||
[alertController addAction:customAction];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIViewController *root = RCTPresentedViewController();
|
||||
|
||||
|
||||
/* On iPad, UIAlertController presents a popover view rather than an action sheet like on iPhone. We must provide the location
|
||||
of the location to show the popover in this case. For simplicity, we'll just display it on the bottom center of the screen
|
||||
to mimic an action sheet */
|
||||
alertController.popoverPresentationController.sourceView = root.view;
|
||||
alertController.popoverPresentationController.sourceRect = CGRectMake(root.view.bounds.size.width / 2.0, root.view.bounds.size.height, 1.0, 1.0);
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
|
||||
alertController.popoverPresentationController.permittedArrowDirections = 0;
|
||||
for (id subview in alertController.view.subviews) {
|
||||
of the location to show the popover in this case. For simplicity, we'll just display it on the bottom center of the screen
|
||||
to mimic an action sheet */
|
||||
self.alertController.popoverPresentationController.sourceView = root.view;
|
||||
self.alertController.popoverPresentationController.sourceRect = CGRectMake(root.view.bounds.size.width / 2.0, root.view.bounds.size.height, 1.0, 1.0);
|
||||
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
self.alertController.popoverPresentationController.permittedArrowDirections = 0;
|
||||
for (id subview in self.alertController.view.subviews) {
|
||||
if ([subview isMemberOfClass:[UIView class]]) {
|
||||
((UIView *)subview).backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[root presentViewController:alertController animated:YES completion:nil];
|
||||
|
||||
[root presentViewController:self.alertController animated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
@ -121,7 +114,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ([action.title isEqualToString:[self.options valueForKey:@"takePhotoButtonTitle"]]) { // Take photo
|
||||
[self launchImagePicker:RNImagePickerTargetCamera];
|
||||
}
|
||||
@ -139,7 +132,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
- (void)launchImagePicker:(RNImagePickerTarget)target
|
||||
{
|
||||
self.picker = [[UIImagePickerController alloc] init];
|
||||
|
||||
|
||||
if (target == RNImagePickerTargetCamera) {
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
self.callback(@[@{@"error": @"Camera not available on simulator"}]);
|
||||
@ -157,10 +150,10 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
else { // RNImagePickerTargetLibrarySingleImage
|
||||
self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
|
||||
}
|
||||
|
||||
|
||||
if ([[self.options objectForKey:@"mediaType"] isEqualToString:@"video"]
|
||||
|| [[self.options objectForKey:@"mediaType"] isEqualToString:@"mixed"]) {
|
||||
|
||||
|
||||
if ([[self.options objectForKey:@"videoQuality"] isEqualToString:@"high"]) {
|
||||
self.picker.videoQuality = UIImagePickerControllerQualityTypeHigh;
|
||||
}
|
||||
@ -170,7 +163,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
else {
|
||||
self.picker.videoQuality = UIImagePickerControllerQualityTypeMedium;
|
||||
}
|
||||
|
||||
|
||||
id durationLimit = [self.options objectForKey:@"durationLimit"];
|
||||
if (durationLimit) {
|
||||
self.picker.videoMaximumDuration = [durationLimit doubleValue];
|
||||
@ -184,13 +177,13 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
} else {
|
||||
self.picker.mediaTypes = @[(NSString *)kUTTypeImage];
|
||||
}
|
||||
|
||||
|
||||
if ([[self.options objectForKey:@"allowsEditing"] boolValue]) {
|
||||
self.picker.allowsEditing = true;
|
||||
}
|
||||
self.picker.modalPresentationStyle = UIModalPresentationCurrentContext;
|
||||
self.picker.delegate = self;
|
||||
|
||||
|
||||
// Check permissions
|
||||
void (^showPickerViewController)() = ^void() {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@ -198,64 +191,60 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
[root presentViewController:self.picker animated:YES completion:nil];
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
if (target == RNImagePickerTargetCamera) {
|
||||
[self checkCameraPermissions:^(BOOL granted) {
|
||||
if (!granted) {
|
||||
self.callback(@[@{@"error": @"Camera permissions not granted"}]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
showPickerViewController();
|
||||
}];
|
||||
}
|
||||
else { // RNImagePickerTargetLibrarySingleImage
|
||||
if (@available(iOS 11.0, *)) {
|
||||
[self checkPhotosPermissions:^(BOOL granted) {
|
||||
if (!granted) {
|
||||
self.callback(@[@{@"error": @"Photo library permissions not granted"}]);
|
||||
return;
|
||||
}
|
||||
|
||||
showPickerViewController();
|
||||
} else {
|
||||
[self checkPhotosPermissions:^(BOOL granted) {
|
||||
if (!granted) {
|
||||
self.callback(@[@{@"error": @"Photo library permissions not granted"}]);
|
||||
return;
|
||||
}
|
||||
|
||||
showPickerViewController();
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString * _Nullable)originalFilenameForAsset:(PHAsset * _Nullable)asset assetType:(PHAssetResourceType)type {
|
||||
if (!asset) { return nil; }
|
||||
|
||||
|
||||
PHAssetResource *originalResource;
|
||||
// Get the underlying resources for the PHAsset (PhotoKit)
|
||||
NSArray<PHAssetResource *> *pickedAssetResources = [PHAssetResource assetResourcesForAsset:asset];
|
||||
|
||||
|
||||
// Find the original resource (underlying image) for the asset, which has the desired filename
|
||||
for (PHAssetResource *resource in pickedAssetResources) {
|
||||
if (resource.type == type) {
|
||||
originalResource = resource;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return originalResource.originalFilename;
|
||||
}
|
||||
|
||||
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
|
||||
{
|
||||
dispatch_block_t dismissCompletionBlock = ^{
|
||||
|
||||
NSURL *imageURL = [info valueForKey:UIImagePickerControllerPHAsset];
|
||||
|
||||
NSURL *imageURL = [info valueForKey:UIImagePickerControllerReferenceURL];
|
||||
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
|
||||
|
||||
|
||||
NSString *fileName;
|
||||
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
|
||||
NSString *tempFileName = [[NSUUID UUID] UUIDString];
|
||||
if (imageURL && [[imageURL absoluteString] rangeOfString:@"ext=GIF"].location != NSNotFound) {
|
||||
fileName = [tempFileName stringByAppendingString:@".gif"];
|
||||
}
|
||||
else if ([[self.options objectForKey:@"imageFileType"] isEqualToString:@"png"]) {
|
||||
else if ([[[self.options objectForKey:@"imageFileType"] stringValue] isEqualToString:@"png"]) {
|
||||
fileName = [tempFileName stringByAppendingString:@".png"];
|
||||
}
|
||||
else {
|
||||
@ -266,18 +255,18 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
NSURL *videoURL = info[UIImagePickerControllerMediaURL];
|
||||
fileName = videoURL.lastPathComponent;
|
||||
}
|
||||
|
||||
|
||||
// We default to path to the temporary directory
|
||||
NSString *path = [[NSTemporaryDirectory()stringByStandardizingPath] stringByAppendingPathComponent:fileName];
|
||||
|
||||
|
||||
// If storage options are provided, we use the documents directory which is persisted
|
||||
if ([self.options objectForKey:@"storageOptions"] && [[self.options objectForKey:@"storageOptions"] isKindOfClass:[NSDictionary class]]) {
|
||||
NSDictionary *storageOptions = [self.options objectForKey:@"storageOptions"];
|
||||
|
||||
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
path = [documentsDirectory stringByAppendingPathComponent:fileName];
|
||||
|
||||
|
||||
// Creates documents subdirectory, if provided
|
||||
if ([storageOptions objectForKey:@"path"]) {
|
||||
NSString *newPath = [documentsDirectory stringByAppendingPathComponent:[storageOptions objectForKey:@"path"]];
|
||||
@ -293,10 +282,10 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create the response object
|
||||
self.response = [[NSMutableDictionary alloc] init];
|
||||
|
||||
|
||||
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) { // PHOTOS
|
||||
UIImage *originalImage;
|
||||
if ([[self.options objectForKey:@"allowsEditing"] boolValue]) {
|
||||
@ -305,17 +294,9 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
else {
|
||||
originalImage = [info objectForKey:UIImagePickerControllerOriginalImage];
|
||||
}
|
||||
|
||||
|
||||
if (imageURL) {
|
||||
PHAsset *pickedAsset;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
pickedAsset = [info objectForKey: UIImagePickerControllerPHAsset];
|
||||
} else {
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
pickedAsset = [PHAsset fetchAssetsWithALAssetURLs:@[imageURL] options:nil].lastObject;
|
||||
#endif
|
||||
}
|
||||
|
||||
PHAsset *pickedAsset = [PHAsset fetchAssetsWithALAssetURLs:@[imageURL] options:nil].lastObject;
|
||||
NSString *originalFilename = [self originalFilenameForAsset:pickedAsset assetType:PHAssetResourceTypePhoto];
|
||||
self.response[@"fileName"] = originalFilename ?: [NSNull null];
|
||||
if (pickedAsset.location) {
|
||||
@ -326,10 +307,9 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
self.response[@"timestamp"] = [[ImagePickerManager ISO8601DateFormatter] stringFromDate:pickedAsset.creationDate];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GIFs break when resized, so we handle them differently
|
||||
if (imageURL && [[imageURL absoluteString] rangeOfString:@"ext=GIF"].location != NSNotFound) {
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
|
||||
[assetsLibrary assetForURL:imageURL resultBlock:^(ALAsset *asset) {
|
||||
ALAssetRepresentation *rep = [asset defaultRepresentation];
|
||||
@ -338,39 +318,38 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:repSize error:nil];
|
||||
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
|
||||
[data writeToFile:path atomically:YES];
|
||||
|
||||
|
||||
NSMutableDictionary *gifResponse = [[NSMutableDictionary alloc] init];
|
||||
[gifResponse setObject:@(originalImage.size.width) forKey:@"width"];
|
||||
[gifResponse setObject:@(originalImage.size.height) forKey:@"height"];
|
||||
|
||||
|
||||
BOOL vertical = (originalImage.size.width < originalImage.size.height) ? YES : NO;
|
||||
[gifResponse setObject:@(vertical) forKey:@"isVertical"];
|
||||
|
||||
|
||||
if (![[self.options objectForKey:@"noData"] boolValue]) {
|
||||
NSString *dataString = [data base64EncodedStringWithOptions:0];
|
||||
[gifResponse setObject:dataString forKey:@"data"];
|
||||
}
|
||||
|
||||
|
||||
NSURL *fileURL = [NSURL fileURLWithPath:path];
|
||||
[gifResponse setObject:[fileURL absoluteString] forKey:@"uri"];
|
||||
|
||||
|
||||
NSNumber *fileSizeValue = nil;
|
||||
NSError *fileSizeError = nil;
|
||||
[fileURL getResourceValue:&fileSizeValue forKey:NSURLFileSizeKey error:&fileSizeError];
|
||||
if (fileSizeValue){
|
||||
[gifResponse setObject:fileSizeValue forKey:@"fileSize"];
|
||||
}
|
||||
|
||||
|
||||
self.callback(@[gifResponse]);
|
||||
} failureBlock:^(NSError *error) {
|
||||
self.callback(@[@{@"error": error.localizedFailureReason}]);
|
||||
}];
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
UIImage *editedImage = [self fixOrientation:originalImage]; // Rotate the image for upload to web
|
||||
|
||||
|
||||
// If needed, downscale image
|
||||
float maxWidth = editedImage.size.width;
|
||||
float maxHeight = editedImage.size.height;
|
||||
@ -381,50 +360,45 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
maxHeight = [[self.options valueForKey:@"maxHeight"] floatValue];
|
||||
}
|
||||
editedImage = [self downscaleImageIfNecessary:editedImage maxWidth:maxWidth maxHeight:maxHeight];
|
||||
|
||||
|
||||
NSData *data;
|
||||
NSString *mimeType;
|
||||
if ([[self.options objectForKey:@"imageFileType"] isEqualToString:@"png"]) {
|
||||
if ([[[self.options objectForKey:@"imageFileType"] stringValue] isEqualToString:@"png"]) {
|
||||
data = UIImagePNGRepresentation(editedImage);
|
||||
mimeType = (__bridge_transfer NSString *)(UTTypeCopyPreferredTagWithClass(kUTTypePNG, kUTTagClassMIMEType));
|
||||
}
|
||||
else {
|
||||
data = UIImageJPEGRepresentation(editedImage, [[self.options valueForKey:@"quality"] floatValue]);
|
||||
mimeType = (__bridge_transfer NSString *)(UTTypeCopyPreferredTagWithClass(kUTTypeJPEG, kUTTagClassMIMEType));
|
||||
}
|
||||
[self.response setObject:mimeType forKey:@"type"];
|
||||
[data writeToFile:path atomically:YES];
|
||||
|
||||
|
||||
if (![[self.options objectForKey:@"noData"] boolValue]) {
|
||||
NSString *dataString = [data base64EncodedStringWithOptions:0]; // base64 encoded image string
|
||||
[self.response setObject:dataString forKey:@"data"];
|
||||
}
|
||||
|
||||
|
||||
BOOL vertical = (editedImage.size.width < editedImage.size.height) ? YES : NO;
|
||||
[self.response setObject:@(vertical) forKey:@"isVertical"];
|
||||
NSURL *fileURL = [NSURL fileURLWithPath:path];
|
||||
NSString *filePath = [fileURL absoluteString];
|
||||
[self.response setObject:filePath forKey:@"uri"];
|
||||
|
||||
|
||||
// add ref to the original image
|
||||
NSString *origURL = [imageURL absoluteString];
|
||||
if (origURL) {
|
||||
[self.response setObject:origURL forKey:@"origURL"];
|
||||
[self.response setObject:origURL forKey:@"origURL"];
|
||||
}
|
||||
|
||||
|
||||
NSNumber *fileSizeValue = nil;
|
||||
NSError *fileSizeError = nil;
|
||||
[fileURL getResourceValue:&fileSizeValue forKey:NSURLFileSizeKey error:&fileSizeError];
|
||||
if (fileSizeValue){
|
||||
[self.response setObject:fileSizeValue forKey:@"fileSize"];
|
||||
}
|
||||
|
||||
|
||||
[self.response setObject:@(editedImage.size.width) forKey:@"width"];
|
||||
[self.response setObject:@(editedImage.size.height) forKey:@"height"];
|
||||
|
||||
|
||||
NSDictionary *storageOptions = [self.options objectForKey:@"storageOptions"];
|
||||
if (storageOptions && [[storageOptions objectForKey:@"cameraRoll"] boolValue] == YES && self.picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
||||
if ([[storageOptions objectForKey:@"waitUntilSaved"] boolValue]) {
|
||||
[library writeImageToSavedPhotosAlbum:originalImage.CGImage metadata:[info valueForKey:UIImagePickerControllerMediaMetadata] completionBlock:^(NSURL *assetURL, NSError *error) {
|
||||
@ -447,15 +421,13 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
} else {
|
||||
[library writeImageToSavedPhotosAlbum:originalImage.CGImage metadata:[info valueForKey:UIImagePickerControllerMediaMetadata] completionBlock:nil];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else { // VIDEO
|
||||
NSURL *videoRefURL = info[UIImagePickerControllerPHAsset];
|
||||
NSURL *videoRefURL = info[UIImagePickerControllerReferenceURL];
|
||||
NSURL *videoURL = info[UIImagePickerControllerMediaURL];
|
||||
NSURL *videoDestinationURL = [NSURL fileURLWithPath:path];
|
||||
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
|
||||
if (videoRefURL) {
|
||||
PHAsset *pickedAsset = [PHAsset fetchAssetsWithALAssetURLs:@[videoRefURL] options:nil].lastObject;
|
||||
NSString *originalFilename = [self originalFilenameForAsset:pickedAsset assetType:PHAssetResourceTypeVideo];
|
||||
@ -468,41 +440,32 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
self.response[@"timestamp"] = [[ImagePickerManager ISO8601DateFormatter] stringFromDate:pickedAsset.creationDate];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if ([videoURL.URLByResolvingSymlinksInPath.path isEqualToString:videoDestinationURL.URLByResolvingSymlinksInPath.path] == NO) {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
|
||||
// Delete file if it already exists
|
||||
if ([fileManager fileExistsAtPath:videoDestinationURL.path]) {
|
||||
[fileManager removeItemAtURL:videoDestinationURL error:nil];
|
||||
}
|
||||
|
||||
|
||||
if (videoURL) { // Protect against reported crash
|
||||
NSError *error = nil;
|
||||
|
||||
// If we have write access to the source file, move it. Otherwise use copy.
|
||||
if ([fileManager isWritableFileAtPath:[videoURL path]]) {
|
||||
[fileManager moveItemAtURL:videoURL toURL:videoDestinationURL error:&error];
|
||||
} else {
|
||||
[fileManager copyItemAtURL:videoURL toURL:videoDestinationURL error:&error];
|
||||
}
|
||||
|
||||
if (error) {
|
||||
self.callback(@[@{@"error": error.localizedFailureReason}]);
|
||||
return;
|
||||
}
|
||||
NSError *error = nil;
|
||||
[fileManager moveItemAtURL:videoURL toURL:videoDestinationURL error:&error];
|
||||
if (error) {
|
||||
self.callback(@[@{@"error": error.localizedFailureReason}]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[self.response setObject:videoDestinationURL.absoluteString forKey:@"uri"];
|
||||
if (videoRefURL.absoluteString) {
|
||||
[self.response setObject:videoRefURL.absoluteString forKey:@"origURL"];
|
||||
}
|
||||
|
||||
|
||||
NSDictionary *storageOptions = [self.options objectForKey:@"storageOptions"];
|
||||
if (storageOptions && [[storageOptions objectForKey:@"cameraRoll"] boolValue] == YES && self.picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
|
||||
#if !TARGET_OS_MACCATALYST
|
||||
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
|
||||
[library writeVideoAtPathToSavedPhotosAlbum:videoDestinationURL completionBlock:^(NSURL *assetURL, NSError *error) {
|
||||
if (error) {
|
||||
@ -520,23 +483,22 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
self.response[@"timestamp"] = [[ImagePickerManager ISO8601DateFormatter] stringFromDate:capturedAsset.creationDate];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.callback(@[self.response]);
|
||||
}
|
||||
}
|
||||
}];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If storage options are provided, check the skipBackup flag
|
||||
if ([self.options objectForKey:@"storageOptions"] && [[self.options objectForKey:@"storageOptions"] isKindOfClass:[NSDictionary class]]) {
|
||||
NSDictionary *storageOptions = [self.options objectForKey:@"storageOptions"];
|
||||
|
||||
|
||||
if ([[storageOptions objectForKey:@"skipBackup"] boolValue]) {
|
||||
[self addSkipBackupAttributeToItemAtPath:path]; // Don't back up the file to iCloud
|
||||
}
|
||||
|
||||
|
||||
if ([[storageOptions objectForKey:@"waitUntilSaved"] boolValue] == NO ||
|
||||
[[storageOptions objectForKey:@"cameraRoll"] boolValue] == NO ||
|
||||
self.picker.sourceType != UIImagePickerControllerSourceTypeCamera)
|
||||
@ -548,7 +510,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
self.callback(@[self.response]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[picker dismissViewControllerAnimated:YES completion:dismissCompletionBlock];
|
||||
});
|
||||
@ -607,12 +569,12 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
- (UIImage*)downscaleImageIfNecessary:(UIImage*)image maxWidth:(float)maxWidth maxHeight:(float)maxHeight
|
||||
{
|
||||
UIImage* newImage = image;
|
||||
|
||||
|
||||
// Nothing to do here
|
||||
if (image.size.width <= maxWidth && image.size.height <= maxHeight) {
|
||||
return newImage;
|
||||
}
|
||||
|
||||
|
||||
CGSize scaledSize = CGSizeMake(image.size.width, image.size.height);
|
||||
if (maxWidth < scaledSize.width) {
|
||||
scaledSize = CGSizeMake(maxWidth, (maxWidth / scaledSize.width) * scaledSize.height);
|
||||
@ -620,11 +582,11 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
if (maxHeight < scaledSize.height) {
|
||||
scaledSize = CGSizeMake((maxHeight / scaledSize.height) * scaledSize.width, maxHeight);
|
||||
}
|
||||
|
||||
|
||||
// If the pixels are floats, it causes a white line in iOS8 and probably other versions too
|
||||
scaledSize.width = (int)scaledSize.width;
|
||||
scaledSize.height = (int)scaledSize.height;
|
||||
|
||||
|
||||
UIGraphicsBeginImageContext(scaledSize); // this will resize
|
||||
[image drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)];
|
||||
newImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
@ -632,7 +594,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
NSLog(@"could not scale image");
|
||||
}
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
@ -640,7 +602,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
if (srcImg.imageOrientation == UIImageOrientationUp) {
|
||||
return srcImg;
|
||||
}
|
||||
|
||||
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
switch (srcImg.imageOrientation) {
|
||||
case UIImageOrientationDown:
|
||||
@ -648,13 +610,13 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
transform = CGAffineTransformTranslate(transform, srcImg.size.width, srcImg.size.height);
|
||||
transform = CGAffineTransformRotate(transform, M_PI);
|
||||
break;
|
||||
|
||||
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, srcImg.size.width, 0);
|
||||
transform = CGAffineTransformRotate(transform, M_PI_2);
|
||||
break;
|
||||
|
||||
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationRightMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, 0, srcImg.size.height);
|
||||
@ -664,14 +626,14 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
case UIImageOrientationUpMirrored:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (srcImg.imageOrientation) {
|
||||
case UIImageOrientationUpMirrored:
|
||||
case UIImageOrientationDownMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, srcImg.size.width, 0);
|
||||
transform = CGAffineTransformScale(transform, -1, 1);
|
||||
break;
|
||||
|
||||
|
||||
case UIImageOrientationLeftMirrored:
|
||||
case UIImageOrientationRightMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, srcImg.size.height, 0);
|
||||
@ -683,7 +645,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
case UIImageOrientationRight:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
CGContextRef ctx = CGBitmapContextCreate(NULL, srcImg.size.width, srcImg.size.height, CGImageGetBitsPerComponent(srcImg.CGImage), 0, CGImageGetColorSpace(srcImg.CGImage), CGImageGetBitmapInfo(srcImg.CGImage));
|
||||
CGContextConcatCTM(ctx, transform);
|
||||
switch (srcImg.imageOrientation) {
|
||||
@ -693,12 +655,12 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
case UIImageOrientationRightMirrored:
|
||||
CGContextDrawImage(ctx, CGRectMake(0,0,srcImg.size.height,srcImg.size.width), srcImg.CGImage);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
CGContextDrawImage(ctx, CGRectMake(0,0,srcImg.size.width,srcImg.size.height), srcImg.CGImage);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
|
||||
UIImage *img = [UIImage imageWithCGImage:cgimg];
|
||||
CGContextRelease(ctx);
|
||||
@ -713,7 +675,7 @@ RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options callback:(RCTResponseS
|
||||
NSError *error = nil;
|
||||
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
|
||||
forKey: NSURLIsExcludedFromBackupKey error: &error];
|
||||
|
||||
|
||||
if(!success){
|
||||
NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
|
||||
}
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
// jest.config.js
|
||||
const { defaults: tsjPreset } = require('ts-jest/presets');
|
||||
|
||||
module.exports = {
|
||||
...tsjPreset,
|
||||
preset: 'react-native',
|
||||
transform: {
|
||||
...tsjPreset.transform,
|
||||
'\\.js$': '<rootDir>/node_modules/react-native/jest/preprocessor.js',
|
||||
},
|
||||
testPathIgnorePatterns: ['<rootDir>/lib/', '<rootDir>/node_modules/', '<rootDir>/example/'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
babelConfig: true,
|
||||
},
|
||||
},
|
||||
setupFilesAfterEnv: [
|
||||
'<rootDir>/jest.setup.js',
|
||||
],
|
||||
};
|
||||
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
/* eslint-env jest */
|
||||
|
||||
import {NativeModules} from 'react-native';
|
||||
|
||||
// Mock the ImagePickerManager native module to allow us to unit test the JavaScript code
|
||||
NativeModules.ImagePickerManager = {
|
||||
showImagePicker: jest.fn(),
|
||||
launchCamera: jest.fn(),
|
||||
launchImageLibrary: jest.fn(),
|
||||
};
|
||||
|
||||
// Reset the mocks before each test
|
||||
global.beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
15954
package-lock.json
generated
15954
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
101
package.json
101
package.json
@ -1,25 +1,16 @@
|
||||
{
|
||||
"name": "react-native-image-picker",
|
||||
"version": "2.3.3",
|
||||
"description": "A React Native module that allows you to use native UI to select media from the device library or directly from the camera",
|
||||
"react-native": "src/index.ts",
|
||||
"types": "lib/typescript/index.d.ts",
|
||||
"main": "lib/commonjs/index.js",
|
||||
"module": "lib/module/index.js",
|
||||
"files": [
|
||||
"/android",
|
||||
"!/android/build",
|
||||
"/ios",
|
||||
"/src",
|
||||
"/lib",
|
||||
"/*.podspec"
|
||||
],
|
||||
"version": "0.27.1",
|
||||
"main": "index.js",
|
||||
"homepage": "https://github.com/react-community/react-native-image-picker",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/react-community/react-native-image-picker.git"
|
||||
},
|
||||
"nativePackage": true,
|
||||
"author": "Marc Shilling (marcshilling)",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Johan du Toit",
|
||||
"email": "jdutoit.dev@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Matheus Santos",
|
||||
"email": "vorj.dux@gmail.com"
|
||||
@ -33,18 +24,6 @@
|
||||
"email": "rusfearuth@gmail.com"
|
||||
}
|
||||
],
|
||||
"homepage": "https://github.com/react-community/react-native-image-picker#readme",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "react-native start",
|
||||
"test": "yarn validate:eslint && yarn validate:typescript",
|
||||
"validate:eslint": "eslint \"src/**/*.{js,ts,tsx}\" \"example/**/*.{js,ts,tsx}\"",
|
||||
"validate:typescript": "tsc --project ./ --noEmit",
|
||||
"test:jest": "jest \"/src/\"",
|
||||
"ci:publish": "yarn semantic-release",
|
||||
"semantic-release": "semantic-release",
|
||||
"prepare": "bob build"
|
||||
},
|
||||
"keywords": [
|
||||
"react-native",
|
||||
"react-native-image-picker",
|
||||
@ -53,67 +32,23 @@
|
||||
"image",
|
||||
"picker"
|
||||
],
|
||||
"dependencies": {},
|
||||
"scripts": {},
|
||||
"types": "./index.d.ts",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.4.5",
|
||||
"@babel/runtime": "^7.4.5",
|
||||
"@react-native-community/bob": "^0.6.0",
|
||||
"@react-native-community/eslint-config": "^0.0.5",
|
||||
"@semantic-release/changelog": "^3.0.4",
|
||||
"@semantic-release/git": "7.0.12",
|
||||
"@types/jest": "^24.0.15",
|
||||
"@types/react": "^16.8.22",
|
||||
"@types/react-native": "^0.57.63",
|
||||
"@typescript-eslint/eslint-plugin": "^1.11.0",
|
||||
"@typescript-eslint/parser": "^1.11.0",
|
||||
"babel-jest": "^24.8.0",
|
||||
"eslint": "5.16.0",
|
||||
"eslint-config-prettier": "^5.0.0",
|
||||
"eslint-plugin-prettier": "3.0.1",
|
||||
"husky": "^2.4.1",
|
||||
"jest": "^24.8.0",
|
||||
"lint-staged": "^8.2.1",
|
||||
"metro-react-native-babel-preset": "^0.54.1",
|
||||
"prettier": "^1.18.2",
|
||||
"react": "16.8.6",
|
||||
"react-native": "0.60.0-rc.2",
|
||||
"react-test-renderer": "16.8.6",
|
||||
"rimraf": "^2.6.3",
|
||||
"semantic-release": "15.13.16",
|
||||
"ts-jest": "^24.0.2",
|
||||
"typescript": "^3.5.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/react-native-community/react-native-image-picker.git"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
"source": "src",
|
||||
"output": "lib",
|
||||
"targets": [
|
||||
[
|
||||
"commonjs",
|
||||
{
|
||||
"flow": true
|
||||
}
|
||||
],
|
||||
"module",
|
||||
"typescript"
|
||||
]
|
||||
"flow-bin": "0.82.0",
|
||||
"husky": "^1.1.0",
|
||||
"lint-staged": "^7.3.0",
|
||||
"prettier": "1.14.3"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged",
|
||||
"pre-push": "yarn test"
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,tsx}": [
|
||||
"yarn eslint --fix",
|
||||
"git add"
|
||||
],
|
||||
"*.java": [
|
||||
"cd android && ./graldew spotlessApply",
|
||||
"*.{js,json,css,md}": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
]
|
||||
}
|
||||
|
||||
@ -6,13 +6,13 @@ Pod::Spec.new do |s|
|
||||
s.name = package['name']
|
||||
s.version = package['version']
|
||||
s.summary = package['description']
|
||||
s.license = package['license']
|
||||
|
||||
s.authors = package['author']
|
||||
s.authors = { 'Marc Shilling' => 'marcshilling@gmail.com' }
|
||||
s.homepage = package['homepage']
|
||||
s.license = package['license']
|
||||
s.platform = :ios, "7.0"
|
||||
|
||||
s.source = { :git => "https://github.com/react-native-community/react-native-image-picker.git", :tag => "v#{s.version}" }
|
||||
s.source = { :git => "https://github.com/marcshilling/react-native-image-picker" }
|
||||
s.source_files = "ios/*.{h,m}"
|
||||
|
||||
s.dependency 'React'
|
||||
|
||||
93
src/index.ts
93
src/index.ts
@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import NativeInterface from './internal/nativeInterface';
|
||||
import {ImagePickerOptions, ImagePickerResponse} from './internal/types';
|
||||
import {processColor} from 'react-native';
|
||||
|
||||
const DEFAULT_OPTIONS: ImagePickerOptions = {
|
||||
title: 'Select a Photo',
|
||||
cancelButtonTitle: 'Cancel',
|
||||
takePhotoButtonTitle: 'Take Photo…',
|
||||
chooseFromLibraryButtonTitle: 'Choose from Library…',
|
||||
quality: 1.0,
|
||||
allowsEditing: false,
|
||||
permissionDenied: {
|
||||
title: 'Permission denied',
|
||||
text:
|
||||
'To be able to take pictures with your camera and choose images from your library.',
|
||||
reTryTitle: 're-try',
|
||||
okTitle: "I'm sure",
|
||||
},
|
||||
tintColor: '',
|
||||
};
|
||||
|
||||
type Callback = (response: ImagePickerResponse) => void;
|
||||
type OptionsOrCallback = ImagePickerOptions | Callback;
|
||||
|
||||
class ImagePicker {
|
||||
showImagePicker(options: ImagePickerOptions, callback: Callback): void;
|
||||
showImagePicker(callback: Callback): void;
|
||||
|
||||
showImagePicker(
|
||||
optionsOrCallback: OptionsOrCallback,
|
||||
callback?: Callback,
|
||||
): void {
|
||||
if (typeof optionsOrCallback === 'function') {
|
||||
return NativeInterface.showImagePicker(
|
||||
{
|
||||
...DEFAULT_OPTIONS,
|
||||
tintColor: processColor(DEFAULT_OPTIONS.tintColor),
|
||||
},
|
||||
optionsOrCallback,
|
||||
);
|
||||
}
|
||||
|
||||
if (callback == null) {
|
||||
throw new Error('callback cannot be undefined');
|
||||
}
|
||||
|
||||
return NativeInterface.showImagePicker(
|
||||
{
|
||||
...DEFAULT_OPTIONS,
|
||||
...optionsOrCallback,
|
||||
tintColor: processColor(
|
||||
optionsOrCallback.tintColor || DEFAULT_OPTIONS.tintColor,
|
||||
),
|
||||
},
|
||||
callback,
|
||||
);
|
||||
}
|
||||
|
||||
launchCamera(options: ImagePickerOptions, callback: Callback): void {
|
||||
return NativeInterface.launchCamera(
|
||||
{
|
||||
...DEFAULT_OPTIONS,
|
||||
...options,
|
||||
tintColor: processColor(options.tintColor || DEFAULT_OPTIONS.tintColor),
|
||||
},
|
||||
callback,
|
||||
);
|
||||
}
|
||||
|
||||
launchImageLibrary(options: ImagePickerOptions, callback: Callback): void {
|
||||
return NativeInterface.launchImageLibrary(
|
||||
{
|
||||
...DEFAULT_OPTIONS,
|
||||
...options,
|
||||
tintColor: processColor(options.tintColor || DEFAULT_OPTIONS.tintColor),
|
||||
},
|
||||
callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default new ImagePicker();
|
||||
|
||||
export * from './internal/types';
|
||||
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {NativeModules} from 'react-native';
|
||||
import {ImagePickerNativeModule} from './privateTypes';
|
||||
|
||||
const ImagePickerManager: ImagePickerNativeModule | undefined =
|
||||
NativeModules.ImagePickerManager;
|
||||
|
||||
// Produce an error if we don't have the native module
|
||||
if (!ImagePickerManager) {
|
||||
throw new Error(`react-native-image-picker: NativeModule.ImagePickerManager is null. To fix this issue try these steps:
|
||||
• Run \`react-native link react-native-image-picker\` in the project root.
|
||||
• Rebuild and re-run the app.
|
||||
• If you are using CocoaPods on iOS, run \`pod install\` in the \`ios\` directory and then rebuild and re-run the app. You may also need to re-open Xcode to get the new pods.
|
||||
• Check that the library was linked correctly when you used the link command by running through the manual installation instructions in the README.
|
||||
* If you are getting this error while unit testing you need to mock the native module. Follow the guide in the README.
|
||||
If none of these fix the issue, please open an issue on the Github repository: https://github.com/react-native-community/react-native-image-picker`);
|
||||
}
|
||||
|
||||
/**
|
||||
* We export the native interface in this way to give easy shared access to it between the
|
||||
* JavaScript code and the tests
|
||||
*/
|
||||
export default ImagePickerManager as ImagePickerNativeModule;
|
||||
@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {ImagePickerResponse, ImagePickerOptions} from './types';
|
||||
|
||||
export interface ImagePickerNativeModule {
|
||||
showImagePicker(
|
||||
options: ImagePickerOptions,
|
||||
callback: (response: ImagePickerResponse) => void,
|
||||
): void;
|
||||
launchCamera(
|
||||
options: ImagePickerOptions,
|
||||
callback: (response: ImagePickerResponse) => void,
|
||||
): void;
|
||||
launchImageLibrary(
|
||||
options: ImagePickerOptions,
|
||||
callback: (response: ImagePickerResponse) => void,
|
||||
): void;
|
||||
}
|
||||
@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
export interface ImagePickerResponse {
|
||||
customButton: string;
|
||||
didCancel: boolean;
|
||||
error: string;
|
||||
data: string;
|
||||
uri: string;
|
||||
origURL?: string;
|
||||
isVertical: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
fileSize: number;
|
||||
type?: string;
|
||||
fileName?: string;
|
||||
path?: string;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
timestamp?: string;
|
||||
}
|
||||
|
||||
export interface ImagePickerCustomButtonOptions {
|
||||
name?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface ImagePickerOptions {
|
||||
title?: string;
|
||||
cancelButtonTitle?: string;
|
||||
takePhotoButtonTitle?: string;
|
||||
chooseFromLibraryButtonTitle?: string;
|
||||
chooseWhichLibraryTitle?: string;
|
||||
customButtons?: ImagePickerCustomButtonOptions[];
|
||||
cameraType?: 'front' | 'back';
|
||||
mediaType?: 'photo' | 'video' | 'mixed';
|
||||
maxWidth?: number;
|
||||
maxHeight?: number;
|
||||
quality?: number;
|
||||
videoQuality?: 'low' | 'medium' | 'high';
|
||||
durationLimit?: number;
|
||||
rotation?: number;
|
||||
allowsEditing?: boolean;
|
||||
noData?: boolean;
|
||||
storageOptions?: ImagePickerStorageOptions;
|
||||
permissionDenied?: ImagePickerPermissionDeniedOptions;
|
||||
tintColor?: number | string;
|
||||
}
|
||||
|
||||
export interface ImagePickerStorageOptions {
|
||||
skipBackup?: boolean;
|
||||
path?: string;
|
||||
cameraRoll?: boolean;
|
||||
waitUntilSaved?: boolean;
|
||||
privateDirectory?: boolean;
|
||||
}
|
||||
|
||||
export interface ImagePickerPermissionDeniedOptions {
|
||||
title: string;
|
||||
text: string;
|
||||
reTryTitle: string;
|
||||
okTitle: string;
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
{
|
||||
"include": ["src/**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"strict": true,
|
||||
"moduleResolution": "node",
|
||||
"lib": ["es2015", "es2016", "esnext"],
|
||||
"jsx": "react-native"
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user