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

# Platform Integration Examples

> Platform-specific integration examples for embedding the P2P.org Widget via iOS, Android, React Native, and iframe

export const WidgetHeaderLinks = () => <CardGroup cols={2}>
    <Card title="Widget Demo" icon="play" href="https://demo.widget.p2p.org" horizontal />
    <Card title="Live Example" icon="link" href="https://widget.p2p.org/" horizontal />
  </CardGroup>;

<WidgetHeaderLinks />

This guide provides integration examples for embedding the P2P.org Widget across different platforms and technologies. Each platform requires specific implementation approaches while maintaining the core functionality.

## Swift (iOS)

Integrate the widget into iOS applications using WKWebView with proper wallet injection.

### Implementation

* Use `WKWebView` with unique client url
* `injected` in `window` must be initialized with your wallet

### Code Example

```swift theme={null}
// A simple widget scene that displays web content in a SwiftUI view
public struct WidgetScene: View {
    @Environment(\.dismiss) private var dismiss

    private let url: URL
    private let title: String

    public init(url: URL, title: String) {
        self.url = url
        self.title = title
    }

    public var body: some View {
        VStack(spacing: 0) {
            WebView(url: url)
                .navigationBarTitle(title, displayMode: .inline)
        }
        .background(Colors.background)
    }
}

fileprivate struct WebView: UIViewRepresentable {
    let url: URL

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.navigationDelegate = context.coordinator
        webView.allowsBackForwardNavigationGestures = true
        return webView
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        let request = URLRequest(url: url)
        webView.load(request)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: WebView

        init(_ parent: WebView) {
            self.parent = parent
        }

        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            // Here must be JS injection of your wallet
            // You can check example of implementation in opensource, like here
            // https://github.com/AlphaWallet/alpha-wallet-ios/blob/master/modules/AlphaWalletBrowser/AlphaWalletBrowser/WKWebViewConfiguration.swift
        }
    }
}
```

### View Model

```swift theme={null}
/// A simple view model for widget scenes
public struct WidgetViewModel {
    private let urlString: String
    private let widgetTitle: String

    public init(urlString: String, title: String) {
        self.urlString = urlString
        self.widgetTitle = title
    }

    /// The URL to load in the widget
    public var url: URL {
        guard let url = URL(string: urlString) else {
            // Fallback to a default URL if the provided string is invalid
            return URL(string: "https://url_of_widget_instance/")!
        }
        return url
    }

    /// The title to display in the navigation bar
    public var title: String {
        return widgetTitle
    }
}
```

## Kotlin (Android)

Integrate the widget into Android applications using WebView with custom wallet injection.

### Implementation

* Use `WebView` with unique client url
* `injected` in `window` must be initialized with your wallet

### Activity Code

```kotlin theme={null}
import android.os.Bundle
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.activity.viewModels

class WebViewActivity : AppCompatActivity() {
    private lateinit var webView: WebView
    private val viewModel: WebViewViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_webview)

        webView = findViewById(R.id.webView)
        setupWebView()

        val url = viewModel.url
        webView.loadUrl(url.toString())
    }

    private fun setupWebView() {
        webView.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
                view?.loadUrl(request?.url.toString())
                return false
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                val jsCode = // Injection of your wallet with actual wallet object
                webView.evaluateJavascript(jsCode) { result ->

                }
            }
        }

        // WebView settings
        webView.settings.apply {
            javaScriptEnabled = true
            loadWithOverviewMode = true
            useWideViewPort = true
        }
    }
}
```

### View Model

```kotlin theme={null}
import android.net.Uri
import androidx.lifecycle.ViewModel

class WebViewViewModel : ViewModel() {
    private val urlString: String = "https://url_of_widget_instance/" // Your dynamic URL
    private val widgetTitle: String = "Widget Title" // The widget title

    val url: Uri
        get() = Uri.parse(urlString)

    val title: String
        get() = widgetTitle
}
```

### Layout XML

```xml theme={null}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
```

## React Native

Integrate the widget into React Native applications using react-native-webview.

### Implementation

* Use `WebView` with unique client url
* `injected` in `window` must be initialized with your wallet

