With the MicroAppSDK, MicroApps can interact consistently with the host app within the ANDP Mobile App β e.g., navigating, displaying messages, sharing data, and presenting errors consistently. This ensures a seamless user experience, even when multiple MicroApps are in use.
This guide explains both what each capability does and how you call it from your MicroApp code.
How it works (Architecture)
The SDK is a React Context. The host app builds the concrete implementations for each API
(navigation, auth, translation, β¦) and provides them through MicroAppSDKProvider. MicroApps
never construct these APIs themselves β they only consume them through a hook.
Host app (apps/andp-mobile/App.tsx)
β builds andpNavigation, andpAuth, translationApi, config, β¦
βΌ
MicroAppSDKMobileProvider β mobile-specific wiring (alerts, toasts, errors, store)
β packages/.../apps/andp-mobile/src/sdk/MicroAppSDKMobileProvider.tsx
βΌ
MicroAppSDKProvider (Context) β the shared contract
β packages/core/src/sdk/MicroAppSDK.tsx
βΌ
Your MicroApp βββΊ useMicroAppSDK() βββΊ { andpNavigation, andpAuth, andpToast, β¦ }
The full contract (every type referenced below) lives in
packages/core/src/sdk/MicroAppSDK.tsx.
Getting Started: Accessing the SDK
Everything is reached through a single hook, useMicroAppSDK(). It returns the full
MicroAppSDKValue object. Destructure only what you need.
import { useMicroAppSDK } from '@andp/core/src/sdk/MicroAppSDK';
const MyMicroAppScreen = () => {
const {
andpNavigation,
andpAuth,
andpTranslation,
andpSharedFunctions,
andpSharedProps,
andpAlert,
andpToast,
andpError,
config,
devMode,
refreshNotifications,
} = useMicroAppSDK();
// ...
};
Convenience hooks
For the most-used APIs there are thin shortcut hooks, so you donβt have to destructure:
import {
useTranslationApi, // β andpTranslation
useAlertApi, // β andpAlert
useToastApi, // β andpToast
useErrorApi, // β andpError
} from '@andp/core/src/sdk/MicroAppSDK';
const toastApi = useToastApi();
const { t } = useTranslationApi();
Web vs. Mobile (important)
The same MicroApp packages run on mobile (with the provider) and on web (without it).
On web, useMicroAppSDK() returns an empty object instead of throwing. MicroApps that ship to
both platforms therefore guard SDK access by platform. This is the established pattern across the
codebase:
import { Platform } from 'react-native';
import { useMicroAppSDK } from '@andp/core/src/sdk/MicroAppSDK';
// Only access the SDK on native; on web fall back to a safe stub.
const { andpToast } = Platform.OS !== 'web' ? useMicroAppSDK() : {};
andpToast?.show({ type: 'success', text1: 'Saved' });
|
Note
|
Platform.OS is constant for the lifetime of the runtime, so this conditional hook call
is safe in practice. If your MicroApp is mobile-only, you can call useMicroAppSDK()
unconditionally.
|
Navigation & App Flows
MicroApps can guide users to app screens and back again β without disrupting the usage flow.
API
| Method | Description |
|---|---|
|
Navigate to a screen (optionally passing params). |
|
Go back to the previous screen. |
Screen-name conventions (mobile)
-
'<microAppName>'β opens the tab/MicroApp, e.g.'services','messages','tasks'. The valid names come frommergedMicroApps(see Custom MicroApps). -
'<microAppName>_<nestedScreen>'β opens a nested screen inside a MicroApp, e.g.'messages_detail'. -
'login'β routes to the auth flow. -
'formgen'β opens the form renderer.
Navigate to a screen
const { andpNavigation } = useMicroAppSDK();
// Open the "services" MicroApp
andpNavigation.change('services');
// Open a detail view and pass parameters
andpNavigation.change('businessCases', { businessObjectId: bo.id });
// Launch the form renderer with parameters
andpNavigation.change('formgen', {
formId: 'my-form-id',
culture: 'de-AT',
businessObjectId: boId,
});
Go back
// "After saving, the Back button returns the user to the overview."
const onSaved = () => {
andpToast.show({ type: 'success', text1: 'Saved' });
andpNavigation.previous();
};
User Context & Login
MicroApps can read the currently logged-in user and trigger a logout when necessary.
API
| Member | Description |
|---|---|
|
The current user, or |
|
Logs the user out. Pass |
IUserData = { firstName, lastName, email, username, dateOfBirth? }.
Personalize with the userβs name
const { andpAuth, andpTranslation } = useMicroAppSDK();
const user = andpAuth.userData;
// "The MicroApp personalizes the view: 'Hello, Max Mustermann'."
const greeting = user
? andpTranslation.t('greeting', { name: `${user.firstName} ${user.lastName}` })
: andpTranslation.t('greeting_guest');
Trigger a logout
// "In case of security-policy violations, the MicroApp can trigger a logout."
const onPolicyViolation = async () => {
const ok = await andpAlert.confirm(
andpTranslation.t('logout_confirm_message'),
{ title: andpTranslation.t('logout'), destructive: true },
);
if (ok) {
andpAuth.logout(true); // also deactivate biometric login
}
};
Multilingualism (i18n)
Texts are translated centrally so that labels, dialogs, and error texts appear consistently in
the appβs language. Translation is backed by i18next (t is an i18next TFunction).
API
| Member | Description |
|---|---|
|
Translate a key. Supports interpolation and |
|
All available cultures, e.g. |
|
The currently active culture. |
|
Switch the active culture. |
Translate a label
const { t } = useTranslationApi();
// "Button shows depending on language: 'Save' / 'Speichern' / 'Enregistrer'."
<Button title={t('save')} />
// With interpolation
<Text>{t('items_count', { count: items.length })}</Text>
// With a fallback (useful while keys are still being added)
<Text>{t('app_back', { defaultValue: 'Back' })}</Text>
Read & switch the language
const { cultures, selectedCulture, setCulture } = useTranslationApi();
return (
<View style={{ flexDirection: 'row' }}>
{cultures.map((c) => (
<TouchableOpacity key={c} onPress={() => setCulture(c)}>
<Text style={c === selectedCulture ? styles.active : undefined}>{c}</Text>
</TouchableOpacity>
))}
</View>
);
Alerts & Confirmations
MicroApps can display notifications and confirmation dialogs β either as native system dialogs
or as fully custom-rendered overlays. All alerts are queued, so two show/confirm calls never
overlap; the second opens when the first is closed.
API
| Method | Description |
|---|---|
|
Show a notification dialog (fire-and-forget). |
|
Show a confirm dialog; resolves |
AlertPayload = { title, message?, buttons?, options?, type?, render? }
ConfirmOpts = { title?, okText?, cancelText?, destructive?, options?, type?, render? }
type is 'native' (default) or 'custom'.
A simple native alert
const alertApi = useAlertApi();
alertApi.show({ title: 'Done', message: 'Your changes were saved.' });
An alert with custom buttons
alertApi.show({
title: 'Delete item?',
message: 'This cannot be undone.',
buttons: [
{ text: 'Cancel', style: 'cancel' },
{ text: 'Delete', style: 'destructive', onPress: () => deleteItem(id) },
],
});
A confirmation (await the result)
// "Dialog: 'Save changes?' β OK / Cancel"
const ok = await alertApi.confirm('Save changes?', {
title: 'Confirm',
okText: 'Save',
cancelText: 'Discard',
});
if (ok) await save();
A fully custom dialog (corporate look)
Pass type: 'custom' and a render function. You receive a close() callback you must call to
dismiss the dialog (and, for confirm, to resolve the promise β close(true) / close(false)).
// "Custom dialog in corporate look incl. additional text and icon."
alertApi.show({
title: 'Welcome',
type: 'custom',
render: ({ title, close }) => (
<View style={styles.customModal}>
<AndpIcon name="circleInfo" />
<Text style={styles.customTitle}>{title}</Text>
<TouchableOpacity style={styles.btn} onPress={() => close()}>
<Text style={styles.btnTxt}>Got it</Text>
</TouchableOpacity>
</View>
),
});
Toast Messages (Short Feedback)
For quick, non-blocking feedback: Success, Info, Warning, Error, Debug β or your own custom type.
API
| Method | Description |
|---|---|
|
Show a toast. |
|
Hide the current toast. |
|
Register a custom toast type at runtime. |
|
Remove a custom toast type. |
ToastShowPayload = { type?, text1?, text2?, position?, autoHide?, visibilityTime?, onShow?, onHide?, onPress?, props?, topOffset?, bottomOffset? }.
Built-in type values: 'default', 'info', 'success', 'error', 'warning', 'debug'
(see Custom Toast Types). position is 'top' (default) or 'bottom'.
Show success / error toasts
const toastApi = useToastApi();
// "After saving, a brief message appears: 'β
Successfully saved'."
toastApi.show({
type: 'success',
text1: 'Successfully saved',
text2: 'Everything went smoothly.',
position: 'top',
visibilityTime: 2000,
});
// "In case of connection issues: 'β οΈ No connection β please try again'."
toastApi.show({
type: 'error',
text1: 'No connection',
text2: 'Please try again.',
position: 'bottom',
visibilityTime: 3000,
});
A tappable toast
toastApi.show({
type: 'error',
text1: 'Upload failed',
text2: 'Tap for details.',
onPress: () => alertApi.show({ title: 'Details', message: lastError }),
});
Register a custom toast type at runtime
For permanent project toast types, prefer the static registration in Custom Toast Types. Use
register for one-off / runtime-defined renderers.
useEffect(() => {
andpToast.register('fancy', ({ text1, text2, onPress, props }) => (
<TouchableOpacity onPress={onPress} style={styles.fancyToast}>
<Text>{props?.icon} {text1}</Text>
{!!text2 && <Text>{text2}</Text>}
</TouchableOpacity>
));
return () => andpToast.unregister('fancy');
}, []);
andpToast.show({ type: 'fancy', text1: 'Hello', props: { icon: 'π' } });
Error Handling & Error Screens
Errors are handled centrally and displayed consistently, including customer-specific error
screens per error type. When you call andpError.show(payload), the provider resolves which UI
to render in this order:
-
payload.renderβ an inline renderer on the payload itself. -
A renderer registered earlier via
andpError.register(type, render). -
A predefined screen from
mergedErrorScreens, matched bypayload.type(see Custom Error Screens). -
The built-in
DefaultErrorScreenfallback (title, message, OK button).
API
| Method | Description |
|---|---|
|
Display an error screen/overlay. |
|
Dismiss the current error overlay. |
|
Register a renderer for an error type. |
ErrorPayload = { type, title?, message?, data?, render?, blocking? }
type is a string \| number. Predefined types live in ErrorScreenTypeEnum
(NO_CONNECTION, NOT_RESPONDING, BACKEND_ERROR, INVALID_VERSION).
Show a predefined error screen
import { ErrorScreenTypeEnum } from '../types/ErrorScreenTypeEnum';
const errorApi = useErrorApi();
// "For permission errors: dedicated screen with recommended action."
errorApi.show({
type: ErrorScreenTypeEnum.NO_CONNECTION,
data: { onRetry: () => refetch() }, // passed through to the screen component as props
});
Show a quick inline error (fallback screen)
// "Fallback: standard error page with an OK button."
errorApi.show({
type: 'generic',
title: 'Something went wrong',
message: 'Please try again later.',
});
A fully custom error renderer
errorApi.show({
type: 'maintenance',
render: ({ title, message, dismiss }) => (
<SafeAreaView style={styles.errContainer}>
<Text style={styles.errTitle}>{title}</Text>
<Text>{message}</Text>
<TouchableOpacity onPress={dismiss}><Text>OK</Text></TouchableOpacity>
</SafeAreaView>
),
title: 'Under maintenance',
message: 'We will be back shortly.',
});
// later
errorApi.dismiss();
Register an error renderer once, reuse by type
useEffect(() => {
errorApi.register('access_denied', ({ dismiss }) => (
<AccessDeniedScreen onAcknowledge={dismiss} />
));
}, []);
// anywhere afterwards
errorApi.show({ type: 'access_denied' });
Shared Functions
Recurring actions can be provided centrally and reused by MicroApps β ideal for standard workflows and cross-MicroApp triggers. Functions are stored by string key in a shared store.
API
| Method | Description |
|---|---|
|
Publish a function under a key. |
|
Remove it. |
|
Look up a function. |
|
List all registered keys. |
|
Tip
|
Namespace your keys by MicroApp to avoid collisions, e.g. 'messages.markMessageRead',
'tasks.refresh'.
|
Provide (register) a function
const { andpSharedFunctions } = useMicroAppSDK();
useEffect(() => {
andpSharedFunctions.register('messages.markMessageRead', (uuid, readBy) => {
markAsRead(uuid, readBy);
});
// Clean up when the MicroApp unmounts
return () => andpSharedFunctions.unregister('messages.markMessageRead');
}, []);
Call a function from another MicroApp
// "MicroApp A triggers 'Refresh' β App updates badges/lists in MicroApp B as well."
const refresh = andpSharedFunctions.get('tasks.refresh');
refresh?.(); // optional-chain: it may not be registered yet
// Real example from the messages MicroApp:
andpSharedFunctions.get('messages.markMessageRead')?.(message.uuid, message.readBy);
Shared Props (Shared Data)
MicroApps can share plain data (filters, status flags, temporary parameters) without workarounds. Values are stored by key in the same shared store and any consumer re-renders when its value changes.
API
| Method | Description |
|---|---|
|
Write a value (use |
|
Read a value imperatively. |
|
Remove a value (where available). |
|
The whole shared-props object (reactive on mobile). |
Set & read a shared value
const { andpSharedProps } = useMicroAppSDK();
// "MicroApp sets filter 'Open tickets only'"
andpSharedProps.set('tickets.filter', { status: 'open' });
// Another view reads it
const filter = andpSharedProps.get('tickets.filter');
React to changes (re-render on update)
Read from state so your component re-renders when the value changes, rather than reading once
with get:
const { andpSharedProps } = useMicroAppSDK();
const filter = andpSharedProps.state?.['tickets.filter'];
useEffect(() => {
applyFilter(filter);
}, [filter]);
A temporary flag between MicroApps (real example)
This is how the messages MicroApp signals "mark this message read" across screens, then clears the flag once handled:
// Screen A requests the action
andpSharedProps.set('messages.markMessageAsRead', true);
// Screen B handles it, then resets it ("a temporary value is removed after completion")
if (andpSharedProps.get('messages.markMessageAsRead')) {
andpSharedFunctions.get('messages.markMessageRead')?.(message.uuid, message.readBy);
andpSharedProps.set('messages.markMessageAsRead', false);
}
Configuration & Operation Mode
MicroApps can read central configuration and the operation mode, and trigger notification refreshes.
API
| Member | Description |
|---|---|
|
The app configuration object (from |
|
|
|
Re-fetch notification counts / badges. |
Read configuration
const { config } = useMicroAppSDK();
const res = await fetch(`${config.portalEndpoint}/api/andp/appconfig`);
Gate behavior behind dev mode / feature flags
const { devMode, config } = useMicroAppSDK();
// "Feature 'New Overview' is activated via configuration."
if (config.features?.newOverview) {
// render the new overview
}
if (devMode) {
// show extra developer tooling
}
Refresh notifications/badges
const { refreshNotifications } = useMicroAppSDK();
// "After reading a message, badges/notifications are updated."
await markMessageRead(uuid);
await refreshNotifications?.();
Provider Setup (Host App β Entry Point)
The host app builds each API implementation and passes it to MicroAppSDKMobileProvider. This is
the entry point in apps/andp-mobile/src/sdk/MicroAppSDKMobileProvider.tsx; it is wired up in
App.tsx. MicroApp authors normally donβt touch this β but it shows where the APIs come from.
// App.tsx (host) β building the implementations
const andpNavigation = {
change: (screen, params) => { /* react-navigation logic */ },
previous: () => { /* goBack */ },
};
const translationApi: AndpTranslationApi = useMemo(
() => ({ cultures, selectedCulture, setCulture, t }),
[cultures, selectedCulture, setCulture, t],
);
const andpAuth = useMemo(
() => ({ userData: authData?.userData, logout: logoutHandler }),
[authData?.userData, logoutHandler],
);
// Wiring the provider
<MicroAppSDKMobileProvider
andpNavigation={andpNavigation}
andpAuth={andpAuth}
andpTranslation={translationApi}
config={jsonConfig}
devMode={isDevMode}
refreshNotifications={refreshNotifications}
>
{/* navigation stacks / MicroApps */}
</MicroAppSDKMobileProvider>
The mobile provider supplies the remaining APIs itself: it implements andpAlert, andpToast,
and andpError (rendering native dialogs, react-native-toast-message, and error overlays), and
backs andpSharedFunctions / andpSharedProps with a Zustand store
(apps/andp-mobile/src/sdk/zustandStore.ts).
Registering Custom Screens, Toasts & MicroApps
Projects extend the app by editing the Custom* definition files. Each ships empty and is merged
on top of the ANDP defaults, so your entries override or add to the built-ins.
Custom MicroApps
Register MicroApps in apps/andp-mobile/src/custom/CustomMicroAppsDefinition.tsx. The name
becomes the screen name you pass to andpNavigation.change(β¦β).
import { MicroAppDefinitionInterface } from '../types/interfaces';
import MyFeatureWrapper from '@andp/feature-my/src/MyFeatureWrapper';
import MyIcon from '../../assets/my-icon.svg';
export const customMicroApps: MicroAppDefinitionInterface[] = [
{
name: 'myFeature',
component: MyFeatureWrapper,
icon: MyIcon,
badge: true, // optional badge on the tab
visibleParams: {
nameKey: 'andp_app_myFeature_name', // i18n keys for label & description
descriptionKey: 'andp_app_myFeature_desc',
},
},
];
These merge into mergedMicroApps in MicroAppsDefinition.tsx.
Custom Toast Types
Define permanent project toast types as components and register them in
CustomToastMessageTypes.tsx. The key (e.g. myBrand) is what you pass as toastApi.show({ type: 'myBrand' }).
// CustomToastMessageTypes.tsx
import { IToastMessageDefinition } from '../types/interfaces';
import MyBrandToast from '../components/toast-messages/MyBrandToast';
export const customAndpToastMessages: IToastMessageDefinition[] = [
{ myBrand: MyBrandToast },
];
A toast component receives { text1, text2, onPress, props }:
// components/toast-messages/MyBrandToast.tsx
const MyBrandToast: React.FC<any> = ({ text1, text2, onPress }) => (
<Pressable onPress={onPress} style={styles.wrap}>
<AndpIcon name="circleCheck" />
{text1 ? <AndpText style={styles.title}>{text1}</AndpText> : null}
{text2 ? <AndpText style={styles.body}>{text2}</AndpText> : null}
</Pressable>
);
export default MyBrandToast;
These merge into mergedToastMessages (defaults: default, info, success, error,
warning, debug).
Custom Error Screens
Map an error type to a screen component in CustomErrorScreenTypes.tsx. The screen receives the
payloadβs data props plus the translation function t.
// CustomErrorScreenTypes.tsx
import { IErrorScreenDefinition } from '../types/interfaces';
import AccessDeniedScreen from '../screens/error-screens/AccessDeniedScreen';
export const customErrorScreens: IErrorScreenDefinition[] = [
{ access_denied: AccessDeniedScreen },
];
Then trigger it from any MicroApp:
errorApi.show({ type: 'access_denied', data: { onRetry: refetch } });
These merge into mergedErrorScreens alongside the ANDP defaults from ErrorScreenTypeEnum.
|
Note
|
The concrete available functions and UI variants (e.g., "custom" Dialogs/Toasts) depend on your
ANDP configuration and the MicroApps activated in your app. The exact API contract is defined
in |
