Uh oh!
There was an error while loading. Please reload this page.
Dev 4073 huawei push integration - #208
Merged
Merged
Conversation
…/FCM token sources, http logger, demo updates)
Bring the Huawei push WIP up to date with master (catalog/loyalty/orders methods + the FCM push-routing/robustness fix + BigPicture demo display). Conflict resolution: - SDK.kt: keep huawei's multi-instance push routing (activeInstances) AND master's currentInstance/isSdkInitialized so SDK.instance returns the initialized SDK and notificationReceived stays guarded. - DemoApplication: Application-side SDK init + BigPicture display listener (master) plus the HTTP-log hook (huawei). - MainActivity: reuse SDK.instance; show the registered push provider + token via the unified PushProvider API (FCM + HMS), seeded from cache and Firebase so it appears immediately; keep POST_NOTIFICATIONS + notification-click. - activity_main.xml: combined header (provider + token + Copy + HTTP Log) over the full demo button list. - build.gradle / strings.xml: drop duplicate google-services apply and the duplicate push_token_copied string left by the merge.
HMS was forced on every consumer as `implementation`, so a plain FCM app had to add the Huawei Maven repo just to resolve the transitive deps, and the demo would not build without agconnect-services.json. Make Huawei opt-in: - HMS deps (hms:push, agconnect-core) -> compileOnly: neither bundled nor listed in the published POM, so FCM-only apps build with no Huawei footprint. - PushTokenManager registers a provider only if its SDK is on the classpath (Class.forName marker check), so HmsTokenSource is never referenced without HMS present -> no NoClassDefFoundError. - Ship consumer-rules.pro (-dontwarn com.huawei.**) so a FCM-only consumer's R8 does not fail on the absent HmsMessageService superclass. - demo-app applies the com.huawei.agconnect plugin only when agconnect-services.json exists (mirrors the existing google-services guard), so the demo builds without it. To enable Huawei push a host app adds the HMS artifacts + the agconnect plugin + agconnect-services.json (documented at the compileOnly declaration).
… present Mirror the SDK's optional-HMS model in the demo consumer. Now that the SDK exposes HMS as compileOnly, the demo (itself a consumer) must add the HMS artifacts, and only when Huawei is configured. Gate them on the same agconnect-services.json presence check that applies the agconnect plugin, so a build without the Huawei config ships a Firebase-only APK with no HMS classes.
HmsMessagingService.onMessageReceived only logged the payload, so data-only HMS pushes (attach_notification=false) were dropped and nothing was shown. Notification messages (attach_notification=true) worked only because HMS Core displays those itself — which is why local test sends appeared but the backend's data sends did not. Route HMS the same way as FCM: extract the message's data map and hand it to the shared SDK entry point, which tracks "received" and forwards it to the OnMessageListener (the rees46 flavor renders it via NotificationHelper). - Add a provider-agnostic Map<String, String>.toNotificationData() mapper; the FCM RemoteMessage extension now delegates to it. - SDK.receiveMessage / onMessage take the data map; add an onMessage(Map) overload for HMS so no Huawei types leak into SDK.kt. - HmsMessagingService forwards message.dataOfMap to SDK.onMessage, guarded so a handler failure never crashes the HMS thread.
Add NotificationDataMapperTest for Map<String, String>.toNotificationData() — the single point both the FCM and HMS messaging services route their data payload through. Covers a full payload (actions/action_urls/event parsed), the data-only title/body case (HMS), an empty payload (null scalars, empty collections, empty event), malformed JSON degrading to empty instead of crashing, and the FCM RemoteMessage.toNotificationData delegating to the shared map mapper.
…ustom event - Guard FirebaseMessaging.getInstance() behind a FirebaseApp presence check so a Huawei-only build (no google-services.json) no longer crashes on MainActivity start. - Rename the demo custom event to the registered "flutter_example" so push/custom returns 200 instead of 400 "Event custom_event not found".
Notification-mode pushes (attach_notification=true) that FCM/HMS auto-display in the background now produce a heads-up notification with sound instead of landing silently in the shade. Same channel id as before; mirrors the React Native SDK reference.
…K logo - SDK: resolve the notification small icon from the host's default_notification_icon meta-data, falling back to the host application icon; stop hardcoding the SDK logo. - Demo: ship its own notification glyph and launcher icon and declare default_notification_icon/color, replacing the @android:drawable/ic_dialog_info placeholder that rendered as an "i in a circle" in the status bar.
StoriesView is a View that expects its code through the app:code attribute and then has to be handed to SDK.initializeStoriesView, which makes it awkward to use from Compose. Add StoriesWidget, a composable that does both through AndroidView: it builds the view with the programmatic constructor, registers it with the SDK, forwards the OnClickListener whose Boolean return keeps the SDK from opening a url the host routes itself, and releases the player on dispose. Rebuild rather than update the view when the code changes, since the block is loaded once during initialize. Take Compose as compileOnly, mirroring the optional Huawei dependency: it stays off every consumer's classpath and out of the published POM, so a View-based app pulls none of it. compileOnly artifacts take no part in manifest merging either, so the SDK keeps minSdk 19 even though Compose itself requires 21.
The stories block sat on the same screen as the SDK method demos, so there was nowhere to show the new Compose wrapper next to the view it wraps. Swap three panes from a bottom navigation bar: "API" keeps the method demos along with the push token panel, which belongs to them rather than being a header shared by every tab; "UI Kit" renders the block with StoriesWidget; and "Legacy UI" with the XML StoriesView plus an OnClickListener. Both UI tabs log their callbacks, and the Compose one can route demo:// links itself, so the opt-out can be exercised from the demo. Drive the initial pane through the navigation listener so the checked item and the visible pane cannot drift apart. The Material component gets a Bridge theme and explicit item colours, since the app itself stays on an AppCompat theme whose colorPrimary leaves the checked tab unreadable. Raise the demo to minSdk 21 for Compose, and opt the layout into fitsSystemWindows so the bar clears the gesture area on Android 15. Also carries the theme groundwork that was still uncommitted: the light-in -every-mode theme with its night override, and the token panel colour.
The previous block was paused and answered with an empty stories array, so both UI tabs could only render an empty row.
Compose is a compileOnly dependency, and such dependencies are absent from the unit test classpath. The Compose compiler plugin refuses to compile the test variant without a runtime it can see, so every unit test in the module stopped compiling once StoriesWidget was added: IncompatibleComposeRuntimeVersionException: The Compose Compiler requires the Compose Runtime to be on the class path, but none could be found. Mirror the compileOnly declarations as testImplementation. This is confined to the test configuration, so the published POM still carries no Compose.
On a fresh install the same token reaches onTokenReceived twice: from the proactive fetch in initialize() and from the messaging service's onNewToken, which fires because the token is created for the first time. shouldSendToken compares against the persisted token, but the token is only persisted in the response callback of the very request the check is meant to prevent, so both deliveries saw an empty cache and both posted mobile_push_tokens. Testers saw two requests on Xiaomi and four on Huawei, where FCM and HMS are both available and each doubles the same way. Claim the provider:token pair in a concurrent set before the request leaves and release it once the token is persisted, so a delivery arriving in between is deduplicated by the cache instead. Failures release the claim immediately so a later delivery can retry. The key includes the provider, so an FCM and an HMS registration never suppress each other.
The notification the SDK builds itself carried neither a priority nor any default alert. From Android 8 the channel decides and NOTIFICATION_CHANNEL is IMPORTANCE_HIGH, so nothing changes there. Below that there are no channels: a heads-up pop-up needs both a high priority and a sound or vibration, and without them the push lands silently in the shade. minSdk is 19, so those devices are still in scope. Both other SDKs that build notifications on Android already do this — the Flutter notifier sets PRIORITY_HIGH with DEFAULT_ALL, and the React Native one sets AndroidImportance.HIGH per notification. This aligns Android with them.
GET /stories/{code} nests both captions of the product carousel toggle inside
a "labels" object:
"labels": { "hide_carousel": "Скрыть товары", "show_carousel": "Товары для геймеров" }
The parser located that object and then read the fields off the parent element
instead, so both captions were always empty and the button rendered blank. The
button itself still worked, which is why this went unnoticed.StoriesManager keeps a single StoriesView reference, so of the two panes only the one that registered last receives loaded stories — the Compose pane, which left the Legacy tab permanently empty. The button re-registers the pane's own view (the XML one directly, the Compose one by rebuilding the widget), which pulls the block back into it. A workaround for the demo, not a fix: the SDK still drives one block at a time. Remove once it can hold more than one.
… story OnClickListener.onCloseDialogClick defaulted to true. In ProductsAdapter a true return closes the story viewer, while false opens the product url — so a host that did not override this callback (the common case) saw a product tap close the story and open nothing. Testers reported it as "the story just closes on tap". Flip the default to false so an untouched listener opens the product, which is what a tap on a product card should do. Hosts that want the old behaviour still get it by returning true explicitly. The KDoc described the inverse of what the code does; corrected it to match.
Groundwork for multi-instance (Release 1), internal only — no public API change and no behaviour change. The static routing state that lived in SDK's companion (currentInstance + activeInstances) moves into an internal SdkRegistry that owns the ordered fan-out set, the current-default pointer and a shop_id -> instance mapping. initialize() now calls SdkRegistry.register(shopId, this); release() calls unregister(this); SDK.instance and the push entry points (onMessage, onPushTokenReceived) read through the registry. Single-instance behaviour is unchanged; the shop_id resolution the public Rees46.initialize/getInstance API will build on is in place and covered by tests. Not wired into the demo yet.
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.