From ce9a8d9766f9957c0af151e9af60f7a437ca0e74 Mon Sep 17 00:00:00 2001 From: gaodeng Date: Sat, 16 May 2026 17:22:00 +0800 Subject: [PATCH 1/2] Add iOS dynamic framework build --- .gitignore | 2 ++ build-ios-dynamic.sh | 50 ++++++++++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 16 ++++++++++++-- 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100755 build-ios-dynamic.sh diff --git a/.gitignore b/.gitignore index f4098d0..d90bdd7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,9 @@ compile_commands.json libsimple.* build/ build-ios/ +build-ios-*/ build-ohos/ +output-ios*/ *.gch bin/ output/ diff --git a/build-ios-dynamic.sh b/build-ios-dynamic.sh new file mode 100755 index 0000000..af88b98 --- /dev/null +++ b/build-ios-dynamic.sh @@ -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" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bfc3ab3..e2bf745 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 "fm.moon.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 "fm.moon.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}) From 5732a822eeb71df6708c09bcc18ebd3ed2657626 Mon Sep 17 00:00:00 2001 From: gaodeng Date: Sat, 16 May 2026 18:15:24 +0800 Subject: [PATCH 2/2] Document React Native op-sqlite usage --- README.md | 1 + examples/react-native-op-sqlite.md | 132 +++++++++++++++++++++++++++++ src/CMakeLists.txt | 4 +- 3 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 examples/react-native-op-sqlite.md diff --git a/README.md b/README.md index 3c64300..33e6f5b 100644 --- a/README.md +++ b/README.md @@ -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) ### 命令行使用 diff --git a/examples/react-native-op-sqlite.md b/examples/react-native-op-sqlite.md new file mode 100644 index 0000000..7fb958b --- /dev/null +++ b/examples/react-native-op-sqlite.md @@ -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')`. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e2bf745..a088e9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,11 +32,11 @@ if (IOS AND BUILD_IOS_DYNAMIC_FRAMEWORK) add_library(simple SHARED ${SOURCE_FILES}) set_target_properties(simple PROPERTIES FRAMEWORK TRUE - MACOSX_FRAMEWORK_IDENTIFIER "fm.moon.simple" + 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 "fm.moon.simple" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.wangfenjin.simple" XCODE_ATTRIBUTE_SKIP_INSTALL "NO" ) elseif (IOS OR BUILD_STATIC)