cd ~/Documents/code/SQLCipherApp git clone https://github.com/sqlcipher/openssl-xcode.git
下載 sqlcipher
cd ~/Documents/code/SQLCipherApp git clone https://github.com/sqlcipher/sqlcipher.git
下載 openssl-1.0.0e
curl -o openssl-1.0.0e.tar.gz http://www.openssl.org/source/openssl-1.0.0e.tar.gz //解壓 tar xzf openssl-1.0.0e.tar.gz
把這三個目錄拷貝到工程目錄中
1、打開Xcode 的設置頁,進入locations ->source trees ,點擊+號添加項目 ,settingname 和 display name 均設為 “OPENSSL_SRC” path設置為你工程目錄下openssl-1.0.0e的所在路徑。比如我的路徑是:/Users/henry/Documents/工程公用/SQLCipherApp/openssl-1.0.0e


//打開數據庫的函數 +(BOOL) OpenDB { NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docPaths = [pathArr objectAtIndex:0]; NSString *dbPath = [docPaths stringByAppendingFormat:@"/myDB.db"]; int status = sqlite3_open([dbPath UTF8String], &GB_DB); if (status != SQLITE_OK) { LOG_CINFO(@"打開數據庫出錯!"); DB_Opened = NO; return DB_Opened; } DB_Opened = YES; sqlite3_stmt *statement; #if UseASE //驗證sql語句是否成功 const char *key = [[GlobalData GetInstance].GB_DBKey UTF8String]; sqlite3_key(GB_DB, key, strlen(key)); #endif if(sqlite3_prepare_v2(GB_DB, [sql UTF8String], -1, &statement, nil) != SQLITE_OK) { LOG_CINFO(@"創建表格失敗!"); return NO; } int success = sqlite3_step(statement); sqlite3_finalize(statement); //[MyDataBase CloseDB]; if (success != SQLITE_DONE) { LOG_CINFO(@"在創建表格的過程中出錯,創建沒有進行完!"); return NO; } return YES; }
//創建需要的數據表 + (void)CreateNeedTable { @autoreleasepool { //插入用戶信息表 LocalDataBase *userTb = [LocalDataBase GetTableWithType:@"user" HasUser:NO]; //先創建 [userTb CreateTableWithKeys:[NSArray arrayWithObjects:@"userid", nil] OtherNeeds:[NSArray arrayWithObjects:@"siteid",@"username",@"password",@"mobilePhone",@"name", nil] Data:nil]; }
//根據參數創建表,keys是主鍵,needs是那些非主鍵,但是必須需要的,如需要用它來排序,搜索的字段,data為數據項的整個data形式,用data是為了減少字段數 -(BOOL) CreateTableWithKeys:(NSArray *)keys OtherNeeds:(NSArray *)needs Data:(NSString *)data { //如果有信息,說明注冊成功了已經 if(self.myTableInfo) { return YES; } //首先確保數據庫是打開的 if (![LocalDataBase OpenDB]) { return NO; } //把所有非數據的字段寫到一個數組中 NSMutableArray *allArr = [NSMutableArray arrayWithCapacity:10]; if ([keys count] > 0) { [allArr addObjectsFromArray:keys]; } if ([needs count] > 0) { [allArr addObjectsFromArray:needs]; } if (self.hasUser) { [allArr insertObject:@"userName" atIndex:0]; } int keysCount = [allArr count]; if (self.myTableInfo == nil) { self.myTableInfo = [NSMutableArray arrayWithCapacity:keysCount+1]; } //插入數據 for(int i = 0; i < keysCount;++i) { NSString *key = [allArr objectAtIndex:i]; [self.myTableInfo addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"text",@"type", key,@"key", nil]]; } //創建sql語句 NSMutableString *cSql = [NSMutableString stringWithFormat:@"create table if not exists %@ (",self.myTableName]; //把非數據類型的字段加入sql語句 for(NSString *key in allArr) { [cSql appendFormat:@"%@ text,",key]; } //把數據類型的字段加入Sql語句 if (data != nil) { [cSql appendFormat:@"%@ blob,",data]; [self.myTableInfo addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"blob",@"type", data,@"key", nil]]; } //添加主鍵 [cSql appendString:@"primary key("]; int keyCount = [keys count]; if (keyCount > 0)//有多個主鍵的情況 { for(int i = 0; i < keyCount - 1; ++i) { NSString *key = [keys objectAtIndex:i]; [cSql appendFormat:@"%@,",key]; } if(self.hasUser) { [cSql appendString:@"userName,"]; } [cSql appendFormat:@"%@)",[keys objectAtIndex:keyCount - 1]]; } else { // if (keyCount == 1)//只有一個主鍵的情況 // { // [cSql appendFormat:@"%@)",[keys objectAtIndex:0]]; // } // else { if(self.hasUser) { [cSql appendString:@"userName)"]; } } } [cSql appendString:@")"]; LOG_CINFO(@"========sql 語句 創建表========="); LOG_CINFO(cSql); { NSMutableDictionary *dic = (NSMutableDictionary *)[GlobalFunc ParseDicFromFile:@"dbInfo.plist"]; if (dic == nil) { dic = [NSMutableDictionary dictionaryWithCapacity:1]; } [dic setObject:self.myTableInfo forKey:self.myTableName]; [GlobalFunc WriteDicToFile:dic FileName:@"dbInfo.plist"]; } return [LocalDataBase CreateTableWithSql:cSql]; }
//向表中插入數據 -(BOOL) InsertDataWithDic:(NSDictionary *)dic Replace:(BOOL) replace { // 打開數據庫 if (!DB_Opened) { if(![LocalDataBase OpenDB]) { LOG_CINFO(@"插入數據失敗,打開數據庫出錯!"); return NO; } } NSMutableDictionary *tmpDic = [NSMutableDictionary dictionaryWithDictionary:dic]; if (self.hasUser) { [tmpDic setObject:[GlobalData GetInstance].GB_UserName forKey:@"userName"]; } NSMutableArray *allKeys = [NSMutableArray arrayWithArray:[tmpDic allKeys]]; NSMutableString *cSql = nil; //生成插入語句 if (replace) { cSql = [NSMutableString stringWithFormat:@"insert or REPLACE into %@(",self.myTableName]; } else { cSql = [NSMutableString stringWithFormat:@"insert into %@(",self.myTableName]; } int keysCount = [allKeys count]; if (keysCount > 0) { for(int i = 0; i < keysCount-1;++i) { [cSql appendFormat:@"%@,",[allKeys objectAtIndex:i]]; } [cSql appendFormat:@"%@)",[allKeys objectAtIndex:keysCount -1]]; } else { return NO; } [cSql appendString:@" values("]; for(int i = 0; i<keysCount -1; ++i) { [cSql appendString:@"?,"]; } [cSql appendString:@"?)"]; LOG_CINFO(@"========sql 語句 插入表========="); LOG_CINFO(cSql); //測試sql 語句是否正確 sqlite3_stmt *statement; const char *insertStatement = [cSql UTF8String]; #if UseASE //驗證sql語句是否成功 const char *key = [[GlobalData GetInstance].GB_DBKey UTF8String]; sqlite3_key(GB_DB, key, strlen(key)); #endif if(sqlite3_prepare_v2(GB_DB, insertStatement, -1, &statement, NULL) != SQLITE_OK) { LOG_CINFO(@"向表格中插入數據失敗,可能Sql語句不正確!"); [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"向表格中插入數據失敗,可能Sql語句不正確,表名為%@",self.myTableName]]; return NO; } for(int i = 0; i < keysCount;++i) { NSString *key = [allKeys objectAtIndex:i]; id value = [tmpDic objectForKey:key]; //如果是Data類型 if ([value isKindOfClass:[NSData class]]) { sqlite3_bind_blob(statement, i+1, [value bytes], [value length], NULL); } else//是字符串類型 { sqlite3_bind_text(statement, i+1, [value UTF8String], -1, NULL); } } int success = sqlite3_step(statement); // 釋放資源 sqlite3_finalize(statement); if (success == SQLITE_ERROR) { LOG_CINFO(@"向表格中插入數據失敗,未知原因提前結束!"); [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"向表格中插入數據失敗,未知原因提前結束,表名為%@",self.myTableName]]; return NO; } LOG_CINFO(@"向表格中插入數據成功!"); return YES; }
//更新表字段,key是要更新的字段名稱,newValue是更新后要設計的值,where是條件(sql語句中的),condition是滿足更新的條件,use是否使用用戶名為條件 -(BOOL) UpdateRecordWithKey:(NSString *)key Value:(NSString *)newValue Where:(NSString *)where Condition:(NSString *)condition UseUser:(BOOL)use { if(![LocalDataBase OpenDB]) { return NO; } @try { NSString *tmpUpdateSql = nil; if (use && self.hasUser) { tmpUpdateSql = [NSString stringWithFormat:@"UPDATE %@ SET %@ = ? where %@ = ? and userName = ?",self.myTableName,key,where]; } else { tmpUpdateSql = [NSString stringWithFormat:@"UPDATE %@ SET %@ = ? where %@ = ?",self.myTableName,key,where];//@"UPDATE tb_bulletlist SET has_read = ? where bulletin_code = ? and user_name=?"; } sqlite3_stmt *statement; LOG_CINFO(@"========sql 語句 更新表========="); LOG_CINFO(tmpUpdateSql); #if UseASE //驗證sql語句是否成功 const char *key = [[GlobalData GetInstance].GB_DBKey UTF8String]; sqlite3_key(GB_DB, key, strlen(key)); #endif if(sqlite3_prepare_v2(GB_DB, [tmpUpdateSql UTF8String], -1, &statement, nil) != SQLITE_OK) { LOG_CINFO(@"更新數據失敗!"); [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"更新數據失敗,表名為%@",self.myTableName]]; return NO; } sqlite3_bind_text(statement, 1, [newValue UTF8String], -1, NULL); sqlite3_bind_text(statement, 2, [condition UTF8String], -1, NULL); if (use && self.hasUser) { sqlite3_bind_text(statement, 3, [[GlobalData GetInstance].GB_UserName UTF8String], -1, NULL); } int success = sqlite3_step(statement); sqlite3_finalize(statement); //[MyDataBase CloseDB]; if (success != SQLITE_DONE) { LOG_CINFO(@"更新數據失敗,未知原因提前結束!"); [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"更新數據失敗,未知原因提前結束,表名為%@",self.myTableName]]; return NO; } } @catch (NSException *e) { // LOG_CERR(e); } return YES; }
//根據傳入的關鍵字和關鍵字的值,得到一條記錄,如果不存在這條記錄,返回為nil,估也可用來判斷是否存在某條記錄,use是否使用用戶名為條件 -(NSMutableDictionary *) GetOneRecordWithKeys:(NSArray *)keys Values:(NSArray *)values UseUser:(BOOL)use { if ([keys count] != [values count]) { // [GlobalFunc ShowNormalAlert:[NSString stringWithFormat:@"GetOneRecordWithKeys 數據查詢參數keys與values個數不一致,表名為%@",self.myTableName]]; return nil; } // 打開數據庫 if (!DB_Opened) { if(![LocalDataBase OpenDB]) { LOG_CINFO(@"查詢數據失敗,打開數據庫出錯!"); return nil; } } NSMutableString *cSql = [NSMutableString stringWithFormat:@"select * from %@ where ",self.myTableName]; if (use && self.hasUser) { [cSql appendFormat:@"userName = '%@' and ",[GlobalData GetInstance].GB_UserName]; } int keyCount = [keys count]; for (int i = 0; i < keyCount; ++i) { if (i == 0) { [cSql appendFormat:@"%@ = '%@'",[keys objectAtIndex:i],[values objectAtIndex:i]]; } else { [cSql appendFormat:@" and %@ = '%@'",[keys objectAtIndex:i],[values objectAtIndex:i]]; } } NSArray *tmpArr = [self GetDataArrWithSql:cSql]; if ([tmpArr count] == 0) { return nil; } else { return [tmpArr objectAtIndex:0]; } }
如果在編譯時提示:No architectures to compile for (ARCHS=armv6,armv7, VALID_ARCHS=armv7 armv7s則將在Bulid Settings選項下面的Architectures和Valid Architectures里面都改成一樣(例如:都填寫 armv6 armv7),問題解決。 對於警告 :warning: implicit declaration of function 'sqlite3_key' is invalid in C99 只需要將Bulid Settings選項下的C Language Dialect 改為:C89[-std-c89] 就可以,即使用c89標准
或者去掉項目中的arm64
以上只是貼出代碼的一部分,可能看起來有些吃力,稍后會把一個完整的使用數據庫的類整理出來。
本文參考:http://blog.csdn.net/kuai0705/article/details/8931996