aegis_guardian 0.1.0
aegis_guardian: ^0.1.0 copied to clipboard
Native Android and iOS runtime security checks, device signing, screen privacy, and Apple App Attest for Flutter.
AegisGuardian for Flutter #
Flutter plugin wrapping AegisGuardian Android 1.2.0 (Maven Central) and iOS 1.0.0 (CocoaPods / Swift Package Manager). Android API 24+, iOS 15+. Development and validation use Flutter 3.44.4 / Dart 3.12.2. Only Android and iOS are registered.
Version 0.1.0 is a preview. Review the limitations and verification status below before adopting it.
Limitations of the Flutter preview #
The plugin exposes a subset of the native SDKs. Implemented does not mean verified on physical devices or against real attacks. See the support matrix for individual APIs and VERIFICATION.md for test results.
Platform and native API differences #
- iOS screenshots cannot be blocked. Screen privacy uses an inactive/capture overlay; capture notifications can arrive after a frame. Android uses
FLAG_SECURE. - USB debugging and developer-options checks are unsupported on iOS. Their report status is
unsupported, notclear. - App identity checks differ: Android compares the APK signing certificate; iOS compares the bundle identifier only. These checks do not provide equivalent tamper protection.
- Attestation is platform-specific. Android key-attestation challenges/certificate chains are not Apple App Attest. iOS rejects
attestationChallenge, returns an empty certificate chain, and exposes separate App Attest helpers. App Attest calls on Android returnunsupported. - Key lookup on iOS:
hasDeviceKey()andgetDevicePublicKey()returnunsupportedbecause the current native SDK has no non-mutating lookup API. Obtain the public key fromcreateDeviceKey()instead; it creates a key if absent. - Reset/delete on Android:
resetDeviceId()anddeleteDeviceKey()returnunsupportedbecause these operations are not exposed by the current native SDK. Also note that AndroidcreateDeviceKey()replaces the existing key, while iOS reuses it. - Web and desktop are unsupported. The plugin is registered only for Android and iOS.
Native features not wrapped in version 0.1.0 #
Play Integrity, OkHttp/URLSession SPKI pinning, the Encryption Gateway client, native tapjacking/touch filtering, and native memory-wiping helpers are not exposed through this Flutter API. Native builder/strict-policy callbacks are represented by explicit Dart policy evaluation and screen-protection calls, rather than a direct wrapper of those APIs.
Installing the plugin does not protect Dio or Dart http traffic automatically. Networking needs a separate integration. Dart buffers and platform-channel copies also prevent this wrapper from guaranteeing native-style memory wiping. Missing wrappers are implementation gaps; they do not mean Flutter cannot call those native features.
What still needs verification #
Automated integration tests passed on an Android API 35 emulator and an iOS 26.5 simulator. Android release scanning and screenshot protection were also checked on the emulator. These results do not establish:
- Hardware attestation trust on Android or Secure Enclave behavior on a physical iPhone. This iOS simulator reported Secure Enclave availability; that result is not physical-iPhone verification.
- Real App Attest enrollment/assertions with configured entitlements and a backend verifier.
- Detection effectiveness against root/jailbreak, Frida, hooking, or controlled VPN/proxy/debugger changes.
- iOS overlay lifecycle, physical-device screenshots/recording, app-switcher privacy, Activity recreation, or multi-window behavior.
- Runtime compatibility on the minimum supported Android API 24 and iOS 15 versions.
Unsupported, unavailable, or unconfigured checks must not be treated as clean results. evaluatePolicy() blocks when a required check is not clear; Android's native SDK still has the probe-failure reporting limitation described below.
Install #
flutter pub add aegis_guardian
For development from this repository, use a local dependency:
dependencies:
aegis_guardian:
path: /path/to/aegis-guardian/flutter/aegis_guardian
The Android build resolves the native AAR from Maven Central. iOS resolves AegisGuardian 1.0.0 using CocoaPods or the ios-1.0.0 Git revision using SwiftPM. Native SDK source is not duplicated in the Flutter package. The native iOS dependency includes its privacy manifest.
Inspect and evaluate policy #
import 'package:aegis_guardian/aegis_guardian.dart';
final guardian = AegisGuardian();
try {
final report = await guardian.scan();
final decision = report.evaluatePolicy({
SecurityCheck.root,
SecurityCheck.frida,
SecurityCheck.hooking,
});
if (!decision.allowed) {
// Apply your app's policy. Verify integrity on your backend too.
}
} catch (error) {
// Inspection unavailable: do not treat a failed call as a clean device.
}
Use scan(expectedSignatureSha256: fingerprint) on Android (64 hex characters, no colons) or scan(expectedBundleIdentifier: bundleId) on iOS. Supplying the other platform's option raises PlatformException(code: 'unsupported'). Bundle ID comparison does not provide Android-style APK signature verification.
Reports contain all ten normalized check names with explicit clear, detected, unavailable, notConfigured or unsupported statuses. root maps to iOS jailbreak, emulator to simulator, and appIdentity to the platform's identity check. Evidence from iOS is preserved. isSecure preserves the native summary, and is not cryptographic proof. Android's current SDK collapses failed individual probes to “not detected”; the Flutter bridge cannot recover unavailable statuses the native SDK does not expose. A required unsupported/unavailable/unconfigured check blocks evaluatePolicy.
Identity and signing #
import 'dart:typed_data';
final id = await guardian.getDeviceId();
final enrollment = await guardian.createDeviceKey();
final signature = await guardian.sign(Uint8List.fromList([1, 2, 3]));
// Send enrollment.publicKey and signature to your backend for verification.
- Public keys are P-256 X.509 SubjectPublicKeyInfo DER; signatures are SHA-256/ECDSA ASN.1 DER on both platforms.
- Android:
createDeviceKeyreplaces the existing native signing key. Enroll intentionally, not on every launch. Supply a fresh backendattestationChallenge(1..128 bytes) for Android Key Attestation and send the returned leaf-first DER certificate chain to the server. A returned chain does not guarantee hardware attestation; the SDK can fall back to a plain key. Verify trust, challenge and app identity on the server. - iOS:
createDeviceKeyreuses the key if present and requires Secure Enclave by default. The certificate chain is empty; Secure Enclave signing is not App Attest. ExplicitrequireSecureEnclave: falseon both create/sign permits development software keys on a simulator. There is no silent downgrade. - iOS identity/signing use a separate namespace derived from the host bundle ID plus
.aegis.flutter. Existing native app keys are not automatically migrated. Android uses the existing native SDK key alias. - Device IDs have platform-specific lifetimes. They are identifiers, not authentication credentials.
Screen privacy #
Call await guardian.setScreenProtection(true) after the Flutter window is attached; pass false to release the plugin's protection. Android sets FLAG_SECURE on the current Activity and reapplies it after configuration changes. The plugin preserves a flag already set by the host. Coordinate ownership if another component also changes the same flag after enabling this plugin.
iOS uses the native inactive/capture overlay on the current Flutter window. It cannot prevent screenshots, and capture notification can arrive after a frame. Enable separately for each engine/window you use; multi-window transitions require device testing. Screen operations remain on the main thread; scan/key operations run on a serial worker queue.
Apple App Attest #
The iOS helpers are isAppAttestSupported, generateAppAttestKey, attestAppAttestKey and generateAppAttestAssertion. Configure the host's App Attest entitlement and backend first. Persist your key ID, and pass a 32-byte SHA-256 hash of server-bound client data for attestation/assertion. The plugin does not invent challenges, configure entitlements, or verify server trust. Android calls return unsupported.
Support matrix #
“Implemented” means bridged; see VERIFICATION.md for what actually ran.
| Function | Android | iOS |
|---|---|---|
| Scan root/jailbreak, emulator/simulator, debugger, Frida, hooking, VPN, proxy | Implemented | Implemented |
| App identity | APK signing certificate SHA-256 | Bundle identifier only |
| USB debugging, developer options | Implemented | unsupported |
| Device ID | Native Widevine/ANDROID_ID/fallback | App-scoped Keychain UUID |
| Create key / sign | Android Keystore | Secure Enclave; explicit development fallback |
| Key attestation challenge / certificate chain | Implemented | unsupported challenge; empty chain |
hasDeviceKey, getDevicePublicKey |
Implemented | unsupported; use create result for public key |
deleteDeviceKey, resetDeviceId |
unsupported by current native API |
Implemented |
| Policy evaluation | Dart policy over native report | Dart policy over native report |
| Screen protection | FLAG_SECURE | Inactive/capture overlay, no screenshot prevention |
| App Attest | unsupported |
Helpers implemented; requires device/backend setup |
| Play Integrity | Not wrapped in 0.1.0 | Not applicable |
| OkHttp / URLSession SPKI pinning | Not wrapped in 0.1.0 | Not wrapped in 0.1.0 |
| Encryption Gateway client | Not wrapped in 0.1.0 | No matching native module in this SDK |
| Native tapjacking/touch filtering | Not wrapped in 0.1.0 | No equivalent exposed |
| Native memory wiping | Not exposed to Dart | No equivalent exposed |
| Native builder / strict callback APIs | Use Dart policy and explicit screen calls | Use Dart policy and explicit screen calls |
Networking through Dio or Dart http is not automatically routed through OkHttp/URLSession and is not protected by installing this package. Adding native pinning alone would not cover that traffic. Managed Dart buffers/platform-channel copies also cannot provide native memory-wiping guarantees. Web/desktop are not supported and calls raise MissingPluginException.
Test #
flutter pub get
flutter analyze
flutter test
cd example
flutter test
flutter test integration_test/plugin_integration_test.dart -d DEVICE_ID
flutter build apk --debug
flutter build ios --release --no-codesign
The integration command builds and runs on the selected simulator/device. On the tested Xcode 27 setup, generic dual-architecture simulator builds need the ARM64 workaround described in VERIFICATION.md. The unsigned iOS release build validates compilation only.
Use the disposable example application for integration tests: they replace Android signing keys and reset/delete iOS example identities/keys. The integration test independently verifies native signatures with PointyCastle and rejects altered messages; these dependencies are test-only.
The example demonstrates scanning and screen privacy. Beyond the Android emulator screenshot check, live App Attest, hardware attestation trust, threat injection, physical-device screenshot behavior and background/foreground behavior require additional configured-device testing; mocks are not evidence that these protections work on a device.
Plugin architecture follows Flutter platform channels.