Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ compile_commands.json
libsimple.*
build/
build-ios/
build-ios-*/
build-ohos/
output-ios*/
*.gch
bin/
output/
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ simple 是一个支持中文和拼音的 [sqlite3 fts5](https://www.sqlite.org/f
* C# 例子 https://github.com/dudylan/SqliteCheck/
* Rust 例子 https://github.com/xuxiaocheng0201/libsimple/
* Android Flutter 的例子 https://github.com/SageMik/sqlite3_simple
* React Native op-sqlite 例子 [examples/react-native-op-sqlite.md](./examples/react-native-op-sqlite.md)

### 命令行使用

Expand Down
50 changes: 50 additions & 0 deletions build-ios-dynamic.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/sh

set -eu

script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
toolchain_file="${script_dir}/contrib/ios.toolchain.cmake"
ios_output_root="${script_dir}/output-ios-dynamic"
final_output_root="${script_dir}/output"

build_variant() {
platform="$1"
build_dir="${script_dir}/build-ios-dynamic-${platform}"
install_dir="${ios_output_root}/${platform}"

cmake -S "${script_dir}" -B "${build_dir}" -G Xcode \
-DCMAKE_TOOLCHAIN_FILE="${toolchain_file}" \
-DPLATFORM="${platform}" \
-DENABLE_BITCODE=0 \
-DDEPLOYMENT_TARGET=12.0 \
-DBUILD_SQLITE3=OFF \
-DBUILD_IOS_DYNAMIC_FRAMEWORK=ON \
-DCMAKE_INSTALL_PREFIX=""

cmake --build "${build_dir}" --config Release
cmake --install "${build_dir}" --config Release --prefix "${install_dir}"
}

rm -rf "${ios_output_root}" "${final_output_root}/libsimple-dynamic.xcframework"
mkdir -p "${final_output_root}"

build_variant OS64
build_variant SIMULATOR64
build_variant SIMULATORARM64

sim64_framework="${ios_output_root}/SIMULATOR64/bin/simple.framework"
simarm64_framework="${ios_output_root}/SIMULATORARM64/bin/simple.framework"
sim_universal_dir="${ios_output_root}/SIMULATOR_UNIVERSAL/bin"
sim_universal_framework="${sim_universal_dir}/simple.framework"

mkdir -p "${sim_universal_dir}"
cp -R "${sim64_framework}" "${sim_universal_framework}"
lipo -create \
"${sim64_framework}/simple" \
"${simarm64_framework}/simple" \
-output "${sim_universal_framework}/simple"

xcodebuild -create-xcframework \
-framework "${ios_output_root}/OS64/bin/simple.framework" \
-framework "${sim_universal_framework}" \
-output "${final_output_root}/libsimple-dynamic.xcframework"
132 changes: 132 additions & 0 deletions examples/react-native-op-sqlite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# React Native op-sqlite usage

This note shows how to load `simple` as a SQLite runtime extension in a React
Native app using [`@op-engineering/op-sqlite`](https://github.com/OP-Engineering/op-sqlite).

`simple` is an FTS5 tokenizer extension, so op-sqlite must be built with FTS5
enabled and with runtime extension loading available.

## Build the extension

Build an iOS xcframework:

```sh
./build-ios-dynamic.sh
```

The output is:

```text
output/libsimple-dynamic.xcframework
```

For Android, use the shared library from the normal Android build/release
artifact and package it as `libsimple.so` for each target ABI.

## iOS

Add the xcframework to your app, for example:

```text
ios/Frameworks/simple.xcframework
```

If you use CocoaPods, create a small local podspec:

```ruby
Pod::Spec.new do |s|
s.name = 'SimpleSQLiteExtension'
s.version = '0.1.0'
s.summary = 'SQLite simple tokenizer extension'
s.homepage = 'https://github.com/wangfenjin/simple'
s.license = { :type => 'MIT' }
s.author = { 'simple contributors' => 'https://github.com/wangfenjin/simple' }
s.source = { :git => 'https://github.com/wangfenjin/simple.git', :tag => s.version.to_s }
s.platform = :ios, '12.0'
s.vendored_frameworks = 'Frameworks/simple.xcframework'
end
```

Then reference it from `ios/Podfile`:

```ruby
target 'YourApp' do
pod 'SimpleSQLiteExtension', :path => '.'
end
```

Run:

```sh
cd ios
pod install
```

## Android

Package `libsimple.so` in your React Native project, for example:

```text
android/app/src/main/jniLibs/arm64-v8a/libsimple.so
android/app/src/main/jniLibs/armeabi-v7a/libsimple.so
android/app/src/main/jniLibs/x86/libsimple.so
android/app/src/main/jniLibs/x86_64/libsimple.so
```

## Load the extension

Load the extension before creating FTS5 tables that use the `simple` tokenizer.

```ts
import { Platform } from 'react-native';
import { getDylibPath, open } from '@op-engineering/op-sqlite';

const db = open({ name: 'search.db' });

if (Platform.OS === 'android') {
db.loadExtension('libsimple', 'sqlite3_simple_init');
} else if (Platform.OS === 'ios') {
const path = getDylibPath('com.wangfenjin.simple', 'simple');
db.loadExtension(path, 'sqlite3_simple_init');
}
```

After loading succeeds, `simple` can be used like any other FTS5 tokenizer:

```ts
db.execute(`
CREATE VIRTUAL TABLE IF NOT EXISTS docs
USING fts5(title, body, tokenize = 'simple');
`);

db.execute('INSERT INTO docs(title, body) VALUES (?, ?)', [
'中华人民共和国国歌',
'支持中文和拼音搜索',
]);

const result = db.execute(
'SELECT rowid, title FROM docs WHERE docs MATCH simple_query(?)',
['中华国歌'],
);
```

To disable pinyin tokens, use the tokenizer option supported by `simple`:

```ts
db.execute(`
CREATE VIRTUAL TABLE IF NOT EXISTS docs_no_pinyin
USING fts5(title, body, tokenize = 'simple 0');
`);
```

## Troubleshooting

- `no such tokenizer: simple` usually means the extension was not loaded before
the FTS5 table was created.
- `not authorized` or `load extension` errors usually mean runtime extension
loading is disabled in the SQLite build used by your app.
- iOS apps should load the framework from the app bundle. With op-sqlite, use
`getDylibPath('com.wangfenjin.simple', 'simple')` for the framework named
`simple.framework`.
- Android should load the library name without the `.so` suffix:
`db.loadExtension('libsimple', 'sqlite3_simple_init')`.
16 changes: 14 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,20 @@ set(SOURCE_FILES
)

OPTION(BUILD_STATIC "Option to build static lib" OFF)
if (IOS OR BUILD_STATIC)
# iOS only support static library.
OPTION(BUILD_IOS_DYNAMIC_FRAMEWORK "Option to build iOS dynamic framework" OFF)
if (IOS AND BUILD_IOS_DYNAMIC_FRAMEWORK)
add_library(simple SHARED ${SOURCE_FILES})
set_target_properties(simple PROPERTIES
FRAMEWORK TRUE
MACOSX_FRAMEWORK_IDENTIFIER "com.wangfenjin.simple"
PUBLIC_HEADER "pinyin.h;simple_highlight.h;simple_tokenizer.h"
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
XCODE_ATTRIBUTE_DEFINES_MODULE "YES"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.wangfenjin.simple"
XCODE_ATTRIBUTE_SKIP_INSTALL "NO"
)
elseif (IOS OR BUILD_STATIC)
# iOS releases default to static libraries unless BUILD_IOS_DYNAMIC_FRAMEWORK is enabled.
add_library(simple STATIC ${SOURCE_FILES})
else()
add_library(simple SHARED ${SOURCE_FILES})
Expand Down
Loading