【说明】
Cocos2d-x已经集成了SQLite3,但是并未做加密处理,处于安全考虑,一般不会直接使用。wxSQLite3是一个开源项目,是对SQLite3的C++封装,并做了加密处理,使用起来也很方便。这里介绍我集成wxSQLite3的过程,期间参考了其他大神的文章,后面已做说明。
【下载】
http://sourceforge.net/projects/wxcode/files/Components/wxSQLite3/
【集成】
1. 下载wxSQLite3后解压,将 wxsqlite3-3.2.1\sqlite3\secure\src 文件夹拷贝到项目中。
2. 由于wxSQLite3内部已经引用,所以在Xcode中只需要引用 “sqlite3.h” 和 “sqlite3secure.c” 两个文件,引用其他文件会导致编译出错。
3. 由于我们需要用到加密功能,所以需要在 “sqlite3.h” 和 “sqlite3secure.c” 两个文件中都添加启用加密宏定义。这里我没有使用预编译宏定义的方式,是因为我更倾向于使用平台无关的方式。但是这里要注意添加的位置,否则可能会编译出错。
#ifndef SQLITE_HAS_CODEC
#define SQLITE_HAS_CODEC
#endif
5. 以上是在Xcode上的集成过程,对于Android平台,需要编写一个一个 Android.mk 文件。这段借鉴网上文章,我还没实践。
LOCAL_PATH := $(call my-dir)
#清理变量定义
include $(CLEAR_VARS)
#模块名称
LOCAL_MODULE := wxsqlite3_static
#库文件名称
LOCAL_MODULE_FILENAME := libwxsqlite3
#定义预编译宏
LOCAL_CFLAGS += -DSQLITE_HAS_CODEC ##该宏用于开启加密功能,我已经把定义写到代码里了,这里可以不要
#源文件
LOCAL_SRC_FILES := src/sqlite3secure.c
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src
#头文件目录
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src
#构建静态库
include $(BUILD_STATIC_LIBRARY)
在 jni/Android.mk 中(不一定是这个,反正就是在应用的Android.mk中)添加引用:
<pre name="code" class="cpp">LOCAL_CFLAGS += -DSQLITE_HAS_CODEC #该宏用于开启加密功能
LOCAL_WHOLE_STATIC_LIBRARIES += wxsqlite3_static #引入静态库
$(call import-module,../Classes/wxsqlite3) #引入模块 (Android.mk位置)
【使用】
使用部分可以参考Cocos2d-x自带的 LocalStorage 类,加密功能需要在 “sqlite3_open()” 和 “sqlite3_close()” 之间调用 “sqlite3_key()” 设置密码。
// SET KEY
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
sqlite3_key(_db, key.c_str(), (int)key.size());
#endif
最后附上我封(xiu)装(gai)的类,基本上都是 LocalStorage 的代码,只做了一点点修改。原本我是做成单例模式的,后来打算把集中存储合并到一个存储类里面,方便使用,就改成了普通类。前面才是重点,这部分不重要。
//====================================================================================
// LSqlite.h
// Local storage by sqlite3.
// Use wxsqlite3 in order to encrypt data.
// Created by Dolphin Lee.
//====================================================================================
#ifndef __L_SQLITE_H__
#define __L_SQLITE_H__
#include "cocos2d.h"
USING_NS_CC;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#include "sqlite3.h"
#else
#include "wxsqlite3/sqlite3.h"
#endif
//====================================================================================
class LSqlite
{
public:
/**
* Constructor function.
*/
LSqlite();
/**
* Frees the allocated resources and close database.
*/
~LSqlite();
public:
/**
* Initializes the database. If path is null, it will create an in-memory DB.
* @param filename Name of database file. (like "data.db")
* @param key The key to encrypt database.
*/
void init(const std::string& filename, const std::string& key);
/**
* Sets an item in the LS.
* The item is divided into key and values.
*/
void setItem(const std::string& key, const std::string& value);
/**
* Gets an item from the LS.
* Will return the value according to key.
*/
std::string getItem(const std::string& key);
/**
* Removes an item from the LS.
* Will delete the value according to key.
*/
void removeItem(const std::string& key);
protected:
/**
* Initializes the database. If path is null, it will create an in-memory DB.
* @param fullpath Full path with file name.
* @param key The key to encrypt database.
*/
void initWithFullpath(const std::string& fullpath, const std::string& key);
/**
* Create table in the database.
* This function has been invoked in init, you don't need to call.
*/
void createTable();
private:
int _initialized;
sqlite3 *_db;
sqlite3_stmt *_stmt_select;
sqlite3_stmt *_stmt_remove;
sqlite3_stmt *_stmt_update;
};
//====================================================================================
#endif
//====================================================================================
// LSqlite.cpp
//====================================================================================
#include "LSqlite.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//====================================================================================
// Create
//====================================================================================
/** constructors */
LSqlite::LSqlite()
{
_initialized = 0;
_db = nullptr;
_stmt_select = nullptr;
_stmt_remove = nullptr;
_stmt_update = nullptr;
}
/** free database */
LSqlite::~LSqlite()
{
if( _initialized )
{
sqlite3_finalize(_stmt_select);
sqlite3_finalize(_stmt_remove);
sqlite3_finalize(_stmt_update);
sqlite3_close(_db);
_initialized = 0;
}
}
/** create table */
void LSqlite::createTable()
{
const char *sql_createtable = "CREATE TABLE IF NOT EXISTS data(key TEXT PRIMARY KEY,value TEXT);";
sqlite3_stmt *stmt;
int ok=sqlite3_prepare_v2(_db, sql_createtable, -1, &stmt, NULL);
ok |= sqlite3_step(stmt);
ok |= sqlite3_finalize(stmt);
if( ok != SQLITE_OK && ok != SQLITE_DONE)
{
printf("[sqlite3] Error in CREATE TABLE\n");
}
}
/** init database */
void LSqlite::initWithFullpath( const std::string& fullpath, const std::string& key)
{
if( ! _initialized )
{
int ret = 0;
// OPEN DATABASE
if (fullpath.empty())
{
ret = sqlite3_open(":memory:",&_db);
}
else
{
ret = sqlite3_open(fullpath.c_str(), &_db);
}
// SET KEY
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
sqlite3_key(_db, key.c_str(), (int)key.size());
#endif
// EXPAND FUNCTION
//sqlite3_exec(_db, "PRAGMA synchronous = OFF", 0 ,0, 0); // 提交性能
//sqlite3_exec(_db, "PRAGMA cache_size = 8000", 0 ,0, 0); // 加大缓存
//sqlite3_exec(_db, "PRAGMA count_changes = 1", 0 ,0, 0); // 返回改变记录数
//sqlite3_exec(_db, "PRAGMA case_sensitive_like = 1", 0 ,0, 0); // 支持中文LIKE查询
// CREATE TABLE
createTable();
// SELECT
const char *sql_select = "SELECT value FROM data WHERE key=?;";
ret |= sqlite3_prepare_v2(_db, sql_select, -1, &_stmt_select, NULL);
// REPLACE
const char *sql_update = "REPLACE INTO data (key, value) VALUES (?,?);";
ret |= sqlite3_prepare_v2(_db, sql_update, -1, &_stmt_update, NULL);
// DELETE
const char *sql_remove = "DELETE FROM data WHERE key=?;";
ret |= sqlite3_prepare_v2(_db, sql_remove, -1, &_stmt_remove, NULL);
if( ret != SQLITE_OK )
{
printf("[sqlite3] Error initializing DB\n");
// report error
}
_initialized = 1;
}
}
//====================================================================================
// Functions
//====================================================================================
/** init database */
void LSqlite::init(const std::string& filename, const std::string& key)
{
std::string path = FileUtils::getInstance()->getWritablePath();
path += filename;
initWithFullpath(path, key);
}
/** sets an item in the LS */
void LSqlite::setItem( const std::string& key, const std::string& value)
{
assert( _initialized );
int ok = sqlite3_bind_text(_stmt_update, 1, key.c_str(), -1, SQLITE_TRANSIENT);
ok |= sqlite3_bind_text(_stmt_update, 2, value.c_str(), -1, SQLITE_TRANSIENT);
ok |= sqlite3_step(_stmt_update);
ok |= sqlite3_reset(_stmt_update);
if( ok != SQLITE_OK && ok != SQLITE_DONE)
{
printf("[sqlite3] Error in locaLSqlite.setItem()\n");
}
}
/** gets an item from the LS */
std::string LSqlite::getItem( const std::string& key )
{
assert( _initialized );
std::string ret;
int ok = sqlite3_reset(_stmt_select);
ok |= sqlite3_bind_text(_stmt_select, 1, key.c_str(), -1, SQLITE_TRANSIENT);
ok |= sqlite3_step(_stmt_select);
const unsigned char *text = sqlite3_column_text(_stmt_select, 0);
if (text)
{
ret = (const char*)text;
}
if( ok != SQLITE_OK && ok != SQLITE_DONE && ok != SQLITE_ROW)
{
printf("[sqlite3] Error in locaLSqlite.getItem()\n");
}
return ret;
}
/** removes an item from the LS */
void LSqlite::removeItem( const std::string& key )
{
assert( _initialized );
int ok = sqlite3_bind_text(_stmt_remove, 1, key.c_str(), -1, SQLITE_TRANSIENT);
ok |= sqlite3_step(_stmt_remove);
ok |= sqlite3_reset(_stmt_remove);
if( ok != SQLITE_OK && ok != SQLITE_DONE)
{
printf("[sqlite3] Error in locaLSqlite.removeItem()\n");
}
}
//====================================================================================
//
//====================================================================================
【参考】
http://blog.csdn.net/linchaolong/article/details/41286297
http://www.yiwuye.com/archives/cocos2d-x-encrpt-sqlite.html
http://www.cocoachina.com/bbs/read.php?tid=199953