Skip to content

Commit

Permalink
Init sqlite3
Browse files Browse the repository at this point in the history
  • Loading branch information
bsjung committed Feb 3, 2020
0 parents commit 1c0c54a
Show file tree
Hide file tree
Showing 18 changed files with 2,034 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.dart_tool
.gdb_history
.packages
.vscode
pubspec.lock
test.db
test.db-journal
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Sample code dart:ffi

This is an illustrative sample for how to use `dart:ffi`.

## Prerequirement

For Windows, Linux, and MacOS, you should make sure, sqlite dev lib installed on your system.

Windows user can download dll from https://www.sqlite.org/download.html

If you do not have any sqlite3.dll or so file, you may found error message:

```
Unhandled exception:
Invalid argument(s): Failed to load dynamic library (126)
#0 _open (dart:ffi-patch/ffi_dynamic_library_patch.dart:13:55)
#1 new DynamicLibrary.open (dart:ffi-patch/ffi_dynamic_library_patch.dart:22:12)
```

## Building and Running this Sample

Building and running this sample is done through pub.
Running `pub get` and `pub run example/main` should produce the following output.

```sh
$ pub get
Resolving dependencies... (6.8s)
+ analyzer 0.35.4
...
+ yaml 2.1.15
Downloading analyzer 0.35.4...
Downloading kernel 0.3.14...
Downloading front_end 0.1.14...
Changed 47 dependencies!
Precompiling executables... (18.0s)
Precompiled test:test.

```

```
$ pub run example/main
1 Chocolade chip cookie Chocolade cookie foo
2 Ginger cookie null 42
3 Cinnamon roll null null
1 Chocolade chip cookie Chocolade cookie foo
2 Ginger cookie null 42
expected exception on accessing result data after close: The result has already been closed.
expected this query to fail: no such column: non_existing_column (Code 1: SQL logic error)
```

## Tutorial

A tutorial walking through the code is available in [docs/sqlite-tutorial.md](docs/sqlite-tutorial.md).
For information on how to use this package within a Flutter app, see [docs/android.md](docs/android.md).
(Note: iOS is not yet supported).
53 changes: 53 additions & 0 deletions docs/android.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
**This documentation is for demonstration/testing purposes only!**

# Using FFI with Flutter

## Android

Before using the FFI on Android, you need to procure an Android-compatible build of the native library you want to link against.
It's important that the shared object(s) be compatible with ABI version you wish to target (or else, that you have multiple builds for different ABIs).
See [https://developer.android.com/ndk/guides/abis] for more details on Android ABIs.
Within Flutter, the target ABI is controlled by the `--target-platform` parameter to the `flutter` command.

The workflow for packaging a native library will depend significantly on the library itself, but to illustrate the challenges at play, we'll demonstrate how to build the SQLite library from source to use with the FFI on an Android device.

### Building SQLite for Android

Every Android device ships with a copy of the SQLite library (`/system/lib/libsqlite.so`).
Unfortunately, this library cannot be loaded directly by apps (see [https://developer.android.com/about/versions/nougat/android-7.0-changes#ndk]).
It is accessible only through Java.
Instead, we can build SQLite directly with the NDK.

First, download the SQLite "amalgamation" source from [https://www.sqlite.org/download.html].
For the sake of brevity, we'll assume the file has been saved as `sqlite-amalgamation-XXXXXXX.zip`, the Android SDK (with NDK extension) is available in `~/Android`, and we're on a Linux workstation.

```sh
unzip sqlite-amalgamation-XXXXXXX.zip
cd sqlite-amalgamation-XXXXXXX
~/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang -c sqlite3.c -o sqlite3.o
~/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ld -shared sqlite3.o -o libsqlite3.so
```

Note the use of the `aarch64` prefix to the compiler: this indicates that we're building a shared object for the `arm64-v8a` ABI.
This will be important later.

### Update Gradle script

Next we need to instruct Gradle to package this library with the app, so it will be available to load off the Android device at runtime.
Create a folder `native-libraries` in the root folder of the app, and update the `android/app/build.gradle` file:

```groovy
android {
// ...
sourceSets {
main {
jniLibs.srcDir "${project.projectDir.path}/../../native-libraries"
}
}
}
```

Within the `native-libraries` folder, the libraries are organized by ABI.
Therefore, we must copy the compiled `libsqlite3.so` into `native-libraries/arm64-v8a/libsqlite3.so`.
If multiple sub-directories are present, the libraries from the sub-directory corresponding to the target ABI will be available in the application's linking path, so the library can be loaded with `DynamicLibrary.open("libsqlite3.so")` in Dart.
Finally, pass `--target-platform=android-arm64` to the `flutter` command when running or building the app since `libsqlite3.so` was compiled for the `arm64-v8a` ABI.
130 changes: 130 additions & 0 deletions docs/lib/scenario-default.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 1c0c54a

Please sign in to comment.