Other platforms
AppAttest ships official bridges for React Native, Capacitor, and Flutter, plus a CocoaPods option for native Swift. They wrap the same SDK and expose the same shape — start, waitForReady, read a secret, observe state — idiomatic to each runtime.
The account, secret, Apple Developer Console, and entitlements steps are identical across every platform. Do steps 1–4 of the Quickstart first; this page only covers the per-platform install and read delta.
App Attest is an Apple capability, so these bridges gate and deliver secrets on the iOS side of your cross-platform app. There is no Android or web attestation path — on those targets the SDK is unavailable and your code should fall back accordingly.
Secrets are write-only on every platform: you set or overwrite a value in the dashboard, but the dashboard can never show a stored value back.
React Native
npm install @appattest/react-native
cd ios && pod install
import { AppAttest, useSecret } from '@appattest/react-native';
// Once, at app launch:
AppAttest.start();
// In a component — re-renders when secrets land:
function ApiView() {
const openaiKey = useSecret('OPENAI_API_KEY');
return openaiKey ? <Ready /> : <Loading />;
}
// Outside components:
await AppAttest.waitForReady();
const key = await AppAttest.getSecret('OPENAI_API_KEY'); // string | null
const all = await AppAttest.getAllSecrets(); // Record<string, string>
Observe lifecycle state with the useAppAttestState() hook.
Capacitor
npm install @appattest/capacitor
npx cap sync
import { AppAttest } from '@appattest/capacitor';
// Once, at app launch:
AppAttest.start();
// Anywhere:
await AppAttest.waitForReady();
const key = await AppAttest.getSecret('OPENAI_API_KEY'); // string | null
const all = await AppAttest.getAllSecrets();
Observe state with await AppAttest.getState() and AppAttest.addStateListener(...).
Flutter
# pubspec.yaml
dependencies:
appattest_flutter: ^0.1.0
flutter pub get
cd ios && pod install
import 'package:appattest_flutter/appattest_flutter.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
AppAttest.start();
runApp(const MyApp());
}
// Anywhere:
await AppAttest.waitForReady();
final key = await AppAttest.secret('OPENAI_API_KEY'); // String?
final all = await AppAttest.allSecrets(); // Map<String, String>
Observe state with AppAttest.stateStream.
Swift via CocoaPods
If you use CocoaPods instead of Swift Package Manager:
pod 'AppAttest'
Then use the SDK exactly as in the Quickstart. The Objective-C facade is available as pod 'AppAttestObjC' for bridge writers and Objective-C consumers; native Swift apps should depend on AppAttest. The bridges pull the iOS pods in automatically — you don’t add them yourself.
Testing without a device
App Attest needs real hardware. For simulator builds, previews, and tests, enable local stubs (one debug mode, stripped from release builds):
- React Native / Capacitor:
AppAttest.setDebugMode('local', { stubs: { OPENAI_API_KEY: 'sk-test-stub' } }) - Flutter:
AppAttest.setDebugMode(DebugMode.local, { 'OPENAI_API_KEY': 'sk-test-stub' })
Errors
Every bridge surfaces the same stable error codes: subscription_required, credits_required, attestation_rejected, service_unavailable, network, debug_mode_release_blocked, invalid_argument. Gate your UI on the observed state rather than catching on the read path.
What’s next
- Quickstart — the shared end-to-end flow (account, secrets, Apple Developer Console, entitlements).
- Apple Developer Console setup — enabling App Attest on your identifier.
- Entitlements reference — what goes in the file and why.