- Background tasks: a JS implementation of the native task module for iOS (NativeBackgroundTasksModule.ios.ts) with the Android module's contract: per-queue order, 3 concurrent chapter downloads, retries with a delay, pause/resume/cancel interruptions, persistence across launches. Tasks run while the app is open; periodic library updates and backups are not scheduled on iOS. The module is Android-only in autolinking now. - Reader assets: WKWebView will not load file:// assets into a page whose base URL is the source's site, so on iOS the reader CSS, JS and font are inlined (scripts/embed-reader-assets.mjs, src/utils/readerAssets). Downloaded chapters get a file: base URL and file access on iOS. Android is unchanged. - Native iOS: downloadFile implemented with URLSession (plugin installs and chapter images); volume-button setActive added as a no-op (it is called on every chapter). - Share receiver stub and silent toasts on iOS; TrackSheet uses showToast. - app.json: bundle id br.dev.marcospaulo.lnreader, http sources allowed, Files sharing, deployment target 16.4. - Fresh installs start with the open-lab plugin repository. - scripts/build-ios-unsigned.sh and docs/ios-sidestore.md. Verified on Linux: tsc, eslint, all Jest suites (plus new iOS queue tests), expo prebuild for iOS, autolinking, and iOS/Android release JS bundles. Not yet built with Xcode or run on a device. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2.9 KiB
LNReader on iOS (SideStore, free Apple ID)
This fork (open-lab/lnreader, branch ios) builds for iOS. Apple only lets you
install your own builds signed with an Apple ID; with a free one the app is valid for
7 days and has to be refreshed. SideStore does the signing and refreshing on the
phone itself.
What is different on iOS
| Works | Not available on iOS |
|---|---|
| Browsing, plugins (the open-lab repository is preconfigured on a fresh install), reading, Custom code (the illustrator snippet), downloads, EPUB reading, TTS, local library | Downloads and library updates in the background: tasks run while the app is open and continue when you return to it. No scheduled library updates or automatic backups. |
| Downloaded chapters with their images | Page turning with the volume buttons (iOS gives apps no volume-key events) |
| Toast messages, "Share to LNReader", DNS-over-HTTPS, crash-log sharing | |
| Folder and file pickers: EPUB export, backup create and restore |
1. Build the .ipa (Mac with Xcode)
git clone https://git.marcospaulo.dev.br/open-lab/lnreader.git
cd lnreader && git switch ios
./scripts/build-ios-unsigned.sh # -> build/LNReader-unsigned.ipa
Needs Xcode with its command line tools, Node 22.11 or newer, pnpm and CocoaPods
(brew install node pnpm cocoapods). The first build takes a while (pods).
Publish it so the phone can download it:
tea releases create --repo open-lab/lnreader --tag ios-$(jq -r .version package.json) \
--title "iOS $(jq -r .version package.json)" --asset build/LNReader-unsigned.ipa
2. Install SideStore on the iPhone (once)
Follow the current guide at https://docs.sidestore.io (the tools change). As of 2026:
- On the iPhone: Settings > Privacy & Security > Developer Mode on (restart when asked).
- Install LocalDevVPN from the App Store; SideStore uses it to sign apps on the phone.
- On a computer (macOS, Windows or Linux) run iloader, connect the iPhone with a cable, sign in with your Apple ID and install SideStore. It also creates the pairing file SideStore needs.
- Open SideStore on the phone and sign in with the same Apple ID.
A free Apple ID allows 3 sideloaded apps at once (SideStore is one) and 10 new app IDs per week.
3. Install LNReader
- On the iPhone, open the release page in Safari and download
LNReader-unsigned.ipa(it lands in Files > Downloads). - Turn LocalDevVPN on, open SideStore > My Apps > +, and pick the
.ipa. - Open LNReader. Under More > Settings > Reader > Custom code > JS, paste the illustrator snippet (it carries your access key, so it is not built in).
Every 7 days
With LocalDevVPN on, open SideStore and tap Refresh All (or let a Shortcuts
automation do it daily). If an app expires it stops opening; refreshing brings it back
with its data intact. Updating LNReader: build and publish a new .ipa, then install
it over the old one from SideStore.