Readium Mobile is a toolkit for ebooks, audiobooks and comics written in Swift & Kotlin.

Overview

Readium Swift Toolkit

Readium Mobile is a toolkit for ebooks, audiobooks and comics written in Swift & Kotlin.

This toolkit is a modular project, which follows the Readium Architecture.

A Test App demonstrates how to integrate the Readium Swift toolkit in your own reading app

Using Readium

Readium libraries are distributed with Swift Package Manager (recommended), Carthage and CocoaPods. It's also possible to clone the repository (or a fork) and depend on the libraries locally.

The Test App contains examples on how to use all these dependency managers.

Swift Package Manager

From Xcode, open File > Add Packages and use Readium's GitHub repository for the package URL: https://github.com/readium/swift-toolkit.git.

You are then free to add one or more Readium libraries to your application. They are designed to work independently.

If you're stuck, find more information at developer.apple.com.

Carthage

Add the following to your Cartfile:

2.2.0 ">
github "readium/swift-toolkit" ~> 2.2.0

Then, follow the usual Carthage steps to add the Readium libraries to your project.

Note that Carthage will build all Readium modules and their dependencies, but you are free to add only the ones you are actually using. The Readium libraries are designed to work independently.

Refer to the following table to know which dependencies are required for each Readium library.

R2Shared R2Streamer R2Navigator ReadiumOPDS ReadiumLCP
R2Shared ✔️ ✔️ ✔️ ✔️
CryptoSwift ✔️ ✔️
DifferenceKit ✔️
Fuzi ✔️ ✔️ ✔️ ✔️ ✔️
GCDWebServer ✔️
Minizip ✔️ ✔️ ✔️ ✔️ ✔️
SQLite.swift ✔️
SwiftSoup ✔️ ✔️ ✔️ ✔️ ✔️
ZIPFoundation ✔️

CocoaPods

Add the following pod statements to your Podfile for the Readium libraries you want to use:

pod 'R2Shared', podspec: 'https://raw.githubusercontent.com/readium/swift-toolkit/2.2.0/Support/CocoaPods/ReadiumShared.podspec'
pod 'R2Streamer', podspec: 'https://raw.githubusercontent.com/readium/swift-toolkit/2.2.0/Support/CocoaPods/ReadiumStreamer.podspec'
pod 'R2Navigator', podspec: 'https://raw.githubusercontent.com/readium/swift-toolkit/2.2.0/Support/CocoaPods/ReadiumNavigator.podspec'
pod 'ReadiumOPDS', podspec: 'https://raw.githubusercontent.com/readium/swift-toolkit/2.2.0/Support/CocoaPods/ReadiumOPDS.podspec'
pod 'ReadiumLCP', podspec: 'https://raw.githubusercontent.com/readium/swift-toolkit/2.2.0/Support/CocoaPods/ReadiumLCP.podspec'

Take a look at CocoaPods's documentation for more information.

Local Git Clone

You may prefer to use a local Git clone if you want to contribute to Readium, or if you are using your own fork.

First, add the repository as a Git submodule of your app repository, then checkout the desired branch or tag:

git submodule add https://github.com/readium/swift-toolkit.git

Next, drag and drop the whole swift-toolkit folder into your project to import Readium as a Swift Package.

Finally, add the Readium libraries you want to use to your app target from the General tab, section Frameworks, Libraries, and Embedded Content.

Building with Readium LCP

Using the toolkit with Readium LCP requires additional dependencies, including the framework R2LCPClient.framework provided by EDRLab. Contact EDRLab to request your private R2LCPClient.framework and the setup instructions.

