SQLite with Android NDK
It isn't possible to use the built-in SQLite via NDK (or it wasn't six months ago when I looked into this), that can only be accessed with Java. However it may be possible to link in your own completely separate C++ build of SQLite.
Add SQLite to Android NDK project
You need to have these 3 files in your project: sqlite3.c
, sqlite3.h
, sqlite3ext.h
(not sure about the last one). Basic operations (create db, create table and insert values):
bool createTable() {
/* Open database */
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open(databaseName, &db);
if (rc != SQLITE_OK) {
//Can't open database/
sqlite3_open_v2(DB_FILE, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
}
/* Create SQL statement */
const char *createQuery =
"CREATE TABLE IF NOT EXISTS cities (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);";
/* Execute SQL statement */
rc = sqlite3_exec(db, createQuery, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
sqlite3_free(zErrMsg);
return false;
}
sqlite3_close(db);
return true;
}
insert:
bool insertToDb(CityWeather *pCityWeather) {
sqlite3 *db;
char *zErrMsg = 0;
int rc;
/* Open database */
rc = sqlite3_open(databaseName, &db);
if (rc) {
sqlite3_open_v2(DB_FILE, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
}
const char *pCityName = pCityWeather->getName().c_str();
char insertQuery[50];
strcpy (insertQuery,"INSERT INTO cities (name) VALUES ('");
strcat (insertQuery, pCityName);
strcat (insertQuery, "');");
puts (insertQuery);
delete pCityWeather;
/* Execute SQL statement */
rc = sqlite3_exec(db, insertQuery, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
sqlite3_free(zErrMsg);
}
sqlite3_close(db);
return true;
}
Connect to SQLite in android NDK NATIVE
Android app does not have its own 'home' directory. The underlying Linux-like runtime has getcwd(), and it will return /
- i.e. the root of the filesystem. Note that the app does not own /
and it cannot write to this directory.
This means that you must pass the full path to any file you want to open, including myDb.db
. You probably want to keep the database in the default database location for the app, such as returned by Context.getDatabasePath(). The best easiest reliable way to get it in C++, is to have Java query it before calling native, and pass the path to C++.
How to use Android NDK SQLite3 extension json1
You need libsqlite3, not an executable, so you don't need to compile shell.c. There is a GitHub project that includes the Android.mk that creates such library for you, you will probably find the static library easier to use in your JNI project.
Add SQLite to Android NDK project
You need to have these 3 files in your project: sqlite3.c
, sqlite3.h
, sqlite3ext.h
(not sure about the last one). Basic operations (create db, create table and insert values):
bool createTable() {
/* Open database */
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open(databaseName, &db);
if (rc != SQLITE_OK) {
//Can't open database/
sqlite3_open_v2(DB_FILE, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
}
/* Create SQL statement */
const char *createQuery =
"CREATE TABLE IF NOT EXISTS cities (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);";
/* Execute SQL statement */
rc = sqlite3_exec(db, createQuery, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
sqlite3_free(zErrMsg);
return false;
}
sqlite3_close(db);
return true;
}
insert:
bool insertToDb(CityWeather *pCityWeather) {
sqlite3 *db;
char *zErrMsg = 0;
int rc;
/* Open database */
rc = sqlite3_open(databaseName, &db);
if (rc) {
sqlite3_open_v2(DB_FILE, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL);
}
const char *pCityName = pCityWeather->getName().c_str();
char insertQuery[50];
strcpy (insertQuery,"INSERT INTO cities (name) VALUES ('");
strcat (insertQuery, pCityName);
strcat (insertQuery, "');");
puts (insertQuery);
delete pCityWeather;
/* Execute SQL statement */
rc = sqlite3_exec(db, insertQuery, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
sqlite3_free(zErrMsg);
}
sqlite3_close(db);
return true;
}
Android NDK: unable to open database file using sqlite3_open
As suggested by Seva Alekseyev, problem was I wrongly assumed that sqlite3_open will create whole path if it doesn't exists but it doesn't. So I need to create /databases manually.
Instead of getting databases directory like this:
String sqliteDir = getApplicationContext().getDatabasePath("MyDb").getPath();
I got it till databases:
String sqliteDir = "/data/data/" + getApplicationContext().getPackageName() + "/databases";
Now in cpp code before calling sqlite3_open, check if it is there.
struct stat sb;
int32_t res = stat(path, &sb);
if (0 == res && (sb.st_mode & S_IFDIR)){
LOGD("Database already exists in path:%s", path);
}else{
LOGD("Creating database path:%s", path);
int status = mkdir(path, S_IRWXU | S_IRWXG | S_IWOTH | S_IXOTH);
if(status != 0){
LOGD("Error occurred while creating database path : %s", path);
return;
}
}
string dbPath = string(path) + "//MyDb";
and then proceed with normal code:
int rc = sqlite3_open(dbPath, _db);
if(rc != SQLITE3_OK) LOGD("Can't open database: %s with path %s\n", KSqlite3::sqlite3_errmsg(_db), dbPath);
else LOGD(" Opened database successfully %s \n", sqlite3_errmsg(_db));
Android NDK cannot cross compile SQLite - crtend_so.o: No such file or directory
Linker can not find startup binaries since you give no path to sysroot. Linker's command line must contain --sysroot=/path/to/android/sysroot
too. Then, -L
option should be used only for third party library paths, not for system ones, so you should get rid of it. Also -lc
is completely redundant since normal binaries are linked against libc by default.
You may pass --sysroot
via LDFLAGS
, exactly like you've done with CFLAGS
at compilation step. But it is a bit ugly. Try to read ./configure --help
carefully. There surely should be clear way how to pass path to sysroot instead of hacking with *FLAGS
variables.
Related Topics
How to Create a C++ Boost Undirected Graph and Traverse It in Depth First Search (Dfs) Order
How to Use Libraries Compiled with Mingw in Msvc
Fastest Way to Convert String to Binary
How to Build Boost 1.64 in 64 Bits
Process Video Stream from Memory Buffer
Why Must I Put a Semicolon at the End of Class Declaration in C++
Do I Have to Use Atomic<Bool> for "Exit" Bool Variable
Vary Range of Uniform_Int_Distribution
"Step Over" When Debugging Multithreaded Programs in Visual Studio
How to Check That the Passed Iterator Is a Random Access Iterator
Fast Divisibility Tests (By 2,3,4,5,.., 16)
Can Branches with Undefined Behavior Be Assumed Unreachable and Optimized as Dead Code
Creating Library with Backward Compatible Abi That Uses Boost