我尝试保护SQLDatabase避免反编译。我将这个问题发布在this。但没人回答。 我尝试使用SQLCipher。
DBHelper.java:
public class DBHelper extends SQLiteOpenHelper {
private static String DB_NAME = "test.sqlite";
private static String DB_PATH = "";
private SQLiteDatabase myDatabase;
private static final String PASS = "sajjad";
private Context context;
public DBHelper(Context context) {
super(context, DB_NAME, null, 2);
if (Build.VERSION.SDK_INT >= 15)
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
else
DB_PATH = Environment.getDataDirectory() + "/data/" + context.getPackageName() + "/databases/";
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void checkAndCopyDatabase() {
boolean dbExist = checkDatabases();
if (dbExist) {
Log.d("TAG", "already exist");
} else {
this.getReadableDatabase(PASS);
}
try {
copyDatabases();
} catch (IOException e) {
e.printStackTrace();
Log.d("TAG", "Error copy DataBase");
}
}
public void openDatabase() {
String myPath = DB_PATH + DB_NAME;
myDatabase = SQLiteDatabase.openDatabase(myPath, PASS, null, SQLiteDatabase.OPEN_READWRITE);
}
private void copyDatabases() throws IOException {
InputStream myInput = context.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int lenght;
while ((lenght = myInput.read(buffer)) > 0)
myOutput.write(buffer, 0, lenght);
}
private boolean checkDatabases() {
SQLiteDatabase checkdb = null;
try {
String myPath = DB_PATH + DB_NAME;
checkdb = SQLiteDatabase.openDatabase(myPath, PASS, null, SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException e) {
}
if (checkdb != null)
checkdb.close();
return checkdb != null ? true : false;
}
public synchronized void close() {
if (myDatabase != null) {
myDatabase.close();
}
super.close();
}
public Cursor QueryData(String query) {
return myDatabase.rawQuery(query, null);
}}
并在MainActivity中将数据库加载到recyclerView:
public class MainActivity extends AppCompatActivity {
DBHelper dataBaseHelper;
Cursor cursor;
ArrayList<Info> arrayList = new ArrayList<Info>();
Info item;
private Adapter adapterMain;
@Override
protected void onCreate(Bundle savedInstanceState) {
SQLiteDatabase.loadLibs(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recy);
dataBaseHelper = new DBHelper(this);
try {
dataBaseHelper.checkAndCopyDatabase();
dataBaseHelper.openDatabase();
} catch (SQLException e) {
e.printStackTrace();
}
try {
cursor = dataBaseHelper.QueryData("SELECT name FROM dictionary");
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
item = new Info();
item.setName(cursor.getString(0));
arrayList.add(item);
} while (cursor.moveToNext());
}
}
} catch (SQLException e) {
e.printStackTrace();
}
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
adapterMain = new Adapter(this, arrayList);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
recyclerView.setAdapter(adapterMain);
}}
在安装应用程序时,该应用程序崩溃了。能帮我吗?
错误:
java.lang.RuntimeException: Unable to start activity ComponentInfo{ir.seljad.sqlitechipher/ir.seljad.sqlitechipher.MainActivity}: **net.sqlcipher.database.SQLiteException: no such table: dictionary: , while compiling: SELECT name FROM dictionary**
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2974)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3059)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1724)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:7000)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
Caused by: net.sqlcipher.database.SQLiteException: no such table: dictionary: , while compiling: SELECT name FROM dictionary
at net.sqlcipher.database.SQLiteCompiledSql.native_compile(Native Method)
at net.sqlcipher.database.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:91)
at net.sqlcipher.database.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:64)
at net.sqlcipher.database.SQLiteProgram.<init>(SQLiteProgram.java:89)
at net.sqlcipher.database.SQLiteQuery.<init>(SQLiteQuery.java:48)
at net.sqlcipher.database.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:60)
at net.sqlcipher.database.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1954)
at net.sqlcipher.database.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1840)
at ir.seljad.sqlitechipher.DBHelper.QueryData(DBHelper.java:102)
at ir.seljad.sqlitechipher.MainActivity.onCreate(MainActivity.java:39)
at android.app.Activity.performCreate(Activity.java:7258)
at android.app.Activity.performCreate(Activity.java:7249)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1222)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2927)
答案 0 :(得分:0)
我认为根本的问题是 databases 目录不存在,因此在检查数据库是否存在时尝试打开数据库会导致异常。由于异常位于try / catch构造中,因此被隐藏。结果是数据库为空,因此没有表。
我建议以下内容:-
使用上下文的getDatabasePath确定路径。 这样就无需对数据库名称(包括构建版本变体)以外的任何内容进行硬编码。
不打开数据库以检查数据库的存在,而是检查文件是否存在。
如果文件存在,则返回true。
如果文件不存在,请检查文件的父文件(数据库目录) )使用 File 的 getParentFile 方法存在。如果父文件不存在,则使用文件的 mkdirs 方法创建目录。
返回false。
有关示例代码,请参见this answer。