|
| 1 | +# SQLite Sync - Android Integration |
| 2 | + |
| 3 | +This guide shows how to integrate SQLite Sync into your Android application. Since extension loading is disabled by default in Android's SQLite implementation, you need an alternative SQLite library that supports extensions. |
| 4 | + |
| 5 | +This example uses the [requery:sqlite-android](https://github.com/requery/sqlite-android) library, but other options include building a custom SQLite with extension support or using other third-party SQLite libraries that enable extension loading. |
| 6 | + |
| 7 | + |
| 8 | +### 1. Add Dependencies |
| 9 | + |
| 10 | +In your `app/build.gradle.kts`: |
| 11 | + |
| 12 | +```kotlin |
| 13 | +dependencies { |
| 14 | + implementation("com.github.requery:sqlite-android:3.49.0") |
| 15 | +} |
| 16 | +``` |
| 17 | + |
| 18 | +### 2. Bundle the Extension |
| 19 | + |
| 20 | +Place your `cloudsync.so` file in: |
| 21 | +`app/src/main/assets/lib/cloudsync.so` |
| 22 | + |
| 23 | +### 3. Basic Integration |
| 24 | + |
| 25 | +```kotlin |
| 26 | +import android.content.Context |
| 27 | +import androidx.activity.ComponentActivity |
| 28 | +import androidx.lifecycle.lifecycleScope |
| 29 | +import io.requery.android.database.sqlite.SQLiteCustomExtension |
| 30 | +import io.requery.android.database.sqlite.SQLiteCustomFunction |
| 31 | +import io.requery.android.database.sqlite.SQLiteDatabase |
| 32 | +import io.requery.android.database.sqlite.SQLiteDatabaseConfiguration |
| 33 | +import io.requery.android.database.sqlite.SQLiteFunction |
| 34 | +import kotlinx.coroutines.Dispatchers |
| 35 | +import kotlinx.coroutines.launch |
| 36 | +import kotlinx.coroutines.withContext |
| 37 | +import java.io.File |
| 38 | +import java.io.FileOutputStream |
| 39 | + |
| 40 | +class MainActivity : ComponentActivity() { |
| 41 | + private fun copyExtensionToFilesDir(context: Context): File { |
| 42 | + val assetManager = context.assets |
| 43 | + val inputStream = assetManager.open("lib/cloudsync.so") |
| 44 | + |
| 45 | + val outFile = File(context.filesDir, "cloudsync.so") |
| 46 | + inputStream.use { input -> |
| 47 | + FileOutputStream(outFile).use { output -> |
| 48 | + input.copyTo(output) |
| 49 | + } |
| 50 | + } |
| 51 | + return outFile |
| 52 | + } |
| 53 | + |
| 54 | + override fun onCreate(savedInstanceState: Bundle?) { |
| 55 | + super.onCreate(savedInstanceState) |
| 56 | + |
| 57 | + // Copy extension from assets to filesystem |
| 58 | + val extensionFile = copyExtensionToFilesDir(this) |
| 59 | + val extensionPath = extensionFile.absolutePath |
| 60 | + |
| 61 | + // Create extension configuration |
| 62 | + val cloudSyncExtension = SQLiteCustomExtension(extensionPath, null) |
| 63 | + |
| 64 | + // Configure database with extension |
| 65 | + val config = SQLiteDatabaseConfiguration( |
| 66 | + "${filesDir.path}/test.db", |
| 67 | + SQLiteDatabase.CREATE_IF_NECESSARY or SQLiteDatabase.OPEN_READWRITE, |
| 68 | + emptyList<SQLiteCustomFunction>(), |
| 69 | + emptyList<SQLiteFunction>(), |
| 70 | + listOf(cloudSyncExtension) |
| 71 | + ) |
| 72 | + |
| 73 | + // Open database |
| 74 | + val db = SQLiteDatabase.openDatabase(config, null, null) |
| 75 | + |
| 76 | + // Test extension loading |
| 77 | + lifecycleScope.launch { |
| 78 | + val version = withContext(Dispatchers.IO) { |
| 79 | + val cursor = db.rawQuery("SELECT cloudsync_version();", null) |
| 80 | + val result = if (cursor.moveToFirst()) { |
| 81 | + cursor.getString(0) |
| 82 | + } else { |
| 83 | + null |
| 84 | + } |
| 85 | + cursor.close() |
| 86 | + result |
| 87 | + } |
| 88 | + |
| 89 | + if (version != null) { |
| 90 | + println("SQLite Sync loaded successfully. Version: $version") |
| 91 | + } else { |
| 92 | + println("Failed to load SQLite Sync extension") |
| 93 | + } |
| 94 | + } |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +For detailed SQLite Sync API documentation, see the main [documentation](../../README.md). |
0 commit comments