insightreader_sdk 1.0.0
insightreader_sdk: ^1.0.0 copied to clipboard
Personalisation for Flutter news apps — reading tracking, time-of-day category insights, streaks, curated notifications, personalised feeds and Gemini AI summaries.
Changelog #
1.0.0 - 2026-08-21 #
First public release on pub.flutter-io.cn. Feature parity with the native iOS
InsightreaderSDK, adapted where the platforms genuinely differ.
Security and distribution #
- Removed the bundle-identifier allowlist.
initialize()no longer performs a runtime licence check and its only failure mode is nowstorageFailure. The allowlist named real customer applications in source, which a published package would have disclosed; it was also bypassable with a two-line dependency override, so it protected nothing. Distribution control is now contractual — seeLICENSE.InsightreaderErrorCode.unauthorizedClientandisUnauthorizedClientare gone with it. - The AI cache is no longer client-writable. Document ids derive from public
article ids, so any client permitted to create
summary_<articleId>could seed an entry that every later reader received as a cache hit — and Firestore rules can validate a document's shape but never its contents. Writes now go toAiCacheConfiguration.writeEndpoint, a trusted server-side writer that derives the id itself. Leaving itnullmeans this install never writes. - Cache reads are validated. An entry whose
kindorarticleIddisagrees with the document, or which has nogeneratedAt, is discarded. Entries older than the newmaxEntryAge(30 days) are treated as a miss, so any entry written before the lockdown expires on its own. - Fixed: disabling the cache also disabled the remote kill switch. The two
are now separate settings —
remoteKillSwitchEnableddefaults totrueand is honoured even whenenabledisfalse.AiCacheConfiguration.disabledopts out of both, which is the only case that needs no Firebase. - Deprecated
maxDocuments. Client-side eviction requiredlistanddeletepermission, which the hardened rules withhold. Trim the collection server-side instead. - Documented Firestore rules tightened to
allow getwithlistandwritedenied, plus App Check enforcement.
Analytics — aligned with the shared cross-platform event sheet #
Event names are final as of this release. One dashboard covers iOS, Android and Flutter.
- All 40 event names now carry the sheet's
_gnisuffix, and theirsdk_prefix is gone:irsdk_article_read→article_read_gni,feed_shown→feed_shown_gni, and so on. All 18 events the sheet lists and this SDK emits now match the sheet exactly. - Removed
notification_enabled/notification_disabled. Replaced by the sheet's singlebriefings_enabled_toggled_gnicarryingenabled: 1|0— the old pair double-counted one reader action. - Changed
briefing_scheduled_gnifrom one aggregate event per refresh, carrying only the earliest fire time, to one event per slot armed, carryingslotand that slot'strigger_epoch_millis. Expect up to 4× the volume. - Changed
briefing_permission_blocked_gnito carryslot, emitted once per enabled slot. Permission is still checked once per refresh; every enabled slot really is blocked. - Changed
ai_summary_failed_gni.error_reasonfrom the raw exception message to the sheet's enum (gemini). The message moved toerror_detail, soerror_reasonis now groupable instead of unbounded. - Added
ai_summary_cache_hit_gniandai_summary_cache_miss_gni. - Added
briefing_tapped_gni(slot,source,category_id). - Added
insights_shown_gnifor the inline streak badge.
sdk_version is still attached to every event as an additive param, and the
ai_summary_generated_gni / ai_summary_failed_gni extras (duration_ms,
ai_engine, and the rest) are retained alongside the sheet's required keys.
Added #
InsightreaderStreakPill— a floating, tappable streak pill, the interactive counterpart to the feed header's inline badge. Emitsinsights_floating_shown_gniandinsights_floating_tapped_gni, completing the sheet's Insights tab.test/analytics_events_test.dart— 18 tests pinning event names, sheet parameter sets, the Firebase name/value constraints, and the emission gate.
Known gaps against the sheet #
41 of the sheet's 59 events remain unemitted. briefing_shown_gni is not
implementable (flutter_local_notifications exposes no delivery callback); the
rest belong to features this SDK does not have — Widget, In-App Update, Google
Sign-in, and the separate streak-reminder and streak-lost notifications. See
README section 16 for the full matrix.
Personalisation #
- Article read tracking with per-category and per-time-of-day aggregation.
- Most-read category, top categories, and both queries scoped to a time segment.
- Blended recommendations: 70% time-of-day affinity, 30% overall popularity.
- Engagement scoring and a reading-rhythm breakdown.
- Reading streaks with milestones at 3, 7, 14, 30, 60, 100 and 365 days, plus daily reading goals.
Notifications #
- Four daily briefings, each built around the reader's top category for that segment.
- Streak-break reminder, independently switchable from the briefings.
- Per-segment and per-field copy overrides.
- Persisted reader preferences that survive re-initialization.
- Typed notification payloads and a tap stream; the SDK never navigates itself.
AI #
- Gemini-backed summaries, key takeaways and 5W1H extraction, behind a
swappable
Summarizerinterface. - Prompts and structured-output schemas ported from the iOS Foundation Models
@Generabledefinitions, so output semantics match. - Batch summarisation up to 10 stories, with per-item failure isolation and bounded concurrency.
- Optional Firestore response cache with FIFO eviction and a remote kill switch.
- Request coalescing, so concurrent callers for one article share a single call.
Feeds #
InsightreaderArticleFeedin four layouts, ranked against the reader's interests.PaginatedArticleFeedwith cross-page deduplication and per-page re-ranking.DynamicJsonParser, which finds the articles array at any nesting depth.ArticleMappingConfigcovering the string, object and array shapes publisher APIs use for categories and images.- Full theming through
FeedStyle,FeedThemeandAdaptiveColor.
Other #
InsightreaderSettingsScreen, a drop-in reader-preferences screen.- Analytics forwarding with event names shared across iOS, Android and Flutter.
- In-app review and store-page helpers.
- Typed
InsightreaderExceptionwith stable error codes throughout.
Deliberate differences from iOS #
maxStoredEventsandanalyticsWindowDaysare honoured. iOS accepts both but applies neither. PassanalyticsWindowDays: 0for identical ranking.- Batch concurrency is bounded by
maxConcurrentRequests, because Gemini is a metered network API rather than a free on-device model. - AI responses are cached, which iOS has no need for.
- HTML block tags are matched case-insensitively, and hexadecimal numeric entities are decoded.