├── .babelrc ├── ios ├── RNCameraRoll │ ├── RNCameraRoll.h │ └── RNCameraRoll.m └── RNCameraRoll.xcodeproj │ └── project.pbxproj ├── android ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── chrisbianca │ │ └── cameraroll │ │ ├── RNCameraRollPackage.java │ │ └── RNCameraRollModule.java └── build.gradle ├── .editorconfig ├── .watchmanconfig ├── RNCameraRoll.podspec ├── docs ├── installation.ios.md └── installation.android.md ├── .eslintrc ├── LICENSE ├── .npmignore ├── .gitignore ├── index.js ├── package.json ├── README.md └── .flowconfig /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /ios/RNCameraRoll/RNCameraRoll.h: -------------------------------------------------------------------------------- 1 | #import "RCTBridgeModule.h" 2 | 3 | @interface RNCameraRoll : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": [ 3 | ".git", 4 | "node_modules", 5 | "android/build", 6 | "android/.idea", 7 | "ios/.idea", 8 | "android/.gradle", 9 | "android/gradle", 10 | ".idea" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /RNCameraRoll.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | package = JSON.parse(File.read('package.json')) 3 | 4 | Pod::Spec.new do |s| 5 | s.name = "RNCameraRoll" 6 | s.version = package["version"] 7 | s.summary = package["description"] 8 | s.description = <<-DESC 9 | An improved camera roll module for React Native 10 | DESC 11 | s.homepage = "https://github.com/chrisbianca/react-native-cameraroll" 12 | s.license = package['license'] 13 | s.author = "Chris Bianca" 14 | s.source = { :git => "https://github.com/chrisbianca/react-native-cameraroll.git", :tag => "v#{s.version}" } 15 | s.social_media_url = 'http://twitter.com/chrisjbianca' 16 | s.platform = :ios, "8.0" 17 | s.preserve_paths = 'README.md', 'package.json', '*.js' 18 | s.source_files = 'ios/RNCameraRoll/*.{h,m}' 19 | s.dependency 'React' 20 | end 21 | -------------------------------------------------------------------------------- /android/src/main/java/com/chrisbianca/cameraroll/RNCameraRollPackage.java: -------------------------------------------------------------------------------- 1 | package com.chrisbianca.cameraroll; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | public class RNCameraRollPackage implements ReactPackage { 14 | @Override 15 | public List createNativeModules(ReactApplicationContext reactContext) { 16 | List modules = new ArrayList<>(); 17 | 18 | modules.add(new RNCameraRollModule(reactContext)); 19 | 20 | return modules; 21 | } 22 | 23 | @Override 24 | public List createViewManagers(ReactApplicationContext reactContext) { 25 | return Collections.emptyList(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/installation.ios.md: -------------------------------------------------------------------------------- 1 | # iOS Installation 2 | 3 | There are multiple ways to install RNCameraRoll dependent on how your project is currently setup: 4 | 5 | ### 1) Existing Cocoapods setup, including React Native as a pod 6 | Simply add the following to your `Podfile`: 7 | 8 | ```ruby 9 | pod 'RNCameraRoll', :path => '../node_modules/react-native-cameraroll' 10 | ``` 11 | 12 | ### 2) Automatically with react-native-cli 13 | React native ships with a `link` command that can be used to link the projects together, which can help automate the process of linking our package environments. 14 | 15 | ```bash 16 | react-native link react-native-cameraroll 17 | ``` 18 | 19 | ### 3) Manually 20 | 21 | If you prefer not to use `react-native link`, we can manually link the package together with the following steps, after `npm install`: 22 | 23 | **A.** In XCode, right click on `Libraries` and find the `Add Files to [project name]`. 24 | 25 | **B.** Add the `node_modules/react-native-cameraroll/ios/RNCameraRoll.xcodeproj` 26 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "parser": "babel-eslint", 4 | "ecmaFeatures": { 5 | "jsx": true 6 | }, 7 | "plugins": [ 8 | "flowtype" 9 | ], 10 | "env": { 11 | "es6": true, 12 | "jasmine": true 13 | }, 14 | "parserOptions": { 15 | "ecmaFeatures": { 16 | "experimentalObjectRestSpread": true 17 | } 18 | }, 19 | "rules": { 20 | "class-methods-use-this": 0, 21 | "no-plusplus": 0, 22 | "no-underscore-dangle": 0, 23 | "no-return-assign": 0, 24 | "no-undef": 0, 25 | "no-use-before-define": 0, 26 | "arrow-body-style": 0, 27 | "import/prefer-default-export": 0, 28 | "radix": 0, 29 | "new-cap": 0, 30 | "max-len": 0, 31 | "no-continue": 0, 32 | "no-console": 0, 33 | "global-require": 0, 34 | "import/extensions": 0, 35 | "import/no-unresolved": 0, 36 | "import/no-extraneous-dependencies": 0, 37 | "react/jsx-filename-extension": 0 38 | }, 39 | "globals": { 40 | "__DEV__": true, 41 | "window": true 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Chris Bianca 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | *.DS_Store 4 | 5 | # Xcode 6 | *.pbxuser 7 | *.mode1v3 8 | *.mode2v3 9 | *.perspectivev3 10 | *.xcuserstate 11 | project.xcworkspace/ 12 | xcuserdata/ 13 | 14 | # Android 15 | 16 | # Built application files 17 | android/*/build/ 18 | 19 | # Crashlytics configuations 20 | android/com_crashlytics_export_strings.xml 21 | 22 | # Local configuration file (sdk path, etc) 23 | android/local.properties 24 | 25 | # Gradle generated files 26 | android/.gradle/ 27 | 28 | # Signing files 29 | android/.signing/ 30 | 31 | # User-specific configurations 32 | android/.idea/gradle.xml 33 | android/.idea/libraries/ 34 | android/.idea/workspace.xml 35 | android/.idea/tasks.xml 36 | android/.idea/.name 37 | android/.idea/compiler.xml 38 | android/.idea/copyright/profiles_settings.xml 39 | android/.idea/encodings.xml 40 | android/.idea/misc.xml 41 | android/.idea/modules.xml 42 | android/.idea/scopes/scope_settings.xml 43 | android/.idea/vcs.xml 44 | android/*.iml 45 | 46 | # OS-specific files 47 | .DS_Store 48 | .DS_Store? 49 | ._* 50 | .Spotlight-V100 51 | .Trashes 52 | ehthumbs.db 53 | Thumbs.dbandroid/gradle 54 | android/gradlew 55 | android/build 56 | android/gradlew.bat 57 | android/gradle/ 58 | docs 59 | .idea 60 | coverage 61 | yarn.lock 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | *.DS_Store 4 | 5 | # Xcode 6 | *.pbxuser 7 | *.mode1v3 8 | *.mode2v3 9 | *.perspectivev3 10 | *.xcuserstate 11 | project.xcworkspace/ 12 | xcuserdata/ 13 | 14 | # Android 15 | 16 | # Built application files 17 | android/*/build/ 18 | 19 | # Crashlytics configuations 20 | android/com_crashlytics_export_strings.xml 21 | 22 | # Local configuration file (sdk path, etc) 23 | android/local.properties 24 | 25 | # Gradle generated files 26 | android/.gradle/ 27 | 28 | # Signing files 29 | android/.signing/ 30 | 31 | # User-specific configurations 32 | android/.idea/gradle.xml 33 | android/.idea/libraries/ 34 | android/.idea/workspace.xml 35 | android/.idea/tasks.xml 36 | android/.idea/.name 37 | android/.idea/compiler.xml 38 | android/.idea/copyright/profiles_settings.xml 39 | android/.idea/encodings.xml 40 | android/.idea/misc.xml 41 | android/.idea/modules.xml 42 | android/.idea/scopes/scope_settings.xml 43 | android/.idea/vcs.xml 44 | android/*.iml 45 | 46 | # OS-specific files 47 | .DS_Store 48 | .DS_Store? 49 | ._* 50 | .Spotlight-V100 51 | .Trashes 52 | ehthumbs.db 53 | Thumbs.dbandroid/gradle 54 | android/gradlew 55 | android/build 56 | android/gradlew.bat 57 | android/gradle/ 58 | .idea 59 | .idea 60 | coverage 61 | yarn.lock 62 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { NativeModules } from 'react-native'; 3 | 4 | const RNCameraRollModule = NativeModules.RNCameraRoll; 5 | 6 | export type AssetRequestType = "image" | "video" | "all"; 7 | export type AssetType = "image" | "video"; 8 | 9 | export type GetAssetsParams = { 10 | assetType: AssetRequestType; 11 | limit: number; 12 | start?: string | number; 13 | } 14 | 15 | export type Location = { 16 | altitude?: number; 17 | heading?: number; 18 | latitude: number; 19 | longitude: number; 20 | speed?: number; 21 | } 22 | 23 | export type Asset = { 24 | filename: string; 25 | height: number; 26 | location: Location; 27 | timestamp: number; 28 | type: AssetType; 29 | uri: string; 30 | width: number; 31 | } 32 | 33 | export type PageInfo = { 34 | end_cursor: string | number; 35 | has_next_page: boolean; 36 | start_cursor: string | number; 37 | } 38 | 39 | export type GetAssetsResponse = { 40 | assets: Array; 41 | page_info: PageInfo; 42 | } 43 | 44 | /** 45 | * @class RNCameraRoll 46 | */ 47 | export default class RNCameraRoll { 48 | /** 49 | * @param params 50 | * @returns {Promise} 51 | */ 52 | static getAssets(params: GetAssetsParams) : Promise { 53 | return RNCameraRollModule.getAssets(params); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // START - required to allow working on this project inside Android Studio 2 | // YES, jcenter is required twice - it somehow tricks studio into compiling deps below 3 | // doesn't break anything anywhere else and projects using this lib work as normal 4 | buildscript { 5 | repositories { 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:2.1.3' 10 | } 11 | } 12 | // END 13 | 14 | apply plugin: 'com.android.library' 15 | 16 | android { 17 | compileSdkVersion 25 18 | buildToolsVersion "23.0.3" 19 | 20 | defaultConfig { 21 | minSdkVersion 16 22 | targetSdkVersion 25 23 | versionCode 1 24 | versionName "1.0" 25 | multiDexEnabled true 26 | } 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | } 31 | } 32 | } 33 | 34 | // START - required to allow working on this project inside Android Studio 35 | // YES, jcenter is required twice - it somehow tricks studio into compiling deps below 36 | // doesn't break anything anywhere else and projects using this lib work as normal 37 | // you'll now have code completion/validation and all the other AS goodies. 38 | allprojects { 39 | repositories { 40 | jcenter() 41 | } 42 | } 43 | // END 44 | 45 | dependencies { 46 | compile fileTree(include: ['*.jar'], dir: 'libs') 47 | compile 'com.facebook.react:react-native:+' 48 | } 49 | -------------------------------------------------------------------------------- /docs/installation.android.md: -------------------------------------------------------------------------------- 1 | # Android Installation 2 | 3 | The simplest way of installing on Android is to use the react-native link CLI command & rebuild the project: 4 | 5 | ``` 6 | react-native link react-native-cameraroll 7 | ``` 8 | 9 | ## Manually 10 | 11 | To install `react-native-cameraroll` manually in our project, we'll need to import the package from `com.chrisbianca.cameraroll` in our project's `android/app/src/main/java/com/[app name]/MainApplication.java` and list it as a package for ReactNative in the `getPackages()` function: 12 | 13 | ```java 14 | package com.youcompany.application; 15 | // ... 16 | import com.chrisbianca.cameraroll.RNCameraRollPackage; 17 | // ... 18 | public class MainApplication extends Application implements ReactApplication { 19 | // ... 20 | 21 | @Override 22 | protected List getPackages() { 23 | return Arrays.asList( 24 | new MainReactPackage(), 25 | new RNCameraRollPackage() // <-- Add this line 26 | ); 27 | } 28 | }; 29 | // ... 30 | } 31 | ``` 32 | 33 | We'll also need to list it in our `android/app/build.gradle` file as a dependency that we want React Native to compile. In the `dependencies` listing, add the `compile` line: 34 | 35 | ```java 36 | dependencies { 37 | compile project(':react-native-cameraroll') 38 | } 39 | ``` 40 | 41 | Add the project path to `android/settings.gradle`: 42 | 43 | ``` 44 | include ':react-native-cameraroll' 45 | project(':react-native-cameraroll').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-cameraroll/android') 46 | ``` 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-cameraroll", 3 | "version": "1.1.0-alpha1", 4 | "description": "A replacement camera roll module for React Native", 5 | "main": "index.js", 6 | "scripts": { 7 | "flow": "flow", 8 | "lint": "eslint ./src" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/chrisbianca/react-native-cameraroll.git" 13 | }, 14 | "author": "Chris Bianca ", 15 | "license": "MIT", 16 | "keywords": [ 17 | "react", 18 | "react-native", 19 | "react-native-cameraroll", 20 | "camera", 21 | "cameraroll" 22 | ], 23 | "bugs": { 24 | "url": "https://github.com/chrisbianca/react-native-cameraroll/issues" 25 | }, 26 | "homepage": "https://github.com/chrisbianca/react-native-cameraroll#readme", 27 | "peerDependencies": { 28 | "react": "*", 29 | "react-native": "*" 30 | }, 31 | "rnpm": { 32 | "ios": { 33 | "project": "ios/RNCameraRoll.xcodeproj" 34 | }, 35 | "android": { 36 | "packageInstance": "new RNCameraRollPackage()" 37 | } 38 | }, 39 | "devDependencies": { 40 | "babel-eslint": "^7.0.0", 41 | "babel-jest": "^14.1.0", 42 | "babel-preset-react-native": "^1.9.0", 43 | "debug": "^2.2.0", 44 | "enzyme": "^2.4.1", 45 | "eslint": "^3.19.0", 46 | "eslint-config-airbnb": "^14.1.0", 47 | "eslint-plugin-flowtype": "^2.30.4", 48 | "eslint-plugin-import": "^2.2.0", 49 | "eslint-plugin-jsx-a11y": "^4.0.0", 50 | "eslint-plugin-react": "^6.10.3", 51 | "flow-bin": "^0.40.0", 52 | "react": "^15.3.0", 53 | "react-dom": "^15.3.0", 54 | "react-native": "^0.42.0" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Camera Roll 2 | 3 | [![npm version](https://img.shields.io/npm/v/react-native-cameraroll.svg)](https://www.npmjs.com/package/react-native-cameraroll) 4 | [![License](https://img.shields.io/npm/l/react-native-cameraroll.svg)](/LICENSE) 5 | 6 | **RNCameraRoll** is a replacement CameraRoll module for React Native that offers consistent behaviour across iOS and Android 7 |
8 | 9 | ### Install 10 | ``` 11 | npm i react-native-cameraroll --save 12 | ``` 13 | 14 | #### Platform specific setup guides: 15 | [![ios](https://a.fsdn.com/sd/topics/ios_64.png)](docs/installation.ios.md) [![android](https://a.fsdn.com/sd/topics/android_64.png)](docs/installation.android.md) 16 | 17 |
18 | 19 | ### Usage 20 | 21 | `import RNCameraRoll from 'react-native-cameraroll';` 22 | 23 | #### `getAssets(params: Object): Promise` 24 | 25 | Retrieve image and/or video assets from the device's Camera Roll. 26 | 27 | ```javascript 28 | RNCameraRoll.getAssets({ assetType: 'image', limit: 20 }) 29 | .then(response => console.log(response)) 30 | .catch(err => console.error(err)); 31 | ``` 32 | 33 | `params` takes the following shape: 34 | ``` 35 | { 36 | assetType: 'image' | 'video' | 'all'; 37 | limit: number; // How many assets to return 38 | start?: string | number; // The start cursor (use end_cursor from previous request) 39 | } 40 | ``` 41 | 42 | The response takes the following shape: 43 | ``` 44 | { 45 | assets: [{ 46 | filename: string; 47 | height: number; 48 | location: { 49 | altitude?: number; 50 | heading?: number; 51 | latitude: number; 52 | longitude: number; 53 | speed?: number; 54 | }; 55 | timestamp: number; 56 | type: 'image' | 'video'; 57 | uri: string; 58 | width: number; 59 | }], 60 | page_info: { 61 | end_cursor: string | number; 62 | has_next_page: boolean; 63 | start_cursor: string | number; 64 | }; 65 | } 66 | ``` 67 | 68 |
69 | 70 | ### Contributing 71 | 72 | We welcome any contribution to the repository. Please ensure your changes to the JavaScript code follow the styling guides controlled by ESlint. Changes to native code should be kept clean and follow the standard of existing code. 73 | 74 |
75 | 76 | ### License 77 | 78 | - MIT 79 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | 4 | # Some modules have their own node_modules with overlap 5 | .*/node_modules/node-haste/.* 6 | 7 | 8 | # React Native problems 9 | .*/node_modules/react-native/Libraries/Animated/src/AnimatedInterpolation.js 10 | .*/node_modules/react-native/Libraries/Animated/src/Interpolation.js 11 | .*/node_modules/react-native/Libraries/BugReporting/dumpReactTree.js 12 | .*/node_modules/react-native/Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js 13 | .*/node_modules/react-native/Libraries/CustomComponents/NavigationExperimental/NavigationPagerStyleInterpolater.js 14 | .*/node_modules/react-native/Libraries/Experimental/WindowedListView.js 15 | .*/node_modules/react-native/Libraries/Image/Image.io.js 16 | .*/node_modules/react-native/Libraries/NavigationExperimental/NavigationExperimental.js 17 | .*/node_modules/react-native/Libraries/NavigationExperimental/NavigationHeaderStyleInterpolator.js 18 | .*/node_modules/react-native/Libraries/Network/FormData.js 19 | .*/node_modules/react-native/Libraries/ReactIOS/YellowBox.js 20 | 21 | 22 | 23 | # Ignore react and fbjs where there are overlaps, but don't ignore 24 | # anything that react-native relies on 25 | .*/node_modules/fbjs/lib/Map.js 26 | .*/node_modules/fbjs/lib/ErrorUtils.js 27 | 28 | # Flow has a built-in definition for the 'react' module which we prefer to use 29 | # over the currently-untyped source 30 | .*/node_modules/react/react.js 31 | .*/node_modules/react/lib/React.js 32 | .*/node_modules/react/lib/ReactDOM.js 33 | 34 | .*/__mocks__/.* 35 | .*/__tests__/.* 36 | 37 | .*/commoner/test/source/widget/share.js 38 | 39 | # Ignore commoner tests 40 | .*/node_modules/commoner/test/.* 41 | 42 | # See https://github.com/facebook/flow/issues/442 43 | .*/react-tools/node_modules/commoner/lib/reader.js 44 | 45 | # Ignore jest 46 | .*/node_modules/jest-cli/.* 47 | 48 | # Ignore Website 49 | .*/website/.* 50 | 51 | # Ignore generators 52 | .*/local-cli/generator.* 53 | 54 | # Ignore BUCK generated folders 55 | .*\.buckd/ 56 | 57 | .*/node_modules/is-my-json-valid/test/.*\.json 58 | .*/node_modules/iconv-lite/encodings/tables/.*\.json 59 | .*/node_modules/y18n/test/.*\.json 60 | .*/node_modules/spdx-license-ids/spdx-license-ids.json 61 | .*/node_modules/spdx-exceptions/index.json 62 | .*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json 63 | .*/node_modules/resolve/lib/core.json 64 | .*/node_modules/jsonparse/samplejson/.*\.json 65 | .*/node_modules/json5/test/.*\.json 66 | .*/node_modules/ua-parser-js/test/.*\.json 67 | .*/node_modules/builtin-modules/builtin-modules.json 68 | .*/node_modules/binary-extensions/binary-extensions.json 69 | .*/node_modules/url-regex/tlds.json 70 | .*/node_modules/joi/.*\.json 71 | .*/node_modules/isemail/.*\.json 72 | .*/node_modules/tr46/.*\.json 73 | .*/node_modules/protobufjs/src/bower.json 74 | .*/node_modules/grpc/node_modules/protobufjs/src/bower.json 75 | 76 | [include] 77 | node_modules/fbjs/lib 78 | 79 | [libs] 80 | lib/flow.js 81 | node_modules/react-native/Libraries/react-native/react-native-interface.js 82 | node_modules/react-native/flow 83 | node_modules/fbjs/flow/lib 84 | 85 | [options] 86 | module.system=haste 87 | 88 | experimental.strict_type_args=true 89 | unsafe.enable_getters_and_setters=true 90 | 91 | esproposal.class_static_fields=enable 92 | esproposal.class_instance_fields=enable 93 | 94 | munge_underscores=true 95 | 96 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 97 | 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' 98 | 99 | suppress_type=$FlowIssue 100 | suppress_type=$FlowFixMe 101 | suppress_type=$FixMe 102 | 103 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-4]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 104 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-4]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 105 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 106 | 107 | [version] 108 | ^0.40.0 109 | -------------------------------------------------------------------------------- /ios/RNCameraRoll/RNCameraRoll.m: -------------------------------------------------------------------------------- 1 | #import "RNCameraRoll.h" 2 | 3 | #import 4 | 5 | #import 6 | #import 7 | #import 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | 14 | #import "RCTAssetsLibraryRequestHandler.h" 15 | 16 | @implementation RNCameraRoll 17 | 18 | RCT_EXPORT_MODULE() 19 | 20 | NSString *const RCTErrorInvalidAssetType = @"E_INVALID_ASSET_TYPE"; 21 | NSString *const RCTErrorPermissionDenied = @"ERROR_PERMISSION_DENIED"; 22 | 23 | 24 | RCT_EXPORT_METHOD(getAssets:(NSDictionary *)params 25 | resolve:(RCTPromiseResolveBlock)resolve 26 | reject:(RCTPromiseRejectBlock)reject) 27 | { 28 | checkPhotoLibraryConfig(); 29 | 30 | PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 31 | if (status == PHAuthorizationStatusDenied || status == PHAuthorizationStatusRestricted) { 32 | reject(RCTErrorPermissionDenied, nil, nil); 33 | return; 34 | } else if (status == PHAuthorizationStatusNotDetermined) { 35 | //prompt for access 36 | [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 37 | if (status == PHAuthorizationStatusAuthorized) { 38 | [self loadAssets:params resolve:resolve reject:reject]; 39 | } else { 40 | reject(RCTErrorPermissionDenied, nil, nil); 41 | return; 42 | } 43 | }]; 44 | } else { 45 | [self loadAssets:params resolve:resolve reject:reject]; 46 | } 47 | } 48 | 49 | - (void) loadAssets:(NSDictionary *) params 50 | resolve:(RCTPromiseResolveBlock) resolve 51 | reject:(RCTPromiseRejectBlock)reject 52 | { 53 | NSUInteger startParam = [RCTConvert NSInteger:params[@"start"]]; 54 | NSUInteger limitParam = [RCTConvert NSInteger:params[@"limit"]]; 55 | NSString *assetTypeParam = [RCTConvert NSString:params[@"assetType"]]; 56 | 57 | PHAssetMediaType assetType; 58 | if ([assetTypeParam isEqualToString:@"image"]) { 59 | assetType = PHAssetMediaTypeImage; 60 | } else if ([assetTypeParam isEqualToString:@"video"]) { 61 | assetType = PHAssetMediaTypeVideo; 62 | } else { 63 | RCTLogError(@"Invalid assetType %@", assetTypeParam); 64 | reject(RCTErrorInvalidAssetType, nil, nil); 65 | return; 66 | } 67 | 68 | PHFetchOptions *allPhotosOptions = [PHFetchOptions new]; 69 | allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]; 70 | 71 | PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithMediaType:assetType options:allPhotosOptions]; 72 | 73 | NSInteger startIndex = startParam ? startParam : 0; 74 | NSInteger length = !limitParam || startIndex + limitParam > allPhotosResult.count ? allPhotosResult.count - startIndex : limitParam; 75 | NSMutableArray *> *assets = [NSMutableArray new]; 76 | 77 | [allPhotosResult enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(startIndex, length)] 78 | options:0 79 | usingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) { 80 | PHAssetMediaType assetType = [asset mediaType]; 81 | [assets addObject:@{ 82 | @"type": assetType == PHAssetMediaTypeImage ? @"image" : @"video", 83 | @"uri": [NSString stringWithFormat:@"ph://%@", asset.localIdentifier], 84 | @"filename": [asset valueForKey:@"filename"], 85 | @"height": @(asset.pixelHeight), 86 | @"width": @(asset.pixelWidth), 87 | @"timestamp": @(asset.creationDate.timeIntervalSince1970), 88 | @"location": asset.location ? @{ 89 | @"latitude": @(asset.location.coordinate.latitude), 90 | @"longitude": @(asset.location.coordinate.longitude), 91 | @"altitude": @(asset.location.altitude), 92 | @"heading": @(asset.location.course), 93 | @"speed": @(asset.location.speed), 94 | } : [NSNull null], 95 | }]; 96 | }]; 97 | resolve(@{ 98 | @"assets": assets, 99 | @"page_info": @{ 100 | @"end_cursor": @(startIndex + length), 101 | @"has_next_page": @(startIndex + length < allPhotosResult.count), 102 | @"start_cursor": @(startIndex), 103 | } 104 | }); 105 | } 106 | 107 | static void checkPhotoLibraryConfig() 108 | { 109 | #if RCT_DEV 110 | if (![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSPhotoLibraryUsageDescription"]) { 111 | RCTLogError(@"NSPhotoLibraryUsageDescription key must be present in Info.plist to use camera roll."); 112 | } 113 | #endif 114 | } 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /android/src/main/java/com/chrisbianca/cameraroll/RNCameraRollModule.java: -------------------------------------------------------------------------------- 1 | package com.chrisbianca.cameraroll; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.AsyncTask; 8 | import android.provider.MediaStore; 9 | import android.provider.MediaStore.Images; 10 | import android.text.TextUtils; 11 | 12 | import com.facebook.react.bridge.GuardedAsyncTask; 13 | import com.facebook.react.bridge.Promise; 14 | import com.facebook.react.bridge.ReactApplicationContext; 15 | import com.facebook.react.bridge.ReactContext; 16 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 17 | import com.facebook.react.bridge.ReactMethod; 18 | import com.facebook.react.bridge.ReadableMap; 19 | import com.facebook.react.bridge.WritableArray; 20 | import com.facebook.react.bridge.WritableMap; 21 | import com.facebook.react.bridge.WritableNativeArray; 22 | import com.facebook.react.bridge.WritableNativeMap; 23 | import com.facebook.react.module.annotations.ReactModule; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import javax.annotation.Nullable; 29 | 30 | @ReactModule(name = "RNCameraRoll") 31 | public class RNCameraRollModule extends ReactContextBaseJavaModule { 32 | 33 | private static final String ERROR_INVALID_ASSET_TYPE = "E_INVALID_ASSET_TYPE"; 34 | private static final String ERROR_PERMISSION_DENIED = "E_PERMISSION_DENIED"; 35 | private static final String ERROR_UNABLE_TO_LOAD = "E_UNABLE_TO_LOAD"; 36 | 37 | private static final String[] FIELDS = new String[] { 38 | Images.Media._ID, 39 | Images.Media.MIME_TYPE, 40 | Images.Media.BUCKET_DISPLAY_NAME, 41 | Images.Media.DATE_TAKEN, 42 | Images.Media.WIDTH, 43 | Images.Media.HEIGHT, 44 | Images.Media.LONGITUDE, 45 | Images.Media.LATITUDE, 46 | Images.Media.DISPLAY_NAME 47 | }; 48 | 49 | private static final String QUERY_DATE_TAKEN = Images.Media.DATE_TAKEN + " < ?"; 50 | 51 | public RNCameraRollModule(ReactApplicationContext reactContext) { 52 | super(reactContext); 53 | } 54 | 55 | @Override 56 | public String getName() { 57 | return "RNCameraRoll"; 58 | } 59 | 60 | @ReactMethod 61 | public void getAssets(final ReadableMap params, final Promise promise) { 62 | String start = params.hasKey("start") ? params.getString("start") : null; 63 | int limit = params.getInt("limit"); 64 | String assetType = params.getString("assetType"); 65 | 66 | new GetAssetsTask( 67 | getReactApplicationContext(), 68 | start, 69 | limit, 70 | assetType, 71 | promise) 72 | .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 73 | } 74 | 75 | private static class GetAssetsTask extends GuardedAsyncTask { 76 | private final Context mContext; 77 | private final @Nullable String mStart; 78 | private final int mLimit; 79 | private final @Nullable String mAssetType; 80 | private final Promise mPromise; 81 | 82 | private GetAssetsTask( 83 | ReactContext context, 84 | @Nullable String start, 85 | int limit, 86 | @Nullable String assetType, 87 | Promise promise) { 88 | super(context); 89 | mContext = context; 90 | mStart = start; 91 | mLimit = limit; 92 | mAssetType = assetType; 93 | mPromise = promise; 94 | } 95 | 96 | @Override 97 | protected void doInBackgroundGuarded(Void... params) { 98 | StringBuilder query = new StringBuilder("1"); 99 | List queryArgs = new ArrayList<>(); 100 | if (!TextUtils.isEmpty(mStart)) { 101 | query.append(" AND " + QUERY_DATE_TAKEN); 102 | queryArgs.add(mStart); 103 | } 104 | Uri uri; 105 | if (mAssetType == null || "all".equals(mAssetType)) { 106 | uri = MediaStore.Files.getContentUri("external"); 107 | query.append(" AND (" + Images.Media.MIME_TYPE + " LIKE ? OR " 108 | + Images.Media.MIME_TYPE + " LIKE ?) "); 109 | queryArgs.add("image/%"); 110 | queryArgs.add("video/%"); 111 | } else if ("image".equals(mAssetType)) { 112 | uri = Images.Media.EXTERNAL_CONTENT_URI; 113 | query.append(" AND " + Images.Media.MIME_TYPE + " LIKE ? "); 114 | queryArgs.add("image/%"); 115 | } else if ("video".equals(mAssetType)) { 116 | uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 117 | query.append(" AND " + Images.Media.MIME_TYPE + " LIKE ? "); 118 | queryArgs.add("video/%"); 119 | } else { 120 | mPromise.reject(ERROR_INVALID_ASSET_TYPE, "Invalid assetType: " + mAssetType); 121 | return; 122 | } 123 | WritableMap response = new WritableNativeMap(); 124 | ContentResolver resolver = mContext.getContentResolver(); 125 | try { 126 | Cursor assetsCursor = resolver.query( 127 | uri, 128 | FIELDS, 129 | query.toString(), 130 | queryArgs.toArray(new String[queryArgs.size()]), 131 | Images.Media.DATE_TAKEN + " DESC, " + Images.Media.DATE_MODIFIED + 132 | " DESC LIMIT " + (mLimit + 1)); 133 | if (assetsCursor == null) { 134 | mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get assets"); 135 | } else { 136 | try { 137 | response.putArray("assets", buildAssets(assetsCursor, response, mLimit)); 138 | response.putMap("page_info", buildPageInfo(assetsCursor, response, mLimit)); 139 | } finally { 140 | assetsCursor.close(); 141 | mPromise.resolve(response); 142 | } 143 | } 144 | } catch (SecurityException e) { 145 | mPromise.reject( 146 | ERROR_PERMISSION_DENIED, 147 | "Could not get assets: need READ_EXTERNAL_STORAGE permission", 148 | e); 149 | } 150 | } 151 | } 152 | 153 | private static WritableMap buildPageInfo(Cursor assetsCursor, WritableMap response, int limit) { 154 | WritableMap pageInfo = new WritableNativeMap(); 155 | pageInfo.putBoolean("has_next_page", limit < assetsCursor.getCount()); 156 | if (limit < assetsCursor.getCount()) { 157 | assetsCursor.moveToPosition(limit - 1); 158 | pageInfo.putString("end_cursor", 159 | assetsCursor.getString(assetsCursor.getColumnIndex(Images.Media.DATE_TAKEN))); 160 | } 161 | return pageInfo; 162 | } 163 | 164 | private static WritableArray buildAssets(Cursor assetsCursor, WritableMap response, 165 | int limit) { 166 | assetsCursor.moveToFirst(); 167 | int idIndex = assetsCursor.getColumnIndex(Images.Media._ID); 168 | int mimeTypeIndex = assetsCursor.getColumnIndex(Images.Media.MIME_TYPE); 169 | int dateTakenIndex = assetsCursor.getColumnIndex(Images.Media.DATE_TAKEN); 170 | int widthIndex = assetsCursor.getColumnIndex(Images.Media.WIDTH); 171 | int heightIndex = assetsCursor.getColumnIndex(Images.Media.HEIGHT); 172 | int longitudeIndex = assetsCursor.getColumnIndex(Images.Media.LONGITUDE); 173 | int latitudeIndex = assetsCursor.getColumnIndex(Images.Media.LATITUDE); 174 | int filenameIndex = assetsCursor.getColumnIndex(Images.Media.DISPLAY_NAME); 175 | 176 | WritableArray assets = new WritableNativeArray(); 177 | for (int i = 0; i < limit && !assetsCursor.isAfterLast(); i++) { 178 | WritableMap asset = new WritableNativeMap(); 179 | asset.putDouble("width", assetsCursor.getInt(widthIndex)); 180 | asset.putDouble("height", assetsCursor.getInt(heightIndex)); 181 | asset.putString("filename", assetsCursor.getString(filenameIndex)); 182 | asset.putDouble("timestamp", assetsCursor.getLong(dateTakenIndex) / 1000d); 183 | 184 | String mimeType = assetsCursor.getString(mimeTypeIndex); 185 | if (mimeType.startsWith("image/")) { 186 | Uri photoUri = Uri.withAppendedPath(Images.Media.EXTERNAL_CONTENT_URI, 187 | assetsCursor.getString(idIndex)); 188 | asset.putString("uri", photoUri.toString()); 189 | asset.putString("type", "image"); 190 | } else { 191 | Uri videoUri = Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, 192 | assetsCursor.getString(idIndex)); 193 | asset.putString("uri", videoUri.toString()); 194 | asset.putString("type", "video"); 195 | } 196 | 197 | double longitude = assetsCursor.getDouble(longitudeIndex); 198 | double latitude = assetsCursor.getDouble(latitudeIndex); 199 | if (longitude > 0 || latitude > 0) { 200 | WritableMap location = new WritableNativeMap(); 201 | location.putDouble("longitude", longitude); 202 | location.putDouble("latitude", latitude); 203 | asset.putMap("location", location); 204 | } 205 | 206 | assets.pushMap(asset); 207 | assetsCursor.moveToNext(); 208 | } 209 | return assets; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /ios/RNCameraRoll.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 839036B31E92BD0A00B483AD /* RNCameraRoll.m in Sources */ = {isa = PBXBuildFile; fileRef = 839036B21E92BD0A00B483AD /* RNCameraRoll.m */; }; 11 | 839036B41E92BD0A00B483AD /* RNCameraRoll.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 839036B11E92BD0A00B483AD /* RNCameraRoll.h */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | 839036AC1E92BD0A00B483AD /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = "include/$(PRODUCT_NAME)"; 19 | dstSubfolderSpec = 16; 20 | files = ( 21 | 839036B41E92BD0A00B483AD /* RNCameraRoll.h in CopyFiles */, 22 | ); 23 | runOnlyForDeploymentPostprocessing = 0; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 839036AE1E92BD0A00B483AD /* libRNCameraRoll.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCameraRoll.a; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 839036B11E92BD0A00B483AD /* RNCameraRoll.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCameraRoll.h; sourceTree = ""; }; 30 | 839036B21E92BD0A00B483AD /* RNCameraRoll.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCameraRoll.m; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | 839036AB1E92BD0A00B483AD /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | 839036A51E92BD0A00B483AD = { 45 | isa = PBXGroup; 46 | children = ( 47 | 839036B01E92BD0A00B483AD /* RNCameraRoll */, 48 | 839036AF1E92BD0A00B483AD /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | 839036AF1E92BD0A00B483AD /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 839036AE1E92BD0A00B483AD /* libRNCameraRoll.a */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | 839036B01E92BD0A00B483AD /* RNCameraRoll */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 839036B11E92BD0A00B483AD /* RNCameraRoll.h */, 64 | 839036B21E92BD0A00B483AD /* RNCameraRoll.m */, 65 | ); 66 | path = RNCameraRoll; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | 839036AD1E92BD0A00B483AD /* RNCameraRoll */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = 839036B71E92BD0B00B483AD /* Build configuration list for PBXNativeTarget "RNCameraRoll" */; 75 | buildPhases = ( 76 | 839036AA1E92BD0A00B483AD /* Sources */, 77 | 839036AB1E92BD0A00B483AD /* Frameworks */, 78 | 839036AC1E92BD0A00B483AD /* CopyFiles */, 79 | ); 80 | buildRules = ( 81 | ); 82 | dependencies = ( 83 | ); 84 | name = RNCameraRoll; 85 | productName = RNCameraRoll; 86 | productReference = 839036AE1E92BD0A00B483AD /* libRNCameraRoll.a */; 87 | productType = "com.apple.product-type.library.static"; 88 | }; 89 | /* End PBXNativeTarget section */ 90 | 91 | /* Begin PBXProject section */ 92 | 839036A61E92BD0A00B483AD /* Project object */ = { 93 | isa = PBXProject; 94 | attributes = { 95 | LastUpgradeCheck = 0830; 96 | ORGANIZATIONNAME = "Christopher Bianca"; 97 | TargetAttributes = { 98 | 839036AD1E92BD0A00B483AD = { 99 | CreatedOnToolsVersion = 8.3; 100 | ProvisioningStyle = Automatic; 101 | }; 102 | }; 103 | }; 104 | buildConfigurationList = 839036A91E92BD0A00B483AD /* Build configuration list for PBXProject "RNCameraRoll" */; 105 | compatibilityVersion = "Xcode 3.2"; 106 | developmentRegion = English; 107 | hasScannedForEncodings = 0; 108 | knownRegions = ( 109 | en, 110 | ); 111 | mainGroup = 839036A51E92BD0A00B483AD; 112 | productRefGroup = 839036AF1E92BD0A00B483AD /* Products */; 113 | projectDirPath = ""; 114 | projectRoot = ""; 115 | targets = ( 116 | 839036AD1E92BD0A00B483AD /* RNCameraRoll */, 117 | ); 118 | }; 119 | /* End PBXProject section */ 120 | 121 | /* Begin PBXSourcesBuildPhase section */ 122 | 839036AA1E92BD0A00B483AD /* Sources */ = { 123 | isa = PBXSourcesBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | 839036B31E92BD0A00B483AD /* RNCameraRoll.m in Sources */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXSourcesBuildPhase section */ 131 | 132 | /* Begin XCBuildConfiguration section */ 133 | 839036B51E92BD0A00B483AD /* Debug */ = { 134 | isa = XCBuildConfiguration; 135 | buildSettings = { 136 | ALWAYS_SEARCH_USER_PATHS = NO; 137 | CLANG_ANALYZER_NONNULL = YES; 138 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 139 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 140 | CLANG_CXX_LIBRARY = "libc++"; 141 | CLANG_ENABLE_MODULES = YES; 142 | CLANG_ENABLE_OBJC_ARC = YES; 143 | CLANG_WARN_BOOL_CONVERSION = YES; 144 | CLANG_WARN_CONSTANT_CONVERSION = YES; 145 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 146 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 147 | CLANG_WARN_EMPTY_BODY = YES; 148 | CLANG_WARN_ENUM_CONVERSION = YES; 149 | CLANG_WARN_INFINITE_RECURSION = YES; 150 | CLANG_WARN_INT_CONVERSION = YES; 151 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 152 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 153 | CLANG_WARN_UNREACHABLE_CODE = YES; 154 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 155 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 156 | COPY_PHASE_STRIP = NO; 157 | DEBUG_INFORMATION_FORMAT = dwarf; 158 | ENABLE_STRICT_OBJC_MSGSEND = YES; 159 | ENABLE_TESTABILITY = YES; 160 | GCC_C_LANGUAGE_STANDARD = gnu99; 161 | GCC_DYNAMIC_NO_PIC = NO; 162 | GCC_NO_COMMON_BLOCKS = YES; 163 | GCC_OPTIMIZATION_LEVEL = 0; 164 | GCC_PREPROCESSOR_DEFINITIONS = ( 165 | "DEBUG=1", 166 | "$(inherited)", 167 | ); 168 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 169 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 170 | GCC_WARN_UNDECLARED_SELECTOR = YES; 171 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 172 | GCC_WARN_UNUSED_FUNCTION = YES; 173 | GCC_WARN_UNUSED_VARIABLE = YES; 174 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 175 | MTL_ENABLE_DEBUG_INFO = YES; 176 | ONLY_ACTIVE_ARCH = YES; 177 | SDKROOT = iphoneos; 178 | }; 179 | name = Debug; 180 | }; 181 | 839036B61E92BD0A00B483AD /* Release */ = { 182 | isa = XCBuildConfiguration; 183 | buildSettings = { 184 | ALWAYS_SEARCH_USER_PATHS = NO; 185 | CLANG_ANALYZER_NONNULL = YES; 186 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 187 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 188 | CLANG_CXX_LIBRARY = "libc++"; 189 | CLANG_ENABLE_MODULES = YES; 190 | CLANG_ENABLE_OBJC_ARC = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_CONSTANT_CONVERSION = YES; 193 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 194 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 195 | CLANG_WARN_EMPTY_BODY = YES; 196 | CLANG_WARN_ENUM_CONVERSION = YES; 197 | CLANG_WARN_INFINITE_RECURSION = YES; 198 | CLANG_WARN_INT_CONVERSION = YES; 199 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 200 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 201 | CLANG_WARN_UNREACHABLE_CODE = YES; 202 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 203 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 204 | COPY_PHASE_STRIP = NO; 205 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 206 | ENABLE_NS_ASSERTIONS = NO; 207 | ENABLE_STRICT_OBJC_MSGSEND = YES; 208 | GCC_C_LANGUAGE_STANDARD = gnu99; 209 | GCC_NO_COMMON_BLOCKS = YES; 210 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 211 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 212 | GCC_WARN_UNDECLARED_SELECTOR = YES; 213 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 214 | GCC_WARN_UNUSED_FUNCTION = YES; 215 | GCC_WARN_UNUSED_VARIABLE = YES; 216 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 217 | MTL_ENABLE_DEBUG_INFO = NO; 218 | SDKROOT = iphoneos; 219 | VALIDATE_PRODUCT = YES; 220 | }; 221 | name = Release; 222 | }; 223 | 839036B81E92BD0B00B483AD /* Debug */ = { 224 | isa = XCBuildConfiguration; 225 | buildSettings = { 226 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; 227 | DEFINES_MODULE = NO; 228 | EMBEDDED_CONTENT_CONTAINS_SWIFT = NO; 229 | ENABLE_BITCODE = YES; 230 | FRAMEWORK_SEARCH_PATHS = ( 231 | "$(inherited)", 232 | "${BUILT_PRODUCTS_DIR}", 233 | "${PROJECT_DIR}/../../../ios/Pods/**", 234 | ); 235 | HEADER_SEARCH_PATHS = ( 236 | "$(inherited)", 237 | "$(SRCROOT)/../../React/**", 238 | "$(SRCROOT)/../../node_modules/react-native/React/**", 239 | "$(SRCROOT)/../../react-native/React/**", 240 | "${SRCROOT}/../../../ios/Pods/**", 241 | ); 242 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 243 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 244 | MACH_O_TYPE = staticlib; 245 | ONLY_ACTIVE_ARCH = YES; 246 | OTHER_LDFLAGS = "-ObjC"; 247 | PRODUCT_NAME = RNCameraRoll; 248 | SKIP_INSTALL = YES; 249 | }; 250 | name = Debug; 251 | }; 252 | 839036B91E92BD0B00B483AD /* Release */ = { 253 | isa = XCBuildConfiguration; 254 | buildSettings = { 255 | CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; 256 | DEFINES_MODULE = NO; 257 | EMBEDDED_CONTENT_CONTAINS_SWIFT = NO; 258 | ENABLE_BITCODE = YES; 259 | FRAMEWORK_SEARCH_PATHS = ( 260 | "$(inherited)", 261 | "${BUILT_PRODUCTS_DIR}", 262 | "${PROJECT_DIR}/../../../ios/Pods/**", 263 | ); 264 | HEADER_SEARCH_PATHS = ( 265 | "$(inherited)", 266 | "$(SRCROOT)/../../React/**", 267 | "$(SRCROOT)/../../node_modules/react-native/React/**", 268 | "$(SRCROOT)/../../react-native/React/**", 269 | "${SRCROOT}/../../../ios/Pods/**", 270 | ); 271 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 272 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 273 | MACH_O_TYPE = staticlib; 274 | ONLY_ACTIVE_ARCH = YES; 275 | OTHER_LDFLAGS = "-ObjC"; 276 | PRODUCT_NAME = RNCameraRoll; 277 | SKIP_INSTALL = YES; 278 | }; 279 | name = Release; 280 | }; 281 | /* End XCBuildConfiguration section */ 282 | 283 | /* Begin XCConfigurationList section */ 284 | 839036A91E92BD0A00B483AD /* Build configuration list for PBXProject "RNCameraRoll" */ = { 285 | isa = XCConfigurationList; 286 | buildConfigurations = ( 287 | 839036B51E92BD0A00B483AD /* Debug */, 288 | 839036B61E92BD0A00B483AD /* Release */, 289 | ); 290 | defaultConfigurationIsVisible = 0; 291 | defaultConfigurationName = Release; 292 | }; 293 | 839036B71E92BD0B00B483AD /* Build configuration list for PBXNativeTarget "RNCameraRoll" */ = { 294 | isa = XCConfigurationList; 295 | buildConfigurations = ( 296 | 839036B81E92BD0B00B483AD /* Debug */, 297 | 839036B91E92BD0B00B483AD /* Release */, 298 | ); 299 | defaultConfigurationIsVisible = 0; 300 | }; 301 | /* End XCConfigurationList section */ 302 | }; 303 | rootObject = 839036A61E92BD0A00B483AD /* Project object */; 304 | } 305 | --------------------------------------------------------------------------------