fix: load SQLCipher.framework explicitly on iOS/macOS#381
Merged
simolus3 merged 2 commits intopowersync-ja:mainfrom Mar 18, 2026
Merged
Conversation
DynamicLibrary.process() (RTLD_DEFAULT) on iOS resolves to Apple's system sqlite3 before SQLCipher. Apple's sqlite3 has extension loading disabled and returns SQLITE_MISUSE (21) from sqlite3_auto_extension, causing PowerSync's extension registration to fail with: SqliteException(21): Could not load extension The Android override already uses openCipherOnAndroid() to explicitly load libsqlcipher.so. This commit adds the equivalent for iOS/macOS: explicitly load SQLCipher.framework/SQLCipher by path so the sqlite3 package uses SQLCipher rather than the system library. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
simolus3
previously approved these changes
Mar 16, 2026
Contributor
simolus3
left a comment
There was a problem hiding this comment.
It's a bit odd that these changes are necessary since the native plugin should link and load SQLCipher already, but I ran integration tests with and without this change and thing worked.
So in case some build setups make this required, these changes look good to me.
Co-authored-by: Simon Binder <oss@simonbinder.eu>
simolus3
approved these changes
Mar 18, 2026
This was referenced Mar 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On iOS (and macOS), PowerSyncSQLCipherOpenFactory fails with:
SqliteException(21): Could not load extension
This happens in PowerSyncOpenFactory.enableExtension() when it calls
sqlite3.ensureExtensionLoaded(), which internally calls sqlite3_auto_extension() and
gets SQLITE_MISUSE (21) back.
Root cause: The sqlite3 Dart package's _defaultOpen() on iOS tries
sqlite3.framework/sqlite3 and CSQLite.framework/CSQLite first (for
sqlite3_flutter_libs). Neither exists when using sqlcipher_flutter_libs, so it falls
back to DynamicLibrary.process() (RTLD_DEFAULT). RTLD_DEFAULT resolves to Apple's
system sqlite3 before SQLCipher, and Apple's system sqlite3 has extension loading
disabled — so sqlite3_auto_extension returns SQLITE_MISUSE.
Fix
The Android override already handles this correctly by explicitly loading
libsqlcipher.so via openCipherOnAndroid(). This PR adds the equivalent for iOS and
macOS: explicitly load SQLCipher.framework/SQLCipher by path, bypassing RTLD_DEFAULT
entirely.
Testing
Verified on a physical iOS device (iPhone). Before this fix the app crashed
immediately on launch. After this fix SQLCipher initialises correctly and PRAGMA
cipher_version returns a result.