├── .circleci └── config.yml ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .npmignore ├── .prettierrc ├── .releaserc ├── LICENSE ├── README.md ├── android ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── reactnativecommunity │ └── cookies │ ├── CookieManagerModule.java │ └── CookieManagerPackage.java ├── index.d.ts ├── index.js ├── ios ├── RNCookieManagerIOS.xcodeproj │ └── project.pbxproj └── RNCookieManagerIOS │ ├── RNCookieManagerIOS.h │ └── RNCookieManagerIOS.m ├── package.json ├── react-native-cookies.podspec └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | orbs: 3 | rn: react-native-community/react-native@3.0.0 4 | 5 | jobs: 6 | checkout_code: 7 | executor: rn/linux_js 8 | steps: 9 | - checkout 10 | - persist_to_workspace: 11 | root: . 12 | paths: . 13 | 14 | analyse_js: 15 | executor: rn/linux_js 16 | steps: 17 | - attach_workspace: 18 | at: . 19 | - rn/yarn_install 20 | - run: 21 | name: Run ESLint 22 | command: yarn lint 23 | 24 | release: 25 | executor: rn/linux_js 26 | steps: 27 | - attach_workspace: 28 | at: . 29 | - rn/yarn_install 30 | - run: 31 | name: Publish to NPM 32 | command: yarn semantic-release || true 33 | 34 | workflows: 35 | ci: 36 | jobs: 37 | - checkout_code 38 | - analyse_js: 39 | requires: 40 | - checkout_code 41 | - release: 42 | requires: 43 | - analyse_js 44 | filters: 45 | branches: 46 | only: master 47 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@react-native-community" 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # node.js 6 | # 7 | node_modules/ 8 | npm-debug.log 9 | yarn-error.log 10 | 11 | # Xcode 12 | # 13 | build/ 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata 23 | *.xccheckout 24 | *.moved-aside 25 | DerivedData 26 | *.hmap 27 | *.ipa 28 | *.xcuserstate 29 | project.xcworkspace 30 | 31 | # Android/IntelliJ 32 | # 33 | build/ 34 | .idea 35 | .gradle 36 | local.properties 37 | *.iml 38 | .classpath 39 | .project 40 | .settings 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | 47 | # VS Code 48 | .vscode 49 | 50 | # Yarn 51 | .yarnrc 52 | .yarn/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .eslintrc 2 | .prettierrc 3 | .releaserc 4 | .circleci/* -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "all" 5 | } 6 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@semantic-release/commit-analyzer", 4 | "@semantic-release/release-notes-generator", 5 | "@semantic-release/npm", 6 | "@semantic-release/github", 7 | [ 8 | "@semantic-release/git", 9 | { 10 | "assets": "package.json", 11 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 12 | } 13 | ] 14 | ] 15 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 React Native Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Cookies - A Cookie Manager for React Native 2 | 3 | Cookie Manager for React Native 4 | 5 | 6 | chat on Discord 8 | 9 | This module was ported from [joeferraro/react-native-cookies](https://github.com/joeferraro/react-native-cookies). This would not exist without the work of the original author, [Joe Ferraro](https://github.com/joeferraro). 10 | 11 | ## Important notices & Breaking Changes 12 | - **v6.0.0**: Package name updated to `@react-native-cookies/cookies`. 13 | - **v5.0.0**: Peer Dependency of >= React Native 0.60.2 14 | - **v4.0.0**: Android SDK version bumpted to 21 15 | - **v3.0.0**: Remove React Native Core dependencies, CookieManager.set() support for Android 16 | - **v2.0.0**: Package name updated to `@react-native-community/cookies`. 17 | 18 | ## Maintainers 19 | 20 | - [Jason Safaiyeh](https://github.com/safaiyeh) ([Twitter @safaiyeh](https://twitter.com/safaiyeh)) from [🪄 Magic Eden](https://magiceden.io) 21 | 22 | ## Platforms Supported 23 | 24 | - ✅ iOS 25 | - ✅ Android 26 | - ❌ Currently lacking support for Windows, macOS, and web. Support for these platforms will be created when there is a need for them. Starts with a posted issue. 27 | 28 | ## Expo 29 | 30 | - ✅ You can use this library with [Development Builds](https://docs.expo.dev/development/introduction/). No config plugin is required. 31 | - ❌ This library can't be used in the "Expo Go" app because it [requires custom native code](https://docs.expo.dev/workflow/customizing/). 32 | 33 | ## Installation 34 | 35 | ``` 36 | yarn add @react-native-cookies/cookies 37 | ``` 38 | 39 | Then link the native iOS package 40 | 41 | ``` 42 | npx pod-install 43 | ``` 44 | 45 | ## Usage 46 | 47 | A cookie object can have one of the following fields: 48 | 49 | ```typescript 50 | export interface Cookie { 51 | name: string; 52 | value: string; 53 | path?: string; 54 | domain?: string; 55 | version?: string; 56 | expires?: string; 57 | secure?: boolean; 58 | httpOnly?: boolean; 59 | } 60 | 61 | export interface Cookies { 62 | [key: string]: Cookie; 63 | } 64 | ``` 65 | 66 | ```javascript 67 | import CookieManager from '@react-native-cookies/cookies'; 68 | 69 | // set a cookie 70 | CookieManager.set('http://example.com', { 71 | name: 'myCookie', 72 | value: 'myValue', 73 | domain: 'some domain', 74 | path: '/', 75 | version: '1', 76 | expires: '2015-05-30T12:30:00.00-05:00' 77 | }).then((done) => { 78 | console.log('CookieManager.set =>', done); 79 | }); 80 | 81 | *NB:* When no `domain` is specified, url host will be used instead. 82 | *NB:* When no `path` is specified, an empty path `/` will be assumed. 83 | 84 | // Set cookies from a response header 85 | // This allows you to put the full string provided by a server's Set-Cookie 86 | // response header directly into the cookie store. 87 | CookieManager.setFromResponse( 88 | 'http://example.com', 89 | 'user_session=abcdefg; path=/; expires=Thu, 1 Jan 2030 00:00:00 -0000; secure; HttpOnly') 90 | .then((success) => { 91 | console.log('CookieManager.setFromResponse =>', success); 92 | }); 93 | 94 | // Get cookies for a url 95 | CookieManager.get('http://example.com') 96 | .then((cookies) => { 97 | console.log('CookieManager.get =>', cookies); 98 | }); 99 | 100 | // list cookies (IOS ONLY) 101 | CookieManager.getAll() 102 | .then((cookies) => { 103 | console.log('CookieManager.getAll =>', cookies); 104 | }); 105 | 106 | // clear cookies 107 | CookieManager.clearAll() 108 | .then((success) => { 109 | console.log('CookieManager.clearAll =>', success); 110 | }); 111 | 112 | // clear a specific cookie by its name (IOS ONLY) 113 | CookieManager.clearByName('http://example.com', 'cookie_name') 114 | .then((success) => { 115 | console.log('CookieManager.clearByName =>', success); 116 | }); 117 | 118 | // flush cookies (ANDROID ONLY) 119 | CookieManager.flush() 120 | .then((success) => { 121 | console.log('CookieManager.flush =>', success); 122 | }); 123 | 124 | // Remove session cookies (ANDROID ONLY) 125 | // Session cookies are cookies with no expires set. Android typically does not 126 | // remove these, it is up to the developer to decide when to remove them. 127 | // The return value is true if any session cookies were removed. 128 | // iOS handles removal of session cookies automatically on app open. 129 | CookieManager.removeSessionCookies() 130 | .then((sessionCookiesRemoved) => { 131 | console.log('CookieManager.removeSessionCookies =>', sessionCookiesRemoved); 132 | }); 133 | ``` 134 | 135 | ### WebKit-Support (iOS only) 136 | 137 | React Native comes with a WebView component, which uses UIWebView on iOS. Introduced in iOS 8 Apple implemented the WebKit-Support with all the performance boost. 138 | 139 | Prior to WebKit-Support, cookies would have been stored in `NSHTTPCookieStorage` and sharedCookiesEnabled must be set on webviews to ensure access to them. 140 | 141 | With WebKit-Support, cookies are stored in a separate webview store `WKHTTPCookieStore` and not necessarily shared with other http requests. Caveat is that this store is available upon mounting the component but not necessarily prior so any attempts to set a cookie too early may result in a false positive. 142 | 143 | To use WebKit-Support, you should be able to simply make advantage of the react-native-webview as is OR alternatively use the webview component like [react-native-wkwebview](https://github.com/CRAlpha/react-native-wkwebview). 144 | 145 | To use this _CookieManager_ with WebKit-Support we extended the interface with the attribute `useWebKit` (a boolean value, default: `FALSE`) for the following methods: 146 | 147 | | Method | WebKit-Support | Method-Signature | 148 | | ----------- | -------------- | ------------------------------------------------------------------------ | 149 | | getAll | Yes | `CookieManager.getAll(useWebKit:boolean)` | 150 | | clearAll | Yes | `CookieManager.clearAll(useWebKit:boolean)` | 151 | | clearByName | Yes | `CookieManager.clearByName(url:string, name: string, useWebKit:boolean)` | 152 | | get | Yes | `CookieManager.get(url:string, useWebKit:boolean)` | 153 | | set | Yes | `CookieManager.set(url:string, cookie:object, useWebKit:boolean)` | 154 | 155 | ##### Usage 156 | 157 | ```javascript 158 | import CookieManager from '@react-native-cookies/cookies'; 159 | 160 | const useWebKit = true; 161 | 162 | // list cookies (IOS ONLY) 163 | CookieManager.getAll(useWebKit) 164 | .then((cookies) => { 165 | console.log('CookieManager.getAll from webkit-view =>', cookies); 166 | }); 167 | 168 | // clear cookies 169 | CookieManager.clearAll(useWebKit) 170 | .then((succcess) => { 171 | console.log('CookieManager.clearAll from webkit-view =>', succcess); 172 | }); 173 | 174 | // clear cookies with name (IOS ONLY) 175 | CookieManager.clearByName('http://example.com', 'cookie name', useWebKit) 176 | .then((succcess) => { 177 | console.log('CookieManager.clearByName from webkit-view =>', succcess); 178 | }); 179 | 180 | // Get cookies as a request header string 181 | CookieManager.get('http://example.com', useWebKit) 182 | .then((cookies) => { 183 | console.log('CookieManager.get from webkit-view =>', cookies); 184 | }); 185 | 186 | // set a cookie 187 | const newCookie: = { 188 | name: 'myCookie', 189 | value: 'myValue', 190 | domain: 'some domain', 191 | path: '/', 192 | version: '1', 193 | expires: '2015-05-30T12:30:00.00-05:00' 194 | }; 195 | 196 | CookieManager.set('http://example.com', newCookie, useWebKit) 197 | .then((res) => { 198 | console.log('CookieManager.set from webkit-view =>', res); 199 | }); 200 | ``` 201 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | 3 | // android/build.gradle 4 | 5 | // based on: 6 | // 7 | // * https://github.com/facebook/react-native/blob/0.60-stable/template/android/build.gradle 8 | // original location: 9 | // - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/build.gradle 10 | // 11 | // * https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle 12 | // original location: 13 | // - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle 14 | 15 | def DEFAULT_COMPILE_SDK_VERSION = 29 16 | def DEFAULT_BUILD_TOOLS_VERSION = '29.0.3' 17 | def DEFAULT_MIN_SDK_VERSION = 21 18 | def DEFAULT_TARGET_SDK_VERSION = 29 19 | 20 | def safeExtGet(prop, fallback) { 21 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | 26 | buildscript { 27 | // The Android Gradle plugin is only required when opening the android folder stand-alone. 28 | // This avoids unnecessary downloads and potential conflicts when the library is included as a 29 | // module dependency in an application project. 30 | // ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies 31 | if (project == rootProject) { 32 | repositories { 33 | google() 34 | jcenter() 35 | } 36 | dependencies { 37 | classpath 'com.android.tools.build:gradle:3.5.3' 38 | } 39 | } 40 | } 41 | 42 | apply plugin: 'com.android.library' 43 | 44 | android { 45 | compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) 46 | buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) 47 | defaultConfig { 48 | minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) 49 | targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) 50 | versionCode 1 51 | versionName "1.0" 52 | } 53 | lintOptions { 54 | abortOnError false 55 | } 56 | } 57 | 58 | repositories { 59 | // ref: https://www.baeldung.com/maven-local-repository 60 | mavenLocal() 61 | maven { 62 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 63 | url "$rootDir/../node_modules/react-native/android" 64 | } 65 | maven { 66 | // Android JSC is installed from npm 67 | url "$rootDir/../node_modules/jsc-android/dist" 68 | } 69 | google() 70 | jcenter() 71 | } 72 | 73 | dependencies { 74 | //noinspection GradleDynamicVersion 75 | implementation 'com.facebook.react:react-native:+' // From node_modules 76 | } 77 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/react-native-cookies/cookies/69fe6557b0f2c286e6df6fa9100391ad2d163860/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Dec 29 13:32:23 PST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnativecommunity/cookies/CookieManagerModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Joseph P. Ferraro 3 | *

4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file here: https://github.com/joeferraro/react-native-cookies/blob/master/LICENSE.md. 6 | */ 7 | 8 | package com.reactnativecommunity.cookies; 9 | 10 | import android.os.Build; 11 | import android.util.Log; 12 | import android.webkit.CookieManager; 13 | import android.webkit.CookieSyncManager; 14 | import android.webkit.ValueCallback; 15 | 16 | import com.facebook.react.bridge.Arguments; 17 | import com.facebook.react.bridge.Promise; 18 | import com.facebook.react.bridge.ReactApplicationContext; 19 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 20 | import com.facebook.react.bridge.ReactMethod; 21 | import com.facebook.react.bridge.ReadableMap; 22 | import com.facebook.react.bridge.WritableMap; 23 | 24 | import java.io.IOException; 25 | import java.net.HttpCookie; 26 | import java.net.URISyntaxException; 27 | import java.net.URL; 28 | import java.text.DateFormat; 29 | import java.text.SimpleDateFormat; 30 | import java.util.Date; 31 | import java.util.List; 32 | import java.util.Locale; 33 | import java.util.TimeZone; 34 | 35 | public class CookieManagerModule extends ReactContextBaseJavaModule { 36 | 37 | private static final boolean USES_LEGACY_STORE = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP; 38 | private static final boolean HTTP_ONLY_SUPPORTED = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; 39 | 40 | private static final String INVALID_URL_MISSING_HTTP = "Invalid URL: It may be missing a protocol (ex. http:// or https://)."; 41 | private static final String INVALID_COOKIE_VALUES = "Unable to add cookie - invalid values"; 42 | private static final String GET_ALL_NOT_SUPPORTED = "Get all cookies not supported for Android (iOS only)"; 43 | private static final String CLEAR_BY_NAME_NOT_SUPPORTED = "Cannot remove a single cookie by name on Android"; 44 | private static final String INVALID_DOMAINS = "Cookie URL host %s and domain %s mismatched. The cookie won't set correctly."; 45 | 46 | private CookieSyncManager mCookieSyncManager; 47 | 48 | CookieManagerModule(ReactApplicationContext context) { 49 | super(context); 50 | this.mCookieSyncManager = CookieSyncManager.createInstance(context); 51 | } 52 | 53 | private CookieManager getCookieManager() throws Exception { 54 | try { 55 | CookieManager cookieManager = CookieManager.getInstance(); 56 | cookieManager.setAcceptCookie(true); 57 | return cookieManager; 58 | } catch (Exception e) { 59 | throw new Exception(e); 60 | } 61 | } 62 | 63 | public String getName() { 64 | return "RNCookieManagerAndroid"; 65 | } 66 | 67 | @ReactMethod 68 | public void set(String url, ReadableMap cookie, Boolean useWebKit, final Promise promise) { 69 | String cookieString = null; 70 | try { 71 | cookieString = toRFC6265string(makeHTTPCookieObject(url, cookie)); 72 | } catch (Exception e) { 73 | promise.reject(e); 74 | return; 75 | } 76 | 77 | if (cookieString == null) { 78 | promise.reject(new Exception(INVALID_COOKIE_VALUES)); 79 | return; 80 | } 81 | 82 | addCookies(url, cookieString, promise); 83 | } 84 | 85 | @ReactMethod 86 | public void setFromResponse(String url, String cookie, final Promise promise) { 87 | if (cookie == null) { 88 | promise.reject(new Exception(INVALID_COOKIE_VALUES)); 89 | return; 90 | } 91 | 92 | addCookies(url, cookie, promise); 93 | } 94 | 95 | @ReactMethod 96 | public void flush(Promise promise) { 97 | try { 98 | getCookieManager().flush(); 99 | promise.resolve(true); 100 | } catch (Exception e) { 101 | promise.reject(e); 102 | } 103 | } 104 | 105 | @ReactMethod 106 | public void removeSessionCookies(final Promise promise) { 107 | try { 108 | getCookieManager().removeSessionCookies(new ValueCallback() { 109 | @Override 110 | public void onReceiveValue(Boolean data) { 111 | promise.resolve(data); 112 | } 113 | }); 114 | } catch (Exception e) { 115 | promise.reject(e); 116 | } 117 | } 118 | 119 | @ReactMethod 120 | public void getFromResponse(String url, Promise promise) throws URISyntaxException, IOException { 121 | promise.resolve(url); 122 | } 123 | 124 | @ReactMethod 125 | public void getAll(Boolean useWebKit, Promise promise) { 126 | promise.reject(new Exception(GET_ALL_NOT_SUPPORTED)); 127 | } 128 | 129 | @ReactMethod 130 | public void get(String url, Boolean useWebKit, Promise promise) { 131 | if (isEmpty(url)) { 132 | promise.reject(new Exception(INVALID_URL_MISSING_HTTP)); 133 | return; 134 | } 135 | try { 136 | String cookiesString = getCookieManager().getCookie(url); 137 | 138 | WritableMap cookieMap = createCookieList(cookiesString); 139 | promise.resolve(cookieMap); 140 | } catch (Exception e) { 141 | promise.reject(e); 142 | } 143 | } 144 | 145 | @ReactMethod 146 | public void clearByName(String url, String name, Boolean useWebKit, final Promise promise) { 147 | promise.reject(new Exception(CLEAR_BY_NAME_NOT_SUPPORTED)); 148 | } 149 | 150 | @ReactMethod 151 | public void clearAll(Boolean useWebKit, final Promise promise) { 152 | try { 153 | CookieManager cookieManager = getCookieManager(); 154 | if (USES_LEGACY_STORE) { 155 | cookieManager.removeAllCookie(); 156 | cookieManager.removeSessionCookie(); 157 | mCookieSyncManager.sync(); 158 | promise.resolve(true); 159 | } else { 160 | cookieManager.removeAllCookies(new ValueCallback() { 161 | @Override 162 | public void onReceiveValue(Boolean value) { 163 | promise.resolve(value); 164 | } 165 | }); 166 | cookieManager.flush(); 167 | } 168 | } catch (Exception e) { 169 | promise.reject(e); 170 | } 171 | } 172 | 173 | private void addCookies(String url, String cookieString, final Promise promise) { 174 | try { 175 | CookieManager cookieManager = getCookieManager(); 176 | if (USES_LEGACY_STORE) { 177 | cookieManager.setCookie(url, cookieString); 178 | mCookieSyncManager.sync(); 179 | promise.resolve(true); 180 | } else { 181 | cookieManager.setCookie(url, cookieString, new ValueCallback() { 182 | @Override 183 | public void onReceiveValue(Boolean value) { 184 | promise.resolve(value); 185 | } 186 | }); 187 | cookieManager.flush(); 188 | } 189 | } catch (Exception e) { 190 | promise.reject(e); 191 | } 192 | } 193 | 194 | private WritableMap createCookieList(String allCookies) throws Exception { 195 | WritableMap allCookiesMap = Arguments.createMap(); 196 | 197 | if (!isEmpty(allCookies)) { 198 | String[] cookieHeaders = allCookies.split(";"); 199 | for (String singleCookie : cookieHeaders) { 200 | List cookies = HttpCookie.parse(singleCookie); 201 | for (HttpCookie cookie : cookies) { 202 | if (cookie != null) { 203 | String name = cookie.getName(); 204 | String value = cookie.getValue(); 205 | if (!isEmpty(name) && !isEmpty(value)) { 206 | WritableMap cookieMap = createCookieData(cookie); 207 | allCookiesMap.putMap(name, cookieMap); 208 | } 209 | } 210 | } 211 | } 212 | } 213 | 214 | return allCookiesMap; 215 | } 216 | 217 | private HttpCookie makeHTTPCookieObject(String url, ReadableMap cookie) throws Exception { 218 | URL parsedUrl = null; 219 | try { 220 | parsedUrl = new URL(url); 221 | } catch (Exception e) { 222 | throw new Exception(INVALID_URL_MISSING_HTTP); 223 | } 224 | 225 | String topLevelDomain = parsedUrl.getHost(); 226 | 227 | if (isEmpty(topLevelDomain)) { 228 | // assume something went terribly wrong here and no cookie can be created 229 | throw new Exception(INVALID_URL_MISSING_HTTP); 230 | } 231 | 232 | HttpCookie cookieBuilder = new HttpCookie(cookie.getString("name"), cookie.getString("value")); 233 | 234 | if (cookie.hasKey("domain") && !isEmpty(cookie.getString("domain"))) { 235 | String domain = cookie.getString("domain"); 236 | // strip the leading . as Android doesn't take it 237 | // but will include subdomains by default 238 | if (domain.startsWith(".")) { 239 | domain = domain.substring(1); 240 | } 241 | 242 | if (!topLevelDomain.contains(domain) && !topLevelDomain.equals(domain)) { 243 | throw new Exception(String.format(INVALID_DOMAINS, topLevelDomain, domain)); 244 | } 245 | 246 | cookieBuilder.setDomain(domain); 247 | } else { 248 | cookieBuilder.setDomain(topLevelDomain); 249 | } 250 | 251 | // unlike iOS, Android will handle no path gracefully and assume "/"" 252 | if (cookie.hasKey("path") && !isEmpty(cookie.getString("path"))) { 253 | cookieBuilder.setPath(cookie.getString("path")); 254 | } 255 | 256 | if (cookie.hasKey("expires") && !isEmpty(cookie.getString("expires"))) { 257 | Date date = parseDate(cookie.getString("expires")); 258 | if (date != null) { 259 | cookieBuilder.setMaxAge(date.getTime()); 260 | } 261 | } 262 | 263 | if (cookie.hasKey("secure") && cookie.getBoolean("secure")) { 264 | cookieBuilder.setSecure(true); 265 | } 266 | 267 | if (HTTP_ONLY_SUPPORTED) { 268 | if (cookie.hasKey("httpOnly") && cookie.getBoolean("httpOnly")) { 269 | cookieBuilder.setHttpOnly(true); 270 | } 271 | } 272 | 273 | return cookieBuilder; 274 | } 275 | 276 | private WritableMap createCookieData(HttpCookie cookie) { 277 | WritableMap cookieMap = Arguments.createMap(); 278 | cookieMap.putString("name", cookie.getName()); 279 | cookieMap.putString("value", cookie.getValue()); 280 | cookieMap.putString("domain", cookie.getDomain()); 281 | cookieMap.putString("path", cookie.getPath()); 282 | cookieMap.putBoolean("secure", cookie.getSecure()); 283 | if (HTTP_ONLY_SUPPORTED) { 284 | cookieMap.putBoolean("httpOnly", cookie.isHttpOnly()); 285 | } 286 | 287 | // if persistent the max Age will be -1 288 | long expires = cookie.getMaxAge(); 289 | if (expires > 0) { 290 | String expiry = formatDate(new Date(expires)); 291 | if (!isEmpty(expiry)) { 292 | cookieMap.putString("expires", expiry); 293 | } 294 | } 295 | return cookieMap; 296 | } 297 | 298 | /** 299 | * As HttpCookie is designed specifically for headers, it only gives us 2 formats on toString 300 | * dependent on the cookie version: 0 = Netscape; 1 = RFC 2965/2109, both without leading "Cookie:" token. 301 | * For our purposes RFC 6265 is the right way to go. 302 | * This is a convenience method to give us the right formatting. 303 | */ 304 | private String toRFC6265string(HttpCookie cookie) { 305 | StringBuilder builder = new StringBuilder(); 306 | 307 | builder.append(cookie.getName()) 308 | .append('=') 309 | .append(cookie.getValue()); 310 | 311 | if (!cookie.hasExpired()) { 312 | long expiresAt = cookie.getMaxAge(); 313 | if (expiresAt > 0) { 314 | String dateString = formatDate(new Date(expiresAt), true); 315 | if (!isEmpty(dateString)) { 316 | builder.append("; expires=").append(dateString); 317 | } 318 | } 319 | } 320 | 321 | if (!isEmpty(cookie.getDomain())) { 322 | builder.append("; domain=") 323 | .append(cookie.getDomain()); 324 | } 325 | 326 | if (!isEmpty(cookie.getPath())) { 327 | builder.append("; path=") 328 | .append(cookie.getPath()); 329 | } 330 | 331 | if (cookie.getSecure()) { 332 | builder.append("; secure"); 333 | } 334 | 335 | if (HTTP_ONLY_SUPPORTED && cookie.isHttpOnly()) { 336 | builder.append("; httponly"); 337 | } 338 | 339 | return builder.toString(); 340 | } 341 | 342 | private boolean isEmpty(String value) { 343 | return value == null || value.isEmpty(); 344 | } 345 | 346 | /** 347 | * Used for pushing cookies expiry time in and out of the library. 348 | * 349 | * @return simple date formatter 350 | */ 351 | private DateFormat dateFormatter() { 352 | // suggested formatting -> return DateTimeFormatter.RFC_1123_DATE_TIME; 353 | // matching ios format as yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ 354 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ", Locale.US); 355 | df.setTimeZone(TimeZone.getTimeZone("GMT")); 356 | return df; 357 | } 358 | 359 | /** 360 | * Used building the correctly formatted date for a cookie string in RFC_1123_DATE_TIME format 361 | * 362 | * @return simple date formatter 363 | */ 364 | private DateFormat RFC1123dateFormatter() { 365 | DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 366 | df.setTimeZone(TimeZone.getTimeZone("GMT")); 367 | return df; 368 | } 369 | 370 | private Date parseDate(String dateString) { 371 | return parseDate(dateString, false); 372 | } 373 | 374 | private Date parseDate(String dateString, boolean rfc1123) { 375 | Date date = null; 376 | try { 377 | date = (rfc1123 ? RFC1123dateFormatter() : dateFormatter()).parse(dateString); 378 | } catch (Exception e) { 379 | String message = e.getMessage(); 380 | Log.i("Cookies", message != null ? message : "Unable to parse date"); 381 | } 382 | return date; 383 | } 384 | 385 | private String formatDate(Date date) { 386 | return formatDate(date, false); 387 | } 388 | 389 | private String formatDate(Date date, boolean rfc1123) { 390 | String dateString = null; 391 | try { 392 | dateString = (rfc1123 ? RFC1123dateFormatter() : dateFormatter()).format(date); 393 | } catch (Exception e) { 394 | String message = e.getMessage(); 395 | Log.i("Cookies", message != null ? message : "Unable to format date"); 396 | } 397 | return dateString; 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /android/src/main/java/com/reactnativecommunity/cookies/CookieManagerPackage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Joseph P. Ferraro 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file here: https://github.com/joeferraro/react-native-cookies/blob/master/LICENSE.md. 6 | */ 7 | 8 | package com.reactnativecommunity.cookies; 9 | 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.bridge.NativeModule; 12 | import com.facebook.react.bridge.JavaScriptModule; 13 | import com.facebook.react.bridge.ReactApplicationContext; 14 | import com.facebook.react.uimanager.ViewManager; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | import java.util.Collections; 19 | import java.util.List; 20 | 21 | public class CookieManagerPackage implements ReactPackage { 22 | 23 | public CookieManagerPackage() {} 24 | 25 | @Override 26 | public List createNativeModules( 27 | ReactApplicationContext reactContext) { 28 | List modules = new ArrayList<>(); 29 | 30 | modules.add(new CookieManagerModule(reactContext)); 31 | return modules; 32 | } 33 | 34 | // Deprecated 35 | public List> createJSModules() { 36 | return Collections.emptyList(); 37 | } 38 | 39 | @Override 40 | public List createViewManagers(ReactApplicationContext reactContext) { 41 | return Arrays.asList(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@react-native-cookies/cookies' { 2 | export interface Cookie { 3 | name: string; 4 | value: string; 5 | path?: string; 6 | domain?: string; 7 | version?: string; 8 | expires?: string; 9 | secure?: boolean; 10 | httpOnly?: boolean; 11 | } 12 | 13 | export interface Cookies { 14 | [key: string]: Cookie; 15 | } 16 | 17 | export interface CookieManagerStatic { 18 | set(url: string, cookie: Cookie, useWebKit?: boolean): Promise; 19 | setFromResponse(url: string, cookie: string): Promise; 20 | 21 | get(url: string, useWebKit?: boolean): Promise; 22 | getFromResponse(url: string): Promise; 23 | 24 | clearAll(useWebKit?: boolean): Promise; 25 | 26 | // Android only 27 | flush(): Promise; 28 | removeSessionCookies(): Promise; 29 | 30 | // iOS only 31 | getAll(useWebKit?: boolean): Promise; 32 | clearByName( 33 | url: string, 34 | name: string, 35 | useWebKit?: boolean, 36 | ): Promise; 37 | } 38 | 39 | const CookieManager: CookieManagerStatic; 40 | 41 | export default CookieManager; 42 | } 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Joseph P. Ferraro 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file here: https://github.com/joeferraro/react-native-cookies/blob/master/LICENSE.md. 6 | */ 7 | 8 | import { NativeModules, Platform } from 'react-native'; 9 | const invariant = require('invariant'); 10 | const RNCookieManagerIOS = NativeModules.RNCookieManagerIOS; 11 | const RNCookieManagerAndroid = NativeModules.RNCookieManagerAndroid; 12 | 13 | let CookieManager; 14 | 15 | if (Platform.OS === 'ios') { 16 | invariant( 17 | RNCookieManagerIOS, 18 | '@react-native-community/cookies: Add RNCookieManagerIOS.h and RNCookieManagerIOS.m to your Xcode project', 19 | ); 20 | CookieManager = RNCookieManagerIOS; 21 | } else if (Platform.OS === 'android') { 22 | invariant( 23 | RNCookieManagerAndroid, 24 | '@react-native-community/cookies: Import libraries to android "react-native link @react-native-community/cookies"', 25 | ); 26 | CookieManager = RNCookieManagerAndroid; 27 | } else { 28 | invariant( 29 | CookieManager, 30 | '@react-native-community/cookies: Invalid platform. This library only supports Android and iOS.', 31 | ); 32 | } 33 | 34 | const functions = ['setFromResponse', 'getFromResponse']; 35 | 36 | module.exports = { 37 | getAll: (useWebKit = false) => CookieManager.getAll(useWebKit), 38 | clearAll: (useWebKit = false) => CookieManager.clearAll(useWebKit), 39 | get: (url, useWebKit = false) => CookieManager.get(url, useWebKit), 40 | set: (url, cookie, useWebKit = false) => 41 | CookieManager.set(url, cookie, useWebKit), 42 | clearByName: (url, name, useWebKit = false) => 43 | CookieManager.clearByName(url, name, useWebKit), 44 | flush: async () => { 45 | if (Platform.OS === 'android') { 46 | await CookieManager.flush(); 47 | } 48 | }, 49 | removeSessionCookies: async () => { 50 | if (Platform.OS === 'android') { 51 | return await CookieManager.removeSessionCookies(); 52 | } 53 | }, 54 | }; 55 | 56 | for (var i = 0; i < functions.length; i++) { 57 | module.exports[functions[i]] = CookieManager[functions[i]]; 58 | } 59 | -------------------------------------------------------------------------------- /ios/RNCookieManagerIOS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1BD726021CF77DD1005DBD79 /* RNCookieManagerIOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BD726011CF77DD1005DBD79 /* RNCookieManagerIOS.m */; }; 11 | A2387BE556B46F28BB9C62FD /* Pods_RNCookieManagerIOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A3E91C9DB889DAEAB299FB5 /* Pods_RNCookieManagerIOS.framework */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | 1BD725D81CF77A8B005DBD79 /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = "include/$(PRODUCT_NAME)"; 19 | dstSubfolderSpec = 16; 20 | files = ( 21 | ); 22 | runOnlyForDeploymentPostprocessing = 0; 23 | }; 24 | /* End PBXCopyFilesBuildPhase section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 1BD725DA1CF77A8B005DBD79 /* libRNCookieManagerIOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCookieManagerIOS.a; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 1BD726001CF77DD1005DBD79 /* RNCookieManagerIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCookieManagerIOS.h; sourceTree = ""; }; 29 | 1BD726011CF77DD1005DBD79 /* RNCookieManagerIOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNCookieManagerIOS.m; sourceTree = ""; }; 30 | 6CDA467A38779CEFE54AF652 /* Pods-RNCookieManagerIOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNCookieManagerIOS.debug.xcconfig"; path = "Target Support Files/Pods-RNCookieManagerIOS/Pods-RNCookieManagerIOS.debug.xcconfig"; sourceTree = ""; }; 31 | 7A3E91C9DB889DAEAB299FB5 /* Pods_RNCookieManagerIOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RNCookieManagerIOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | AC0CCEFD0D5DDBC08A3F9FDB /* Pods-RNCookieManagerIOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNCookieManagerIOS.release.xcconfig"; path = "Target Support Files/Pods-RNCookieManagerIOS/Pods-RNCookieManagerIOS.release.xcconfig"; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 1BD725D71CF77A8B005DBD79 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | A2387BE556B46F28BB9C62FD /* Pods_RNCookieManagerIOS.framework in Frameworks */, 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | 1ABCC227200901826854EA3A /* Frameworks */ = { 48 | isa = PBXGroup; 49 | children = ( 50 | 7A3E91C9DB889DAEAB299FB5 /* Pods_RNCookieManagerIOS.framework */, 51 | ); 52 | name = Frameworks; 53 | sourceTree = ""; 54 | }; 55 | 1BD725CD1CF7795C005DBD79 = { 56 | isa = PBXGroup; 57 | children = ( 58 | 1BD725FF1CF77DD1005DBD79 /* RNCookieManagerIOS */, 59 | 1BD725DB1CF77A8B005DBD79 /* Products */, 60 | 71405C5FF90D2ACAB4F0366B /* Pods */, 61 | 1ABCC227200901826854EA3A /* Frameworks */, 62 | ); 63 | sourceTree = ""; 64 | }; 65 | 1BD725DB1CF77A8B005DBD79 /* Products */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 1BD725DA1CF77A8B005DBD79 /* libRNCookieManagerIOS.a */, 69 | ); 70 | name = Products; 71 | sourceTree = ""; 72 | }; 73 | 1BD725FF1CF77DD1005DBD79 /* RNCookieManagerIOS */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 1BD726001CF77DD1005DBD79 /* RNCookieManagerIOS.h */, 77 | 1BD726011CF77DD1005DBD79 /* RNCookieManagerIOS.m */, 78 | ); 79 | path = RNCookieManagerIOS; 80 | sourceTree = ""; 81 | }; 82 | 71405C5FF90D2ACAB4F0366B /* Pods */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 6CDA467A38779CEFE54AF652 /* Pods-RNCookieManagerIOS.debug.xcconfig */, 86 | AC0CCEFD0D5DDBC08A3F9FDB /* Pods-RNCookieManagerIOS.release.xcconfig */, 87 | ); 88 | path = Pods; 89 | sourceTree = ""; 90 | }; 91 | /* End PBXGroup section */ 92 | 93 | /* Begin PBXNativeTarget section */ 94 | 1BD725D91CF77A8B005DBD79 /* RNCookieManagerIOS */ = { 95 | isa = PBXNativeTarget; 96 | buildConfigurationList = 1BD725E31CF77A8B005DBD79 /* Build configuration list for PBXNativeTarget "RNCookieManagerIOS" */; 97 | buildPhases = ( 98 | 749140BD317DEE62C1AE6F51 /* [CP] Check Pods Manifest.lock */, 99 | 1BD725D61CF77A8B005DBD79 /* Sources */, 100 | 1BD725D71CF77A8B005DBD79 /* Frameworks */, 101 | 1BD725D81CF77A8B005DBD79 /* CopyFiles */, 102 | ); 103 | buildRules = ( 104 | ); 105 | dependencies = ( 106 | ); 107 | name = RNCookieManagerIOS; 108 | productName = RNCookieManagerIOS; 109 | productReference = 1BD725DA1CF77A8B005DBD79 /* libRNCookieManagerIOS.a */; 110 | productType = "com.apple.product-type.library.static"; 111 | }; 112 | /* End PBXNativeTarget section */ 113 | 114 | /* Begin PBXProject section */ 115 | 1BD725CE1CF7795C005DBD79 /* Project object */ = { 116 | isa = PBXProject; 117 | attributes = { 118 | LastUpgradeCheck = 1130; 119 | TargetAttributes = { 120 | 1BD725D91CF77A8B005DBD79 = { 121 | CreatedOnToolsVersion = 7.3.1; 122 | }; 123 | }; 124 | }; 125 | buildConfigurationList = 1BD725D11CF7795C005DBD79 /* Build configuration list for PBXProject "RNCookieManagerIOS" */; 126 | compatibilityVersion = "Xcode 3.2"; 127 | developmentRegion = English; 128 | hasScannedForEncodings = 0; 129 | knownRegions = ( 130 | English, 131 | en, 132 | ); 133 | mainGroup = 1BD725CD1CF7795C005DBD79; 134 | productRefGroup = 1BD725DB1CF77A8B005DBD79 /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | 1BD725D91CF77A8B005DBD79 /* RNCookieManagerIOS */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXShellScriptBuildPhase section */ 144 | 749140BD317DEE62C1AE6F51 /* [CP] Check Pods Manifest.lock */ = { 145 | isa = PBXShellScriptBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | ); 149 | inputFileListPaths = ( 150 | ); 151 | inputPaths = ( 152 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 153 | "${PODS_ROOT}/Manifest.lock", 154 | ); 155 | name = "[CP] Check Pods Manifest.lock"; 156 | outputFileListPaths = ( 157 | ); 158 | outputPaths = ( 159 | "$(DERIVED_FILE_DIR)/Pods-RNCookieManagerIOS-checkManifestLockResult.txt", 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | shellPath = /bin/sh; 163 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 164 | showEnvVarsInLog = 0; 165 | }; 166 | /* End PBXShellScriptBuildPhase section */ 167 | 168 | /* Begin PBXSourcesBuildPhase section */ 169 | 1BD725D61CF77A8B005DBD79 /* Sources */ = { 170 | isa = PBXSourcesBuildPhase; 171 | buildActionMask = 2147483647; 172 | files = ( 173 | 1BD726021CF77DD1005DBD79 /* RNCookieManagerIOS.m in Sources */, 174 | ); 175 | runOnlyForDeploymentPostprocessing = 0; 176 | }; 177 | /* End PBXSourcesBuildPhase section */ 178 | 179 | /* Begin XCBuildConfiguration section */ 180 | 1BD725D21CF7795C005DBD79 /* Debug */ = { 181 | isa = XCBuildConfiguration; 182 | buildSettings = { 183 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 184 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 185 | CLANG_WARN_BOOL_CONVERSION = YES; 186 | CLANG_WARN_COMMA = YES; 187 | CLANG_WARN_CONSTANT_CONVERSION = YES; 188 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 189 | CLANG_WARN_EMPTY_BODY = YES; 190 | CLANG_WARN_ENUM_CONVERSION = YES; 191 | CLANG_WARN_INFINITE_RECURSION = YES; 192 | CLANG_WARN_INT_CONVERSION = YES; 193 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 194 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 195 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 196 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 197 | CLANG_WARN_STRICT_PROTOTYPES = YES; 198 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 199 | CLANG_WARN_UNREACHABLE_CODE = YES; 200 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 201 | ENABLE_STRICT_OBJC_MSGSEND = YES; 202 | ENABLE_TESTABILITY = YES; 203 | GCC_NO_COMMON_BLOCKS = YES; 204 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 205 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 206 | GCC_WARN_UNDECLARED_SELECTOR = YES; 207 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 208 | GCC_WARN_UNUSED_FUNCTION = YES; 209 | GCC_WARN_UNUSED_VARIABLE = YES; 210 | ONLY_ACTIVE_ARCH = YES; 211 | }; 212 | name = Debug; 213 | }; 214 | 1BD725D31CF7795C005DBD79 /* Release */ = { 215 | isa = XCBuildConfiguration; 216 | buildSettings = { 217 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 218 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 219 | CLANG_WARN_BOOL_CONVERSION = YES; 220 | CLANG_WARN_COMMA = YES; 221 | CLANG_WARN_CONSTANT_CONVERSION = YES; 222 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 223 | CLANG_WARN_EMPTY_BODY = YES; 224 | CLANG_WARN_ENUM_CONVERSION = YES; 225 | CLANG_WARN_INFINITE_RECURSION = YES; 226 | CLANG_WARN_INT_CONVERSION = YES; 227 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 228 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 229 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 230 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 231 | CLANG_WARN_STRICT_PROTOTYPES = YES; 232 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 233 | CLANG_WARN_UNREACHABLE_CODE = YES; 234 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 235 | ENABLE_STRICT_OBJC_MSGSEND = YES; 236 | GCC_NO_COMMON_BLOCKS = YES; 237 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 238 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 239 | GCC_WARN_UNDECLARED_SELECTOR = YES; 240 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 241 | GCC_WARN_UNUSED_FUNCTION = YES; 242 | GCC_WARN_UNUSED_VARIABLE = YES; 243 | }; 244 | name = Release; 245 | }; 246 | 1BD725E11CF77A8B005DBD79 /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | baseConfigurationReference = 6CDA467A38779CEFE54AF652 /* Pods-RNCookieManagerIOS.debug.xcconfig */; 249 | buildSettings = { 250 | ALWAYS_SEARCH_USER_PATHS = NO; 251 | CLANG_ANALYZER_NONNULL = YES; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_WARN_BOOL_CONVERSION = YES; 257 | CLANG_WARN_CONSTANT_CONVERSION = YES; 258 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 259 | CLANG_WARN_EMPTY_BODY = YES; 260 | CLANG_WARN_ENUM_CONVERSION = YES; 261 | CLANG_WARN_INT_CONVERSION = YES; 262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 263 | CLANG_WARN_UNREACHABLE_CODE = YES; 264 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 265 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 266 | COPY_PHASE_STRIP = NO; 267 | DEBUG_INFORMATION_FORMAT = dwarf; 268 | ENABLE_STRICT_OBJC_MSGSEND = YES; 269 | ENABLE_TESTABILITY = YES; 270 | FRAMEWORK_SEARCH_PATHS = ( 271 | "$(SRCROOT)/../../React/**", 272 | "$(inherited)", 273 | "$(SRCROOT)/node_modules/react-native/React/**", 274 | "$(SRCROOT)/../react-native/React/**", 275 | "$(SRCROOT)/../../../node_modules/react-native/React/**", 276 | ); 277 | GCC_C_LANGUAGE_STANDARD = gnu99; 278 | GCC_DYNAMIC_NO_PIC = NO; 279 | GCC_NO_COMMON_BLOCKS = YES; 280 | GCC_OPTIMIZATION_LEVEL = 0; 281 | GCC_PREPROCESSOR_DEFINITIONS = ( 282 | "DEBUG=1", 283 | "$(inherited)", 284 | ); 285 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 286 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 287 | GCC_WARN_UNDECLARED_SELECTOR = YES; 288 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 289 | GCC_WARN_UNUSED_FUNCTION = YES; 290 | GCC_WARN_UNUSED_VARIABLE = YES; 291 | HEADER_SEARCH_PATHS = ( 292 | "$(SRCROOT)/../../React/**", 293 | "$(inherited)", 294 | "$(SRCROOT)/node_modules/react-native/React/**", 295 | "$(SRCROOT)/../react-native/React/**", 296 | "$(SRCROOT)/../../../node_modules/react-native/React/**", 297 | ); 298 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 299 | MTL_ENABLE_DEBUG_INFO = YES; 300 | ONLY_ACTIVE_ARCH = YES; 301 | OTHER_LDFLAGS = "-ObjC"; 302 | PRODUCT_NAME = "$(TARGET_NAME)"; 303 | SDKROOT = iphoneos; 304 | SKIP_INSTALL = YES; 305 | }; 306 | name = Debug; 307 | }; 308 | 1BD725E21CF77A8B005DBD79 /* Release */ = { 309 | isa = XCBuildConfiguration; 310 | baseConfigurationReference = AC0CCEFD0D5DDBC08A3F9FDB /* Pods-RNCookieManagerIOS.release.xcconfig */; 311 | buildSettings = { 312 | ALWAYS_SEARCH_USER_PATHS = NO; 313 | CLANG_ANALYZER_NONNULL = YES; 314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 315 | CLANG_CXX_LIBRARY = "libc++"; 316 | CLANG_ENABLE_MODULES = YES; 317 | CLANG_ENABLE_OBJC_ARC = YES; 318 | CLANG_WARN_BOOL_CONVERSION = YES; 319 | CLANG_WARN_CONSTANT_CONVERSION = YES; 320 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 321 | CLANG_WARN_EMPTY_BODY = YES; 322 | CLANG_WARN_ENUM_CONVERSION = YES; 323 | CLANG_WARN_INT_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_UNREACHABLE_CODE = YES; 326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 327 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 328 | COPY_PHASE_STRIP = NO; 329 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 330 | ENABLE_NS_ASSERTIONS = NO; 331 | ENABLE_STRICT_OBJC_MSGSEND = YES; 332 | FRAMEWORK_SEARCH_PATHS = ( 333 | "$(SRCROOT)/../../React/**", 334 | "$(inherited)", 335 | "$(SRCROOT)/node_modules/react-native/React/**", 336 | "$(SRCROOT)/../react-native/React/**", 337 | "$(SRCROOT)/../../../node_modules/react-native/React/**", 338 | ); 339 | GCC_C_LANGUAGE_STANDARD = gnu99; 340 | GCC_NO_COMMON_BLOCKS = YES; 341 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 342 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 343 | GCC_WARN_UNDECLARED_SELECTOR = YES; 344 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 345 | GCC_WARN_UNUSED_FUNCTION = YES; 346 | GCC_WARN_UNUSED_VARIABLE = YES; 347 | HEADER_SEARCH_PATHS = ( 348 | "$(SRCROOT)/../../React/**", 349 | "$(inherited)", 350 | "$(SRCROOT)/node_modules/react-native/React/**", 351 | "$(SRCROOT)/../react-native/React/**", 352 | "$(SRCROOT)/../../../node_modules/react-native/React/**", 353 | ); 354 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 355 | MTL_ENABLE_DEBUG_INFO = NO; 356 | OTHER_LDFLAGS = "-ObjC"; 357 | PRODUCT_NAME = "$(TARGET_NAME)"; 358 | SDKROOT = iphoneos; 359 | SKIP_INSTALL = YES; 360 | VALIDATE_PRODUCT = YES; 361 | }; 362 | name = Release; 363 | }; 364 | /* End XCBuildConfiguration section */ 365 | 366 | /* Begin XCConfigurationList section */ 367 | 1BD725D11CF7795C005DBD79 /* Build configuration list for PBXProject "RNCookieManagerIOS" */ = { 368 | isa = XCConfigurationList; 369 | buildConfigurations = ( 370 | 1BD725D21CF7795C005DBD79 /* Debug */, 371 | 1BD725D31CF7795C005DBD79 /* Release */, 372 | ); 373 | defaultConfigurationIsVisible = 0; 374 | defaultConfigurationName = Release; 375 | }; 376 | 1BD725E31CF77A8B005DBD79 /* Build configuration list for PBXNativeTarget "RNCookieManagerIOS" */ = { 377 | isa = XCConfigurationList; 378 | buildConfigurations = ( 379 | 1BD725E11CF77A8B005DBD79 /* Debug */, 380 | 1BD725E21CF77A8B005DBD79 /* Release */, 381 | ); 382 | defaultConfigurationIsVisible = 0; 383 | defaultConfigurationName = Release; 384 | }; 385 | /* End XCConfigurationList section */ 386 | }; 387 | rootObject = 1BD725CE1CF7795C005DBD79 /* Project object */; 388 | } 389 | -------------------------------------------------------------------------------- /ios/RNCookieManagerIOS/RNCookieManagerIOS.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Joseph P. Ferraro 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file here: https://github.com/joeferraro/react-native-cookies/blob/master/LICENSE.md. 6 | */ 7 | 8 | #import 9 | 10 | #import 11 | 12 | @interface RNCookieManagerIOS : NSObject 13 | 14 | @property (nonatomic, strong) NSDateFormatter *formatter; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/RNCookieManagerIOS/RNCookieManagerIOS.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Joseph P. Ferraro 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file here: https://github.com/joeferraro/react-native-cookies/blob/master/LICENSE.md. 6 | */ 7 | 8 | #import "RNCookieManagerIOS.h" 9 | #import 10 | 11 | static NSString * const NOT_AVAILABLE_ERROR_MESSAGE = @"WebKit/WebKit-Components are only available with iOS11 and higher!"; 12 | static NSString * const INVALID_URL_MISSING_HTTP = @"Invalid URL: It may be missing a protocol (ex. http:// or https://)."; 13 | static NSString * const INVALID_DOMAINS = @"Cookie URL host %@ and domain %@ mismatched. The cookie won't set correctly."; 14 | 15 | static inline BOOL isEmpty(id value) 16 | { 17 | return value == nil 18 | || ([value respondsToSelector:@selector(length)] && [(NSData *)value length] == 0) 19 | || ([value respondsToSelector:@selector(count)] && [(NSArray *)value count] == 0); 20 | } 21 | 22 | @implementation RNCookieManagerIOS 23 | 24 | - (instancetype)init 25 | { 26 | self = [super init]; 27 | if (self) { 28 | self.formatter = [NSDateFormatter new]; 29 | [self.formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"]; 30 | } 31 | return self; 32 | } 33 | 34 | + (BOOL)requiresMainQueueSetup 35 | { 36 | return NO; 37 | } 38 | 39 | RCT_EXPORT_MODULE() 40 | 41 | RCT_EXPORT_METHOD( 42 | set:(NSURL *)url 43 | cookie:(NSDictionary *)props 44 | useWebKit:(BOOL)useWebKit 45 | resolver:(RCTPromiseResolveBlock)resolve 46 | rejecter:(RCTPromiseRejectBlock)reject) 47 | { 48 | NSHTTPCookie *cookie; 49 | @try { 50 | cookie = [self makeHTTPCookieObject:url props:props]; 51 | } 52 | @catch ( NSException *e ) { 53 | reject(@"", [e reason], nil); 54 | return; 55 | } 56 | 57 | if (useWebKit) { 58 | if (@available(iOS 11.0, *)) { 59 | dispatch_async(dispatch_get_main_queue(), ^(){ 60 | WKHTTPCookieStore *cookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; 61 | [cookieStore setCookie:cookie completionHandler:^() { 62 | resolve(@(YES)); 63 | }]; 64 | }); 65 | } else { 66 | reject(@"", NOT_AVAILABLE_ERROR_MESSAGE, nil); 67 | } 68 | } else { 69 | [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; 70 | resolve(@(YES)); 71 | } 72 | } 73 | 74 | RCT_EXPORT_METHOD( 75 | setFromResponse:(NSURL *)url 76 | cookie:(NSString *)cookie 77 | resolver:(RCTPromiseResolveBlock)resolve 78 | rejecter:(RCTPromiseRejectBlock)reject) { 79 | 80 | NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:@{@"Set-Cookie": cookie} forURL:url]; 81 | [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:url mainDocumentURL:nil]; 82 | resolve(@(YES)); 83 | } 84 | 85 | RCT_EXPORT_METHOD( 86 | getFromResponse:(NSURL *)url 87 | resolver:(RCTPromiseResolveBlock)resolve 88 | rejecter:(RCTPromiseRejectBlock)reject) { 89 | NSURLRequest *request = [NSURLRequest requestWithURL:url]; 90 | [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] 91 | completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 92 | 93 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; 94 | NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:httpResponse.allHeaderFields forURL:response.URL]; 95 | NSMutableDictionary *dics = [NSMutableDictionary dictionary]; 96 | 97 | for (int i = 0; i < cookies.count; i++) { 98 | NSHTTPCookie *cookie = [cookies objectAtIndex:i]; 99 | [dics setObject:cookie.value forKey:cookie.name]; 100 | [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; 101 | } 102 | resolve(dics); 103 | }]; 104 | } 105 | 106 | RCT_EXPORT_METHOD( 107 | get:(NSURL *)url 108 | useWebKit:(BOOL)useWebKit 109 | resolver:(RCTPromiseResolveBlock)resolve 110 | rejecter:(RCTPromiseRejectBlock)reject) 111 | { 112 | if (useWebKit) { 113 | if (@available(iOS 11.0, *)) { 114 | dispatch_async(dispatch_get_main_queue(), ^(){ 115 | NSString *topLevelDomain = url.host; 116 | 117 | if (isEmpty(topLevelDomain)) { 118 | reject(@"", INVALID_URL_MISSING_HTTP, nil); 119 | return; 120 | } 121 | 122 | WKHTTPCookieStore *cookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; 123 | [cookieStore getAllCookies:^(NSArray *allCookies) { 124 | NSMutableDictionary *cookies = [NSMutableDictionary dictionary]; 125 | for (NSHTTPCookie *cookie in allCookies) { 126 | if ([topLevelDomain containsString:cookie.domain] || 127 | [cookie.domain isEqualToString: topLevelDomain]) { 128 | [cookies setObject:[self createCookieData:cookie] forKey:cookie.name]; 129 | } 130 | } 131 | resolve(cookies); 132 | }]; 133 | }); 134 | } else { 135 | reject(@"", NOT_AVAILABLE_ERROR_MESSAGE, nil); 136 | } 137 | } else { 138 | NSMutableDictionary *cookies = [NSMutableDictionary dictionary]; 139 | for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:url]) { 140 | [cookies setObject:[self createCookieData:cookie] forKey:cookie.name]; 141 | } 142 | resolve(cookies); 143 | } 144 | } 145 | 146 | RCT_EXPORT_METHOD( 147 | clearAll:(BOOL)useWebKit 148 | resolver:(RCTPromiseResolveBlock)resolve 149 | rejecter:(RCTPromiseRejectBlock)reject) 150 | { 151 | if (useWebKit) { 152 | if (@available(iOS 11.0, *)) { 153 | dispatch_async(dispatch_get_main_queue(), ^(){ 154 | // https://stackoverflow.com/questions/46465070/how-to-delete-cookies-from-wkhttpcookiestore#answer-47928399 155 | NSSet *websiteDataTypes = [NSSet setWithArray:@[WKWebsiteDataTypeCookies]]; 156 | NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0]; 157 | [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes 158 | modifiedSince:dateFrom 159 | completionHandler:^() { 160 | resolve(@(YES)); 161 | }]; 162 | }); 163 | } else { 164 | reject(@"", NOT_AVAILABLE_ERROR_MESSAGE, nil); 165 | } 166 | } else { 167 | NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 168 | for (NSHTTPCookie *c in cookieStorage.cookies) { 169 | [cookieStorage deleteCookie:c]; 170 | } 171 | [[NSUserDefaults standardUserDefaults] synchronize]; 172 | resolve(@(YES)); 173 | } 174 | } 175 | 176 | RCT_EXPORT_METHOD( 177 | clearByName:(NSURL *)url 178 | name:(NSString *)name 179 | useWebKit:(BOOL)useWebKit 180 | resolver:(RCTPromiseResolveBlock)resolve 181 | rejecter:(RCTPromiseRejectBlock)reject) { 182 | __block NSNumber * foundCookies = @NO; 183 | NSMutableArray * foundCookiesList = [NSMutableArray new]; 184 | 185 | if (useWebKit) { 186 | if (@available(iOS 11.0, *)) { 187 | dispatch_async(dispatch_get_main_queue(), ^(){ 188 | NSString *topLevelDomain = url.host; 189 | 190 | if (isEmpty(topLevelDomain)) { 191 | reject(@"", INVALID_URL_MISSING_HTTP, nil); 192 | return; 193 | } 194 | 195 | WKHTTPCookieStore *cookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; 196 | [cookieStore getAllCookies:^(NSArray *allCookies) { 197 | for (NSHTTPCookie *cookie in allCookies) { 198 | if ([name isEqualToString:cookie.name] && [self isMatchingDomain:topLevelDomain cookieDomain:cookie.domain]) { 199 | [foundCookiesList addObject:cookie]; 200 | foundCookies = @YES; 201 | } 202 | } 203 | for (NSHTTPCookie *fCookie in foundCookiesList) { 204 | [cookieStore deleteCookie:fCookie completionHandler:nil]; 205 | } 206 | resolve(foundCookies); 207 | }]; 208 | }); 209 | } else { 210 | reject(@"", NOT_AVAILABLE_ERROR_MESSAGE, nil); 211 | } 212 | } else { 213 | NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 214 | for (NSHTTPCookie *c in cookieStorage.cookies) { 215 | if ([[c name] isEqualToString:name] && [self isMatchingDomain:url.host cookieDomain:c.domain]) { 216 | [cookieStorage deleteCookie:c]; 217 | foundCookies = @YES; 218 | } 219 | } 220 | resolve(foundCookies); 221 | } 222 | } 223 | 224 | RCT_EXPORT_METHOD( 225 | getAll:(BOOL)useWebKit 226 | resolver:(RCTPromiseResolveBlock)resolve 227 | rejecter:(RCTPromiseRejectBlock)reject) 228 | { 229 | if (useWebKit) { 230 | if (@available(iOS 11.0, *)) { 231 | dispatch_async(dispatch_get_main_queue(), ^(){ 232 | WKHTTPCookieStore *cookieStore = [[WKWebsiteDataStore defaultDataStore] httpCookieStore]; 233 | [cookieStore getAllCookies:^(NSArray *allCookies) { 234 | resolve([self createCookieList: allCookies]); 235 | }]; 236 | }); 237 | } else { 238 | reject(@"", NOT_AVAILABLE_ERROR_MESSAGE, nil); 239 | } 240 | } else { 241 | NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 242 | resolve([self createCookieList:cookieStorage.cookies]); 243 | } 244 | } 245 | 246 | -(NSDictionary *)createCookieList:(NSArray*)cookies 247 | { 248 | NSMutableDictionary *cookieList = [NSMutableDictionary dictionary]; 249 | for (NSHTTPCookie *cookie in cookies) { 250 | [cookieList setObject:[self createCookieData:cookie] forKey:cookie.name]; 251 | } 252 | return cookieList; 253 | } 254 | 255 | -(NSHTTPCookie *)makeHTTPCookieObject:(NSURL *)url 256 | props:(NSDictionary *)props 257 | { 258 | NSString *topLevelDomain = url.host; 259 | 260 | if (isEmpty(topLevelDomain)){ 261 | NSException* myException = [NSException 262 | exceptionWithName:@"Exception" 263 | reason:INVALID_URL_MISSING_HTTP 264 | userInfo:nil]; 265 | @throw myException; 266 | } 267 | 268 | NSString *name = [RCTConvert NSString:props[@"name"]]; 269 | NSString *value = [RCTConvert NSString:props[@"value"]]; 270 | NSString *path = [RCTConvert NSString:props[@"path"]]; 271 | NSString *domain = [RCTConvert NSString:props[@"domain"]]; 272 | NSString *version = [RCTConvert NSString:props[@"version"]]; 273 | NSDate *expires = [RCTConvert NSDate:props[@"expires"]]; 274 | NSNumber *secure = [RCTConvert NSNumber:props[@"secure"]]; 275 | NSNumber *httpOnly = [RCTConvert NSNumber:props[@"httpOnly"]]; 276 | 277 | NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary]; 278 | [cookieProperties setObject:name forKey:NSHTTPCookieName]; 279 | [cookieProperties setObject:value forKey:NSHTTPCookieValue]; 280 | 281 | if (!isEmpty(path)) { 282 | [cookieProperties setObject:path forKey:NSHTTPCookiePath]; 283 | } else { 284 | [cookieProperties setObject:@"/" forKey:NSHTTPCookiePath]; 285 | } 286 | if (!isEmpty(domain)) { 287 | // Stripping the leading . to ensure the following check is accurate 288 | NSString *strippedDomain = domain; 289 | if ([strippedDomain hasPrefix:@"."]) { 290 | strippedDomain = [strippedDomain substringFromIndex:1]; 291 | } 292 | 293 | if (![topLevelDomain containsString:strippedDomain] && 294 | ![topLevelDomain isEqualToString: strippedDomain]) { 295 | NSException* myException = [NSException 296 | exceptionWithName:@"Exception" 297 | reason: [NSString stringWithFormat:INVALID_DOMAINS, topLevelDomain, domain] 298 | userInfo:nil]; 299 | @throw myException; 300 | } 301 | 302 | [cookieProperties setObject:domain forKey:NSHTTPCookieDomain]; 303 | } else { 304 | [cookieProperties setObject:topLevelDomain forKey:NSHTTPCookieDomain]; 305 | } 306 | if (!isEmpty(version)) { 307 | [cookieProperties setObject:version forKey:NSHTTPCookieVersion]; 308 | } 309 | if (!isEmpty(expires)) { 310 | [cookieProperties setObject:expires forKey:NSHTTPCookieExpires]; 311 | } 312 | if ([secure boolValue]) { 313 | [cookieProperties setObject:secure forKey:NSHTTPCookieSecure]; 314 | } 315 | if ([httpOnly boolValue]) { 316 | [cookieProperties setObject:httpOnly forKey:@"HttpOnly"]; 317 | } 318 | 319 | NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties]; 320 | 321 | return cookie; 322 | } 323 | 324 | -(NSDictionary *)createCookieData:(NSHTTPCookie *)cookie 325 | { 326 | NSMutableDictionary *cookieData = [NSMutableDictionary dictionary]; 327 | [cookieData setObject:cookie.name forKey:@"name"]; 328 | [cookieData setObject:cookie.value forKey:@"value"]; 329 | [cookieData setObject:cookie.path forKey:@"path"]; 330 | [cookieData setObject:cookie.domain forKey:@"domain"]; 331 | [cookieData setObject:[NSString stringWithFormat:@"%@", @(cookie.version)] forKey:@"version"]; 332 | if (!isEmpty(cookie.expiresDate)) { 333 | [cookieData setObject:[self.formatter stringFromDate:cookie.expiresDate] forKey:@"expires"]; 334 | } 335 | [cookieData setObject:[NSNumber numberWithBool:(BOOL)cookie.secure] forKey:@"secure"]; 336 | [cookieData setObject:[NSNumber numberWithBool:(BOOL)cookie.HTTPOnly] forKey:@"httpOnly"]; 337 | return cookieData; 338 | } 339 | 340 | -(BOOL)isMatchingDomain:(NSString *)originDomain 341 | cookieDomain:(NSString *)cookieDomain 342 | { 343 | if ([originDomain isEqualToString: cookieDomain]) { 344 | return @YES; 345 | } 346 | NSString *parentDomain = [cookieDomain hasPrefix:@"."] ? cookieDomain : [@"." stringByAppendingString: cookieDomain]; 347 | return [originDomain hasSuffix:parentDomain]; 348 | } 349 | 350 | @end 351 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@react-native-cookies/cookies", 3 | "version": "6.2.1", 4 | "description": "Cookie Manager for React Native", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/react-native-cookies/cookies.git", 8 | "baseUrl": "https://github.com/react-native-cookies/cookies" 9 | }, 10 | "keywords": [ 11 | "react native", 12 | "react-native-component", 13 | "android", 14 | "ios", 15 | "cookies", 16 | "webview" 17 | ], 18 | "files": [ 19 | "android", 20 | "ios", 21 | "index.d.ts", 22 | "react-native-cookies.podspec" 23 | ], 24 | "author": { 25 | "name": "Jason Safaiyeh", 26 | "email": "safaiyeh@protonmail.com" 27 | }, 28 | "license": "MIT", 29 | "licenseFilename": "LICENSE", 30 | "readmeFilename": "README.md", 31 | "bugs": { 32 | "url": "https://github.com/react-native-cookies/cookies/issues" 33 | }, 34 | "homepage": "https://github.com/react-native-cookies/cookies#readme", 35 | "main": "index.js", 36 | "types": "index.d.ts", 37 | "scripts": { 38 | "lint": "eslint index.js", 39 | "semantic-release": "semantic-release" 40 | }, 41 | "dependencies": { 42 | "invariant": "^2.2.4" 43 | }, 44 | "peerDependencies": { 45 | "react-native": ">= 0.60.2" 46 | }, 47 | "devDependencies": { 48 | "@react-native-community/eslint-config": "^0.0.6", 49 | "@react-native-community/eslint-plugin": "^1.0.0", 50 | "@semantic-release/git": "^8.0.0", 51 | "eslint": "^6.8.0", 52 | "semantic-release": "^17.2.3" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /react-native-cookies.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "react-native-cookies" 7 | s.version = package["version"] 8 | s.summary = package["description"] 9 | s.homepage = package["homepage"] 10 | s.license = package["license"] 11 | s.author = { package["author"]["name"] => package["author"]["email"] } 12 | s.source = { :git => "git@github.com:react-native-community/cookies.git", :tag => "v#{s.version}" } 13 | s.requires_arc = true 14 | s.platform = :ios, "7.0" 15 | s.preserve_paths = "*.framework" 16 | s.source_files = "ios/**/*.{h,m}" 17 | s.dependency "React-Core" 18 | end 19 | --------------------------------------------------------------------------------