-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Type of Request
Product Proposal (larger features)
Feature Description
TL;DR
This proposal introduces a plugin-based architecture for additional course block types in the Open edX mobile applications (iOS and Android).
New and optional block types (such as PDF, SCORM, H5P, interactive content, etc.) will be implemented as separate mobile plugins/modules, which can be included only in the builds that need them. Core mobile apps remain lean and focused, without embedding client-specific or heavy block logic.
Existing baseline block types already implemented in the mobile apps remain in Core and continue to work as they do today. The plugin architecture applies only to new and additional block types.
Overview
The Open edX ecosystem is steadily expanding with new course block types and LMS extensions (XBlocks and other integrations).
Today, each new block type that needs mobile support typically requires changes to the Core iOS/Android apps and often brings heavy dependencies, even if only a subset of Open edX instances use that functionality.
This proposal defines a plugin-based architecture for additional course block types in the mobile apps, so that:
- The Core apps stay thin, stable, and close to upstream.
- New or optional block types are shipped as separate mobile modules/plugins.
- Operators only pay (in size and complexity) for the blocks they actually use.
Problem
1. Adding a new block type to mobile currently requires Core changes
To support a new block type on mobile, developers often have to:
- Modify the Core iOS/Android application.
- Touch multiple files (enums, switches, adapters, DI modules, etc.).
- Rebuild all white-label/mobile apps.
- Accept higher risk of regressions and merge conflicts during upgrades.
2. Heavy and niche block types expand app size for everyone
Many additional block types (e.g., PDF viewers, SCORM players, certain interactive engines) rely on large third-party libraries.
These libraries increase the binary size of the mobile apps, even for instances that never use these block types.
3. Custom XBlocks do not scale well in current mobile architecture
The platform already has a rich ecosystem of XBlock extensions on the LMS side.
However, under the current mobile architecture:
- Adding mobile support for each new XBlock often leads to forks or local patches of the Core apps.
- Sharing and reusing mobile implementations across instances is difficult.
Use Cases
-
As an LMS operator, I need to enable mobile support for PDF/SCORM/H5P and other advanced block types in order to deliver a consistent course experience on iOS and Android without forking or patching the Core mobile apps.
-
As a mobile developer working for a specific Open edX instance, I need to add a new custom course block type to the mobile apps in order to support a unique content format for my client, by adding a single module/dependency instead of changing multiple files in the Core and dealing with merge conflicts.
-
As an Open edX mobile maintainer, I need to keep the Core mobile apps as close as possible to upstream in order to simplify upgrades and reduce custom code, by moving instance-specific or heavy block logic into external plugins.
-
As a course author who relies on XBlocks such as SCORM/H5P/other extensions, I need to be confident that my blocks can be rendered on mobile in order to offer a unified learning experience across web and mobile, without duplicating content.
Proposed Solution
High-Level Concept
We propose a shared architectural model for plugin-based blocks in the mobile apps.
The Core mobile application
The Core mobile application:
- Contains:
- Core course/block models.
- Minimal infrastructure code.
- A central block provider registry.
- Does not contain rendering or business logic for new or instance-specific blocks.
Plugin modules for block types (iOS and Android)
- Each plugin implements support for one or more specific block types (PDF, SCORM, H5P, interactive custom content, etc.).
- Plugins register themselves in the block registry of the mobile app.
- Operators include only the plugins they need by adding dependencies:
- SPM on iOS.
- Gradle on Android.
Important scope constraint
- Existing baseline block types already implemented in the mobile apps (e.g., video, HTML, problem, discussion, etc.) remain in Core and continue to work as they do today.
- The plugin architecture is intended for new and additional block types only, at least in the initial phase.
UX / UI
From a learner’s and instructor’s perspective
- Existing blocks continue to behave as they do now.
- Additional block types appear in the course outline as regular units, but their rendering is delegated to plugins.
- Depending on the block type, a plugin may:
- Render inline content within the lesson view (e.g., PDF viewer embedded in the unit).
- Navigate to a dedicated screen or player (e.g., SCORM runtime view).
- Fall back to a clear “not supported on mobile” message if the required plugin is not present.
From a mobile developer/operator perspective
- Enabling a new block type becomes a build-time decision:
- Add an SPM package (iOS) or Gradle dependency (Android).
- Optionally toggle a feature flag or white-label configuration.
- No direct changes to Core logic are required to add or remove block types, as long as the contracts and registry are stable.
iOS: Plugin Architecture for Additional Block Types
On iOS, we propose the following structure.
Extensible block type representation
BlockType is extended with a case such as:
case custom(String)This allows it to represent arbitrary string-based types received from the backend.
For existing baseline block types (video, html, problem, discussion, etc.), BlockType continues to behave as it does today.
Block provider registry
The Core app defines a central CourseBlockRegistry that:
- Stores a mapping
{ String blockType → CourseBlockProvider }. - Exposes thread-safe methods for registering and retrieving providers.
Provider contract
A protocol CourseBlockProvider is introduced, for example:
identifier: String— the string block type that the provider supports (aligned with the LMSblock_typevalue).makeView(context: CourseBlockProviderContext) -> AnyView— constructs the SwiftUI view for the given block.
CourseBlockProviderContext includes:
- The course block model (
CourseBlock). - Positional information (index, current index).
- Container size and layout hints.
- Connectivity information.
- Streaming quality and video-related helpers (when relevant).
- Interfaces for offline loading, analytics, logging, and other shared services.
Integration with Core UI
The lesson screen (e.g., CourseUnitView) is updated to:
- Attempt to obtain a custom block view from
CourseBlockRegistrybased on the block type. - If a provider is found, render the plugin’s SwiftUI view.
- If not, fall back to the existing logic (e.g.,
LessonType+switch), preserving full backward compatibility for baseline blocks.
Plugins as SPM packages
Each new additional block type is implemented as a separate Swift Package that:
- Imports a shared foundation module (see Implementation plan) that defines
BlockType,CourseBlockProvider,CourseBlockProviderContext, and required service protocols. - Implements
CourseBlockProviderfor one or more block types. - Registers itself with
CourseBlockRegistryduring initialization (for example, via a bootstrap function invoked from the app).
This way, the Core iOS app depends only on stable contracts and the registry; block-specific UI and logic live fully inside separate SPM modules.
Android: Plugin Architecture for Additional Block Types
On Android, we propose a conceptually similar architecture.
Foundation library
A dedicated foundation library provides:
CourseUnitBlockExtensionsRegistry— the central registry for block extensions.CourseUnitBlockExtension— the extension point interface (block handler).CourseUnitBlockContext— the runtime context for rendering a block (block data, services, etc.).BlockTypePluginandBlockTypePluginLoader— interfaces and loading mechanism for plugins, e.g., usingServiceLoader.
Integration with the Open edX Android app
The course unit container (e.g., CourseUnitContainerAdapter) is refactored to:
- Use
CourseUnitBlockExtensionsRegistryto resolve which extension should render a given block type. - Keep the existing behavior for baseline block types registered by default (either in Core or in a dedicated registration module).
Baseline blocks remain supported as they are today, while additional block types are handled via the extension registry.
Plugins as Gradle dependencies
Each new additional block type is implemented in a separate Android Library module that:
- Implements
BlockTypePlugin, which registers one or moreCourseUnitBlockExtensioninstances in the registry at runtime. - May use
ServiceLoaderto allow automatic discovery by the application.
Enabling a new block type in a particular mobile build becomes:
- Adding a single line in
build.gradle, such as:
implementation "org.example:my-block-plugin:x.y.z"The plugin is then discovered and registered automatically, without code changes in the Core app.
Implementation Plan
Scope focus: this proposal covers additional/new block types. Moving existing baseline blocks from Core to plugins is explicitly out of scope for the initial phase.
1. Finalise contracts (iOS + Android)
Define and stabilise:
- Registry interfaces (
CourseBlockRegistry,CourseUnitBlockExtensionsRegistry). - Provider contracts (
CourseBlockProvider,CourseUnitBlockExtension/BlockTypePlugin). - The minimal set of services and data included in the block context (connectivity, offline storage, analytics, logging, etc.).
Deliverable: a short technical design document and initial interfaces in the foundation modules.
2. Create or refine foundation layers
Introduce or refine a shared foundation module for each platform (e.g., OEXFoundation for iOS, a core foundation library for Android) that contains:
- Block type definitions (including
custom(String)on iOS). - Provider and context contracts.
- Key service interfaces required by block plugins.
Update the Core mobile apps so that they depend on these contracts rather than on block-specific implementations.
3. Integrate the plugin architecture into Core UI (iOS + Android)
iOS:
- Update the course unit view to use
CourseBlockRegistryfirst and fall back to existing logic for baseline blocks.
Android:
- Ensure
CourseUnitBlockExtensionsRegistryis used by the course unit container to resolve block rendering, while keeping existing handling intact for baseline block types.
4. Pilot plugins
Select 1–2 additional block types as pilot candidates (for example, PDF and/or SCORM).
Implement them as separate modules:
- iOS: Swift Packages implementing
CourseBlockProviderand associated UI. - Android: Android Libraries implementing
BlockTypePluginandCourseUnitBlockExtension.
Validate:
- Correct rendering in mobile apps when the plugin is present.
- Clear and safe behavior when a course contains that block type but the plugin is not included in a specific mobile build (e.g., “not supported on mobile” message).
5. Documentation and contributor guidelines
Create a concise developer guide explaining:
- How to implement a new mobile block plugin.
- How to map LMS-side
block_typevalues to mobile plugins. - Recommendations on dependency size, performance, and offline behaviour.
Resources and Funding
Raccoon Gang is currently looking for funding for this proposal.
Long-Term Ownership and Maintenance Plans
Core architecture (registry, contracts, foundation)
- Owned by the Open edX mobile maintainers (e.g., Axim Collaborative mobile team and contributors).
- Changes follow the normal Open edX review and release processes.
Individual block plugins
- Each plugin has a clearly identified owner (organization or team) listed in its README/documentation.
Possible split:
- “Official” plugins for widely used formats (e.g., PDF, SCORM) maintained by core teams or key partners.
- Community plugins maintained on a best-effort basis.
Compatibility and Versioning
- Foundation/contract modules are versioned and document supported mobile app versions.
- Plugins specify the foundation versions they support and can deprecate older contracts over time.
Contact Person
Ivan Stepanok
📧 [email protected]
Open Questions
-
Pilot plugins and priorities
- Which block types should be prioritized as pilot plugins?
- PDF?
- SCORM?
- H5P?
- Other high-value formats requested by the community?
- Which block types should be prioritized as pilot plugins?
-
Minimal context surface
- What is the minimal set of services and data that must be included in
CourseBlockProviderContext/CourseUnitBlockContext(e.g., connectivity, offline storage, analytics, logging, navigation hooks)? - What should remain optional or plugin-specific?
- What is the minimal set of services and data that must be included in
-
Long-term strategy for baseline blocks
- Should existing baseline blocks (video, HTML, problem, discussion, etc.) remain in Core indefinitely?
- Or should we consider migrating them to the same plugin mechanism over time, once the architecture proves stable?
-
Publication and catalog of plugins
- Do we want a centralized catalog of “official” mobile block plugins (similar to how XBlocks are documented today)?
- If yes, where should it live?
- Open edX documentation?
- A dedicated catalog page?
- A GitHub organization?
Link to Product Proposal
https://openedx.atlassian.net/wiki/x/KgA7PgE
Status
New
Proposed By
Ivan Stepanok (Raccoon Gang)
Metadata
Metadata
Assignees
Labels
Type
Projects
Status