Skip to content

Commit 45db071

Browse files
authored
Add iOS dynamic framework build and React Native op-sqlite docs (#206)
* Add iOS dynamic framework build * Document React Native op-sqlite usage
1 parent 4ed0089 commit 45db071

5 files changed

Lines changed: 199 additions & 2 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ compile_commands.json
55
libsimple.*
66
build/
77
build-ios/
8+
build-ios-*/
89
build-ohos/
10+
output-ios*/
911
*.gch
1012
bin/
1113
output/

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ simple 是一个支持中文和拼音的 [sqlite3 fts5](https://www.sqlite.org/f
2626
* C# 例子 https://github.com/dudylan/SqliteCheck/
2727
* Rust 例子 https://github.com/xuxiaocheng0201/libsimple/
2828
* Android Flutter 的例子 https://github.com/SageMik/sqlite3_simple
29+
* React Native op-sqlite 例子 [examples/react-native-op-sqlite.md](./examples/react-native-op-sqlite.md)
2930

3031
### 命令行使用
3132

build-ios-dynamic.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/bin/sh
2+
3+
set -eu
4+
5+
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
6+
toolchain_file="${script_dir}/contrib/ios.toolchain.cmake"
7+
ios_output_root="${script_dir}/output-ios-dynamic"
8+
final_output_root="${script_dir}/output"
9+
10+
build_variant() {
11+
platform="$1"
12+
build_dir="${script_dir}/build-ios-dynamic-${platform}"
13+
install_dir="${ios_output_root}/${platform}"
14+
15+
cmake -S "${script_dir}" -B "${build_dir}" -G Xcode \
16+
-DCMAKE_TOOLCHAIN_FILE="${toolchain_file}" \
17+
-DPLATFORM="${platform}" \
18+
-DENABLE_BITCODE=0 \
19+
-DDEPLOYMENT_TARGET=12.0 \
20+
-DBUILD_SQLITE3=OFF \
21+
-DBUILD_IOS_DYNAMIC_FRAMEWORK=ON \
22+
-DCMAKE_INSTALL_PREFIX=""
23+
24+
cmake --build "${build_dir}" --config Release
25+
cmake --install "${build_dir}" --config Release --prefix "${install_dir}"
26+
}
27+
28+
rm -rf "${ios_output_root}" "${final_output_root}/libsimple-dynamic.xcframework"
29+
mkdir -p "${final_output_root}"
30+
31+
build_variant OS64
32+
build_variant SIMULATOR64
33+
build_variant SIMULATORARM64
34+
35+
sim64_framework="${ios_output_root}/SIMULATOR64/bin/simple.framework"
36+
simarm64_framework="${ios_output_root}/SIMULATORARM64/bin/simple.framework"
37+
sim_universal_dir="${ios_output_root}/SIMULATOR_UNIVERSAL/bin"
38+
sim_universal_framework="${sim_universal_dir}/simple.framework"
39+
40+
mkdir -p "${sim_universal_dir}"
41+
cp -R "${sim64_framework}" "${sim_universal_framework}"
42+
lipo -create \
43+
"${sim64_framework}/simple" \
44+
"${simarm64_framework}/simple" \
45+
-output "${sim_universal_framework}/simple"
46+
47+
xcodebuild -create-xcframework \
48+
-framework "${ios_output_root}/OS64/bin/simple.framework" \
49+
-framework "${sim_universal_framework}" \
50+
-output "${final_output_root}/libsimple-dynamic.xcframework"

examples/react-native-op-sqlite.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# React Native op-sqlite usage
2+
3+
This note shows how to load `simple` as a SQLite runtime extension in a React
4+
Native app using [`@op-engineering/op-sqlite`](https://github.com/OP-Engineering/op-sqlite).
5+
6+
`simple` is an FTS5 tokenizer extension, so op-sqlite must be built with FTS5
7+
enabled and with runtime extension loading available.
8+
9+
## Build the extension
10+
11+
Build an iOS xcframework:
12+
13+
```sh
14+
./build-ios-dynamic.sh
15+
```
16+
17+
The output is:
18+
19+
```text
20+
output/libsimple-dynamic.xcframework
21+
```
22+
23+
For Android, use the shared library from the normal Android build/release
24+
artifact and package it as `libsimple.so` for each target ABI.
25+
26+
## iOS
27+
28+
Add the xcframework to your app, for example:
29+
30+
```text
31+
ios/Frameworks/simple.xcframework
32+
```
33+
34+
If you use CocoaPods, create a small local podspec:
35+
36+
```ruby
37+
Pod::Spec.new do |s|
38+
s.name = 'SimpleSQLiteExtension'
39+
s.version = '0.1.0'
40+
s.summary = 'SQLite simple tokenizer extension'
41+
s.homepage = 'https://github.com/wangfenjin/simple'
42+
s.license = { :type => 'MIT' }
43+
s.author = { 'simple contributors' => 'https://github.com/wangfenjin/simple' }
44+
s.source = { :git => 'https://github.com/wangfenjin/simple.git', :tag => s.version.to_s }
45+
s.platform = :ios, '12.0'
46+
s.vendored_frameworks = 'Frameworks/simple.xcframework'
47+
end
48+
```
49+
50+
Then reference it from `ios/Podfile`:
51+
52+
```ruby
53+
target 'YourApp' do
54+
pod 'SimpleSQLiteExtension', :path => '.'
55+
end
56+
```
57+
58+
Run:
59+
60+
```sh
61+
cd ios
62+
pod install
63+
```
64+
65+
## Android
66+
67+
Package `libsimple.so` in your React Native project, for example:
68+
69+
```text
70+
android/app/src/main/jniLibs/arm64-v8a/libsimple.so
71+
android/app/src/main/jniLibs/armeabi-v7a/libsimple.so
72+
android/app/src/main/jniLibs/x86/libsimple.so
73+
android/app/src/main/jniLibs/x86_64/libsimple.so
74+
```
75+
76+
## Load the extension
77+
78+
Load the extension before creating FTS5 tables that use the `simple` tokenizer.
79+
80+
```ts
81+
import { Platform } from 'react-native';
82+
import { getDylibPath, open } from '@op-engineering/op-sqlite';
83+
84+
const db = open({ name: 'search.db' });
85+
86+
if (Platform.OS === 'android') {
87+
db.loadExtension('libsimple', 'sqlite3_simple_init');
88+
} else if (Platform.OS === 'ios') {
89+
const path = getDylibPath('com.wangfenjin.simple', 'simple');
90+
db.loadExtension(path, 'sqlite3_simple_init');
91+
}
92+
```
93+
94+
After loading succeeds, `simple` can be used like any other FTS5 tokenizer:
95+
96+
```ts
97+
db.execute(`
98+
CREATE VIRTUAL TABLE IF NOT EXISTS docs
99+
USING fts5(title, body, tokenize = 'simple');
100+
`);
101+
102+
db.execute('INSERT INTO docs(title, body) VALUES (?, ?)', [
103+
'中华人民共和国国歌',
104+
'支持中文和拼音搜索',
105+
]);
106+
107+
const result = db.execute(
108+
'SELECT rowid, title FROM docs WHERE docs MATCH simple_query(?)',
109+
['中华国歌'],
110+
);
111+
```
112+
113+
To disable pinyin tokens, use the tokenizer option supported by `simple`:
114+
115+
```ts
116+
db.execute(`
117+
CREATE VIRTUAL TABLE IF NOT EXISTS docs_no_pinyin
118+
USING fts5(title, body, tokenize = 'simple 0');
119+
`);
120+
```
121+
122+
## Troubleshooting
123+
124+
- `no such tokenizer: simple` usually means the extension was not loaded before
125+
the FTS5 table was created.
126+
- `not authorized` or `load extension` errors usually mean runtime extension
127+
loading is disabled in the SQLite build used by your app.
128+
- iOS apps should load the framework from the app bundle. With op-sqlite, use
129+
`getDylibPath('com.wangfenjin.simple', 'simple')` for the framework named
130+
`simple.framework`.
131+
- Android should load the library name without the `.so` suffix:
132+
`db.loadExtension('libsimple', 'sqlite3_simple_init')`.

src/CMakeLists.txt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,20 @@ set(SOURCE_FILES
2727
)
2828

2929
OPTION(BUILD_STATIC "Option to build static lib" OFF)
30-
if (IOS OR BUILD_STATIC)
31-
# iOS only support static library.
30+
OPTION(BUILD_IOS_DYNAMIC_FRAMEWORK "Option to build iOS dynamic framework" OFF)
31+
if (IOS AND BUILD_IOS_DYNAMIC_FRAMEWORK)
32+
add_library(simple SHARED ${SOURCE_FILES})
33+
set_target_properties(simple PROPERTIES
34+
FRAMEWORK TRUE
35+
MACOSX_FRAMEWORK_IDENTIFIER "com.wangfenjin.simple"
36+
PUBLIC_HEADER "pinyin.h;simple_highlight.h;simple_tokenizer.h"
37+
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
38+
XCODE_ATTRIBUTE_DEFINES_MODULE "YES"
39+
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.wangfenjin.simple"
40+
XCODE_ATTRIBUTE_SKIP_INSTALL "NO"
41+
)
42+
elseif (IOS OR BUILD_STATIC)
43+
# iOS releases default to static libraries unless BUILD_IOS_DYNAMIC_FRAMEWORK is enabled.
3244
add_library(simple STATIC ${SOURCE_FILES})
3345
else()
3446
add_library(simple SHARED ${SOURCE_FILES})

0 commit comments

Comments
 (0)