├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── axsy │ ├── CallbackContext.java │ ├── SQLitePlugin.java │ ├── SQLitePluginConverter.java │ └── SQLitePluginPackage.java ├── example ├── .buckconfig ├── .eslintrc.js ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .watchmanconfig ├── App.tsx ├── __tests__ │ └── App-test.js ├── android │ ├── app │ │ ├── _BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets │ │ │ └── www │ │ │ │ └── 2x.db │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.tsx ├── ios │ ├── Podfile │ ├── Podfile.lock │ ├── example-tvOS │ │ └── Info.plist │ ├── example-tvOSTests │ │ └── Info.plist │ ├── example.xcodeproj │ │ └── project.pbxproj │ ├── example.xcworkspace │ │ └── contents.xcworkspacedata │ ├── example │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── main.m │ │ └── www │ │ │ └── 2x.db │ └── exampleTests │ │ ├── Info.plist │ │ └── exampleTests.m ├── jest.config.js ├── metro.config.js ├── package-lock.json ├── package.json ├── react-native.config.js ├── tsconfig.json └── windows │ ├── .gitignore │ ├── example.sln │ └── example │ ├── App.xaml │ ├── App.xaml.cs │ ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png │ ├── Bundle │ └── assets │ │ └── app.json │ ├── Package.appxmanifest │ ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml │ ├── ReactAssets │ └── .gitignore │ ├── example.csproj │ └── example_TemporaryKey.pfx ├── instructions ├── addFilesToProject.png ├── addFilesToProjectSelect.png ├── addlibs.png ├── libs.png ├── libssummary.png ├── projectStructureAfter.png └── require.png ├── ios ├── SQLite.h ├── SQLite.m ├── SQLite.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── SQLiteResult.h └── SQLiteResult.m ├── package-lock.json ├── package.json ├── react-native-sqlcipher-storage.podspec ├── src ├── index.js └── sqlite.core.js ├── windows ├── .gitignore ├── react-native-sqlcipher-storage.sln └── react-native-sqlcipher-storage │ ├── Properties │ └── AssemblyInfo.cs │ ├── ReactPackageManager.cs │ ├── SqliteModule.cs │ └── react-native-sqlcipher-storage.csproj └── windowsOld └── SQLite3-WinRT ├── SQLite3 ├── .vs │ └── SQLite3 │ │ └── v14 │ │ └── .suo ├── Common.cpp ├── Common.h ├── Constants.cpp ├── Constants.h ├── Database.cpp ├── Database.h ├── SQLCipher │ ├── .gitignore │ ├── SQLCipher.sln │ └── SQLCipher │ │ ├── Class1.cpp │ │ ├── Class1.h │ │ ├── PropertySheet.props │ │ ├── PropertySheet1.props │ │ ├── SQLCipher.vcxproj │ │ ├── SQLCipher.vcxproj.filters │ │ ├── pch.cpp │ │ └── pch.h ├── SQLiteModule.cs ├── Statement.cpp └── Statement.h └── SQLite3JS └── js └── SQLite3.js /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # OSX 30 | # 31 | .DS_Store 32 | 33 | # Xcode 34 | # 35 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 36 | 37 | ## Build generated 38 | build/ 39 | DerivedData 40 | 41 | ## Various settings 42 | *.pbxuser 43 | !default.pbxuser 44 | *.mode1v3 45 | !default.mode1v3 46 | *.mode2v3 47 | !default.mode2v3 48 | *.perspectivev3 49 | !default.perspectivev3 50 | xcuserdata 51 | IDEWorkspaceChecks.plist 52 | 53 | ## Other 54 | *.xccheckout 55 | *.moved-aside 56 | *.xcuserstate 57 | *.xcscmblueprint 58 | *.xcscheme 59 | 60 | android/.gradle/ 61 | # node.js 62 | # 63 | node_modules/ 64 | npm-debug.log 65 | *.iml 66 | .idea 67 | local.properties 68 | 69 | # Created by https://www.gitignore.io/api/rade,gradle 70 | 71 | #!! ERROR: rade is undefined. Use list command to see defined gitignore types !!# 72 | 73 | ### Gradle ### 74 | .gradle 75 | gradle 76 | gradlew 77 | gradlew.bat 78 | 79 | # Ignore Gradle GUI config 80 | gradle-app.setting 81 | 82 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 83 | !gradle-wrapper.jar 84 | 85 | # Eclipse 86 | .project 87 | 88 | .vs/ 89 | # generated by bob 90 | lib/ 91 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 andpor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-sqlcipher-storage 2 | SQLCipher plugin for React Native. Based on the hard work already put in on the react-native-sqlite-storage project and on cordova-sqlcipher-adapter, this is a minor change to the former in order to use the sqlcipher backend from the latter. 3 | 4 | Features: 5 | 1. iOS and Android supported via identical JavaScript API. 6 | 2. Android in pure Java and Native modes 7 | 3. SQL transactions 8 | 4. JavaScript interface via plain callbacks or Promises. 9 | 5. Pre-populated SQLite database import from application sandbox 10 | 11 | 12 | #How to use (iOS): 13 | 14 | #### Step 1. NPM install 15 | 16 | ```shell 17 | npm install --save react-native-sqlcipher-storage 18 | ``` 19 | 20 | #### Step 2. XCode SQLite project dependency set up 21 | 22 | Drag the SQLite Xcode project as a dependency project into your React Native XCode project 23 | 24 | ![alt tag](https://raw.github.com/axsy-dev/react-native-sqlcipher-storage/master/instructions/libs.png) 25 | 26 | #### Step 3. XCode SQLite libraries dependency set up 27 | 28 | Add libSQLite.a (from Workspace location) to the required Libraries and Frameworks. Also add Security.framework (XCode 7) in the same fashion using Required Libraries view (Do not just add them manually as the build paths will not be properly set) 29 | 30 | ![alt tag](https://raw.github.com/axsy-dev/react-native-sqlcipher-storage/master/instructions/addlibs.png) 31 | 32 | #### Step 4. Application JavaScript require 33 | 34 | Add var SQLite = require('react-native-sqlcipher-storage') to your index.ios.js 35 | 36 | ![alt tag](https://raw.github.com/axsy-dev/react-native-sqlcipher-storage/master/instructions/require.png) 37 | 38 | #### Step 5. Application JavaScript code using the SQLite plugin 39 | 40 | Add JS application code to use SQLite API in your index.ios.js etc. Here is some sample code. For full working example see test/TestRunner/index.ios.js. 41 | 42 | ```javascript 43 | errorCB(err) { 44 | console.log("SQL Error: " + err); 45 | }, 46 | 47 | successCB() { 48 | console.log("SQL executed fine"); 49 | }, 50 | 51 | openCB() { 52 | console.log("Database OPENED"); 53 | }, 54 | 55 | var db = SQLite.openDatabase({"name": "test.db", "key": "password"}, openCB, errorCB); 56 | db.transaction((tx) => { 57 | tx.executeSql('SELECT * FROM Employees a, Departments b WHERE a.department = b.department_id', [], (tx, results) => { 58 | console.log("Query completed"); 59 | 60 | // Get rows with Web SQL Database spec compliance. 61 | 62 | var len = results.rows.length; 63 | for (let i = 0; i < len; i++) { 64 | let row = results.rows.item(i); 65 | console.log(`Employee name: ${row.name}, Dept Name: ${row.deptName}`); 66 | } 67 | 68 | // Alternatively, you can use the non-standard raw method. 69 | 70 | /* 71 | let rows = results.rows.raw(); // shallow copy of rows Array 72 | 73 | rows.map(row => console.log(`Employee name: ${row.name}, Dept Name: ${row.deptName}`)); 74 | */ 75 | }); 76 | }); 77 | ``` 78 | 79 | #How to use (Android): 80 | 81 | #### Step 1 - NPM Install 82 | 83 | ```shell 84 | npm install --save react-native-sqlcipher-storage 85 | ``` 86 | #### Step 2 - Update Gradle Settings 87 | 88 | ```gradle 89 | // file: android/settings.gradle 90 | ... 91 | 92 | include ':react-native-sqlcipher-storage' 93 | project(':react-native-sqlcipher-storage').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sqlcipher-storage/src/android') 94 | ``` 95 | 96 | #### Step 3 - Update app Gradle Build 97 | 98 | ```gradle 99 | // file: android/app/build.gradle 100 | ... 101 | 102 | dependencies { 103 | ... 104 | compile project(':react-native-sqlcipher-storage') 105 | } 106 | ``` 107 | 108 | #### Step 4 - Register React Package (this should work on React version but if it does not , try the ReactActivity based approach 109 | 110 | ```java 111 | ... 112 | import org.pgsqlite.SQLitePluginPackage; 113 | 114 | public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { 115 | 116 | private ReactInstanceManager mReactInstanceManager; 117 | private ReactRootView mReactRootView; 118 | 119 | @Override 120 | protected void onCreate(Bundle savedInstanceState) { 121 | super.onCreate(savedInstanceState); 122 | mReactRootView = new ReactRootView(this); 123 | mReactInstanceManager = ReactInstanceManager.builder() 124 | .setApplication(getApplication()) 125 | .setBundleAssetName("index.android.bundle") // this is dependant on how you name you JS files, example assumes index.android.js 126 | .setJSMainModuleName("index.android") // this is dependant on how you name you JS files, example assumes index.android.js 127 | .addPackage(new MainReactPackage()) 128 | .addPackage(new SQLitePluginPackage(this)) // register SQLite Plugin here 129 | .setUseDeveloperSupport(BuildConfig.DEBUG) 130 | .setInitialLifecycleState(LifecycleState.RESUMED) 131 | .build(); 132 | mReactRootView.startReactApplication(mReactInstanceManager, "AwesomeProject", null); //change "AwesomeProject" to name of your app 133 | setContentView(mReactRootView); 134 | } 135 | ... 136 | 137 | ``` 138 | 139 | Alternative approach on newer versions of React Native (0.18+): 140 | 141 | ```java 142 | import org.pgsqlite.SQLitePluginPackage; 143 | 144 | public class MainActivity extends ReactActivity { 145 | ...... 146 | 147 | /** 148 | * A list of packages used by the app. If the app uses additional views 149 | * or modules besides the default ones, add more packages here. 150 | */ 151 | @Override 152 | protected List getPackages() { 153 | return Arrays.asList( 154 | new SQLitePluginPackage(this)) // register SQLite Plugin here 155 | new MainReactPackage()); 156 | } 157 | } 158 | ``` 159 | 160 | #### Step 5 - Require and use in Javascript - see full examples (callbacks and Promise) in test directory. 161 | 162 | ```js 163 | // file: index.android.js 164 | 165 | var React = require('react-native'); 166 | var SQLite = require('react-native-sqlcipher-storage') 167 | ... 168 | ``` 169 | #How to use (Windows Universal Platform): 170 | Preceding steps 171 | Its assumed you have a winjs project and have done the following 172 | ```shell 173 | npm install -g react-native-winjs-cli 174 | react-native-winjs init 175 | ``` 176 | 177 | #### Step 1 - NPM Install 178 | ```shell 179 | npm install --save react-native-sqlcipher-storage 180 | 181 | ``` 182 | 183 | #### Step 2 - Build OpenSSL 184 | Download and build OpenSSL (static library variant) from here: https://github.com/Microsoft/openssl/ following the instructions in INSTALL.WINUNIVERSAL. You'll also need to create an environment variable OPENSSL to point at the install location 185 | 186 | #### Add SqlCipher to your windows project 187 | 1. File -> Add -> Existing Project 188 | 2. Select project in src\windows\SQLite3-WinRT\SQLite3\SqlCipher\SqlCipher\SQLCipher.vcxproj 189 | 3. In your main windows universal application, Select References and add SqlCipher 190 | 4. The webpack process will not bundle the file in src\windows\SQLite3-WinRT\SQLite3JS. Add that file to your visual studio project and to the html file that drives the project. 191 | 192 | # TestRunner 193 | 194 | in test/TestRunner there is an example ready to go. From that directory do : 195 | 196 | 1. npm install 197 | 2. android : react-native run-android 198 | 3. ios : react-native run-ios 199 | 4. windows : (After building OpenSSL); open src\windows\SQLite3-WinRT\SQLite3\SqlCipher\SqlCipher.sln. Run the TestRunner app 200 | 201 | 202 | Enjoy! 203 | #Original react-native-sqlite-storage plugin from andpor 204 | https://github.com/andpor/react-native-sqlite-storage 205 | 206 | #Original Cordova SQLite Bindings from Chris Brody 207 | https://github.com/litehelpers/Cordova-sqlite-storage 208 | 209 | #Cordova SQLCipher Bindings from Chris Brody 210 | https://github.com/litehelpers/Cordova-sqlcipher-adapter 211 | 212 | The issues and limitations for the actual SQLite can be found on these sites. 213 | 214 | https://msdn.microsoft.com/en-us/windows/uwp/debug-test-perf/windows-runtime-components-and-optimizing-interop 215 | 216 | 217 | Windows implemnetation 218 | c++ implementation is problematic on windows due to lack of OPENSSL build 219 | Possibility to use sqleet which has no such dependency? 220 | https://github.com/resilar/sqleet -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | // android/build.gradle 3 | 4 | // based on: 5 | // 6 | // * https://github.com/facebook/react-native/blob/0.60-stable/template/android/build.gradle 7 | // original location: 8 | // - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/build.gradle 9 | // 10 | // * https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle 11 | // original location: 12 | // - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle 13 | 14 | def DEFAULT_COMPILE_SDK_VERSION = 28 15 | def DEFAULT_BUILD_TOOLS_VERSION = '28.0.3' 16 | def DEFAULT_MIN_SDK_VERSION = 16 17 | def DEFAULT_TARGET_SDK_VERSION = 28 18 | 19 | def safeExtGet(prop, fallback) { 20 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 21 | } 22 | 23 | apply plugin: 'com.android.library' 24 | apply plugin: 'maven-publish' 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.4.1' 38 | } 39 | } 40 | } 41 | 42 | android { 43 | compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) 44 | buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) 45 | 46 | defaultConfig { 47 | minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) 48 | targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) 49 | versionCode 1 50 | versionName "1.0" 51 | } 52 | lintOptions { 53 | abortOnError false 54 | } 55 | } 56 | 57 | repositories { 58 | // ref: https://www.baeldung.com/maven-local-repository 59 | mavenLocal() 60 | maven { 61 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 62 | url "$rootDir/../node_modules/react-native/android" 63 | } 64 | maven { 65 | // Android JSC is installed from npm 66 | url "$rootDir/../node_modules/jsc-android/dist" 67 | } 68 | google() 69 | jcenter() 70 | } 71 | 72 | dependencies { 73 | implementation 'com.facebook.react:react-native:+' 74 | implementation 'net.zetetic:android-database-sqlcipher:4.4.2@aar' 75 | implementation "androidx.sqlite:sqlite:2.0.1" 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/src/main/java/com/axsy/CallbackContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Written by Andrzej Porebski Nov 14/2015 3 | * 4 | * Copyright (c) 2015, Andrzej Porebski 5 | */ 6 | package com.axsy; 7 | 8 | import com.facebook.react.bridge.Callback; 9 | import com.facebook.react.bridge.WritableArray; 10 | import com.facebook.react.bridge.WritableMap; 11 | 12 | 13 | 14 | public class CallbackContext { 15 | 16 | private static final String LOG_TAG = CallbackContext.class.getSimpleName(); 17 | 18 | private Callback successCallback; 19 | private Callback errorCallback; 20 | 21 | public CallbackContext(Callback success, Callback error) { 22 | this.successCallback = success; 23 | this.errorCallback = error; 24 | } 25 | 26 | /** 27 | * Helper for success callbacks that just returns the Status.OK by default 28 | * 29 | * @param message The message to add to the success result. 30 | */ 31 | public void success(WritableMap message) { 32 | successCallback.invoke(message); 33 | } 34 | 35 | /** 36 | * Helper for success callbacks that just returns the Status.OK by default 37 | * 38 | * @param message The message to add to the success result. 39 | */ 40 | public void success(String message) { 41 | successCallback.invoke(message); 42 | } 43 | 44 | /** 45 | * Helper for success callbacks that just returns the Status.OK by default 46 | * 47 | * @param message The message to add to the success result. 48 | */ 49 | public void success(WritableArray message) { 50 | successCallback.invoke(message); 51 | } 52 | 53 | /** 54 | * Helper for success callbacks that just returns the Status.OK by default 55 | */ 56 | public void success() { 57 | successCallback.invoke("Success"); 58 | } 59 | 60 | /** 61 | * Helper for error callbacks that just returns the Status.ERROR by default 62 | * 63 | * @param message The message to add to the error result. 64 | */ 65 | public void error(WritableMap message) { 66 | errorCallback.invoke(message); 67 | } 68 | 69 | /** 70 | * Helper for error callbacks that just returns the Status.ERROR by default 71 | * 72 | * @param message The message to add to the error result. 73 | */ 74 | public void error(String message) { 75 | errorCallback.invoke(message); 76 | } 77 | } -------------------------------------------------------------------------------- /android/src/main/java/com/axsy/SQLitePluginConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Written by Andrzej Porebski Nov 14/2015 3 | * 4 | * Copyright (c) 2015, Andrzej Porebski 5 | */ 6 | 7 | package com.axsy; 8 | 9 | import com.facebook.react.bridge.NoSuchKeyException; 10 | import com.facebook.react.bridge.ReadableArray; 11 | import com.facebook.react.bridge.ReadableMap; 12 | import com.facebook.react.bridge.ReadableType; 13 | 14 | public abstract class SQLitePluginConverter { 15 | 16 | /** 17 | * Returns the value at {@code key} if it exists, coercing it if 18 | * necessary. 19 | */ 20 | static String getString(ReadableMap map, String key, String defaultValue) { 21 | if (map == null){ 22 | return defaultValue; 23 | } 24 | try { 25 | ReadableType type = map.getType(key); 26 | switch (type) { 27 | case Number: 28 | double value = map.getDouble(key); 29 | if (value == (long) value) { 30 | return String.valueOf((long) value); 31 | } else { 32 | return String.valueOf(value); 33 | } 34 | case Boolean: 35 | return String.valueOf(map.getBoolean(key)); 36 | case String: 37 | return map.getString(key); 38 | case Null: 39 | return null; 40 | default: 41 | return defaultValue; 42 | } 43 | } catch(NoSuchKeyException ex){ 44 | return defaultValue; 45 | } 46 | } 47 | 48 | /** 49 | * Returns the value at {@code key} if it exists, coercing it if 50 | * necessary. 51 | */ 52 | static boolean getBoolean(ReadableMap map, String key, boolean defaultValue) { 53 | if (map == null){ 54 | return defaultValue; 55 | } 56 | try { 57 | ReadableType type = map.getType(key); 58 | switch (type) { 59 | case Boolean: 60 | return map.getBoolean(key); 61 | case String: { 62 | String value = map.getString(key); 63 | if ("true".equalsIgnoreCase(value)) { 64 | return true; 65 | } else if ("false".equalsIgnoreCase(value)) { 66 | return false; 67 | } 68 | return false; 69 | } 70 | case Number: { 71 | double value = map.getDouble(key); 72 | if (value == (long) 0) { 73 | return Boolean.FALSE; 74 | } else { 75 | return Boolean.TRUE; 76 | } 77 | } 78 | case Null: 79 | return false; 80 | default: 81 | return defaultValue; 82 | } 83 | } catch(NoSuchKeyException ex){ 84 | return defaultValue; 85 | } 86 | } 87 | 88 | /** 89 | * Returns the value at {@code index} if it exists, coercing it if 90 | * necessary. 91 | */ 92 | static String getString(ReadableArray array, int index, String defaultValue) { 93 | if (array == null){ 94 | return defaultValue; 95 | } 96 | try { 97 | ReadableType type = array.getType(index); 98 | switch (type) { 99 | case Number: 100 | double value = array.getDouble(index); 101 | if (value == (long) value) { 102 | return String.valueOf((long) value); 103 | } else { 104 | return String.valueOf(value); 105 | } 106 | case Boolean: 107 | return String.valueOf(array.getBoolean(index)); 108 | case String: 109 | return array.getString(index); 110 | case Null: 111 | return null; 112 | default: 113 | return defaultValue; 114 | } 115 | } catch(NoSuchKeyException ex){ 116 | return defaultValue; 117 | } 118 | } 119 | 120 | /** 121 | * Returns the value at {@code index} if it exists, coercing it if 122 | * necessary. 123 | */ 124 | static boolean getBoolean(ReadableArray array, int index, boolean defaultValue) { 125 | if (array == null){ 126 | return defaultValue; 127 | } 128 | try { 129 | ReadableType type = array.getType(index); 130 | switch (type) { 131 | case Boolean: 132 | return array.getBoolean(index); 133 | case String: { 134 | String value = array.getString(index); 135 | if ("true".equalsIgnoreCase(value)) { 136 | return true; 137 | } else if ("false".equalsIgnoreCase(value)) { 138 | return false; 139 | } 140 | return false; 141 | } 142 | case Number: { 143 | double value = array.getDouble(index); 144 | if (value == 0) { 145 | return Boolean.FALSE; 146 | } else { 147 | return Boolean.TRUE; 148 | } 149 | } 150 | case Null: 151 | return false; 152 | default: 153 | return defaultValue; 154 | } 155 | } catch(NoSuchKeyException ex){ 156 | return defaultValue; 157 | } 158 | } 159 | 160 | 161 | static Object get(ReadableMap map,String key,Object defaultValue){ 162 | if (map == null){ 163 | return defaultValue; 164 | } 165 | 166 | try { 167 | Object value = null; 168 | ReadableType type = map.getType(key); 169 | switch(type){ 170 | case Boolean: 171 | value = map.getBoolean(key); 172 | break; 173 | case Number: 174 | value = map.getDouble(key); 175 | break; 176 | case String: 177 | value = map.getString(key); 178 | break; 179 | case Map: 180 | value = map.getMap(key); 181 | break; 182 | case Array: 183 | value = map.getArray(key); 184 | break; 185 | case Null: 186 | value = null; 187 | break; 188 | } 189 | return value; 190 | } catch (NoSuchKeyException ex){ 191 | return defaultValue; 192 | } 193 | } 194 | 195 | static Object get(ReadableArray array,int index,Object defaultValue){ 196 | if (array == null){ 197 | return defaultValue; 198 | } 199 | 200 | try { 201 | Object value = null; 202 | ReadableType type = array.getType(index); 203 | switch(type){ 204 | case Boolean: 205 | value = array.getBoolean(index); 206 | break; 207 | case Number: 208 | value = array.getDouble(index); 209 | break; 210 | case String: 211 | value = array.getString(index); 212 | break; 213 | case Map: 214 | value = array.getMap(index); 215 | break; 216 | case Array: 217 | value = array.getArray(index); 218 | break; 219 | case Null: 220 | break; 221 | } 222 | return value; 223 | } catch (NoSuchKeyException ex){ 224 | return defaultValue; 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /android/src/main/java/com/axsy/SQLitePluginPackage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Written by Andrzej Porebski Nov 14/2015 3 | * 4 | * Copyright (c) 2015, Andrzej Porebski 5 | */ 6 | package com.axsy; 7 | 8 | import android.app.Activity; 9 | 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.bridge.JavaScriptModule; 12 | import com.facebook.react.bridge.NativeModule; 13 | import com.facebook.react.bridge.ReactApplicationContext; 14 | import com.facebook.react.uimanager.ViewManager; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Collections; 18 | 19 | import java.util.List; 20 | 21 | public class SQLitePluginPackage implements ReactPackage { 22 | 23 | /** 24 | * @deprecated, use method without activity 25 | * activity parameter is ignored 26 | */ 27 | public SQLitePluginPackage(Activity activity){ 28 | this(); 29 | } 30 | 31 | public SQLitePluginPackage() { 32 | } 33 | 34 | @Override 35 | public List createNativeModules( 36 | ReactApplicationContext reactContext) { 37 | List modules = new ArrayList<>(); 38 | 39 | modules.add(new SQLitePlugin(reactContext)); 40 | 41 | return modules; 42 | } 43 | 44 | @Override 45 | public List createViewManagers(ReactApplicationContext reactContext) { 46 | return Collections.emptyList(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | 9 | ; Ignore polyfills 10 | node_modules/react-native/Libraries/polyfills/.* 11 | 12 | ; These should not be required directly 13 | ; require from fbjs/lib instead: require('fbjs/lib/warning') 14 | node_modules/warning/.* 15 | 16 | ; Flow doesn't support platforms 17 | .*/Libraries/Utilities/LoadingView.js 18 | 19 | [untyped] 20 | .*/node_modules/@react-native-community/cli/.*/.* 21 | 22 | [include] 23 | 24 | [libs] 25 | node_modules/react-native/Libraries/react-native/react-native-interface.js 26 | node_modules/react-native/flow/ 27 | 28 | [options] 29 | emoji=true 30 | 31 | esproposal.optional_chaining=enable 32 | esproposal.nullish_coalescing=enable 33 | 34 | module.file_ext=.js 35 | module.file_ext=.json 36 | module.file_ext=.ios.js 37 | 38 | munge_underscores=true 39 | 40 | module.name_mapper='^react-native$' -> '/node_modules/react-native/Libraries/react-native/react-native-implementation' 41 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' 42 | 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\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' 43 | 44 | suppress_type=$FlowIssue 45 | suppress_type=$FlowFixMe 46 | suppress_type=$FlowFixMeProps 47 | suppress_type=$FlowFixMeState 48 | 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ 51 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 52 | 53 | [lints] 54 | sketchy-null-number=warn 55 | sketchy-null-mixed=warn 56 | sketchy-number=warn 57 | untyped-type-import=warn 58 | nonstrict-import=warn 59 | deprecated-type=warn 60 | unsafe-getters-setters=warn 61 | inexact-spread=warn 62 | unnecessary-invariant=warn 63 | signature-verification-failure=warn 64 | deprecated-utility=error 65 | 66 | [strict] 67 | deprecated-type 68 | nonstrict-import 69 | sketchy-null 70 | unclear-type 71 | unsafe-getters-setters 72 | untyped-import 73 | untyped-type-import 74 | 75 | [version] 76 | ^0.105.0 77 | -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | yarn-error.log 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | !debug.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | /ios/Pods/ 60 | -------------------------------------------------------------------------------- /example/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/App.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * sqlite.ios.promise.js 3 | * 4 | * Created by Andrzej Porebski on 10/29/15. 5 | * Copyright (c) 2015 Andrzej Porebski. 6 | * 7 | * Test App using Promise for react-naive-sqlite-storage 8 | * 9 | * This library is available under the terms of the MIT License (2008). 10 | * See http://opensource.org/licenses/alphabetical for full text. 11 | */ 12 | 'use strict'; 13 | 14 | import SQLite from 'react-native-sqlcipher-storage'; 15 | 16 | SQLite.DEBUG(true); 17 | SQLite.enablePromise(true); 18 | 19 | import React from 'react'; 20 | import { 21 | StyleSheet, 22 | Text, 23 | View, 24 | Button, 25 | FlatList, 26 | SafeAreaView 27 | } from 'react-native'; 28 | import RNFS from "react-native-fs"; 29 | 30 | 31 | type Database = Object; 32 | var database_name = "Test.db"; 33 | var database_key = "password"; 34 | var bad_database_key = "bad"; 35 | var db: Database; 36 | 37 | class App extends React.Component { 38 | 39 | state : {progress: string[]} = { 40 | progress: [] 41 | } 42 | 43 | componentWillUnmount() { 44 | this.closeDatabase(); 45 | } 46 | 47 | errorCB = (err: string) => { 48 | console.log("error: ",err); 49 | const { progress } = this.state 50 | progress.push(`Error : ${err}`); 51 | this.setState({progress}); 52 | } 53 | 54 | addProgress = (text) => { 55 | let {progress} = this.state; 56 | this.setState({progress: [...progress, text]}); 57 | } 58 | 59 | populateDatabase = (db: Database) => { 60 | this.addProgress("Database integrity check"); 61 | db.executeSql('SELECT 1 FROM Version LIMIT 1').then(() =>{ 62 | this.addProgress("Database is ready ... executing query ..."); 63 | 64 | db.transaction(this.queryEmployees).then(() => { 65 | this.addProgress("Processing completed"); 66 | }); 67 | }).catch((error) =>{ 68 | console.log("Received error: ", error) 69 | this.addProgress("Database not yet ready ... populating data"); 70 | db.transaction(this.populateDB).then(() =>{ 71 | this.addProgress("Database populated ... executing query ..."); 72 | db.transaction(this.queryEmployees).then((result) => { 73 | this.addProgress("Processing completed"); 74 | }); 75 | }); 76 | }); 77 | } 78 | 79 | populateDB = (tx) => { 80 | 81 | this.addProgress("Executing DROP stmts"); 82 | 83 | tx.executeSql('DROP TABLE IF EXISTS Employees;'); 84 | tx.executeSql('DROP TABLE IF EXISTS Offices;'); 85 | tx.executeSql('DROP TABLE IF EXISTS Departments;'); 86 | 87 | this.addProgress("Executing CREATE stmts"); 88 | 89 | tx.executeSql('CREATE TABLE IF NOT EXISTS Version( ' 90 | + 'version_id INTEGER PRIMARY KEY NOT NULL); ').catch((error: Error) => { 91 | this.errorCB(error.message); 92 | }); 93 | 94 | tx.executeSql('CREATE TABLE IF NOT EXISTS Departments( ' 95 | + 'department_id INTEGER PRIMARY KEY NOT NULL, ' 96 | + 'name VARCHAR(30) ); ').catch((error: Error) => { 97 | this.errorCB(error.message) 98 | }); 99 | 100 | tx.executeSql('CREATE TABLE IF NOT EXISTS Offices( ' 101 | + 'office_id INTEGER PRIMARY KEY NOT NULL, ' 102 | + 'name VARCHAR(20), ' 103 | + 'longtitude FLOAT, ' 104 | + 'latitude FLOAT ) ; ').catch((error: Error) => { 105 | this.errorCB(error.message) 106 | }); 107 | 108 | tx.executeSql('CREATE TABLE IF NOT EXISTS Employees( ' 109 | + 'employe_id INTEGER PRIMARY KEY NOT NULL, ' 110 | + 'name VARCHAR(55), ' 111 | + 'office INTEGER, ' 112 | + 'department INTEGER, ' 113 | + 'FOREIGN KEY ( office ) REFERENCES Offices ( office_id ) ' 114 | + 'FOREIGN KEY ( department ) REFERENCES Departments ( department_id ));').catch((error: Error) => { 115 | this.errorCB(error.message) 116 | }); 117 | 118 | this.addProgress("Executing INSERT stmts"); 119 | 120 | 121 | tx.executeSql('INSERT INTO Departments (name) VALUES ("Client Services");'); 122 | tx.executeSql('INSERT INTO Departments (name) VALUES ("Investor Services");'); 123 | tx.executeSql('INSERT INTO Departments (name) VALUES ("Shipping");'); 124 | tx.executeSql('INSERT INTO Departments (name) VALUES ("Direct Sales");'); 125 | 126 | tx.executeSql('INSERT INTO Offices (name, longtitude, latitude) VALUES ("Denver", 59.8, 34.1);'); 127 | tx.executeSql('INSERT INTO Offices (name, longtitude, latitude) VALUES ("Warsaw", 15.7, 54.1);'); 128 | tx.executeSql('INSERT INTO Offices (name, longtitude, latitude) VALUES ("Berlin", 35.3, 12.1);'); 129 | tx.executeSql('INSERT INTO Offices (name, longtitude, latitude) VALUES ("Paris", 10.7, 14.1);'); 130 | 131 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES (?,?,?);', ["Sylvester Stallone", 2, 4]); 132 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES (?,?,?);', ["Elvis Presley", 2, 4]); 133 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES ("Leslie Nelson", 3, 4);'); 134 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES ("Fidel Castro", 3, 3);'); 135 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES ("Bill Clinton", 1, 3);'); 136 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES ("Margaret thischer", 1, 3);'); 137 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES ("Donald Trump", 1, 3);'); 138 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES ("Dr DRE", 2, 2);'); 139 | tx.executeSql('INSERT INTO Employees (name, office, department) VALUES ("Samantha Fox", 2, 1);'); 140 | this.addProgress("all config SQL done"); 141 | }; 142 | 143 | queryEmployees = (tx) => { 144 | 145 | console.log("Executing employee query"); 146 | tx.executeSql('SELECT a.name, b.name as deptName FROM Employees a, Departments b WHERE a.department = b.department_id').then(([tx,results]) => { 147 | this.addProgress("Query completed"); 148 | var len = results.rows.length; 149 | for (let i = 0; i < len; i++) { 150 | let row = results.rows.item(i); 151 | this.addProgress(`Empl Name: ${row.name}, Dept Name: ${row.deptName}`); 152 | } 153 | }).catch((error: Error) => { 154 | console.log(error); 155 | }); 156 | }; 157 | 158 | loadAndQueryDB = (goodPassword) => { 159 | this.addProgress("Opening database ..."); 160 | this.addProgress(goodPassword ? "Good Password" : "Bad Password"); 161 | SQLite.openDatabase({'name': database_name, 'key': goodPassword ? database_key : bad_database_key}).then((DB) => { 162 | db = DB; 163 | this.addProgress("Database OPEN"); 164 | this.populateDatabase(DB); 165 | }).catch((error: Error) => { 166 | this.addProgress("Database failed to open") 167 | }); 168 | }; 169 | 170 | closeDb = async () => { 171 | try { 172 | await db.close(); 173 | this.addProgress("Database CLOSED"); 174 | } 175 | catch(error) { 176 | this.errorCB(error.message); 177 | } 178 | } 179 | 180 | closeDatabase = () => { 181 | if (db) { 182 | this.setState({progress: ["Closing DB"]}, this.closeDb); 183 | } else { 184 | this.addProgress("Database was not OPENED"); 185 | } 186 | }; 187 | 188 | deleteDatabase = () => { 189 | this.setState({progress: ["Deleting database"]}, async () => { 190 | try { 191 | await SQLite.deleteDatabase(database_name); 192 | this.addProgress("Database DELETED"); 193 | } 194 | catch(error) { 195 | this.errorCB(error.message); 196 | } 197 | }); 198 | }; 199 | 200 | runDemo = () => { 201 | const progress = ["Starting SQLite Demo"]; 202 | this.setState({progress}, () =>this.loadAndQueryDB(true)); 203 | }; 204 | 205 | runBadPwd = () => { 206 | this.setState({progress: ["Trying to open with bad password"]}, async () => { 207 | await this.closeDb(); 208 | await this.loadAndQueryDB(false); 209 | 210 | }); 211 | } 212 | 213 | renderProgressEntry = ({item}: {item: string})=> { 214 | return ( 215 | 216 | {item} 217 | 218 | ) 219 | }; 220 | 221 | migrateDb = async () => { 222 | try { 223 | const DB = await SQLite.openDatabase({name: "2x.db", createFromLocation: 1, key: "test"}); 224 | this.addProgress("Migrated database"); 225 | await DB.close(); 226 | this.addProgress("Closed database"); 227 | await SQLite.deleteDatabase("2x.db"); 228 | this.addProgress("Deleted Database"); 229 | } 230 | catch(err) { 231 | this.addProgress("Database migration failed"); 232 | } 233 | } 234 | 235 | render(){ 236 | return ( 237 | 238 |