> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go.gbgplc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FAQ

> Frequently asked questions about GBGBridge.

## General

### What iOS versions does GBGBridge support?

iOS 15.0 and later. This covers all iPhone and iPad models that support iOS 15.

### Does GBGBridge have any external dependencies?

No. GBGBridge uses only Apple system frameworks: Foundation, WebKit, Combine, SwiftUI, and AVFoundation (for `CameraDetector`). It has zero third-party dependencies.

### What Swift version is required?

Swift 5.9 or later. The framework is built with `BUILD_LIBRARY_FOR_DISTRIBUTION` enabled, which generates `.swiftinterface` files for binary module stability. This means you don't need to match the exact Swift compiler version used to build the framework.

### How is GBGBridge distributed?

As an XCFramework via Swift Package Manager (SPM). The package contains a pre-built binary target that includes slices for both iOS device (arm64) and iOS Simulator (arm64 + x86\_64).

### How large is the framework?

The GBGBridge binary is approximately 50 KB. It adds negligible size to your app.

## Integration

### Can I use GBGBridge with UIKit?

Yes. Use `BridgeWebViewConfigurator` to configure a `WKWebView` in your UIKit view controller. See the [Embedding Guide](/docs/go-v2/developer-integration/sdks/ios/embedding#uikit-integration) for details.

### Can I use multiple BridgeHost instances?

Each `BridgeHost` should be associated with one `WKWebView`. If you have multiple WebViews (e.g., multiple journey tabs), create a separate `BridgeHost` for each.

### Can I change capabilities after initialization?

With typed slots (`init(hostVersion:)`), capabilities are inherently dynamic. Set or clear `handler` to change support, toggle `isEnabled` to temporarily disable, and update `permissionState` as permissions change. The capability query response is built dynamically on each query.

With the configuration-based init, the `capabilities` dictionary is `@Published` and mutable, but the built-in `CapabilityQueryHandler` reads from a closure set at initialization. For fully dynamic capabilities in that path, replace the built-in handler with a custom one:

```swift theme={null}
host.unregister(action: "capability.query")
host.register(handler: CapabilityQueryHandler(
    capabilities: { [weak host] in host?.capabilities ?? [:] },
    hostVersion: "1.0.0"
))
```

### Do I need to handle the `capability.query` action myself?

No. `BridgeHost` automatically registers a `CapabilityQueryHandler` that responds to `capability.query` requests. With `init(hostVersion:)`, it builds the response from typed slots and custom capabilities. With `init(configuration:)`, it reads from the `BridgeConfiguration`.

### What is the difference between typed slots and custom capabilities?

**Typed slots** (`host.documentCapture`, `host.selfieCapture`) are built-in `CaptureCapability` properties for well-known capture operations. They handle result encoding, busy rejection, and permission state automatically. Handlers return `CaptureResult` values.

**Custom capabilities** (`registerCustomCapability()`) support any action. Handlers receive a `BridgeResponder` and build responses manually using `JSONValue` dictionaries. Use this for non-camera capabilities like NFC.

Both appear in `capability.query` responses. If both are registered for the same ID, the typed slot takes precedence.

### How does permission state work?

Each typed slot has a `permissionState` property (default: `.notDetermined`). Populate it using `CameraDetector.check()`:

```swift theme={null}
let camera = CameraDetector.check()
host.documentCapture.permissionState = camera.permissionState
```

This is included in the `capability.query` response as a `permissionState` field, allowing the web journey to detect permission issues before attempting capture.

### What happens if the web journey sends a request for an action I haven't registered?

The request is added to `host.pendingRequests` and `bridgeHost(_:unhandledRequest:)` is called on the delegate. You can respond to it manually via `host.respond(to:status:data:error:)`.

If you don't respond, the request sits in `pendingRequests` indefinitely. The web journey may implement its own timeout.

## Messaging

### Are messages guaranteed to be delivered?

Messages sent via the bridge are in-process or inter-process calls through WebKit. They are delivered reliably as long as:

* The WebView is attached to the host.
* The web page has not navigated away.
* `window.GBGBridge.receive` is defined on the web side.

There is no built-in retry or delivery confirmation mechanism.

### What is the maximum message size?

There is no hard limit imposed by GBGBridge. However, very large messages (e.g., multi-megabyte Base64 images) can cause memory pressure. For large data transfers, consider passing file paths instead of inline data.

### Can I send messages before the web page loads?

Messages sent before the page loads (or before the web journey sets up its `receive()` function) will be lost. The default bootstrap script creates a no-op `receive()`, so the call won't error — but the data won't be processed.

<Tip>
  Wait for a signal from the web journey (e.g., a `journey.ready` event) before sending messages.
</Tip>

### Is the message order preserved?

Messages are processed in the order they arrive. Responses are sent in the order `respond()` is called. WebKit's `evaluateJavaScript` calls are executed sequentially.

### What happens to events — does anyone respond to them?

Events are fire-and-forget. They have no expected response. Both the native host and the web journey can send events. Use events for notifications, state updates, and lifecycle signals.

## Capabilities

### How does the web journey know what capabilities are available?

The web journey sends a `capability.query` request. The built-in handler responds with the environment (`"ios"`), host version, and a map of all declared capabilities with their `supported` status, `version`, and optionally `permissionState`.

### What if a capability is hardware-dependent?

For camera capabilities, use `CameraDetector.check()` and conditionally set the handler:

```swift theme={null}
let camera = CameraDetector.check()
if camera.hardwareAvailable {
    host.documentCapture.handler = { ... }
    host.documentCapture.permissionState = camera.permissionState
}
```

For NFC, check at initialization time:

```swift theme={null}
import CoreNFC

if NFCTagReaderSession.readingAvailable {
    host.registerCustomCapability("nfc.read", version: "1.0") { request, responder in
        // Handle NFC
    }
}
```

### What NFC entitlements do I need?

To use NFC in your host app:

1. Add the **Near Field Communication Tag Reading** capability in Xcode.
2. Include `com.apple.developer.nfc.readersession.formats` in your entitlements.
3. Add `NSNFCReaderUsageDescription` to Info.plist.

GBGBridge itself does not require these — they are only needed if your NFC handler calls `CoreNFC` APIs.

## Security

### Is communication between the host and web journey encrypted?

Communication uses WebKit's internal IPC mechanism. It does not traverse the network, so TLS is not applicable. Messages are memory-to-memory within the device.

### Can other apps intercept bridge messages?

No. The WebView runs within your app's sandbox. The script message handler channel is private to your app process.

### Should I validate incoming message data?

Yes. Treat data from the web journey the same way you would treat user input. Validate required fields, check value ranges, and reject malformed requests.

## Debugging

### How do I see what messages are being exchanged?

Use the `BridgeHostDelegate` to log all messages:

```swift theme={null}
func bridgeHost(_ host: BridgeHost, didReceive message: BridgeMessage) {
    print("[\(message.type.rawValue)] \(message.payload.action)")
}
```

Or observe `host.$receivedMessages` via Combine.

### Can I use Safari Web Inspector?

Yes. Enable Web Inspector on your device (Settings → Safari → Advanced → Web Inspector), connect to a Mac, and inspect the WebView from Safari's Develop menu. You can examine `window.GBGBridge` and test messages from the console.

### Why do I see "WebView not attached" errors?

The `BridgeHost` holds a weak reference to the WebView. If the WebView is deallocated, sending messages will produce this error. Ensure the WebView's lifetime matches or exceeds the host's lifetime.

## Next Steps

* [Getting Started](/docs/go-v2/developer-integration/sdks/ios/getting-started) — First integration walkthrough
* [Troubleshooting](/docs/go-v2/developer-integration/sdks/ios/troubleshooting) — Detailed issue resolution
* [API Reference](/docs/go-v2/developer-integration/sdks/ios/api-reference) — Complete type reference
