-
Notifications
You must be signed in to change notification settings - Fork 110
SQLitePCL.Batteries.Init
An initialization function provided by SQLitePCL.raw's bundle packages.
The original version of the method, before the "V2" version came around.
Both versions of this method do exactly the same thing.
The original version of this method did not support bait-and-switch across bundle types. I realized this was a design mistake too late, as correcting it would be a breaking change. So I left the original unchanged and added a V2 version of the method.
The V2 version is the preferred choice. For that reason, the rest of this writeup speaks in terms of the V2 version.
A bundle package is a meta-package that does two things:
- Use nuget dependencies to bring in other packages as needed for the platform. These include a SQLitePCLRaw.provider package, and if needed, one or more SQLitePCLRaw.lib packages.
- Provide the
SQLitePCL.Batteries_V2.Init()
function to get things properly configured for that platform.
Bundle packages have ids that start with SQLitePCLRaw.bundle_
. For example:
- SQLitePCLRaw.bundle_e_sqlite3
- SQLitePCLRaw.bundle_sqlcipher
- SQLitePCLRaw.bundle_green
Each bundle package has a different policy about which instance of the native SQLite library is being used. The name reflects that policy.
- bundle_e_sqlite3 always brings in e_sqlite3, a native SQLite library which is built specifically for SQLitePCL.raw users.
- bundle_sqlcipher brings in the appropriate platform build of sqlcipher, a variant of SQLite with support for encryption. The sqlcipher builds are maintained by Couchbase.
- bundle_green is just like bundle_e_sqlite3, except that on iOS, it uses the SQLite library provided by iOS.
Each one contains an implementation of ISQLite3Provider.
It is the even-lower-level interface that SQLitePCL.raw uses to talk to the native SQLite library.
The ISQLite3Provider abstraction hides the details of how the native code is called. The pinvoke/DllImport code exists inside the implementation of ISQLite3Provider, not in the main assembly. And since Silverlight platforms do not support DllImport, Windows Phone 8.0 has an implementation of ISQLite3Provider which is completely different, using C++/CLI instead.
The main SQLitePCL.raw assembly does not contain any implementations of ISQLite3Provider. An implementation must be injected by calling SQLitePCL.raw.SetProvider().
It calls SQLitePCLRaw.SetProvider() to inject an instance of ISQLite3Provider, which tells SQLitePCL.raw how to talk to a specific instance of the native SQLite3 library.
From your app's platform-specific initialization code. For example:
- On iOS, you might call it from the FinishedLaunching() method of your AppDelegate class.
- On Android, you might call it from somewhere in your MainApplication or MainActivity class.
- In an MvvmCross app, you might call it from InitializeFirstChance().
- etc
I am referencing SQLitePCL.raw from a PCL. Can I just call Batteries_V2.Init() from my portable code?
Yes, you can call Batteries.Init() from portable code, using the bait-and-switch technique. In other words, you have to add the bundle package to both your portable project and your app project.
Note that the original Batteries.Init()
cannot bait-and-switch from one bundle assembly to a different one. For example: If your PCL references bundle_green for its call to Batteries.Init(), then you need to add bundle_green to your app project -- adding bundle_sqlcipher instead will not work.
But the newer Batteries_V2.Init()
supports bait-and-switch across different types of bundles.
My library depends on SQLitePCL.raw. How do I spare users of my library from the need to call SQLitePCL.Batteries_V2.Init()
?
- Take a dep on SQLitePCLRaw.bundle_e_sqlite3 (or similar)
- Call SQLitePCLRaw.Batteries_V2.Init(), preferably from a static constructor
If your library is a PCL, this will be a bait-and-switch situation, so SQLitePCLRaw.bundle_whatever will need to end up getting added to the app project, one way or another.
Then your library users will need to do so.
If no implementation of ISQLite3Provider is injected, all operations will throw an exception which attempts to explain what needs to be done. At the time of this writing, that message says:
You need to call SQLitePCL.raw.SetProvider(). If you are using a bundle package, this is done by calling SQLitePCL.Batteries.Init().
I may change this error message to improve it. I am also considering allowing it to be customized, so that libraries can provide more specific instructions.
It allows them to choose which bundle they want to use. For example, they could choose SQLitePCLRaw.bundle_sqlcipher if they want.
So if my library package takes a dep on SQLitePCLRaw.bundle_green, can my users choose, say, bundle_sqlcipher instead?
With the original Batteries.Init(), no.
With Batteries_V2.Init(), yes.
Maybe your library wants to use SQLite as merely an implementation detail that is not visible to users.
Yep.
Not anymore. Android N disallows this.
In other words, if your library supports Android and wants to use SQLite, even as a hidden implementation detail, your library's users will somehow have to bundle a SQLite library into their app.
Taking away flexibility in this area would definitely make things simpler, and would probably eliminate the need for an initialization call, but requests for that flexibility have been very common. Lots of people ask me how they can substitute sqlcipher, or a custom SQLite build, and so on.
Maybe you could just bundle several ISQLite3Provider implementations into the main assembly and call them all in a certain order and use the first one that works?
I tried that. Some AOT-based implementations choke if the app contains DllImport calls that are unresolved. Windows Universal 8.0 apps were failing store validation because of SQLitePCL.raw. As AOT gets more common in the .NET world, I expect more such problems.