infobip_mobilemessaging_huawei 1.0.1
infobip_mobilemessaging_huawei: ^1.0.1 copied to clipboard
Android Flutter plugin for Infobip Huawei Mobile Messaging with HMS Push, Inbox, native and embedded Chat, outgoing RTC audio/video, and screen sharing.
Infobip Mobile Messaging Huawei for Flutter #
A community-maintained Android Flutter plugin for Infobip Huawei Mobile Messaging 8.14.0 and RTC Core 2.5.28. This is not an official Infobip-maintained Flutter package. Install the published package on pub.dev. This README documents release 1.0.1.
Features #
- HMS Push registration, messages, notification taps and action taps.
- User and installation management, personalization, custom events and Mobile Inbox.
- Native and embedded Chat, native attachments, unread counters and backend JWT providers.
- Outgoing RTC audio/video calls, local/remote rendering, call controls and notifications.
- Android Screen-as-Camera sharing with consent, capture notification and camera restoration.
Supported Platforms #
Android only, with HMS Push. iOS, web, desktop, FCM push transport and a Dart background isolate are not supported. RTC Core has Firebase/GMS transitive dependencies; Google-free operation is not certified.
Requirements #
| Component | Requirement |
|---|---|
| Dart / Flutter | ^3.9.0 / >=3.35.7 |
| Android | minSdk 26; compileSdk 36; example targetSdk 36 |
| Screen sharing | Android 10 / API 29+ |
| Java compilation | 17 |
| Example tooling | AGP 8.13.0, Kotlin 2.1.0, Gradle 8.13 |
| Infobip Huawei MM / Inbox / Chat | 8.14.0 |
| Infobip RTC Core | 2.5.28 |
HMS Push requires a compatible Huawei Mobile Services environment. Validate your integration on physical Huawei hardware. Android 36 Robolectric tests require Java 21.
Installation #
Install the package from pub.dev:
flutter pub add infobip_mobilemessaging_huawei
Or add it to your host application's pubspec.yaml, then run flutter pub get:
dependencies:
flutter:
sdk: flutter
infobip_mobilemessaging_huawei: ^1.0.1
The example uses a local path dependency to test the repository checkout. Use the hosted dependency above in your own application.
Quick Start #
Complete these steps in order before calling Dart APIs:
- Create the Huawei Android app, register your actual signing certificate, enable Push Kit, and download its configuration file.
- Create an Infobip mobile application profile, enable Huawei push and save its matching Huawei credentials. Copy the Application Code.
- Configure your Android host's JSON, numeric
app_id, Gradle and permissions. - Initialize with the Application Code, subscribe to events, then register push.
- Confirm registration and deliver one test push on a physical Huawei device.
- Add Chat or RTC only after configuring those optional services in Infobip.
The examples below use the public package import. Application codes and routing IDs are configuration, not JWT signing keys. Pass values from your application's configuration; never put production signing secrets in Dart or build defines.
Huawei AppGallery Connect Setup #
You need a Huawei developer account with access to AppGallery Connect (AGC). Menu labels can vary; the following uses logical sections rather than assuming an exact current portal layout. See Huawei's Android integration guide and Infobip's AGC setup guide.
-
Sign in to AppGallery Connect and create or select a project for your app.
-
Add an Android / mobile phone application to that project. Enter its name and the exact package name from
applicationIdin your host'sandroid/app/build.gradle.kts(orbuild.gradle).namespacealone is not the installed package. Each flavor/application-ID suffix must match its AGC app. -
Obtain the SHA-256 fingerprint of the certificate signing the installed APK:
cd android ./gradlew :app:signingReportAdd that fingerprint in the app's signing-certificate information in AGC. Configure debug and release certificates as appropriate; with store signing, use the certificate signing the delivered app. Never upload a private keystore.
-
In the project's API/service management, enable Push Kit for the app. Complete any Push Kit activation or data-location prompts shown by AGC.
-
Download
agconnect-services.jsonfrom this Android app's configuration information after the package/signing/service settings are saved. Refresh the download when configuration changes. Place it at:your_flutter_app/android/app/agconnect-services.jsonKeep environment-specific files private and out of public source control.
-
Find the Huawei App ID in the app information, or
client.app_idin the downloaded JSON. It is a numeric ID. Copy it to the host string resource described below. Do not use the app secret, client ID or package name there. -
Find the matching Huawei App Secret in the app's credential information. Configure this only in the Infobip profile's Huawei push settings; it is not a Flutter initialization argument. Do not paste it into the README or Dart.
-
Configure Gradle as below and install on a physical Huawei device with a compatible, updated HMS Core. Check HMS Core in the device's installed apps and resolve service/update prompts. An emulator or successful compilation does not establish HMS availability. This plugin has no public HMS-availability check method; verify registration and delivery using the Push section.
Huawei App ID, Infobip Application Code, Infobip Application ID and RTC Calls Configuration ID are different values and cannot be substituted for one another.
Infobip Portal Setup #
You need an Infobip account with access to Mobile App Messaging and the products you intend to use. Ask your account administrator to enable the products and assign appropriate permissions. Chat additionally needs the Live Chat/Conversations setup and an available agent; RTC requires Web and In-app Calls entitlement.
Mobile Messaging and Huawei push #
- Open the mobile application profiles section of the Infobip web interface. Create a Sandbox profile for testing; use a separate Production profile when appropriate. Give it a recognizable name.
- Enable its Huawei environment and supply the matching Huawei App ID and App Secret from AGC in the Huawei push credential settings. These are server-side push credentials, not Google Firebase credentials. Save the profile.
- Copy its generated Application Code to Dart's
applicationCode. Keep the profile, JSON, Android package, Huawei ID and signing fingerprint aligned. - Review profile security for user-data operations and Mobile Inbox. JWT policy may require backend-issued tokens. Production Inbox uses JWT authorization; Sandbox can use Application Code or JWT. Never weaken policy to hide an auth failure.
- After installation registration, send a test push to that profile's test device using Infobip's push messaging tools. Confirm receipt and a notification tap.
See mobile application profiles for current account configuration. The Android environment there describes Firebase; this plugin uses Huawei.
Optional Chat #
Create a Live Chat widget, connect it to your Mobile Messaging profile, and
configure routing/agent availability. Select the widget's installation/security
mode to match your app. Widget configuration is synchronized through the native
SDK: initialize activates Chat; this plugin does not take a widget ID in initialization.
Installation-based Chat uses the registered installation context. For a widget
requiring JWT authentication, your backend authenticates the user and signs
fresh widget tokens using that widget's key. Personalize the installation with a
matching user identity before opening authenticated Chat. Supply tokens through
setChatJwtProvider, as shown below. The Widget ID and key ID identify the
signing configuration; the widget secret key remains on the backend.
Chat JWT is independent of Mobile Messaging JWT and Inbox JWT.
See widget setup and Chat authentication.
Optional Mobile Inbox and user management #
Use the same Mobile Messaging profile and its user/Inbox authorization policies.
Your backend must authorize access to the requested externalUserId. Configure
JWT signing on the backend when required by the profile. setJwt configures MM
request authorization; fetchInbox(jwt: ...) can override it for one request.
Inbox is a message feature, distinct from the agent contact-center product.
See user and Inbox examples.
Optional outgoing RTC Calls #
Have your account/backend administrator create a Calls Configuration for
application calls and provide its callsConfigurationId. A custom Calls API
application needs event subscriptions and backend logic to accept/route the call
to its intended peer. Use the ID returned by that configuration's creation/API
response; do not copy a Push Configuration ID or assume a Chat widget routes calls.
The exact RTC configuration menu and account-specific routing are not verified
here. Consult Calls configuration and subscriptions or your
Infobip administrator for the supported configuration in your account.
The plugin fetches an RTC token natively through initialized Mobile Messaging.
There is no Dart RTC-token or API-key argument. An omitted identity uses the
registered installation's pushRegistrationId; wait for registration first.
An explicit identity is the authorized caller/token subject, not a callee.
Your backend/account must authorize it and the configuration. There is no callee
parameter; backend routing decides the destination. Outgoing calls do not need
WebRTCUI; incoming HMS calls and Chat calling remain unsupported.
Android Configuration #
All paths here are relative to your Flutter host, not the plugin's android/
library. The example host uses the same layout under example/android/.
App ID resource and metadata #
Create or update android/app/src/main/res/values/strings.xml:
<resources>
<string name="app_id" translatable="false">YOUR_NUMERIC_HUAWEI_APP_ID</string>
<string name="app_name">My app</string>
</resources>
Replace YOUR_NUMERIC_HUAWEI_APP_ID with the actual nonzero digits from AGC before
building. The literal placeholder is invalid. The plugin explicitly validates
app_id; JSON or manifest metadata alone cannot replace this resource.
app_name is optional for the SDK's default notification title. No
infobip_application_code resource is required: the code comes from Dart.
AGConnect processes app metadata from JSON. Check the merged manifest's
com.huawei.hms.client.appid value against your Huawei ID. If your host already
sets it explicitly, the value must be appid=YOUR_NUMERIC_HUAWEI_APP_ID; avoid
conflicting duplicate metadata. The repository example sets this metadata from
JSON itself, but still requires a separately configured app_id string.
Gradle (Kotlin DSL) #
Merge these entries into existing files; keep Flutter's plugin loader,
includeBuild, Android/Kotlin plugins and repository setup. This matches the
repository's AGConnect declaration 1.9.1.301; it is not a claim that this is
Huawei's latest release. Do not add the standard Infobip Android core or RTC UI
alongside this Huawei plugin.
In android/settings.gradle.kts, inside the existing pluginManagement:
resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.huawei.agconnect") {
useModule("com.huawei.agconnect:agcp:${requested.version}")
}
}
}
repositories {
maven("https://developer.huawei.com/repo/")
google()
mavenCentral()
gradlePluginPortal()
}
In the existing settings plugins block:
id("com.huawei.agconnect") version "1.9.1.301" apply false
Ensure the dependency repositories also contain Huawei Maven. If your host
uses dependencyResolutionManagement in settings, merge into its repositories:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
maven("https://storage.googleapis.com/download.flutter.io")
maven("https://developer.huawei.com/repo/")
}
}
If repositories instead live in android/build.gradle.kts under
allprojects.repositories, add Huawei Maven there. Keep one coherent repository
policy; FAIL_ON_PROJECT_REPOS conflicts with this plugin's project repositories.
In android/app/build.gradle.kts, apply AGConnect in the existing plugins block
and set Android levels in the existing Android block:
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("dev.flutter.flutter-gradle-plugin")
id("com.huawei.agconnect")
}
android {
compileSdk = 36
defaultConfig {
minSdk = 26
targetSdk = 36 // example host target; follow your release target policy
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions { jvmTarget = "17" }
}
For Groovy hosts, use maven { url 'https://developer.huawei.com/repo/' } and
id 'com.huawei.agconnect' with the equivalent declaration in settings. Follow
Huawei's integration guide for your existing Gradle style.
The repository example declares AGConnect with apply false but does not apply
it in its app module: configuring the example privately is a separate step.
Activity and permissions #
Embedded Chat requires FlutterFragmentActivity in
android/app/src/main/kotlin/<your/package>/MainActivity.kt:
package com.example.app // replace with your host package
import io.flutter.embedding.android.FlutterFragmentActivity
class MainActivity : FlutterFragmentActivity()
In android/app/src/main/AndroidManifest.xml, review these permissions outside
<application> (the merged SDK/plugin manifest may already contribute them):
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
Request notification permission on Android 13+, microphone for audio calls, microphone and camera for video, and Bluetooth connect on Android 12+ for RTC routing. Use your host's Android permission implementation or chosen permission package and handle denial in the UI. The plugin does not request call permissions. The example's permission channel is example-only, not a public plugin API.
The plugin contributes private microphone/camera/mediaProjection foreground services and their normal permissions. Review the merged manifest and start calls from a resumed Activity. Screen sharing additionally shows fresh Android capture consent each time; no static permission replaces that consent.
Flutter Initialization #
import 'package:flutter/widgets.dart';
import 'package:flutter/services.dart';
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
Future<bool> initializeMessaging(
String applicationCode,
void Function(String) showSafeError,
) async {
WidgetsFlutterBinding.ensureInitialized();
try {
await InfobipMobileMessagingHuawei.initialize(applicationCode: applicationCode);
return true;
} on PlatformException catch (error) {
showSafeError(error.code); // Never log raw details.
return false;
} on ArgumentError {
showSafeError('missing_application_code');
return false;
}
}
Call this once during app startup and enable feature controls only after success. Surface a safe setup message when it returns false. For native UI operations, wait until your app is visible and its Activity resumed.
Initialize before using SDK features. Initialization also activates Chat. If it
fails with chat_unavailable, Mobile Messaging remains initialized: wait at least
one second and retry with the same application code. A concurrent/cooldown
retry returns chat_activation_busy. Bound retries in your application.
The default message store is enabled. MM setJwt authorization is separate from
Chat JWT authentication. See messaging and Chat integration
for storage settings, user/installation examples, Inbox, JWTs and cleanup.
Push Notifications #
Initialize first and request Android notification permission in your host. Then subscribe before requesting registration:
import 'dart:async';
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
Future<StreamSubscription<Installation>> registerPush(
void Function(Installation) onRegistration,
void Function(Object) onError,
) async {
final subscription = InfobipMobileMessagingHuawei.notifications
.onRegistrationUpdated.listen(onRegistration, onError: onError);
try {
await InfobipMobileMessagingHuawei.registerForRemoteNotifications();
return subscription;
} catch (_) {
await subscription.cancel();
rethrow; // Caller shows a safe failure and offers retry.
}
}
Registration is asynchronous: method completion alone does not prove HMS token
acquisition or delivery. In onRegistration, check for nonempty
pushRegistrationId and pushServiceToken without printing them. Registration
updates do not replay: use getInstallation() to inspect the cached state after
reattachment. Observe notifications.onMessageReceived and
notifications.onNotificationTapped, send a test push from the matching Infobip
profile, and verify foreground/background receipt and tap behavior on device.
Never set the HMS token manually; the native SDK acquires and refreshes it.
Cancel subscriptions when their owner is disposed. HMS token acquisition/refresh belongs to the native SDK. A pending notification tap can replay once on subscription; other MM events do not replay. Treat payloads and deep links as untrusted input. See notification event examples.
Chat Integration #
Configure/link the widget in Infobip, initialize and confirm installation registration first. For JWT mode, personalize and install the provider before opening Chat. Then open native Chat from a visible screen:
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
Future<bool> openChat() async {
try {
await InfobipMobileMessagingHuawei.showChat();
return true;
} catch (_) {
return false; // Show safe availability/authentication feedback in your UI.
}
}
For embedded Chat, use InfobipHuaweiChatView with one
InfobipHuaweiChatController per attached view, bounded layout and a
FlutterFragmentActivity host. Native composer attachments are supported;
programmatic sending is text-only. Unread updates do not replay: query the current count.
Use setChatJwtProvider to retrieve fresh backend-issued widget/identity tokens.
MM/Inbox JWTs use separate contracts. Provider requests expire after 25 seconds in
Dart and 30 seconds natively, with 32 pending requests per side. Bound your backend
network work too. See Chat examples and authentication
and the API compatibility reference.
For JWT-enabled widgets, use an authenticated backend request with a network timeout. This helper accepts your app's token-fetch function; implement it on your backend/API client, never by signing JWTs in Flutter:
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
Future<void> configureAuthenticatedChat(
String externalUserId,
Future<String> Function() fetchBackendChatJwt,
void Function(Object) onAuthError,
) async {
await InfobipMobileMessagingHuawei.personalize(PersonalizeContext(
userIdentity: UserIdentity(externalUserId: externalUserId),
));
await InfobipMobileMessagingHuawei.setChatJwtProvider(
() => fetchBackendChatJwt().timeout(const Duration(seconds: 10)),
onAuthError,
);
}
Handle personalization/provider setup failures in the calling UI. Return a fresh, nonempty token per callback, with a subject matching the personalized identity.
Inbox and User Management #
Use personalize(PersonalizeContext(...)) for a signed-in user's identity,
fetchUser() for server refresh and depersonalize() at logout. Do not use SDK
cleanup as a logout shortcut. Install setJwt before protected MM user requests.
For Production Inbox, fetch a backend-issued Inbox JWT, then call:
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
Future<Inbox> loadInbox(String externalUserId, String backendInboxJwt) =>
InfobipMobileMessagingHuawei.fetchInbox(
externalUserId: externalUserId,
jwt: backendInboxJwt,
options: FilterOptions(limit: 20),
);
Handle request failures and expired tokens in the caller. Never accept a client
user ID as sufficient backend authorization. A Sandbox profile configured for
Application Code auth may omit jwt; a global setJwt value still takes
precedence. setInboxMessagesSeen retains installation context and has no JWT
parameter. See user, installation and Inbox examples.
RTC Audio / Video Calls #
Initialize MM, register if using the default installation identity, grant call permissions and start from a resumed Activity. The native provider acquires RTC tokens through initialized MM; your backend must authorize the identity and routing. Calls configuration ID is distinct from RTC push configuration ID. Routing selects the peer; there is no callee argument.
Subscribe before starting and grant the host permissions described above. Use the Calls Configuration ID supplied by your backend/account administrator:
import 'dart:async';
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
StreamSubscription<HuaweiRtcEvent> observeCalls(
void Function(HuaweiRtcEvent) updateCall,
void Function(Object) onError,
) => HuaweiRtc.events.listen(updateCall, onError: onError);
Future<HuaweiRtcCall?> startAudio(
String callsConfigurationId,
void Function(String) showSafeError,
) async {
try {
return await HuaweiRtc.callApplication(HuaweiRtcCallRequest(
callsConfigurationId: callsConfigurationId,
type: HuaweiRtcCallType.audio,
));
} on HuaweiRtcException catch (error) {
showSafeError(error.code);
return null;
} on ArgumentError {
showSafeError('invalid_call_configuration');
return null;
}
}
For video, additionally grant camera permission:
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
Future<HuaweiRtcCall?> startVideo(
String callsConfigurationId,
void Function(String) showSafeError,
) async {
try {
return await HuaweiRtc.callApplication(HuaweiRtcCallRequest(
callsConfigurationId: callsConfigurationId,
type: HuaweiRtcCallType.video,
));
} on HuaweiRtcException catch (error) {
showSafeError(error.code);
return null;
} on ArgumentError {
showSafeError('invalid_call_configuration');
return null;
}
}
Keep the event subscription through the call and cancel it when its owner is
disposed. Use an authorized identity in the request only if your backend
requires one; otherwise these examples use the registered installation identity.
Subscribe before starting. Method completion means a native call object exists;
await established for connection and finished for termination. Only one active
call or pending request is allowed. getActiveCall() can be null during token fetch.
Use HuaweiRtcVideoView for bounded local/remote views and HuaweiRtc controls
for mute, speaker/audio routes and camera enable/switch. Mutations require the
current ID and an established foreground call. Handle returnToCall and consume
takeNotificationCall() on attachment/resume to restore your existing call screen.
Navigation away does not hang up. Hang up and await finished before MM cleanup
or account changes. See the RTC integration guide
for rendering, controls, notifications, events and errors.
Screen Sharing #
Screen-as-Camera replaces the outgoing camera stream on Android 10+; it does not create a separate screen track. Start with an established video call, enabled camera and focused Activity:
import 'package:infobip_mobilemessaging_huawei/infobip_mobilemessaging_huawei.dart';
Future<ScreenAsCameraState> startScreen(String callId) =>
HuaweiRtcScreenAsCamera.startScreenAsCamera(callId: callId);
Future<ScreenAsCameraState> stopScreen(String callId) =>
HuaweiRtcScreenAsCamera.stopScreenAsCamera(callId: callId);
Every start requires fresh Android consent. Capture has a foreground notification and Stop action. Backgrounding may leave capture active; Activity detach, call end, revocation or a changed resize report triggers Stop. Restart requires new consent.
Output is 640×480, fitted with black bars; portrait text has limited detail.
Camera switching/toggling is locked during capture/shutdown. Confirm
projectionTerminated and resourcesReleased after Stop. On
screen_stop_uncertain, query state and retry Stop or use Android capture controls.
cameraOutputRestored confirms local submission, not remote display.
See the screen-sharing guide for states, privacy and device checks.
Configuration Reference #
Only the Application Code is required by the Dart initialize signature. Huawei
host configuration is also required for this plugin's Android initialization.
Rows marked optional apply only when you enable that feature. Non-secret IDs
still identify your environment; do not publish private customer configuration.
| Configuration | Provider | Where to obtain | Where to configure | Required for | Secret / Non-secret |
|---|---|---|---|---|---|
Android applicationId / package name |
Your app / Huawei | Host app Gradle; register exactly in AGC | android/app/build.gradle.kts and AGC app |
Required: matching Huawei app | Non-secret |
| Signing certificate SHA-256 | Your signing certificate | :app:signingReport / release certificate |
AGC signing-certificate information | Required: installed build's Huawei configuration | Non-secret fingerprint; private keystore is secret |
Huawei App ID / app_id |
Huawei AGC | App information / JSON client.app_id |
Host strings.xml, AGC metadata and Infobip Huawei profile |
Required: host initialization and push | Non-secret numeric ID |
agconnect-services.json |
Huawei AGC | Download Android app configuration | android/app/agconnect-services.json |
Required: documented Huawei host setup | Private configuration; may contain credential material, do not publish |
| Huawei App Secret | Huawei AGC | App credential information | Infobip profile's Huawei push settings only | Required: Infobip sends HMS push | Secret; no Dart input |
Infobip Application Code / applicationCode |
Infobip | Saved mobile application profile | initialize(applicationCode: ...) |
Required: MM initialization, basis for Chat/RTC | Client-distributed authorization value; protect from logs, not a backend signing key |
| Infobip Application ID | Infobip / your backend | App/profile or backend provisioning record | Backend tools if needed; no plugin input | Not required by this plugin's initialization | Non-secret ID; not Huawei App ID |
App Key / backend AppKey |
Your backend | Backend provisioning; exact meaning belongs to your backend contract | No plugin input; backend-owned | Not required by this plugin | Treat as sensitive; not assumed to be an Infobip API key or JWT key |
| Infobip API key | Infobip | Account API-key management | Backend API client only | Optional: server-side push, Calls or other API provisioning | Secret; never a Flutter initialization input |
| Infobip base URL | Infobip / your backend | Account/API configuration | Backend API client if needed | Not a Dart plugin parameter; native MM owns its endpoint configuration | Non-secret endpoint |
| Chat widget configuration / linkage | Infobip Live Chat | Widget configuration | Connect widget to Mobile Messaging profile in Infobip | Optional: Chat | Non-secret configuration |
Chat Widget ID / chatWidgetId |
Infobip Live Chat | Widget configuration | Backend Chat JWT issuer; example test field only for local signing | Optional: JWT-enabled Chat, not initialize |
Non-secret ID |
Chat key ID / chatKeyId (ski) |
Infobip Live Chat | Widget's generated secret-key record | Backend JWT claims / isolated example test config | Optional: Chat JWT signing | Non-secret key identifier |
Chat secret key / chatSecretKey |
Infobip Live Chat | Widget security / generated keys | Backend signer only in production | Optional: Chat JWT signing | Secret Base64 key; never ship in production Flutter |
Chat JWT / chatJwtToken |
Your authenticated backend | Fresh token endpoint | setChatJwtProvider callback |
Optional: widget JWT authentication | Sensitive short-lived token; distinct from MM JWT |
Mobile Messaging JWT / jwtToken |
Your authenticated backend | MM token endpoint | setJwt(jwt) |
Optional: profile security requires JWT for MM requests | Sensitive token |
Inbox JWT / request jwt |
Your authenticated backend | Inbox-authorized token endpoint | fetchInbox(jwt: ...) or global setJwt |
Required: Production Inbox; optional per Sandbox policy | Sensitive token; not a Chat JWT |
MM/Inbox key ID and signing key / jwtKid, jwtSecretKey |
Infobip profile / backend | Profile JWT authorization key configuration | Backend signer; isolated example local signing fields only | Optional: issuing MM/Inbox JWTs | ID non-secret; key secret (example expects hex) |
User identity / externalUserId |
Your identity backend | Authenticated account record | UserIdentity, Inbox request; match JWT subject |
Optional: personalization, protected Chat/Inbox | Personal data; not a password or signing key |
RTC Calls Configuration ID / callsConfigurationId |
Infobip Calls | Calls configuration creation/API response or administrator | HuaweiRtcCallRequest |
Required: outgoing RTC | Non-secret routing ID |
RTC Push Configuration ID / WebRTCUI.configurationId |
Infobip WebRTC | Push registration configuration | No active supported incoming HMS flow; do not pass as Calls ID | Not required for outgoing calls; incoming calls unsupported | Non-secret configuration ID |
RTC Identity / request identity |
Your backend or native installation | Authorized caller subject; default pushRegistrationId |
Optional HuaweiRtcCallRequest.identity |
Optional override; otherwise registration must complete | Identity / personal data; not destination |
| RTC token | Native MM backend response | Acquired natively for each outgoing call | Native SDK only; no Dart token argument | Outgoing RTC, automatic acquisition | Sensitive temporary token |
HMS token / pushServiceToken and pushRegistrationId |
HMS / Infobip SDK | Registration events or installation snapshot | Native SDK managed; inspect presence only | Push; registration ID also default RTC identity | Sensitive device identifiers; not manual configuration |
app_name |
Your app | App display name | Host strings.xml |
Optional: SDK notification title | Non-secret |
defaultMessageStorage |
Your app | Storage/privacy decision | Before initialize, default true |
Optional: default local message store | Non-secret setting |
The example-only TTL, content, Inbox filters, feature flags and installation settings are listed in the example configuration table. They are test controls, not additional portal credentials.
Troubleshooting #
| Symptom | Check / next step |
|---|---|
hms_configuration_missing |
Host app_id must contain actual digits, nonzero, without spaces; JSON/manifest alone is insufficient |
| Huawei dependencies cannot resolve | Add Huawei Maven to both plugin resolution and dependency repositories; check repository policy and connectivity |
| AGConnect processing fails | Apply its app plugin, place the correct JSON in android/app/, and match the variant's package |
| Registration never arrives | HMS Core availability, package/signing fingerprint, Push Kit enabled, network; inspect cached installation without logging tokens |
| Registered but no push | Matching Infobip Huawei credentials/profile, correct recipient, push enabled, notification permission/channels and Huawei background restrictions |
chat_unavailable |
Check linked widget, registration, account service and connectivity; MM stays initialized, retry same code after at least one second with a bounded retry |
chat_activation_busy |
Concurrent activation or one-second cooldown; wait and avoid parallel initialization retries |
| Chat authentication failure | Widget mode, fresh backend Chat JWT, matching personalized identity and widget key; MM JWT is not a replacement |
| User/Inbox authorization rejected | Profile policy, token expiry and authorized external user ID; Production Inbox requires JWT |
rtc_not_initialized |
Initialize MM; omitted identity additionally needs completed installation registration |
rtc_permission_denied |
Host must obtain microphone/camera and Android 12+ Bluetooth connect grants before calling |
rtc_token_failed / numeric 10300 |
Verify account authorization, caller identity and backend routing with Infobip; the rejection predicate is not proven by a client error alone |
rtc_call_already_active |
One call or pending token request allowed; await finished before another call |
| Call object returned but no media | Wait for established; confirm backend routing/peer, permissions and network; method completion is not answer confirmation |
| Embedded Chat fails | Use FlutterFragmentActivity, bounded layout and one controller per attached view |
screen_stop_uncertain |
Query state, retry Stop or use Android capture controls; do not claim capture ended until release flags confirm it |
Never paste raw SDK errors, headers, tokens or user messages into public bug reports. Use sanitized codes and a description of the setup checks performed.
Known Limitations #
- Android only; no iOS, web, desktop, FCM push transport or Dart background isolate.
- Incoming HMS RTC and official
enableCalls/enableChatCallsparity are unsupported.infobipWebRtcEnabled=trueis rejected; see WebRTC safeguards. - RTC Core retains Firebase/GMS transitive dependencies; Google-free operation is not certified.
- No multiparty gallery, separate screen track, screen-resolution setting or seamless resize.
- Chat thread management and composer draft setters are unavailable.
- Real backend acceptance, HMS delivery, signed/minified hosts, OEM lifecycle, GL/JNI behavior, 16 KB runtime compatibility and performance require device validation.
Follow the example guide for private configuration and manual checks. Historical audit reports remain in Git and are excluded from the pub.dev package.
Security #
SEC-01 remains PARTIALLY MITIGATED; this package is not security-certified. Huawei MM 8.14.0 logs authorization headers upstream. RTC 2.5.28 logs signaling messages that may expose temporary TURN credentials; setting its logger to OFF does not disable direct stdout calls.
The optional host Release R8 workaround removes matching print/println calls
application-wide, including functional stream/file output. It requires R8
optimization, does not cover RTC printf, and does not guarantee removal of all
sensitive logs. Read SECURITY.md before production integration.
Vendor reporting is not a publication requirement and does not resolve this issue.
Use backend-issued tokens; never embed production signing secrets or log tokens, headers, messages, raw SDK errors or captured content. Explain MediaProjection's scope and provide Stop: it can capture private content outside your app.
Documentation #
- Messaging, Push, Chat, user management and Inbox
- Outgoing RTC: events, rendering, controls and notifications
- Screen sharing: privacy, lifecycle and device checks
- Incoming-call safeguards
- Public API compatibility
- Physical-device example setup
- Security and third-party notices
The guides describe this package's API. Upstream examples may use different Flutter/native APIs or newer SDK versions; do not copy their initialization flags, dependencies or incoming-call methods into this integration.
License #
The MIT License, copyright (c) 2026 Naser Alomosh, applies to code and content the repository owner has the right to license. Third-party SDKs, libraries, generated files and other third-party materials remain subject to their respective licenses and notices; MIT does not grant additional redistribution rights for them. See third-party notices for the bundled Gradle wrapper and Flutter-generated registration code.