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.

MicroApps can guide users to app screens and back again β€” without disrupting the usage flow.

API

Method Description

andpNavigation.change(screen: string, params?: object): void

Navigate to a screen (optionally passing params).

andpNavigation.previous(): void

Go back to the previous screen.

Screen-name conventions (mobile)

  • '<microAppName>' β€” opens the tab/MicroApp, e.g. 'services', 'messages', 'tasks'. The valid names come from mergedMicroApps (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

andpAuth.userData: IUserData | undefined

The current user, or undefined if not logged in.

andpAuth.logout(setBiometricAuthToInactive?: boolean): void

Logs the user out. Pass true to also deactivate biometric auth.

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

andpTranslation.t(key, options?)

Translate a key. Supports interpolation and defaultValue.

andpTranslation.cultures: string[]

All available cultures, e.g. ['de-AT', 'de-CH'].

andpTranslation.selectedCulture: string

The currently active culture.

andpTranslation.setCulture(culture: string): void

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

andpAlert.show(payload: AlertPayload): void

Show a notification dialog (fire-and-forget).

andpAlert.confirm(message: string, opts?: ConfirmOpts): Promise<boolean>

Show a confirm dialog; resolves true (OK) or false (Cancel).

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

andpToast.show(payload: ToastShowPayload): void

Show a toast.

andpToast.hide(): void

Hide the current toast.

andpToast.register(type: string, render): void

Register a custom toast type at runtime.

andpToast.unregister(type: string): void

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:

  1. payload.render β€” an inline renderer on the payload itself.

  2. A renderer registered earlier via andpError.register(type, render).

  3. A predefined screen from mergedErrorScreens, matched by payload.type (see Custom Error Screens).

  4. The built-in DefaultErrorScreen fallback (title, message, OK button).

API

Method Description

andpError.show(payload: ErrorPayload): void

Display an error screen/overlay.

andpError.dismiss(): void

Dismiss the current error overlay.

andpError.register(type: ErrorType, render: ErrorRenderFn): void

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

andpSharedFunctions.register(key: string, fn: SharedFn): void

Publish a function under a key.

andpSharedFunctions.unregister(key: string): void

Remove it.

andpSharedFunctions.get(key: string): SharedFn | undefined

Look up a function.

andpSharedFunctions.list(): string[]

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

andpSharedProps.set(key: string, value: any): void

Write a value (use undefined to clear).

andpSharedProps.get(key: string): any

Read a value imperatively.

andpSharedProps.removeItem?(key: string): void

Remove a value (where available).

andpSharedProps.state?: Record<string, any>

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

config: any

The app configuration object (from andpConfig.json), e.g. config.portalEndpoint, config.store_url.

devMode: boolean

true when the app runs in developer mode.

refreshNotifications?(): Promise<void> | void

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 packages/core/src/sdk/MicroAppSDK.tsx; the mobile implementations live in apps/andp-mobile/src/sdk/ and apps/andp-mobile/src/custom/.