Shared Packages
shared_consent Free
- Tier
- Freeversion 0.1.5
- Command
archipelago generate shared_consent- Generates
shared/consent_apishared/consent_impl
- Used by
- app_scaffold, analytics_sdk, feature_flag_sdk, monitoring_sdk, journey_tracker, push_notification_sdk and 4 more
Telemetry consent gate and PII scrubbing packages (
shared/consent_api,shared/consent_impl), wired intobootstrap.dartbefore dependency injection.
What it is
Every consent-gated feature asks one ConsentGate before it sends or keeps anything. The gate fails closed: every purpose is denied until the app records a decision. flutter_modular_monorepo generates this brick, so its projects already contain both packages and the bootstrap call. This brick is the only source of the consent packages.
Run it by hand only on projects created before consent shipped. app_blackbox_recorder generates it for you when shared/consent_api is missing.
Variables
None.
Usage
archipelago generate shared_consent --output <project-root>What the hook does
- Adds
shared/consent_apiandshared/consent_implto the workspace. - Adds
consent_implto the app'spubspec.yaml. - Inserts
await ConsentInitializer.initialize(GetIt.I);beforeawait initializeInjector()inapps/<app>/lib/bootstrap.dart, with theconsent_implimport. It skips a bootstrap that already calls it. - If
bootstrap.darthas noinitializeInjector(line, it warns and you add the call by hand. - Records
shared_consentinarchipelago.yaml.
Record a decision
await getIt<ConsentGate>().record(
purpose: ConsentPurpose.diagnostics,
granted: true,
);The four purposes (analytics, diagnostics, marketing, targeting) are independent. In debug builds, --dart-define=CONSENT_DEBUG_GRANT_ALL=true grants all of them for QA. Do not seed a granted state in code.
Scoped consent for mini-apps
ConsentPurpose is a closed enum for app-level purposes. Grants to a mini-app are keyed by an open subject string (miniapp:<publisherId>/<miniAppId>) and a scope key, so they have their own types in the same package:
| Type | Role |
|---|---|
ScopedConsentDecision | One decision for one subject and scope (UTC time, source, manifest version, server record id). |
ScopedConsentStore | Persistence port. SharedPreferencesScopedConsentStore keeps one JSON list under archipelago.consent.scoped.v1, apart from the purpose record. |
ScopedConsentGate | isGranted(subject, scope), decisionsFor, subjects, changes, recordAll, putAll, revokeSubject. PersistedScopedConsentGate is the implementation. Fail-closed. |
ScopedConsentSync | Port to the server record. The default NoopScopedConsentSync keeps consent on the device (isAvailable is false). |
ConsentInitializer.initialize registers ScopedConsentGate and ScopedConsentSync in the global GetIt next to ConsentGate. Pass scopedSync: to plug in a backend, or scopedStore: to swap storage. Nothing reads them unless the partner mini-app SDK is present.
Recording is two steps. Push to the server first, then record locally with the returned id. If the push throws, record nothing, because a grant the server does not know cannot produce a token:
final recordId = await getIt<ScopedConsentSync>().push(subject, {'profile.name': true}, manifestVersion);
await getIt<ScopedConsentGate>().recordAll(subject, {'profile.name': true}, policyVersion: manifestVersion, recordId: recordId);revokeSubject records a refusal for every scope of the subject. The refusals stay as audit records and the subject leaves subjects. Decisions pulled from the server go in through putAll and overwrite a stale local grant. Without a real sync, scopes that need a server record (identity) cannot be granted.
You do not usually call these by hand. webview_sdk_advanced ships the partner consent UI on top of them (PartnerConsentController, PartnerConsentSheet and the settings pages); see Partner consent.