### Code Example

```tsx theme={null}
import React, { useEffect, useRef } from "react";
import { View, Text, StyleSheet } from "react-native";
import { WebView } from "react-native-webview";

const WebViewScreen = () => {
  // Ref to interact with the WebView
  const webViewRef = useRef(null);

  const url = "https://url_of_widget_instance/";

  // UseEffect to inject JS after the page has loaded
  const onLoadEnd = () => {
    const jsCode = `
      // Injection of your wallet with actual wallet object
    `;
    // Inject JavaScript after page load
    if (webViewRef.current) {
      webViewRef.current.injectJavaScript(jsCode);
    }
  };

  return (
    <View>
      <WebView
        ref={webViewRef}
        source={{ uri: url }}
        style={styles.webview}
        javaScriptEnabled={true}
        onLoadEnd={onLoadEnd} // Trigger JS injection after page load
        startInLoadingState={true}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  webview: {
    flex: 1,
  },
});

export default WebViewScreen;
```

## Web Integration (No Custom Wallet)

For web applications where you don't need custom wallet integration, use a simple iframe approach.

### Implementation

* Use `iframe` with unique client url
* For wallet connection, RainbowKit is used internally

### Code Example

```html theme={null}
<iframe src="https://url_of_widget_instance/" frameborder="0" width="100%" height="100%" />
```

### Sending events from host to widget (postMessage)

If you embed the widget via an iframe and need to notify it about host-side events (e.g. **theme change**), use `postMessage`.

**Host → widget message format:**

```js theme={null}
iframeEl.contentWindow?.postMessage(
  { scope: "p2p-widget", type: "setTheme", payload: { theme: "dark" } },
  "https://url_of_widget_instance",
);
```

**Supported message types:**

* `setTheme` with payload `{ theme: "light" | "dark" }`

**Security / origin allowlist:**

The widget validates `event.origin`. Configure allowed origins contacting our team.

### Responsive Integration

```html theme={null}
<div style="position: relative; width: 100%; height: 600px;">
  <iframe
    src="https://url_of_widget_instance/"
    frameborder="0"
    style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
    allowfullscreen
  />
</div>
```

## Security Considerations

When integrating the widget across platforms, consider these security aspects:

### JavaScript Injection

* Always validate and sanitize any data before injecting JavaScript
* Use secure communication channels between your app and the widget
* Implement proper error handling for wallet injection failures

### Network Security

* Ensure HTTPS is used for all widget URLs
* Implement certificate pinning where possible
* Handle network failures gracefully

### Wallet Security

* Never expose private keys or sensitive wallet data
* Use secure storage mechanisms for wallet credentials
* Implement proper session management

## Testing Integration

### Platform-Specific Testing

**iOS Testing:**

* Test on different iOS versions and device sizes
* Verify WKWebView security settings
* Test wallet injection scenarios

**Android Testing:**

* Test on various Android versions and devices
* Verify WebView security configurations
* Test JavaScript bridge functionality

**React Native Testing:**

* Test on both iOS and Android platforms
* Verify WebView component behavior
* Test navigation and state management

**Web Testing:**

* Test iframe behavior across browsers
* Verify responsive design
* Test wallet connection flows

## Troubleshooting

### Common Issues

**Wallet Injection Failures:**

```javascript theme={null}
// Check if wallet injection was successful
if (typeof window.ethereum === "undefined") {
  console.error("Wallet injection failed");
  // Implement fallback or error handling
}
```

**Network Connectivity:**

```javascript theme={null}
// Handle network errors
webView.onerror = function (error) {
  console.error("WebView error:", error);
  // Show error message to user
};
```

**Cross-Platform Compatibility:**

* Ensure URLs are properly formatted for each platform
* Test deep linking and navigation flows
* Verify consistent behavior across platforms


## Related topics

- [Theme Customization](/docs/widget-theme-customization.md)
- [Widget Overview](/docs/widget-overview.md)
- [Overview](/docs/unified-api-overview.md)
- [Morpho](/docs/morpho.md)
- [P2P.ORG Documentation Hub](/index.md)