Comments
  • Implement Pop-Up Noterefs

    Implement Pop-Up Noterefs

    The r2-navigator-kotlin has a click handler that is bridged from JS that checks for <a epub:type="noteref"> and displays the target content in a modal.

    Relevant code:=

    var handleClick = function(event) {
        Android.handleClick(event.target.outerHTML)
    };
    

    and

    @android.webkit.JavascriptInterface
    fun handleClick(html: String) {
        val doc = Jsoup.parse(html)
        val link = doc.select("a[epub:type=noteref]")?.first()
        link?.let { noteref ->
            val href = noteref.attr("href")
            if (href.indexOf("#") > 0) {
                val id = href.substring(href.indexOf('#') + 1)
                var absolute = getAbsolute(href, resourceUrl!!)
                absolute = absolute.substring(0, absolute.indexOf("#"))
                val document = Jsoup.connect(absolute).get()
                val aside = document.select("aside#$id").first()?.html()
                aside?.let {
                    val safe = Jsoup.clean(aside, Whitelist.relaxed())
    
                    // Initialize a new instance of LayoutInflater service
                    val inflater = activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
    
                    // Inflate the custom layout/view
                    val customView = inflater.inflate(R.layout.popup_footnote, null)
    
                    // Initialize a new instance of popup window
                    val mPopupWindow = PopupWindow(
                        customView,
                        ListPopupWindow.WRAP_CONTENT,
                        ListPopupWindow.WRAP_CONTENT
                    )
                    mPopupWindow.isOutsideTouchable = true
                    mPopupWindow.isFocusable = true
    
                    // Set an elevation value for popup window
                    // Call requires API level 21
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        mPopupWindow.elevation = 5.0f
                    }
    
                    val textView = customView.findViewById(R.id.footnote) as TextView
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        textView.text = Html.fromHtml(safe, Html.FROM_HTML_MODE_COMPACT)
                    } else {
                        textView.text = Html.fromHtml(safe)
                    }
    
                    // Get a reference for the custom view close button
                    val closeButton = customView.findViewById(R.id.ib_close) as ImageButton
    
                    // Set a click listener for the popup window close button
                    closeButton.setOnClickListener {
                        // Dismiss the popup window
                        mPopupWindow.dismiss()
                    }
    
                    // Finally, show the popup window at the center location of root relative layout
                    mPopupWindow.showAtLocation(this, Gravity.CENTER, 0, 0)
    
                    overrideUrlLoading = false
                }
            }
        }
    }
    

    The same could be implemented for iOS.

    Current click handling:

    function onClick(event) {
      if (event.defaultPrevented || isInteractiveElement(event.target)) {
        return;
      }
    
      if (!window.getSelection().isCollapsed) {
        // There's an on-going selection, the tap will dismiss it so we don't forward it.
        return;
      }
    
      webkit.messageHandlers.tap.postMessage({
        "screenX": event.screenX,
        "screenY": event.screenY,
        "clientX": event.clientX,
        "clientY": event.clientY,
      });
    

    In terms of implementation, I'll start with comparing to the Android version.

    In reading through the behavior, it appears that all taps (on any element) call the Kotlin function before the event is propagated through the DOM. The Kotlin checks to see if the tapped element is a[epub:type=noteref] and if so, identifies the target material. It's important to do this in the host code, rather than JS, so that you can access whatever file is being targeted. If the Kotlin func successfully displays the modal, it does a little semaphore action (so to speak) to the WebView delegate to cancel the navigation. (That last bit is a little convoluted since shouldOverrideUrlLoading appears to be employed in reverse, but that's what I gather.)

    In contrast, the iOS click handler explicitly avoids calling across the JS bridge to Swift for any interactive elements, including <a> tags. The recursive isInteractiveElement JS function references this https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling regarding don't-mess-up-the-author's-scripts.

    Links

    This test contains 3 links with different behaviors:

    1. normal link, which should take the user to the previous test;
    2. scripted link, which should display a hidden element below the second paragraph;
    3. scripted link, which is using window.location to send the user to the next test.

    The test is here and looks like:

    <a href="../Text/test-005.xhtml">I’m a simple link to the previous chapter (Audio controls with buttons)</a>
    <a id="anchor-hook" href="#note">I’m a link which will be used to display something below this paragraph</a>
    <a id="anchor-programmatic" href="#anchor-programmatic">I’m a link using window.location to the next chapter (DOM Storage)</a>
    

    along with

    var hook = document.getElementById("anchor-hook"),
        prog = document.getElementById("anchor-programmatic"),
        note = document.getElementById("note");
    
    hook.addEventListener("click", function(e) {
      e.preventDefault();
      if (note.style.display === "none") {
        note.style.display = "block";
      } else {
    	note.style.display = "none";
      }
    }, false);
    
    prog.addEventListener("click", function(e) {
      e.preventDefault();
      window.location = "../Text/test-007.xhtml";
    }, false);
    

    I am tempted to check for epub:type=noteref in the JS and call a new, special Swift handler specifically for this purpose. I think that links of that type should be handled by the app and any user scripts are forfeit.

    The other question in my mind is what to do on the targeted content, because typically (in my understanding of things) it should be hidden. Not sure if the author should have to display:none it or if that should be part of the styles injected by the app...I lean towards the latter.

    I intend to do this work over the next day or two, but I wanted to ask for feedback before my PR leaps full-armed from the brow of Jove.

    opened by tooolbox 41
  • Should we raise the minimum supported iOS version to iOS 10?

    Should we raise the minimum supported iOS version to iOS 10?

    EDIT: We talked about this issue on the last dev meeting, and agreed on dropping support for iOS 9. Unfortunately, we don't have the resources to maintain the toolkit on such older versions. Apple is not making it easy.

    The next tagged release will be the last one supporting iOS 9.


    I'm testing the waters.

    Right now, Readium supports down to iOS 9, but:

    • the PDF navigator requires iOS 11
    • the audiobook navigator will require iOS 10

    Personally, I think it's time to raise the minimum requirement to iOS 10.

    3.3% of iPads are < iOS 10, and only 0.1% on iPhones. https://david-smith.org/iosversionstats/

    Any disagreement?

    opened by mickael-menu 17
  • Question: Didn't get highlighted text.

    Question: Didn't get highlighted text.

    Hey, I want to get Highlighted text in EPUBViewController. So I have added custom editAction
    var config = EPUBNavigatorViewController.Configuration() config.editingActions.append(EditingAction(title: "Highlight", action: #selector(highlight)))

    @objc func highlight(_ sender: Any) { print(epubNavigator.currentLocation?.text.highlight) }

    but I am getting nil in highlight.
    
    Is there something else that I am missing here ?
    
    opened by vishalpatel-simformsolutions 17
  • Support for Swift Package Manager

    Support for Swift Package Manager

    Xcode 11 finally brought native support for SPM, including iOS!

    As the official package manager for iOS development, this should be the default choice used in Readium projects.

    I think this could also simplify the build settings of the test app, that are right now split between Carthage and submodules. We could maybe use only SPM, setup either with a direct path to the submodules or with the URLs to the Git repositories.

    enhancement help wanted 
    opened by mickael-menu-mantano 16
  • How can I set full-screen background image

    How can I set full-screen background image

    There are two questions: I try to set full-screen background image to each page of one chapter and the cover page. To do so, I set the Navigator full-screen, then the top bar and bottom bar just cover the Navigator. The first question is how to set the top/bottom margin of each page, since the top/bottom line of text is covered by the top/bottom bar content. Another question is about the background image. I use the css style "background-repeat: repeat-y;". It work well in Android with Readium SDK, but not work in iOS with R2.

    opened by ClassWizard 14
  • Restoring last read position occasionally fails, opening EPUB to beginning of chapter instead

    Restoring last read position occasionally fails, opening EPUB to beginning of chapter instead

    Overview

    Reopening an EPUB trying to restore the last read position seem to work inconsistently, sometimes opening the book to the beginning of the chapter. This bug is currently blocking our transition to R2 which otherwise is complete.

    I am unable to reproduce the issue on iOS 14. However I can reproduce it roughly one time out of 5 attempts using the same steps, book, build and device on iOS 13, 12 and 10. (I never tried on 11.) It is easier to reproduce with long books trying to restore a position toward the end of one of the last chapters, but it's pretty random.

    I can't reproduce this in the r2-testapp but I'll try to explain what I tried in detail what I am observing.

    Build / Test Set-up

    • Xcode 11.5 toolchain
    • carthage 0.36.0
    • R2 version 2.0.0-beta.1
    • test devices: iPhone 11 iOS 14.4 / iPhone 6 iOS 12.5.1
    • simulators: iPads / iPhones iOS 13.5, 12.4, 10.3.1
    • Focusing on epubs without DRM (e.g. Treasure Island, which is also present in the testapp). DRM'ed books exhibit same behavior though.

    R2 Set-up

    The way R2 is integrated in our app (SimplyE) matches the r2-testapp's -- as a matter of fact I copied its architecture. As far as restoring the reading position is concerned, my understanding is that one simply has to pass the desired Locator to the initialLocation parameter in the EPUBNavigatorViewController initializer. Is this correct or is there more to it?

    I also verified the locator i am passing is always the same, with or without experiencing the bug.

    Investigation

    I've tried to follow how the initialLocation locator is propagated at runtime inside the R2 navigator code, to try to understand where it is getting lost. I see that it is passed to the reloadSpreads(at:) function, and there i verified a non-zero initialIndex is always found.

    The code then flows to PaginationView::setCurrentIndex(_:location:) and then loadView(at:location:completion:). I verified the guards in those functions are not triggered.

    From there control passes to EPUBReflowableSpreadView::go(to:completion:), which may be called multiple times during initialization from many places. I assume this is expected?

    This is where things get confusing. When the bug happens the last go(to:completion:) call is for a Locator with progression == 0. This seems to come from a polling timer, for updating the user setting style. In this last function invocation we call go(to:) with the currentLocation value, which is incorrect because its progression is 0. Shouldn't that still be the initialLocation i passed in in the navigator's initializer, since the reader is still setting itself up? (There's a spinner on the screen at this time.) I just can't figure out where that initialLocation ends up going, or why/if it's being overwritten.

    From another POV, I noticed that on the r2-testapp navigator(_:locationDidChange:) is called twice (once with progression==0, then with the correct locator) but on our app it's only called once, and when the bug happens the locator.progression is 0. That callback is also called from another polling timer, which makes me think order of execution is not guaranteed to be identical across 2 identical instantiations of the navigator.

    I also noticed that if i start putting a lot of breakpoints with debugger output (which slows down execution), the bug is more likely to be triggered. This hints at possible race conditions, but it's just a conjecture.

    Long write-up, sorry... final thoughts

    I've tried many other approaches (e.g. trying to follow the spreads set-up, or how the Locator progression property is being set) but probably i should stop here since I'm rambling at this point.

    Thanks in advance for any help/pointers/suggestions. I realize the fact that the r2-testapp is fine probably means I have a bug in my set-up, but on the other hand this random behavior could mean something is off inside r2-navigator, but I ran out of things to look into.

    bug help wanted 
    opened by ettore 12
  • Add user interface to search through a publication

    Add user interface to search through a publication

    (Please respond in this issue if you want to contribute this feature and have any question)

    The PR https://github.com/readium/r2-shared-swift/pull/135 adds a new SearchService feature to search through the content of a publication. We need to expose this in the user interface of the test app.

    Here are some general guidelines:

    • SearchService is described in this proposal.
    • The search interface needs to be added for the ReaderViewController if publication.isSearchable is true.
    • It would be best to load the next page of results (iterator.next() when scrolling to the end of the results table view)

    Starting a search

    To start a new search, use publication.search(). It will asynchronously return a SearchIterator if the search is valid. This iterator can be used to get the search results.

    let cancellable = publication.search(query: "banana") { result in
        switch result {
            case .success(let iterator):
                // show results using iterator
            case .failure(let error):
                // display error
        }
    }
    

    Showing the results

    The results will be displayed in a table view. Every time the user scrolls to the end of the scroll view, you need to request the next page of results with iterator.next(). It will return a LocatorCollection, or nil if the search is finished.

    let cancellable = iterator.next { result in
        switch result {
            case .success(let collection):
                if let collection = collection {
                    // append `collection.locators` to the table view
                } else {
                    // search is finished
                }
            case .failure(let error):
                // display error
        }
    }
    

    For each Locator cell:

    • If locator.title is different from the previous locator.title, create a new section with this title in the table view
    • Display the locator.locations.totalProgression in the cell
    • Display the search snippet with locator.text.before + locator.text.highlight + locator.text.after, putting emphasis on the locator.text.highlight portion.

    Cancelling the search

    When the user cancels the search, you need to dispose of the search properly:

    • If publication.search() didn't return an iterator yet, call cancel() on the Cancellable returned by publication.search().
    • If a SearchIterator was received:
      • call cancel() on the Cancellable returned by the last iterator.next() call
      • call iterator.close()
    opened by mickael-menu 11
  • Publish to CocoaPods

    Publish to CocoaPods

    opened by jspizziri 11
  • Xcode cannot find libxml2

    Xcode cannot find libxml2

    I'm trying to add readium to a Swift project using Xcode 11.3.1. I've added the following two lines to my Podfile

      pod 'R2Navigator', :git => 'https://github.com/readium/r2-navigator-swift.git'
      pod 'R2Streamer', :git => 'https://github.com/readium/r2-streamer-swift.git'
    

    When I build the project I get the following error:

    R2Streamer Group Swift Compiler Error Group /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.2.sdk/usr/include/libxml2/libxml/HTMLparser.h:15:10: 'libxml/xmlversion.h' file not found Could not build Objective-C module 'libxml2'

    How can I get the pod for R2Streamer to find the libxml2 header?

    Thanks, Jeff

    help wanted 
    opened by jeffgilbert 10
  • Install using CocoaPods not resolving right GCDWebServer

    Install using CocoaPods not resolving right GCDWebServer

    I tried to install r2-streamer-swift using CocoaPods and saw that it has GCDWebServer as a dependency.

    The issue is that the Cartfile uses a forked ( and working ) version of GCDWebServer ( erdlab/GCDWebServer ), meaning that the Cocoapods installs can't work without that exact dependency.

    Is there any reason why the forked version of GCDWebServer isn't available on CocoaPods ? If no, can we publish the forker server on CocoaPods to then update the podspec file of this project ?

    My main issue is that I'm using this package as a dependency on a React Native project, which is only compatible with Cocoapods dependencies.

    help wanted question 
    opened by MAVERlCK 10
  • JSON serialization of Publication is missing specification properties

    JSON serialization of Publication is missing specification properties

    When serializing a Publication, a lot of properties from the JSON schema specification are missing. The JSON serialization should be reviewed and completed, adapting the existing unit tests.

    Core specification: https://readium.org/webpub-manifest/ Default metadata context: https://readium.org/webpub-manifest/contexts/default/ JSON Schema: https://readium.org/webpub-manifest/schema/publication.schema.json The JSON Schema is used more and more as the reference document these days.

    bug 
    opened by mickael-menu-mantano 10
  • Fix CGPDF returning unlocked pdf instead of error

    Fix CGPDF returning unlocked pdf instead of error

    opened by nwilmet-vivlio 0
  • Highlight decorations not working on some graphic epubs

    Highlight decorations not working on some graphic epubs

    Bug Report

    What happened?

    Highlight decorations (background color or underline) are not being drawn over text in cases where the text is rendered over fullscreen images. These are fixed layout EPUBs.

    Expected behavior

    Highlight decorations should work.

    How to reproduce?

    Open the attached epub and try to add a highlight.

    Environment

    • Readium version: 2.4.0

    Development environment

    macOS: 12.6 platform: arm64 zsh: command not found: carthage carthage: Xcode 13.4.1 Build version 13F100

    Testing device

    Additional context

    • Are you willing to fix the problem and contribute a pull request? Yes or No

    No

    9780062432155.epub.zip

    bug 
    opened by streamg 0
  • [VO]: Toggling the VO while a book is open will freeze the app in a few seconds

    [VO]: Toggling the VO while a book is open will freeze the app in a few seconds

    Bug Report

    What happened?

    While the a book is open, toggling the VoiceOver will freeze the app in a few seconds and the app will be unresponsive, and multiple attempt will also cause the device to get very hot.

    https://user-images.githubusercontent.com/3314171/201693659-8fe4a098-8dbd-4157-90fe-38fb02e93d51.MP4

    Environment

    • Readium version: 2.4.0

    Development environment

    macOS: 13.0 platform: x86_64 carthage: 0.38.0 Xcode 14.1 Build version 14B47b

    Testing device

    • iOS version: 16.0.3(20A392)
    • Model (e.g. iPhone 11 Pro Max): iPhone 11
    • Is it an emulator? No
    opened by 838 2
  • Empty Table of Contents List for PDF LCP

    Empty Table of Contents List for PDF LCP

    Bug Report

    What happened?

    We tried to open PDF (LCP) file both in our App(with Swift-toolkit integration) and Test app. We were able to successfully open it. However, we experienced an empty Table of Contents for pdf files.

    mediaType : application/pdf+lcp Extension: lcpdf Sample PDF LCP https://tuxedo-preprod-icdp.yondu.net/api/ebook/mobile/lcp/get-book-lcp/be7ec450-4617-4b53-bc92-d910951636ea/293 [passphrase: 293]

    We tried to view the PDF with LCP in other Ebook Reader like Thorium and it can fetch the publication's table contents. However in the Test app and our app, we can't retrieve it. Hope you can assist us on how to fetch it thanks!

    Expected behavior

    We expected to view the table of contents list like the one we are using on .epub files.

    How to reproduce?

    Using Test App:

    1. Press the "+" button on the right navigation bar and select From a URL.
    2. Enter https://tuxedo-preprod-icdp.yondu.net/api/ebook/mobile/lcp/get-book-lcp/be7ec450-4617-4b53-bc92-d910951636ea/293
    3. Enter 293 as passphrase.
    4. Open Book
    5. View Table of Contents (from the Option Hamburger menu).

    Result on Test App: Screen Shot 2022-09-19 at 5 14 09 PM

    Logs upon Opening PDF

    Screen Shot 2022-09-19 at 5 01 55 PM

    vs

    Logs on .epub Files

    Screen Shot 2022-09-19 at 6 28 59 PM

    Environment

    • Readium version: Using Swift Package Manager: { "identity" : "swift-toolkit", "kind" : "remoteSourceControl", "location" : "https://github.com/readium/swift-toolkit.git", "state" : { "branch" : "main", "revision" : "2e0c647221612f923f9888851c848c88d14f7679" } }

    Development environment

    Testing device

    • iOS version: 15.5
    • Model (e.g. iPhone 11 Pro Max): iPhone 13 Pro Max
    • Is it an emulator? Yes

    Tried it also on actual device. Problem also occurs.

    Additional context

    • Are you willing to fix the problem and contribute a pull request? No
    feature request 
    opened by Tenten18 1
  • SwiftUI: Open a book on tap

    SwiftUI: Open a book on tap

    This PR aims to open a book somehow.

    Changes:

    • extracted new services BookOpener, BookImporter , BookRemover from the LibraryService
    • added a wrapper over the ReaderViewController
    • improved navigation - when we open a book, a bottom tab bar disappears
    • refactored Container, as now it has more responsibilities

    Out of scope (coming soon in the next PRs):

    • Highlights, Search, and any other Reader supporting views
    opened by gatamar 0
  • Unable to add Annotation on image only content

    Unable to add Annotation on image only content

    Bug Report

    I was trying to add annotations to image only means I selected only image no text and was unable to add annotation as locator was giving null

    What happened?

    Select any image by dragging (no text only image )try to add annotation to it. It will not work

    Expected behavior

    One should be able to add annotations to image only content

    How to reproduce?

    Environment

    • Readium version:

    Development environment

    • Open epub having image in its content
    • Go to place where image is present
    • Select only image and no text
    • try to add annotation
    • you will not be able to add annotation
    • PFB scrrenshot for more understanding

    Testing device

    • iOS version: any
    • Model (e.g. iPhone 11 Pro Max): any
    • Is it an emulator? Yes

    Image 02-09-22 at 1 42 PM

    opened by rohitvishwakarma1819 1
Releases(2.4.0)
  • 2.4.0(Sep 26, 2022)

    Take a look at the migration guide

    Added

    Shared

    Navigator

    Streamer

    Deprecated

    Shared

    • Locator(link: Link) is deprecated as it may create an incorrect Locator if the link type is missing.
      • Use publication.locate(Link) instead.

    Fixed

    • #244 Fixed build with Xcode 14 and Carthage/CocoaPods.

    Navigator

    • Fixed memory leaks in the EPUB and PDF navigators.
    • #61 Fixed serving EPUB resources when the HREF contains an anchor or query parameters.
    • Performance issue with EPUB fixed-layout when spreads are enabled.
    • Disable scrolling in EPUB fixed-layout resources, in case the viewport is incorrectly set.
    • Fix vertically bouncing EPUB resources in iOS 16.

    Streamer

    • Fixed memory leak in the PublicationServer.

    LCP

    • The LCP authentication dialog is now fully localized and supports Dark Mode (contributed by @openm1nd).
    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Apr 21, 2022)

    Take a look at the migration guide

    Added

    Shared

    • Get the sanitized Locator text ready for user display with locator.text.sanitized().
    • A new Publication.conforms(to:) API to identify the profile of a publication.
    • Support for the conformsTo RWPM metadata, to identify the profile of a Publication.
    • Support for right-to-left PDF documents by extracting the reading progression from the ViewerPreferences/Direction metadata.
    • HTTP client:
      • A new HTTPClient.download() API to download HTTP resources to a temporary location.
      • HTTPRequest and DefaultHTTPClient take an optional userAgent property to customize the user agent.

    Navigator

    • The new NavigatorDelegate.navigator(_:didJumpTo:) API is called every time the navigator jumps to an explicit location, which might break the linear reading progression.
      • For example, it is called when clicking on internal links or programmatically calling Navigator.go(to:), but not when turning pages.
      • You can use this callback to implement a navigation history by differentiating between continuous and discontinuous moves.

    Deprecated

    Shared

    • Publication.format is now deprecated in favor of the new Publication.conforms(to:) API which is more accurate.
      • For example, replace publication.format == .epub with publication.conforms(to: .epub) before opening a publication with the EPUBNavigatorViewController.

    Changed

    LCP

    • The LCPService now uses a provided HTTPClient instance for all HTTP requests.

    Fixed

    Navigator

    • #14 Backward compatibility (iOS 10+) of JavaScript files is now handled with Babel.
    • Throttle the reload of EPUB spreads to avoid losing the position when the reader gets back to the foreground.

    LCP

    • Fixed the notification of acquisition progress.
    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Nov 9, 2021)

    Take a look at the migration guide

    Added

    Shared

    • Support for Paragraph Margins user setting.

    Navigator

    • A new translate EPUB and PDF editing action is available for iOS 15.

    Fixed

    Shared

    • Improved performances of the search service used with EPUB.

    Navigator

    • Fixed turning pages of an EPUB reflowable resource with an odd number of columns. A virtual blank trailing column is appended to the resource when displayed as two columns.
    Source code(tar.gz)
    Source code(zip)
Owner
Readium
Our mission is to foster the development of an open and modern collaborative playground for digital reading technologies.
Readium
Ethereum Wallet Toolkit for iOS - You can implement an Ethereum wallet without a server and blockchain knowledge.

Introduction EtherWalletKit is an Ethereum Wallet Toolkit for iOS. I hope cryptocurrency and decentralized token economy become more widely adapted. H

Sung Woo Chang 136 Dec 25, 2022
Parse iOS mobile provisioning files into Swift models

SwiftyProvisioningProfile This library provides a way to decode a .mobileprovision file into a Swift model. Installation The recommended installation

James Sherlock 60 Nov 25, 2022
A simple Pokedex app written in Swift that implements the PokeAPI, using Combine and data driven UI.

SwiftPokedex SwiftPokedex is a simple Pokedex app written by Viktor Gidlöf in Swift that implements the PokeAPI. For full documentation and implementa

Viktor G 26 Dec 14, 2022
Simple and Lightweight App Version Tracking for iOS written in Swift

AEAppVersion Simple and lightweight iOS App Version Tracking written in Swift I made this for personal use, but feel free to use it or contribute. For

Marko Tadić 12 Nov 11, 2022
Swift-HorizontalPickerView - Customizable horizontal picker view component written in Swift for UIKit/iOS

Horizontal Picker View Customizable horizontal picker view component written in

Afraz Siddiqui 8 Aug 1, 2022
A utility that reminds your iPhone app's users to review the app written in pure Swift.

SwiftRater SwiftRater is a class that you can drop into any iPhone app that will help remind your users to review your app on the App Store/in your ap

Takeshi Fujiki 289 Dec 12, 2022
An extensible monitoring framework written in Swift

XestiMonitors Overview Reference Documentation Requirements Installation CocoaPods Carthage Swift Package Manager Usage Core Location Monitors Core Mo

J. G. Pusey 271 Oct 5, 2022
noppefoxwolf/notion is a notion.so API library written in swift.

notion noppefoxwolf/notion is a notion.so API library written in swift. Installation Xcode Project > Swift Packages [email protected]:noppefoxwolf/notion

noppefoxwolf 44 Oct 7, 2022
Just another NES emulator written in Swift

SwiftNes This repo contains all the source code for my experimental 100 days of NES challenge. What is this all about? I'm planning to build a fully w

Tibor Bödecs 44 Dec 24, 2021
A Powerful , Extensible CSS Parser written in pure Swift.

A Powerful , Extensible CSS Parser written in pure Swift.

null 273 Sep 9, 2022
Python VM written in Swift

Violet Violet is one of those Swift <-> Python interop thingies, except that this time we implement the whole language from scratch. Name comes from V

LiarPrincess 157 Dec 14, 2022
A (slow) ray tracer written in Swift.

Blitzlichtgewitter Blitzlichtgewitter is a (slow) ray tracer written in Swift. It loosely follows the steps described in The Ray Tracer Challenge by J

Lennart Stolz 1 Dec 21, 2021
A simple, but efficient CSV Parser, written in Swift.

CSV CSV.swift is a powerful swift library for parsing CSV files that supports reading as [String], [String: String] and Decodable, without sacrificing

Ben Koska 4 Nov 28, 2022
Questrade API written in Swift

QuestradeAPI Getting Started The QuestAPI is made up of two main concepts: ResponseProviders API ResponseProviders The job of the provider is to retur

Eli Slade 2 Mar 15, 2022
A parser combinator library written in the Swift programming language.

SwiftParsec SwiftParsec is a Swift port of the Parsec parser combinator library. It allows the creation of sophisticated parsers from a set of simple

David Dufresne 219 Nov 6, 2022
Simple getter for bundle informations, written in Swift

BundleInfos Simple getter for bundle informations It's simple and static way for getting information from main bundle Requirements iOS 8.0+ Xcode 7.3

Jay Choi 1 Dec 3, 2017
Super powerful remote config utility written in Swift (iOS, watchOS, tvOS, OSX)

Mission Control Super powerful remote config utility written in Swift (iOS, watchOS, tvOS, OSX) Brought to you by Have you ever wished you could chang

appculture 113 Sep 9, 2022
SuggestionsBox helps you build better a product trough your user suggestions. Written in Swift. 🗳

SuggestionsBox An iOS library to aggregate users feedback about suggestions, features or comments in order to help you build a better product. Swift V

Manuel Escrig 100 Feb 6, 2022
FancyGradient is a UIView subclass which let's you animate gradients in your iOS app. It is purely written in Swift.

FancyGradient is a UIView subclass which let's you animate gradients in your iOS app. It is purely written in Swift. Quickstart Static gradient let fa

Derek Jones 11 Aug 25, 2022