{"id":19357927,"url":"https://github.com/milibris/android-milibris-reader-sdk","last_synced_at":"2026-04-02T13:28:49.548Z","repository":{"id":144737142,"uuid":"518872228","full_name":"miLibris/android-milibris-reader-sdk","owner":"miLibris","description":"Reader SDK for the miLibris platform ","archived":false,"fork":false,"pushed_at":"2026-03-25T11:21:45.000Z","size":96671,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-03-26T14:00:24.247Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/miLibris.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-28T14:09:44.000Z","updated_at":"2026-03-25T11:21:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"ed863b52-2562-44c9-bdf4-6c66110050dc","html_url":"https://github.com/miLibris/android-milibris-reader-sdk","commit_stats":null,"previous_names":[],"tags_count":58,"template":false,"template_full_name":null,"purl":"pkg:github/miLibris/android-milibris-reader-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miLibris%2Fandroid-milibris-reader-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miLibris%2Fandroid-milibris-reader-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miLibris%2Fandroid-milibris-reader-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miLibris%2Fandroid-milibris-reader-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/miLibris","download_url":"https://codeload.github.com/miLibris/android-milibris-reader-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miLibris%2Fandroid-milibris-reader-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31307096,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T07:09:41.999Z","updated_at":"2026-04-02T13:28:49.542Z","avatar_url":"https://github.com/miLibris.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MiLibrisReaderSDK\n\nMiLibrisReaderSDK is the new miLibris reading SDK (previously called MLPDFReaderSDK). It includes the MLFoundation library which allows unpacking miLibris contents.\n\n- [Prerequisites](#prerequisites)\n    - [Setup](#setup)\n      - [Environment](#environment)\n- [Implementation](#implementation)\n    * [Usual workflow](#usual-workflow)\n    - [Download a complete archive](#download-a-complete-archive)\n    - [Unpack a complete archive with MLFoundation](#unpack-a-complete-archive-with-mlfoundation)\n    - [Read unpacked contents](#read-unpacked-contents)\n- [Customization](#customization)\n    - [Optional Features](#optional-features)\n        - [Print](#print)\n        - [Search publication](#search-publication)\n        - [Interstitial advert](#interstitial-advert)\n    - [Configure the reader tutorial](#configure-the-reader-tutorial)\n    - [Event tracking](#event-tracking)\n    - [Resume reading at the last read page](#resume-reading-at-the-last-read-page)\n    - [Provide article sharing functionality](#provide-article-sharing-functionality)\n    - [Customize logo](#customize-logo)\n        - [`DisplayMode` variants in article reader](#displaymode-variants-in-article-reader)\n        - [Override capsule](#override-capsule)\n            - [Remove the capsule](#remove-the-capsule)\n    - [Apply your branding to the reader UI](#apply-your-branding-to-the-reader-ui)\n- [Sample project](#sample-project)\n\n## Prerequisites\n\nMiLibrisReaderSDK developed in Kotlin requires Android 5 or higher, and uses glide to load images as external library and other androidX libraries like ViewModel and appCompact.  \nEvery app using the SDK must be configured with a licence key provided by miLibris. A licence key cannot be used in more than one application.\n\n### Setup\n\nThe library is available on our maven and can be added to your Android project as follow:\n\n```groovy\nrepositories {\n    google()\n    mavenCentral()\n    maven { url 'https://maven-android-sdk.milibris.net/' }\n}\n\ndependencies {\n    def miLibrisReader = \"1.19.1\"\n    api(\"com.milibris:one-reader:$miLibrisReader\") {   //If you ever have conflict with the version used in our library add this line\n        exclude group: \"androidx.lifecycle\"\n    }\n    api \"com.milibris:milibris-reader:$miLibrisReader\"\n}\n```  \n\nIn order for the SDK to work properly you need to add the licence key provided in your manifest as below\n\n```xml\n\n\u003capplication....\u003e\n    \u003cmeta-data android:name=\"com.milibris.pdfreader.licencekey\" android:value=\"YOUR_LICENCE_KEY\" /\u003e\n\u003c/application\u003e  \n```  \n\n#### Environment\n\nBy default, the SDK will communicate with miLibris production environment.\nTo change the target, you can override the base URL in your manifest as below\n\n```xml\n\n\u003capplication....\u003e\n    \u003cmeta-data android:name=\"com.milibris.api.v4.baseUrl\" android:value=\"TARGET_BASE_URL\" /\u003e\n\u003c/application\u003e  \n```  \n\n## Implementation\n\n### Usual workflow\n\nIn order to read a content, your application will likely implement the following steps:\n\n1. Download a complete archive (with the *.complete extension) from the miLibris  \n   platform.\n2. Unpack the archive using MLFoundation\n3. Launch Reader to read the unpacked contents\n\n### Download a complete archive\n\nRefer to the miLibris API documentation to obtain a ticket for the issue you want to download, in the `x-ml-pdf` format.\n\nYou can then download the complete archive with the following URL: `https://content.milibris.com/access/%@/download.complete` (replace `%@` with the mid of your ticket).\n\nThe JWT token returned by the API can be ignored.\n\n### Unpack a complete archive with MLFoundation\n\nA complete archive can be easily unpacked with the MLFoundation library utilities (see  \nexample below, extracting a sample.complete file in Android assets).\n\n```kotlin\nprivate fun unpackArchive() {\n    val foundationContext: com.milibris.foundation.FoundationContext =\n        com.milibris.foundation.Foundation.createContext(applicationContext)\n    try {\n        val archive: com.milibris.foundation.CompleteArchive =\n            com.milibris.foundation.CompleteArchive(\n                foundationContext,\n                assets.openFd(\"$pdfName.complete\").createInputStream()\n            )\n        archive.unpackTo(File(getExternalFilesDir(null), pdfName))\n    } catch (e: Throwable) {\n        e.printStackTrace()\n    }\n}  \n```  \n\n### Read unpacked contents\n\nOnce unpacked, you can open the content by starting OneReaderActivity:\n\n```kotlin\n// Initialize the reader to open the contents val productRepo = XmlPdfReaderDataSource(readerSettings) productRepo.init(applicationContext, contentPath)  \nstartActivity(\n    OneReaderActivity.newIntent(\n        context = this,\n        readerSettings = ReaderSettings(),\n        productRepository = productRepo,\n        readerListener = ORListener(dataSource = productRepo, \"issueMid\", this),\n        searchProvider = CustomSearchProvider(), // @see Search publication optional feature\n        sharedElementImageUrl = coverImageURL,\n        sharedElementRatio = coverRatio\n    )\n)\n```  \n\n## Customization\n\n### Optional Features\n\nWe are providing a ReaderSettings class where you can customize the reader as you please to enable or disable some features.\n\n```kotlin\n val readerSettings = ReaderSettings().apply {\n    isFaceCropEnabled = true\n    debugBoxes = true\n    targetPageNumber = targetPage\n    textToSpeechEnabled = true\n    shareEnabled = true\n    enableSummaryImages = true\n    logo = R.drawable.milibris\n    isSummaryEnabled = true\n    isPrintEnabled = true\n}\n```\n\n#### Print\n\nTo allow users to print currently displayed pages we enable the `ReaderSettings` `isPrintEnabled` option.\nThis feature is disabled by default.\n\n#### Search publication\n\nTo enable searching in a publication, we are providing a provider:\n```kotlin\nOneReaderActivity.newIntent(\n    searchProvider = CustomSearchProvider(),\n)\n```\n\nThis object implements the `SearchProvider` interface:\n\n```kotlin\ninterface SearchProvider {\n    fun search(searchText: String, completion: (Result\u003cSearchResponse\u003e) -\u003e Unit)\n}\n```\n\n@see [CustomSearchProvider.kt](app/src/main/java/com/milibris/reader/sdk/sample/CustomSearchProvider.kt)\n\nThe search result can be:\n- a list of matching results `SearchResponseItem`\n- an empty list to present a \"no result\" screen\n- a failure to present a \"technical error\" screen\n\nEach `SearchResponseItem` must describe a `SearchResponseItemArticle` and a list of highlights `String`.\n\nFor now:\n- only the first `highlight` is presented.\n- the `SearchResponse` `suggestions` are not used.\n\nBy default, without any `SearchProvider` provided, this feature is disabled.\n\n#### Interstitial advert\n\nThe reader can present a page as an interstitial advert when an issue is opened.\nTo enable this feature, the reader must be provided a `PageAdRepository` implementation.\nThe miLibris reader includes a default one that allows the interstitial to be shown the first time an issue is opened:\n\n```kotlin\nOneReaderActivity.newIntent(\n    productRepository = productRepo,\n    pageAdRepository = MiLibrisPageAdRepository(productRepository),\n)\n```\n\n### Configure the reader tutorial\n\nThe reader is configured to display a tutorial the first time that it is opened on a new device. You can disable it you want:\n\n```kotlin\n val readerSettings = ReaderSettings().apply {\n    showReaderTutorials = false\n} \n```\n\nOr this way if you don't want the tutorial to be shown on previews for example\n\n```kotlin\n class ORListener(\n    private val dataSource: XmlPdfReaderDataSource\n) : ReaderListener {\n\n    override fun canOpenTutorials(): Boolean {\n        return dataSource.materialParser.isPreview.not()\n    }\n}\n```\n\n### Event tracking\n\nIf you want to track user events on reader you need to implement create your own class that implements The ReaderListener :\n\n```kotlin\n  class ORListener : ReaderListener {\n    override fun onCloseButtonClickListener() {}\n    override fun onIssueRead() {}\n    override fun onIssuePageRead(pageNumber: Int, isCalledFromArticles: Boolean) {}\n    override fun onSummaryOpened(isOpenedFromArticles: Boolean) {}\n    // ....  \n}\n```  \n\n### Resume reading at the last read page\n\nWhen users close the reader and later open the same issue again, they might expect the reader to open at the last page that they consulted. You can implement this feature in two steps:\n\n- Implement the ReaderListener to save the last page consulted by a user\n- Open the reader with the last consulted page\n\n```kotlin\nprivate var targetPage: Int = 1\nprivate fun openReader() {\n    startActivity(\n        OneReaderActivity.newIntent(\n            this,\n            ReaderSettings().apply {\n                targetPageNumber = targetPage\n            },\n            productRepo,\n            ORListener()\n        )\n    )\n}\n\nclass ORListener : ReaderListener {\n    override fun onIssuePageRead(pageNumber: Int, isCalledFromArticles: Boolean) {\n        targetPage = pageNumber\n    }\n}\n```\n\n### Provide article sharing functionality\n\nYou can provide a sharing provider to the reader in order to add a \"Share\" button on articles. Your will be responsible for providing the URL to share for an article.\n\n- Activate sharing option in ReaderSettting by setting shareURl\n- Implement your own sharing login in ReaderListener\n- Open the reader with the last consulted page\n\n```kotlin\nval readerSetting = ReaderSettings().apply {\n    shareEnabled = true\n}\n\nclass ORListener(\n    private val dataSource: XmlPdfReaderDataSource,\n    private val context: Context\n) : ReaderListener {\n    override fun onShareClicked(article: IArticle) {\n        val milibrisArticle = dataSource.getMilibrisArticle(article)\n        val articleUrl = \"${dataSource.readerSettings.shareUrl}/share/article/$issueMid/${milibrisArticle?.mid}\"\n        val intentBuilder = ShareCompat.IntentBuilder(context)\n            .setType(\"text/plain\")\n            .setText(articleUrl)\n        intentBuilder.startChooser()\n    }\n}\n```\n\n### Customize logo\n\n#### `DisplayMode` variants in article reader\n\nWhile reading articles, user can change the `DisplayMode` to `AUTO`, `LIGHT`, or `DARK`.\n\nTo match this configuration, we can set a logo for each of these options.\n```kotlin\nval readerSetting = ReaderSettings().apply {\n    logo = R.drawable.milibris                 // AUTO\n    logoLight = R.drawable.milibris_light      // LIGHT\n    logoDark = R.drawable.milibris_dark        // DARK\n}\n```\n_If `logoLight` and `logoDark` are not provided, `logo` will be used._\n\nThe `AUTO` mode relies on Android built-in configuration based drawable:\n```\n├── res\n│   ├── drawable\n│   │   ├── milibris.xml          // Used in AUTO when OS is in light mode\n│   │   ├── milibris_light.png\n│   │   ├── milibris_dark.png\n│   ├── drawable-night\n│   │   ├── milibris.xml          // Used in AUTO when OS is in dark mode\n\n```\n\n#### Override capsule\n\nLogo appearance is defined by the `ORLogo` style:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cresources\u003e\n    \u003cstyle name=\"ORLogo\"\u003e\n        \u003citem name=\"android:layout_width\"\u003e@dimen/or_logo_capsule_width\u003c/item\u003e       \u003c!-- 100dp --\u003e\n        \u003citem name=\"android:layout_height\"\u003e@dimen/or_logo_capsule_height\u003c/item\u003e     \u003c!--  36dp --\u003e\n        \u003citem name=\"android:padding\"\u003e@dimen/half_margin\u003c/item\u003e                      \u003c!--   8dp --\u003e\n        \u003citem name=\"android:background\"\u003e@drawable/or_logo_capsule_background\u003c/item\u003e \u003c!-- background drawable --\u003e\n    \u003c/style\u003e\n\u003c/resources\u003e\n```\n\nwhere `android:background` is overriden when `DisplayMode` changes to use:\n\n```kotlin\n@drawable/or_logo_capsule_stroke_color                    // AUTO\n@drawable/or_logo_capsule_stroke_color_light.xml          // LIGHT\n@drawable/or_logo_capsule_stroke_color_dark.xml           // DARK\n```\n_these are simple corner rounded bordered shapes_\n\n##### Remove the capsule\n\nTo completely remove the capsule, you can override this style to remove the padding:\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cresources\u003e\n    \u003cstyle name=\"ORLogo\"\u003e\n        \u003citem name=\"android:layout_width\"\u003e@dimen/or_logo_capsule_width\u003c/item\u003e\n        \u003citem name=\"android:layout_height\"\u003e@dimen/or_logo_capsule_height\u003c/item\u003e\n        \u003citem name=\"android:padding\"\u003e0dp\u003c/item\u003e \u003c!-- set the padding to zero --\u003e\n        \u003citem name=\"android:background\"\u003e@drawable/or_logo_capsule_background\u003c/item\u003e\n    \u003c/style\u003e\n\u003c/resources\u003e\n```\nand override the three drawable resources used as background with empty drawables:\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003cselector /\u003e\n```\n\n### Apply your branding to the reader UI\n\nMany components of the reader UI can be customized to match your brand, And for you to do that you just need to override the definition os some color and drawable ressources. The complete reference can be found in [docs/config.md](./docs/config.md#readerconfig).\n\n## Sample project\n\nA sample project is provided to help you implement the reader integration. It contains an example to unpack a complete archive and to open if with PdfReader class.\n\nIf your miLibris content has articles, you can implement your own sharing solution by adding your own code in onShareClicked() just like shown in this sample in the class ORListener\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilibris%2Fandroid-milibris-reader-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmilibris%2Fandroid-milibris-reader-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmilibris%2Fandroid-milibris-reader-sdk/lists"}