This project is a host application example for the YouScribe Flutter SDK.
It is intentionally built with as few dependencies as possible so the SDK integration stays easy to read. The app demonstrates the complete host-side flow described in INTEGRATION-1.2.0.md: authentication, SDK initialization, token refresh, product opening, download orchestration, cache inspection, file deletion, and event logging.
The UI is intentionally split in two layers:
- a simple reader-first path centered on
productId -> YouScribeReader; - a second layer exposing the programmatic SDK APIs with inline explanations.
- SDK initialization with
YouScribeSDK.initialize(). - Host-managed authentication with lib/src/api.dart using a generic identifier.
- Auth token propagation with
updateAuthToken(). - Product preflight with
readProduct(). - Reader launch with
YouScribeReader(productId: ...), adapting to PDF, EPUB, or audio. - Reader lifecycle hooks through
PdfReadingHooks,EpubReadingHooks, andAudioReadingHooks, includingonReaderBackground/onReaderForeground. - Reader theming through
YouScribeReaderThemeand per-reader overrides (pdfReaderTheme,epubReaderTheme,audioReaderTheme). - Custom loading screens through
productLoadingBuilderandreaderLoadingBuilder. - Audio time-credit management: the warning threshold via
AudioReaderConfiguration.warningCalculator, exhaustion handling viaAudioReaderCallbacks.onTimeCreditExhausted, andTimeCreditExhaustedError. - Download start with
download(productId: ...). - Download resume with
trackDownload(productId: ...). - Global active download observation with
watchActiveDownloads(). - Direct task cancellation with
DownloadTask.cancel(). - SDK-level cancellation with
stopDownload(productId). - Cache checks with
isFileAvailable()andgetDownloadedFiles(). - File cleanup with
deleteFile(productId: ...). - SDK event monitoring with
YouScribeSDK.instance.events, includingReaderBackgroundEvent/ReaderForegroundEvent. - Host-driven token refresh using the SDK
onTokenExpiredcallback.
The example keeps a small, explicit architecture:
- lib/main.dart: application bootstrap.
- lib/src/app/demo_app.dart: app theme and root widget.
- lib/src/app/demo_controller.dart: the single source of truth for host state, SDK calls, token refresh, download tracking, and event logging.
- lib/src/app/demo_page.dart: responsive demo UI.
- lib/src/app/demo_models.dart: small app-specific models.
- lib/src/api.dart: host authentication helper used by the demo.
This structure keeps the responsibilities clear:
- the host app owns authentication;
- the controller owns orchestration and state transitions;
- the UI stays focused on presenting the SDK features.
The SDK does not manage sign-in, so this example uses lib/src/api.dart to authenticate against the YouScribe API and retrieve an auth token.
The sign-in field is intentionally labeled identifier instead of email , because the backend endpoint accepts a generic identifier.
For the demo only, the password is kept in memory after sign-in so the onTokenExpired callback can re-authenticate through the same host flow. In a production host application you should replace this with your own secure refresh-token strategy.
This demo does not tie authentication to updateLocalDataDiscriminator() . The SDK keeps its active local scope as-is during sign-in and sign-out.
The app first emphasizes the simplest integration path:
- authenticate the host app;
- enter a product ID;
- open
YouScribeReader.
That is the path most host applications should start with because the SDK manages the reader-opening flow for you.
The programmatic section remains available underneath and documents when to use:
isFileAvailable()readProduct()download()trackDownload()DownloadTask.cancel()stopDownload()
Each action is described directly in the UI so the demo can be used as a guided integration reference.
The SDK is published on the private Wyatt-FOSS Dart registry (the older Wyatt-Studio org no longer serves youscribe_sdk 1.2.0). The example app declares youscribe_sdk and also adds dependency_overrides for the private transitive packages so flutter pub get resolves them from the same registry:
youscribe_audio_playeryouscribe_epub_readeryouscribe_pdf_reader
Without those overrides, pub attempts to resolve some transitive packages from pub.dev and dependency resolution fails.
Since 1.2.0, youscribe_epub_reader depends on flutter_readium, which is pinned through two additional dependency_overrides pointing at a git fork (https://github.com/hugo-pcl/flutter_readium.git, ref feat/auto-scroll).
youscribe_audio_player is also declared as a direct dependency (not just an override). This is a workaround, not a design choice: youscribe_sdk's barrel file (package:youscribe_sdk/youscribe_sdk.dart) does not export AudioReaderCallbacks, even though it exports the sibling AudioReaderTheme, AudioReaderConfiguration, and TimeCreditConsumption types from the same package. Similarly, demo_controller.dart imports package:youscribe_sdk/src/core/errors/youscribe_error.dart directly (with // ignore: implementation_imports) because TimeCreditExhaustedError is not exported either, despite being documented in the integration guide. Both should be fixed upstream in the SDK's barrel export list; once they are, the direct youscribe_audio_player dependency and the src/ import in this example can be removed.
The Android host app is configured for the Nutrient-backed PDF reader and the Readium-backed EPUB reader used by the SDK:
compileSdk = 36minSdk = 24- Java 17 and Kotlin JVM 17
androidx.appcompatdependency- direct
io.nutrient:nutrient:11.2.1visibility forFlutterAppCompatActivity FlutterAppCompatActivityPSPDFKit.Theme.Defaultas the Android normal themeback_icon.xmlin the drawable resourcesINTERNETpermission in the main manifest- core library desugaring (
isCoreLibraryDesugaringEnabled = trueandcoreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")), required by Readium's Java 8+ dependencies
These changes are already applied in this example project.
The integration guide currently mentions compileSdkVersion 35 as a baseline, but the current resolved plugin set used by this example requires Android SDK 36. The active Nutrient Flutter plugin also targets minSdk 24 , so the example app is pinned to those working values.
EPUB reading is implemented on top of the Readium engine (flutter_readium), which needs native configuration on both platforms:
- Android: core library desugaring (see above), already required by
minSdk 24. - iOS:
ios/Podfileaddsuse_modular_headers!and six Readium pods (ReadiumShared,ReadiumInternal,ReadiumStreamer,ReadiumNavigator,ReadiumOPDSat swift-toolkit 3.9.0, andReadiumZIPFoundation3.0.1) insidetarget 'Runner'. The Runner target'sIPHONEOS_DEPLOYMENT_TARGETis raised to16.0to match Readium's requirements.
Run pod install in ios/ after flutter pub get to fetch these pods.
- Install dependencies:
flutter pub get- Launch the app:
flutter run- Sign in with a YouScribe account in the demo UI.
- Enter a product ID that the authenticated account can access.
- Start with
Open with YouScribeReader. - Then explore the programmatic actions if your host app needs finer control:
Check availability
Call readProduct()
Download
Temporary download
Track existing download
Cancel tracked task
Stop download
- Inspect the downloaded files and the event log to understand how the SDK behaves inside a host application.
- The sample product ID shown in the UI is only a placeholder.
- The app focuses on clarity over abstraction-heavy patterns.
- The example uses only Flutter framework primitives for state management.
- The demo is designed to complement the SDK documentation, not replace your app-specific architecture.
The project was validated with:
flutter analyze