Basic Overview of Extending COSMO Mobile Solution
- What is the purpose of customizing COSMO Mobile Solution for specific business needs?
- What are the limitations and best practices when extending the solution?
- How can developers extend the solution by adding pages, fields, and functions?
- What are the key methods for integrating custom functionality into COSMO Mobile Solution?
Tip
Summary: This section provides an in-depth overview for developers looking to extend and customize COSMO Mobile Solution to meet specific business requirements. It covers the core methods for modifying pages, adding new fields, and incorporating custom functions and actions. The documentation emphasizes practical steps for integrating custom solutions, utilizing service-enabled functions, triggers, and extending pages through AL code.
COSMO Mobile Solution is a configurable framework and mobile user interface built on top of Microsoft Dynamics 365 Business Central. It enables users to access standard Business Central processes through Android-based handheld devices.
The solution offers a high degree of configurability, allowing common business requirements — such as applying filters, defining page relationships, using conditional formatting, and managing field visibility or order — to be addressed efficiently. This level of configurability significantly reduces the need for custom development, saving both time and resources.
However, certain scenarios may require development when configuration alone is insufficient. In such cases, new fields, functionalities, or pages can be added to meet specific customer requirements. Even then, the primary objective remains to eliminate the use of separate development environments or programming languages other than AL.
Overview and Prerequisites
This document outlines how to extend COSMO Mobile Solution with custom business processes. It focuses exclusively on development specific to COSMO Mobile Solution and does not address general Business Central development practices. Although the modern terminal of COSMO Factory Data Capture leverages the configurability of COSMO Mobile Solution, it is not covered in this document. Similarly, migration from legacy cc|Mobile developments is not discussed; refer to the upgrade guide for further details.
Important
It is recommended to review the basics of customizing COSMO Mobile Solution pages before proceeding.
Before beginning development, ensure that you have reviewed the technical requirements and the instructions for linking Business Central with the Intermediate Layer.
Important
The use of Android emulators for testing is not recommended, as they may not accurately reflect the behavior of physical devices. Emulators can cause stability and performance issues. Similarly, low-end devices may result in inconsistent performance and should be avoided.
For further guidance, see the recommended Android device requirements for use with the mobile application.
Architecture
COSMO Mobile Solution is a page-based framework, meaning that the pages displayed in the mobile application correspond to actual Business Central pages. However, instead of being rendered by Business Central, these pages are published as OData web services. The mobile application then dynamically generates its user interface using the metadata and configuration of these pages.
The architecture consists of three primary layers:
- Backend: Microsoft Dynamics 365 Business Central, where pages are developed in AL and exposed as web services.
- Frontend: A lightweight mobile application that serves purely as a user interface.
- Intermediate Layer: Responsible for secure communication between the frontend and backend.
All development tasks for COSMO Mobile Solution are carried out in AL, following this architectural structure.
What is OData?
OData is a protocol that enables the creation of RESTful services. These services allow resources, defined in a data model and identified by URLs, to be accessed and manipulated through simple HTTP requests.
Web Services, OData V4, and COSMO Mobile Solution
The mobile application communicates with Business Central through pages and codeunits published via the OData V4 protocol. Since the mobile application operates outside of the Business Central GUI, user interface elements and triggers behave differently or may not function at all.
Because of this, enhancements to the Business Central GUI may be incompatible, ignored, or may cause runtime errors in the mobile application. Additionally, session handling differs significantly and will be discussed in the following section.
OData V4 uses an etag to identify a table record. This value is a hash generated from the published fields and the last modified timestamp. For further details, refer to force etag update.
Limitations and Workarounds
Web Service Session Handling
When accessing Business Central via web services, each operation is executed within a new session:
- Listing records: A new session is created to open the company, apply filters, collect data, and then close the session.
- Viewing a card: The same process occurs in a separate session.
- Invoking a function: Yet another session is created.
In contrast to the web client — where such operations share a single session — temporary data storage (e.g., using temp tables or single instance codeunits) is not feasible in this context.
Session-Based Restrictions and Alternatives
- Temporary Tables: These are not suitable for storing data across multiple operations, as their content is lost once the session ends. Use them only if the data is needed during the current operation. For persistent temporary storage between operations, COSMO Mobile Solution offers the
CCS MS Web Service Helpertable. See the Temporary Table section for more details. - Global Variables: Similar to temporary tables, global variables do not retain values between sessions. If data needs to persist, use the
CCS MS Web Service Helpertable. Alternatively, for data tied to a specific record, consider creating a dedicated field in the database. - Single Instance Codeunits: These are limited to the scope of a single session and cannot maintain state between operations. To work around this limitation, use the
CCS MS Web Service Helpertable for shared data handling.
UI-Based Restrictions and Best Practices
Web services operate without a graphical user interface (UI). Pages exposed via web services function primarily as data wrappers around tables, rather than as interactive UI components. As a result, many UI elements and behaviors are not supported when accessed through web services. For this reason, there is no distinction between Card and List page types at the web service level—they are interpreted the same way. The following limitations arise from this architecture:
- All pages published for use with COSMO Mobile Solution must be defined as
Listtype pages. The actual layout presented in the mobile application is determined by the configuration settings, not by the page type specified in AL code. - The
OnClosePagetrigger will not execute when the page is accessed via a web service. - The
OnAfterCurrRecordtrigger is executed for every record because there is no UI context in web services to determine a "current" record. UseOnAfterGetRecordinstead when working with web services. - Page actions are not supported. Instead, use
[ServiceEnabled]functions or define unbound functions that can be called from the mobile application as actions. - Table relations are ignored by the web service layer. Any field lookups or drill-down behaviors must be configured manually. The same applies to the
OnLookuptrigger. - Since web services lack a UI, calling
Run()orRunModal()on pages or reports will cause runtime errors. The same applies to theConfirm()function. Avoid using these in source code intended for mobile pages. If shared code is used by both the web and the mobile application, check for UI availability usingif GuiAllowed then. For navigation, configure drill-down behavior, and for confirmations, use function actions and message templates. - Calls to
Message()and progress dialogs have no effect in web services. Progress indicators are automatically shown in the mobile application. To display messages, use conditional views and message templates. - The
CurrFieldNovariable always returns0in web service calls. Avoid relying on it. In general, its use is discouraged by Microsoft and maintained only for backward compatibility. - Without a UI,
StyleandStyleExprproperties have no effect. To achieve visual customization, use conditional views to highlight fields or lines with specific styles.
Other Limitations and Unsupported Entities
Global variables can be used as page fields, but their values must be assigned in:
- the
OnInserttrigger, - the
OnModifytrigger, and - the
OnAfterGetRecordtrigger.
Since the
etagcalculation includes all page fields, it must be recalculated during every data operation.- the
FlowFilteris not currently supported by COSMO Mobile Solution. If a mobile user needs to modify a filter, a wrapper page field should be created.If a page, field, or function is not available in the COSMO Mobile Solution configuration (i.e., it doesn't display after a metadata refresh), it generally means it is not supported by Microsoft in OData.
When two or more page fields share the same
SourceExpression, the OData interface will ignore the duplicates.Procedures marked as
[ServiceEnabled]and those defined in a published codeunit should use parameters with simple data types, such asCode,Decimal,Date, etc. Complex types likeRecord,Variant,Codeunit,JsonObject, etc., are not supported by OData. The only exception isRecordId, which can be used as a function parameter, for example, in an unbound function.
Development and Configuration Recommendations
Page Types
As mentioned above, all pages used with COSMO Mobile Solution should be of type List. Unlike the web client where separate List and Card pages are required, in COSMO Mobile Solution, a single page can serve both purposes based on the configuration:
- List: Displays only a list view. Typically used for lookups.
- Card: Displays only a single record. Used when only one record is relevant, such as for report request pages (e.g., "Calculate Consumption"), parameter pages, or when the logic requires a card view (e.g., creating a new item tracking line).
- List and Card: Supports both list and card views. This is the most versatile setup.
- Headerline: Combines a header (List and Card) and its lines in a single view — useful for scenarios like pick documents.
Filters
While SourceTableView can be used to apply hard-coded filters to a page, this should only be done when it’s critical that the filter remains unchanged. Otherwise, using page filters and relation filters is recommended for better flexibility and reusability.
Filter Precedence
When data is requested by the mobile application, different types of filters can be applied depending on how the page is accessed:
- If accessed directly from a role, both user-defined filters (set in the mobile application) and page filters apply. Page filters are processed first, followed by user filters.
- If accessed via a relation (e.g., lookup or drill down), page filters and relation filters are merged. If both define filters on the same field, the relation filter takes precedence. User filters are applied afterward on the resulting dataset.
Note
The Intermediate Layer automatically merges all filter types. Only the final merged filters are passed to Business Central, so performance is not negatively impacted.
Function Actions
Functions can be invoked directly from a page or initiated by the user. These functions can be extended using function actions, enabling features like:
- confirmation dialogs,
- parameter pages,
- closing or refreshing the page after execution,
- or triggering follow-up actions.
See the documentation for a full list of capabilities.
Page Triggers
Currently, you can define the following trigger types on a page:
- OnOpen Function: Triggered when a card page is opened or a new record is initialized.
- OnClose Function: Triggered before a card page is closed or a new record is initialized.
- OnClose List Function: Triggered before a list page is closed. Only unbound functions can be used for this trigger.
Function actions can also be associated with these triggers. While it is technically possible to set these triggers as the Next Function for another action, this is not recommended.
User-Specific Configuration
Typically, the global page customization is used to define the core business logic (such as filters, relations, coloring, messaging, etc.). Although it's possible to customize the configuration at the user level, this is not recommended. User-level configurations cannot be exported or imported. If any changes are made to the global customization, the user-level settings will be overwritten with the global values. Furthermore, many user-level settings are immutable and can only be defined globally.
Instead of customizing at the user level, it is better to use user variables. User variables can be used as default values, page filters, relations, conditional views, printing setups, and more.
Using Special Function Parameters
Certain reserved parameter names are available for [ServiceEnabled] procedures. These parameters are optional but can be helpful in specific scenarios:
isFirst: Boolean: If the procedure is called from a card view, this is alwaystrue. If called from a list view for multiple records, it will betrueonly for the first record. This is useful for initializing batch processing.isLast: Boolean: If the procedure is called from a card view, this is alwaystrue. If called from a list view for multiple records, it will betrueonly for the last record. This is useful for finalizing batch processing.serviceName: Text: This parameter holds the published name of the web service if the procedure needs to know which web service page called it. This is commonly used for unbound functions.recordId: RecordId: If the procedure is not defined on a page and needs to know which record to process, this parameter contains theRecordId. This is typically used alongsideserviceNamein unbound functions. Note that this value may be empty, particularly in unbound functions related to List Functions or OnClose List Functions.
Using isFirst and isLast Parameters
When the isFirst and isLast parameters are not utilized, the procedure will execute for each record individually. By using these parameters, batch processing can be implemented, allowing all records to be processed within a single session. This approach can often result in better performance. Example code:
[ServiceEnabled]
internal procedure DoSomething(IsFirst: Boolean; IsLast: Boolean)
begin
if IsFirst then
InitializeRecordStore();
StoreTheRecordForProcessing(Rec);
if IsLast then
DoTheBatchProcessingOnTheStoredRecords()
end;
Predefined Function Parameters in Page Customizations
If a parameter name in a [ServiceEnabled] or published procedure matches a field on the owning page and their types align, the field value will be automatically copied to the parameter. For more details, refer to function parameters. Additionally, if the values come from a parameter page, those values will take precedence over the record values.
Development Examples
Extending an Existing Page with a New Field
- Add a new field to a page. Example code:
pageextension 50000 MyPageExt extends "CCS MS Items WS"
{
layout
{
addlast(GroupName)
{
field("My New Field"; Rec."My New Field")
{
ApplicationArea = All;
ToolTip = ' ', Locked = true; // in the web service interface the tooltips are not used
}
}
}
}
- Refresh the metadata of the given page to reflect the changes.
- After the refresh, the new field will appear in the field list.
- The field will now be available for use in the mobile application and can be utilized for filters, conditions, etc.
Extending an Existing Page with a New Function
Using a Custom Function
Since [ServiceEnabled] functions cannot be added directly through a page extension, alternative approaches must be used to extend existing pages with custom functions. Most pages include placeholder functions like CustomFunction1, CustomFunction2, etc. Each of these custom functions triggers an integration event when called.
- Implement an event subscriber for given custom function. Example code:
[EventSubscriber(ObjectType::Page, Page::"CCS MS Items WS", 'OnCustomFunction1', '', false, false)]
local procedure CCSMSItemsWS_OnCustomFunction1(var Item: Record Item)
begin
// TODO: implement the custom business logic for the given Item
end;
- In the page settings, check the Visible checkbox for
CustomFunction1and move it to the desired position. - Define the caption for
CustomFunction1in the required language. - Specify an icon for
CustomFunction1for visual clarity. - After refreshing the schema in the mobile application,
CustomFunction1will appear in the card view and be available for use.
Using an Unbound Function
In some cases, the pre-existing custom functions are insufficient, or no custom functions are implemented for a page. In such situations, adding an unbound function to the page customization can provide a solution.
- Implement a procedure in a published codeunit. Example code:
internal procedure DoSomethingWithItem(serviceName: Text; recordId: RecordId)
var
Item: Record Item;
begin
if (RecordId.TableNo = Database::Item) and (ServiceName = 'CCSMSItemsWS') then begin
Item.Get(RecordId)
// TODO: implement the custom business logic for the given Item
end;
end;
- Search for and add the newly created function as an unbound function to the
CCSMSItemsWSpage customization. - In the page settings, check the Visible checkbox for the unbound function and move it to the desired position.
- Define the caption for the unbound function in the required language.
- Specify an icon for the unbound function for visual clarity.
- After refreshing the schema in the mobile application, the unbound function will appear in the card view and be available for use.
Adding a New Custom Page
- Implement a custom page as a list page, adding the necessary fields to the repeater and implementing the required
[ServiceEnabled]functions, which will be used as actions in the mobile application. Example code:
page 50000 "My Custom Ws Page"
{
PageType = List;
UsageCategory = None;
SourceTable = Item;
Caption = 'Items';
layout
{
repeater(GroupName)
{
field("No."; Rec."No.")
{
ApplicationArea = All;
ToolTip = ' ', Locked = true; // in the web service interface the tooltips are not used
}
field(Description; Rec.Description)
{
ApplicationArea = All;
ToolTip = ' ', Locked = true; // in the web service interface the tooltips are not used
}
}
}
[ServiceEnabled]
internal procedure DoSomething(isFirst: Boolean; isLast: Boolean)
begin
// TODO: Implement the batch processing for the records
end;
}
- Publish the newly created page as a web service in Business Central.
- Add the published web service as a new page customization setting the Page Type to List and Card
- Customize the page layout: arrange the fields and functions, hide them, or set them as read-only using the corresponding configuration properties.
- Define captions and icons for the functions as needed.
- Include one or more fields and functions in the List View.
- Add the page to the appropriate role.
- Once the schema is refreshed in the mobile application, the page will appear in the specified role, and the implementation and configuration will be complete
Debugging and Logging
Since COSMO Mobile Solution operates through the web service layer of Business Central, debugging via the web client will not be effective. To debug a web service call, you need to attach the AL debugger to the web service session. Use the following launch.json template for debugging:
{
"name": "Name of the debugging context",
"request": "attach",
"breakOnNext": "WebServiceClient",
"type": "al",
"environmentType": "OnPrem",
"server": "http://server-url",
"serverInstance": "Instance name",
"port": 7049,
"authentication": "UserPassword",
"breakOnError": true,
"enableLongRunningSqlStatements": true,
"enableSqlInformationDebugger": true
}
Most (though not all) processes in COSMO Mobile Solution are logged in a dedicated debugging log table. Logging can be enabled in the Mobile Solution Settings. The collected textual logs can be exported using the Export Debug Logs action. The logging method is available for extension apps, and the stored log provides valuable information about processes related to COSMO Mobile Solution, which may help in identifying the source of issues.
Feedback
Submit feedback for this page .