首页 > 解决方案 > SQL Cipher android studio中的“没有这样的表”

问题描述

我试图保护我的 SQLDatabase 免受反编译。我在发布此问题。但没有人回答。我尝试使用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)

标签: androidsqlite

解决方案


我认为根本问题是数据库目录不存在,因此在检查数据库是否存在时尝试打开数据库会导致异常。由于它位于 try/catch 构造中,因此该异常被隐藏。结果是一个空数据库,因此没有表。

我建议如下:-

  1. 使用 Context 的getDatabasePath来确定路径。这消除了对数据库名称以外的任何内容(包括构建版本变体)进行硬编码的需要。

  2. 不要打开数据库检查数据库是否存在,而是检查文件是否存在。

  3. 如果文件存在,则返回 true。

  4. 如果File不存在,则使用FilegetParentFile方法检查File的父File(数据库目录)是否存在。如果父File不存在,则使用Filemkdirs方法创建目录。

  5. 返回假。

有关示例代码,请参见此答案


推荐阅读