Sqlite with Android Ndk

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



Leave a reply



Submit